diff --git a/GNUmakefile b/GNUmakefile index bce3b4a..dfbf4d7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -4,6 +4,7 @@ default: testacc .PHONY: testacc testacc: docker rm -f remotehost + docker rm -f remotehost2 docker network rm remote || true docker network create remote docker build -t remotehost tests diff --git a/docs/data-sources/file.md b/docs/data-sources/file.md index 24c506d..26a89ab 100644 --- a/docs/data-sources/file.md +++ b/docs/data-sources/file.md @@ -52,6 +52,7 @@ data "remote_file" "server2_hosts" { ### Read-Only - **content** (String) Content of file. +- **result_conn** (List of Object) Result of applying provider's `conn` as default to optional `conn` (see [below for nested schema](#nestedatt--result_conn)) ### Nested Schema for `conn` @@ -71,3 +72,18 @@ Optional: - **sudo** (Boolean) Use sudo to gain access to file. Defaults to `false`. + +### Nested Schema for `result_conn` + +Read-Only: + +- **host** (String) +- **password** (String) +- **port** (Number) +- **private_key** (String) +- **private_key_env_var** (String) +- **private_key_path** (String) +- **sudo** (Boolean) +- **user** (String) + + diff --git a/docs/resources/file.md b/docs/resources/file.md index 4fae84f..352691c 100644 --- a/docs/resources/file.md +++ b/docs/resources/file.md @@ -57,6 +57,10 @@ resource "remote_file" "server2_bashrc" { - **id** (String) The ID of this resource. - **permissions** (String) Permissions of file. Defaults to `0644`. +### Read-Only + +- **result_conn** (List of Object) Computed conn for handling default functionality. (see [below for nested schema](#nestedatt--result_conn)) + ### Nested Schema for `conn` @@ -75,3 +79,18 @@ Optional: - **sudo** (Boolean) Use sudo to gain access to file. Defaults to `false`. + +### Nested Schema for `result_conn` + +Read-Only: + +- **host** (String) +- **password** (String) +- **port** (Number) +- **private_key** (String) +- **private_key_env_var** (String) +- **private_key_path** (String) +- **sudo** (Boolean) +- **user** (String) + + diff --git a/internal/provider/connection.go b/internal/provider/connection.go index ea4afd1..a0e7959 100644 --- a/internal/provider/connection.go +++ b/internal/provider/connection.go @@ -60,22 +60,22 @@ var connectionSchemaResource = &schema.Resource{ } func ConnectionFromResourceData(d *schema.ResourceData) (string, *ssh.ClientConfig, error) { - _, ok := d.GetOk("conn") + _, ok := d.GetOk("result_conn") if !ok { return "", nil, fmt.Errorf("resouce does not have a connection configured") } clientConfig := ssh.ClientConfig{ - User: d.Get("conn.0.user").(string), + User: d.Get("result_conn.0.user").(string), HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - password, ok := d.GetOk("conn.0.password") + password, ok := d.GetOk("result_conn.0.password") if ok { clientConfig.Auth = append(clientConfig.Auth, ssh.Password(password.(string))) } - private_key, ok := d.GetOk("conn.0.private_key") + private_key, ok := d.GetOk("result_conn.0.private_key") if ok { signer, err := ssh.ParsePrivateKey([]byte(private_key.(string))) if err != nil { @@ -84,7 +84,7 @@ func ConnectionFromResourceData(d *schema.ResourceData) (string, *ssh.ClientConf clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer)) } - private_key_path, ok := d.GetOk("conn.0.private_key_path") + private_key_path, ok := d.GetOk("result_conn.0.private_key_path") if ok { content, err := ioutil.ReadFile(private_key_path.(string)) if err != nil { @@ -97,7 +97,7 @@ func ConnectionFromResourceData(d *schema.ResourceData) (string, *ssh.ClientConf clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer)) } - private_key_env_var, ok := d.GetOk("conn.0.private_key_env_var") + private_key_env_var, ok := d.GetOk("result_conn.0.private_key_env_var") if ok { private_key := os.Getenv(private_key_env_var.(string)) signer, err := ssh.ParsePrivateKey([]byte(private_key)) @@ -107,6 +107,6 @@ func ConnectionFromResourceData(d *schema.ResourceData) (string, *ssh.ClientConf clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer)) } - host := fmt.Sprintf("%s:%d", d.Get("conn.0.host").(string), d.Get("conn.0.port").(int)) + host := fmt.Sprintf("%s:%d", d.Get("result_conn.0.host").(string), d.Get("result_conn.0.port").(int)) return host, &clientConfig, nil } diff --git a/internal/provider/data_source_remote_file.go b/internal/provider/data_source_remote_file.go index 9c40d61..f1584e4 100644 --- a/internal/provider/data_source_remote_file.go +++ b/internal/provider/data_source_remote_file.go @@ -22,6 +22,12 @@ func dataSourceRemoteFile() *schema.Resource { Description: "Connection to host where files are located.", Elem: connectionSchemaResource, }, + "result_conn": { + Type: schema.TypeList, + Computed: true, + Description: "Result of applying provider's `conn` as default to optional `conn`", + Elem: connectionSchemaResource, + }, "path": { Description: "Path to file on remote host.", Type: schema.TypeString, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a3df8ec..53d1583 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -83,27 +83,24 @@ func configure(version string, p *schema.Provider) func(context.Context, *schema } } -func (c *apiClient) connectionResourceData(d *schema.ResourceData) (*schema.ResourceData, error) { - _, ok := d.GetOk("conn") +func (c *apiClient) applyResultConn(d *schema.ResourceData) (*schema.ResourceData, error) { + conn, ok := d.GetOk("conn") if ok { + d.Set("result_conn", conn) return d, nil } - _, ok = c.resourceData.GetOk("conn") + conn, ok = c.resourceData.GetOk("conn") if ok { - return c.resourceData, nil + d.Set("result_conn", conn) + return d, nil } return nil, errors.New("neither the provider nor the resource/data source have a configured connection") } func (c *apiClient) getRemoteClient(d *schema.ResourceData) (*RemoteClient, error) { - resourceData, err := c.connectionResourceData(d) - if err != nil { - return nil, err - } - - connectionID := resourceConnectionHash(resourceData) + connectionID := resourceConnectionHash(d) defer c.mux.Unlock() for { c.mux.Lock() @@ -119,7 +116,7 @@ func (c *apiClient) getRemoteClient(d *schema.ResourceData) (*RemoteClient, erro return client, nil } - client, err = remoteClientFromResourceData(resourceData) + client, err := remoteClientFromResourceData(d) if err != nil { return nil, err } @@ -139,12 +136,7 @@ func remoteClientFromResourceData(d *schema.ResourceData) (*RemoteClient, error) } func (c *apiClient) closeRemoteClient(d *schema.ResourceData) error { - resourceData, err := c.connectionResourceData(d) - if err != nil { - return err - } - - connectionID := resourceConnectionHash(resourceData) + connectionID := resourceConnectionHash(d) c.mux.Lock() defer c.mux.Unlock() @@ -160,12 +152,12 @@ func (c *apiClient) closeRemoteClient(d *schema.ResourceData) error { func resourceConnectionHash(d *schema.ResourceData) string { elements := []string{ - d.Get("conn.0.host").(string), - d.Get("conn.0.user").(string), - strconv.Itoa(d.Get("conn.0.port").(int)), - resourceStringWithDefault(d, "conn.0.password", ""), - resourceStringWithDefault(d, "conn.0.private_key", ""), - resourceStringWithDefault(d, "conn.0.private_key_path", ""), + d.Get("result_conn.0.host").(string), + d.Get("result_conn.0.user").(string), + strconv.Itoa(d.Get("result_conn.0.port").(int)), + resourceStringWithDefault(d, "result_conn.0.password", ""), + resourceStringWithDefault(d, "result_conn.0.private_key", ""), + resourceStringWithDefault(d, "result_conn.0.private_key_path", ""), } return strings.Join(elements, "::") } diff --git a/internal/provider/resource_remote_file.go b/internal/provider/resource_remote_file.go index 017be10..f6e527b 100644 --- a/internal/provider/resource_remote_file.go +++ b/internal/provider/resource_remote_file.go @@ -26,6 +26,12 @@ func resourceRemoteFile() *schema.Resource { Description: "Connection to host where files are located.", Elem: connectionSchemaResource, }, + "result_conn": { + Type: schema.TypeList, + Computed: true, + Description: "Computed conn for handling default functionality.", + Elem: connectionSchemaResource, + }, "path": { Description: "Path to file on remote host.", Type: schema.TypeString, @@ -50,18 +56,19 @@ func resourceRemoteFile() *schema.Resource { } func resourceRemoteFileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - connectionResourceData, err := meta.(*apiClient).connectionResourceData(d) + d, err := meta.(*apiClient).applyResultConn(d) if err != nil { return diag.Errorf(err.Error()) } - d.SetId(fmt.Sprintf("%s:%s", connectionResourceData.Get("conn.0.host").(string), d.Get("path").(string))) + + d.SetId(fmt.Sprintf("%s:%s", d.Get("result_conn.0.host").(string), d.Get("path").(string))) client, err := meta.(*apiClient).getRemoteClient(d) if err != nil { return diag.Errorf("error while opening remote client: %s", err.Error()) } - sudo, ok := d.GetOk("conn.0.sudo") + sudo, ok := d.GetOk("result_conn.0.sudo") if ok && sudo.(bool) { err := client.WriteFileSudo(d) if err != nil { @@ -87,18 +94,19 @@ func resourceRemoteFileCreate(ctx context.Context, d *schema.ResourceData, meta } func resourceRemoteFileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - connectionResourceData, err := meta.(*apiClient).connectionResourceData(d) + d, err := meta.(*apiClient).applyResultConn(d) if err != nil { return diag.Errorf(err.Error()) } - d.SetId(fmt.Sprintf("%s:%s", connectionResourceData.Get("conn.0.host").(string), d.Get("path").(string))) + + d.SetId(fmt.Sprintf("%s:%s", d.Get("result_conn.0.host").(string), d.Get("path").(string))) client, err := meta.(*apiClient).getRemoteClient(d) if err != nil { return diag.Errorf("error while opening remote client: %s", err.Error()) } - sudo, ok := d.GetOk("conn.0.sudo") + sudo, ok := d.GetOk("result_conn.0.sudo") if ok && sudo.(bool) { exists, err := client.FileExistsSudo(d) if err != nil { @@ -132,12 +140,17 @@ func resourceRemoteFileUpdate(ctx context.Context, d *schema.ResourceData, meta } func resourceRemoteFileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d, err := meta.(*apiClient).applyResultConn(d) + if err != nil { + return diag.Errorf(err.Error()) + } + client, err := meta.(*apiClient).getRemoteClient(d) if err != nil { return diag.Errorf("error while opening remote client: %s", err.Error()) } - sudo, ok := d.GetOk("conn.0.sudo") + sudo, ok := d.GetOk("result_conn.0.sudo") if ok && sudo.(bool) { exists, err := client.FileExistsSudo(d) if err != nil {