Skip to content

Commit

Permalink
Support sudo
Browse files Browse the repository at this point in the history
  • Loading branch information
tenstad committed May 3, 2021
1 parent db85d8a commit 69c3b85
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 49 deletions.
8 changes: 4 additions & 4 deletions examples/data-sources/remotefile_data_source/data-source.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
data "remotefile" "bar" {
conn {
host = "foo.com"
port = "22"
username = "foo"
private_key = "<ssh private key>"
host = "foo.com"
port = 22
username = "foo"
password = "<password>"
}
path = "/tmp/bar.txt"
}
3 changes: 2 additions & 1 deletion examples/resources/remotefile_resource/resource.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
resource "remotefile" "foo" {
conn {
host = "foo.com"
port = "22"
port = 22
username = "foo"
sudo = true
private_key = "<ssh private key>"
}
path = "/tmp/foo.txt"
Expand Down
6 changes: 6 additions & 0 deletions internal/provider/data_source_remotefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ func dataSourceRemotefile() *schema.Resource {
Required: true,
Description: "The username on the target host.",
},
"sudo": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Use sudo to gain access to read file.",
},
"password": {
Type: schema.TypeString,
Optional: true,
Expand Down
127 changes: 127 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package provider

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"strings"

"github.com/bramvdbogaerde/go-scp"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -98,6 +100,131 @@ func newClient(d *schema.ResourceData) (*apiClient, error) {
return &client, nil
}

func (c *apiClient) writeFile(d *schema.ResourceData) error {
scpClient, err := c.getSCPClient()
if err != nil {
return err
}
defer scpClient.Close()

return scpClient.CopyFile(strings.NewReader(d.Get("content").(string)), d.Get("path").(string), d.Get("permissions").(string))
}

func (c *apiClient) writeFileSudo(d *schema.ResourceData) error {
sshClient, err := c.getSSHClient()
if err != nil {
return err
}

session, err := sshClient.NewSession()
if err != nil {
return err
}
defer session.Close()

stdin, err := session.StdinPipe()
if err != nil {
return err
}

content := d.Get("content").(string)
go func() {
stdin.Write([]byte(content))
stdin.Close()
}()

cmd := fmt.Sprint("cat /dev/stdin | sudo tee ", d.Get("path").(string))
return session.Run(cmd)
}

func (c *apiClient) chmodFileSudo(d *schema.ResourceData) error {
sshClient, err := c.getSSHClient()
if err != nil {
return err
}

session, err := sshClient.NewSession()
if err != nil {
return err
}
defer session.Close()

cmd := fmt.Sprintf("sudo chmod %s %s", d.Get("permissions").(string), d.Get("path").(string))
return session.Run(cmd)
}

func (c *apiClient) readFile(d *schema.ResourceData) error {
sftpClient, err := c.getSFTPClient()
if err != nil {
return err
}
defer sftpClient.Close()

file, err := sftpClient.Open(d.Get("path").(string))
if err != nil {
return err
}
defer file.Close()

content := bytes.Buffer{}
_, err = file.WriteTo(&content)

if err != nil {
return err
}

d.Set("content", string(content.String()))
return nil
}

func (c *apiClient) readFileSudo(d *schema.ResourceData) error {
sshClient, err := c.getSSHClient()
if err != nil {
return err
}

session, err := sshClient.NewSession()
if err != nil {
return err
}
defer session.Close()

cmd := fmt.Sprint("sudo cat ", d.Get("path").(string))
content, err := session.Output(cmd)
if err != nil {
return err
}

d.Set("content", string(content))
return nil
}

func (c *apiClient) deleteFile(d *schema.ResourceData) error {
sftpClient, err := c.getSFTPClient()
if err != nil {
return err
}
defer sftpClient.Close()

return sftpClient.Remove(d.Get("path").(string))
}

func (c *apiClient) deleteFileSudo(d *schema.ResourceData) error {
sshClient, err := c.getSSHClient()
if err != nil {
return err
}

session, err := sshClient.NewSession()
if err != nil {
return err
}
defer session.Close()

cmd := fmt.Sprint("sudo cat ", d.Get("path").(string))
return session.Run(cmd)
}

func (c apiClient) getSSHClient() (*ssh.Client, error) {
sshClient, err := ssh.Dial("tcp", c.host, &c.clientConfig)
if err != nil {
Expand Down
83 changes: 43 additions & 40 deletions internal/provider/resource_remotefile.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package provider

import (
"bytes"
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -42,6 +40,12 @@ func resourceRemotefile() *schema.Resource {
Required: true,
Description: "The username on the target host.",
},
"sudo": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Use sudo to gain access to read/write file.",
},
"password": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -90,16 +94,21 @@ func resourceRemotefileCreate(ctx context.Context, d *schema.ResourceData, meta
return diag.Errorf(err.Error())
}

scpClient, err := client.getSCPClient()
if err != nil {
return diag.Errorf(err.Error())
}
defer scpClient.Close()

err = scpClient.CopyFile(strings.NewReader(d.Get("content").(string)), d.Get("path").(string), d.Get("permissions").(string))

if err != nil {
return diag.Errorf("error while copying file: %s", err.Error())
sudo, ok := d.GetOk("conn.0.sudo")
if ok && sudo.(bool) {
err := client.writeFileSudo(d)
if err != nil {
return diag.Errorf("error while creating remote file with sudo: %s", err.Error())
}
err = client.chmodFileSudo(d)
if err != nil {
return diag.Errorf("error while changing permissions of remote file with sudo: %s", err.Error())
}
} else {
err := client.writeFile(d)
if err != nil {
return diag.Errorf("error while creating remote file: %s", err.Error())
}
}

return diag.Diagnostics{}
Expand All @@ -113,26 +122,18 @@ func resourceRemotefileRead(ctx context.Context, d *schema.ResourceData, meta in
return diag.Errorf(err.Error())
}

sftpClient, err := client.getSFTPClient()
if err != nil {
return diag.Errorf(err.Error())
sudo, ok := d.GetOk("conn.0.sudo")
if ok && sudo.(bool) {
err := client.readFileSudo(d)
if err != nil {
return diag.Errorf("error while removing remote file with sudo: %s", err.Error())
}
} else {
err := client.readFile(d)
if err != nil {
return diag.Errorf("error while removing remote file: %s", err.Error())
}
}
defer sftpClient.Close()

file, err := sftpClient.Open(d.Get("path").(string))
if err != nil {
return diag.Errorf("error while opening remote file: %s", err.Error())
}
defer file.Close()

content := bytes.Buffer{}
_, err = file.WriteTo(&content)

if err != nil {
return diag.Errorf("error while reading remote file: %s", err.Error())
}

d.Set("content", string(content.String()))

return diag.Diagnostics{}
}
Expand All @@ -147,15 +148,17 @@ func resourceRemotefileDelete(ctx context.Context, d *schema.ResourceData, meta
return diag.Errorf(err.Error())
}

sftpClient, err := client.getSFTPClient()
if err != nil {
return diag.Errorf(err.Error())
}
defer sftpClient.Close()

err = sftpClient.Remove(d.Get("path").(string))
if err != nil {
return diag.Errorf("error while removing remote file: %s", err.Error())
sudo, ok := d.GetOk("conn.0.sudo")
if ok && sudo.(bool) {
err := client.deleteFileSudo(d)
if err != nil {
return diag.Errorf("error while removing remote file with sudo: %s", err.Error())
}
} else {
err := client.deleteFile(d)
if err != nil {
return diag.Errorf("error while removing remote file: %s", err.Error())
}
}

return diag.Diagnostics{}
Expand Down
5 changes: 3 additions & 2 deletions internal/provider/resource_remotefile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ func TestAccResourceRemotefile(t *testing.T) {
const testAccResourceRemotefile = `
resource "remotefile" "foo" {
conn {
host = "localhost"
host = "terraform-provider-remotefile-test"
username = "root"
sudo = true
password = "password"
port = 8022
port = 22
}
path = "/tmp/foo.txt"
content = "bar"
Expand Down
3 changes: 2 additions & 1 deletion tests/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM alpine:latest

RUN apk add --no-cache \
openssh \
bash \
openssh \
sudo \
&& ssh-keygen -A \
&& sed -i "s/#\?PermitRootLogin.*/PermitRootLogin yes/" /etc/ssh/sshd_config \
&& mkdir /root/.ssh \
Expand Down
2 changes: 1 addition & 1 deletion tests/run.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ssh-keygen -f "$HOME/.ssh/known_hosts" -R "[localhost]:8022"
docker build -t terraform-provider-remotefile-test .
docker run --rm -d -p 8022:22 terraform-provider-remotefile-test
docker run --rm -d -p 8022:22 --name terraform-provider-remotefile-test terraform-provider-remotefile-test

0 comments on commit 69c3b85

Please sign in to comment.