From d5e501c65b63b748858db95b239d84f3f0e24e76 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 16 Apr 2025 09:12:51 +0200 Subject: [PATCH] feat: Implement upload permissions in docker_container resource (#693) --- .../provider/resource_docker_container.go | 7 ++ .../resource_docker_container_funcs.go | 9 ++- .../resource_docker_container_test.go | 69 +++++++++++-------- ...cDockerContainerUploadConfigPermissions.tf | 15 ++++ 4 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 testdata/resources/docker_container/testAccDockerContainerUploadConfigPermissions.tf diff --git a/internal/provider/resource_docker_container.go b/internal/provider/resource_docker_container.go index fe2547e4..f4fc64fd 100644 --- a/internal/provider/resource_docker_container.go +++ b/internal/provider/resource_docker_container.go @@ -820,6 +820,13 @@ func resourceDockerContainer() *schema.Resource { Optional: true, ForceNew: true, }, + "permissions": { + Type: schema.TypeString, + Description: "The permission mode for the file in the container. Has precedence over `executable`.", + Optional: true, + ForceNew: true, + ValidateDiagFunc: validateStringMatchesPattern(`^0[0-7]{3}$`), + }, "source": { Type: schema.TypeString, Description: "A filename that references a file which will be uploaded as the object content. This allows for large file uploads that do not get stored in state. Conflicts with `content` & `content_base64`", diff --git a/internal/provider/resource_docker_container_funcs.go b/internal/provider/resource_docker_container_funcs.go index 7b66ca5f..ebffcc73 100644 --- a/internal/provider/resource_docker_container_funcs.go +++ b/internal/provider/resource_docker_container_funcs.go @@ -12,6 +12,7 @@ import ( "log" "math/big" "os" + "strconv" "strings" "time" @@ -475,10 +476,16 @@ func resourceDockerContainerCreate(ctx context.Context, d *schema.ResourceData, } file := upload.(map[string]interface{})["file"].(string) executable := upload.(map[string]interface{})["executable"].(bool) + permission := upload.(map[string]interface{})["permissions"].(string) buf := new(bytes.Buffer) tw := tar.NewWriter(buf) - if executable { + if permission != "" { + mode, err = strconv.ParseInt(permission, 8, 32) + if err != nil { + return diag.Errorf("Error parsing permission: %s", err) + } + } else if executable { mode = 0o744 } else { mode = 0o644 diff --git a/internal/provider/resource_docker_container_test.go b/internal/provider/resource_docker_container_test.go index 16567ecf..87f87c4f 100644 --- a/internal/provider/resource_docker_container_test.go +++ b/internal/provider/resource_docker_container_test.go @@ -675,40 +675,42 @@ func testAccCheckSwapLimit(t *testing.T) { } } -func TestAccDockerContainer_upload(t *testing.T) { +func TestAccDockerContainer_uploadPermission(t *testing.T) { var c types.ContainerJSON ctx := context.Background() - testCheck := func(*terraform.State) error { - client := testAccProvider.Meta().(*ProviderConfig).DockerClient + testCheck := func(expected_mode string) func(*terraform.State) error { + return func(*terraform.State) error { + client := testAccProvider.Meta().(*ProviderConfig).DockerClient - srcPath := "/terraform/test.txt" - r, _, err := client.CopyFromContainer(ctx, c.ID, srcPath) - if err != nil { - return fmt.Errorf("Unable to download a file from container: %s", err) - } - - tr := tar.NewReader(r) - if header, err := tr.Next(); err != nil { - return fmt.Errorf("Unable to read content of tar archive: %s", err) - } else { - mode := strconv.FormatInt(header.Mode, 8) - if !strings.HasSuffix(mode, "744") { - return fmt.Errorf("File permissions are incorrect: %s", mode) + srcPath := "/terraform/test.txt" + r, _, err := client.CopyFromContainer(ctx, c.ID, srcPath) + if err != nil { + return fmt.Errorf("Unable to download a file from container: %s", err) } - } - fbuf := new(bytes.Buffer) - if _, err := fbuf.ReadFrom(tr); err != nil { - return err - } - content := fbuf.String() + tr := tar.NewReader(r) + if header, err := tr.Next(); err != nil { + return fmt.Errorf("Unable to read content of tar archive: %s", err) + } else { + mode := strconv.FormatInt(header.Mode, 8) + if !strings.HasSuffix(mode, expected_mode) { + return fmt.Errorf("File permissions are incorrect: %s", mode) + } + } - if content != "foo" { - return fmt.Errorf("file content is invalid") - } + fbuf := new(bytes.Buffer) + if _, err := fbuf.ReadFrom(tr); err != nil { + return err + } + content := fbuf.String() - return nil + if content != "foo" { + return fmt.Errorf("file content is invalid") + } + + return nil + } } resource.Test(t, resource.TestCase{ @@ -719,7 +721,7 @@ func TestAccDockerContainer_upload(t *testing.T) { Config: loadTestConfiguration(t, RESOURCE, "docker_container", "testAccDockerContainerUploadConfig"), Check: resource.ComposeTestCheckFunc( testAccContainerRunning("docker_container.foo", &c), - testCheck, + testCheck("744"), resource.TestCheckResourceAttr("docker_container.foo", "name", "tf-test"), resource.TestCheckResourceAttr("docker_container.foo", "upload.#", "1"), resource.TestCheckResourceAttr("docker_container.foo", "upload.0.content", "foo"), @@ -728,6 +730,19 @@ func TestAccDockerContainer_upload(t *testing.T) { resource.TestCheckResourceAttr("docker_container.foo", "upload.0.file", "/terraform/test.txt"), ), }, + { + Config: loadTestConfiguration(t, RESOURCE, "docker_container", "testAccDockerContainerUploadConfigPermissions"), + Check: resource.ComposeTestCheckFunc( + testAccContainerRunning("docker_container.foo", &c), + testCheck("600"), + resource.TestCheckResourceAttr("docker_container.foo", "name", "tf-test"), + resource.TestCheckResourceAttr("docker_container.foo", "upload.#", "1"), + resource.TestCheckResourceAttr("docker_container.foo", "upload.0.content", "foo"), + resource.TestCheckResourceAttr("docker_container.foo", "upload.0.content_base64", ""), + resource.TestCheckResourceAttr("docker_container.foo", "upload.0.permissions", "0600"), + resource.TestCheckResourceAttr("docker_container.foo", "upload.0.file", "/terraform/test.txt"), + ), + }, }, }) } diff --git a/testdata/resources/docker_container/testAccDockerContainerUploadConfigPermissions.tf b/testdata/resources/docker_container/testAccDockerContainerUploadConfigPermissions.tf new file mode 100644 index 00000000..edd4913d --- /dev/null +++ b/testdata/resources/docker_container/testAccDockerContainerUploadConfigPermissions.tf @@ -0,0 +1,15 @@ +resource "docker_image" "foo" { + name = "nginx:latest" + keep_locally = true +} + +resource "docker_container" "foo" { + name = "tf-test" + image = docker_image.foo.image_id + + upload { + content = "foo" + file = "/terraform/test.txt" + permissions = "0600" + } +}