From 08c0b48e9785dedc5d658d96ff7a10d994b4184f Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Thu, 2 Jul 2020 14:38:59 -0400 Subject: [PATCH 1/9] Added support for copy file to container --- container.go | 2 ++ docker.go | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/container.go b/container.go index 044dbfa3ee..105e16d1ca 100644 --- a/container.go +++ b/container.go @@ -49,6 +49,8 @@ type Container interface { NetworkAliases(context.Context) (map[string][]string, error) // get container network aliases for a network Exec(ctx context.Context, cmd []string) (int, error) ContainerIP(context.Context) (string, error) // get container ip + CopyToContainer(ctx context.Context, containerPath string, content io.Reader) error + CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent string, fileMode int64) error } // ImageBuildInfo defines what is needed to build an image diff --git a/docker.go b/docker.go index ba8fd741cd..029f8d8998 100644 --- a/docker.go +++ b/docker.go @@ -1,6 +1,7 @@ package testcontainers import ( + "archive/tar" "bytes" "context" "encoding/binary" @@ -306,6 +307,31 @@ func (c *DockerContainer) Exec(ctx context.Context, cmd []string) (int, error) { return exitCode, nil } +func (c *DockerContainer) CopyToContainer(ctx context.Context, containerPath string, content io.Reader) error { + return c.provider.client.CopyToContainer(ctx, c.ID, containerPath, content, types.CopyToContainerOptions{}) +} + +func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent string, fileMode int64) error { + buffer := &bytes.Buffer{} + + tw := tar.NewWriter(buffer) + defer tw.Close() + + hdr := &tar.Header{ + Name: fileName, + Mode: fileMode, + Size: int64(len(fileContent)), + } + if err := tw.WriteHeader(hdr); err !=nil { + return err + } + if _, err := tw.Write([]byte(fileContent)); err != nil { + return err + } + + return c.CopyToContainer(ctx, containerPath, buffer) +} + // StartLogProducer will start a concurrent process that will continuously read logs // from the container and will send them to each added LogConsumer func (c *DockerContainer) StartLogProducer(ctx context.Context) error { From d5ae5993807cddb91993befdb8c16f8b0db95e65 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Fri, 10 Jul 2020 10:26:45 -0400 Subject: [PATCH 2/9] Fix fmt --- docker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker.go b/docker.go index 029f8d8998..6bc106b7be 100644 --- a/docker.go +++ b/docker.go @@ -322,7 +322,7 @@ func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath Mode: fileMode, Size: int64(len(fileContent)), } - if err := tw.WriteHeader(hdr); err !=nil { + if err := tw.WriteHeader(hdr); err != nil { return err } if _, err := tw.Write([]byte(fileContent)); err != nil { From 1ca2158ed14bb639865ba8085d92399743a40629 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Fri, 10 Jul 2020 11:04:15 -0400 Subject: [PATCH 3/9] Updated copy to container signature and added test --- container.go | 2 +- docker.go | 4 ++-- docker_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/container.go b/container.go index 105e16d1ca..f98ed064f1 100644 --- a/container.go +++ b/container.go @@ -50,7 +50,7 @@ type Container interface { Exec(ctx context.Context, cmd []string) (int, error) ContainerIP(context.Context) (string, error) // get container ip CopyToContainer(ctx context.Context, containerPath string, content io.Reader) error - CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent string, fileMode int64) error + CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error } // ImageBuildInfo defines what is needed to build an image diff --git a/docker.go b/docker.go index 6bc106b7be..a02f0a3f69 100644 --- a/docker.go +++ b/docker.go @@ -311,7 +311,7 @@ func (c *DockerContainer) CopyToContainer(ctx context.Context, containerPath str return c.provider.client.CopyToContainer(ctx, c.ID, containerPath, content, types.CopyToContainerOptions{}) } -func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent string, fileMode int64) error { +func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error { buffer := &bytes.Buffer{} tw := tar.NewWriter(buffer) @@ -325,7 +325,7 @@ func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath if err := tw.WriteHeader(hdr); err != nil { return err } - if _, err := tw.Write([]byte(fileContent)); err != nil { + if _, err := tw.Write(fileContent); err != nil { return err } diff --git a/docker_test.go b/docker_test.go index 5a6c27db8d..a748e33561 100644 --- a/docker_test.go +++ b/docker_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io/ioutil" "net/http" "path/filepath" "testing" @@ -1267,3 +1268,31 @@ func TestContainerNonExistentImage(t *testing.T) { }) } + +func TestDockerContainerCopyFileToContainer(t *testing.T) { + ctx := context.Background() + + nginxC, err := GenericContainer(ctx, GenericContainerRequest{ + ContainerRequest: ContainerRequest{ + Image: "nginx:1.17.6", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForListeningPort("80/tcp"), + }, + Started: true, + }) + defer nginxC.Terminate(ctx) + + fileContent, err := ioutil.ReadFile("./testresources/hello.sh") + if err != nil { + t.Fatal(err) + } + copiedFilePath := "hello_copy.sh" + nginxC.CopyFileToContainer(ctx,"/", copiedFilePath, fileContent, 700) + c, err := nginxC.Exec(ctx, []string{"bash", copiedFilePath}) + if err != nil { + t.Fatal(err) + } + if c != 0 { + t.Fatalf("File %s should exist, expected return code 0, got %v", copiedFilePath, c) + } +} From 88c7fb9dc7f719b8fead823788b0c3f399febcc5 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Fri, 10 Jul 2020 11:49:35 -0400 Subject: [PATCH 4/9] Added documentation --- .gitignore | 1 + docs/features/copy_file.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/features/copy_file.md diff --git a/.gitignore b/.gitignore index 53bde68083..053636ef51 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ site/ .direnv/ src/mkdocs-codeinclude-plugin src/pip-delete-this-directory.txt +.idea/ diff --git a/docs/features/copy_file.md b/docs/features/copy_file.md new file mode 100644 index 0000000000..4b4e12bad1 --- /dev/null +++ b/docs/features/copy_file.md @@ -0,0 +1,23 @@ +# Copy Files To Container + +If you would like to copy a file to a container, you can do it using the `CopyFileToContainer` method... + +```go +ctx := context.Background() + +nginxC, err := GenericContainer(ctx, GenericContainerRequest{ + ContainerRequest: ContainerRequest{ + Image: "nginx:1.17.6", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForListeningPort("80/tcp"), + }, + Started: true, + }) + +fileContent, err := ioutil.ReadFile("./testresources/hello.sh") + if err != nil { + t.Fatal(err) + } +nginxC.CopyFileToContainer(ctx, "/", "hello_copy.sh", fileContent, 700) +``` + From 09b0430646dadc377ca513657ff613dd3f2395b8 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Fri, 10 Jul 2020 11:59:56 -0400 Subject: [PATCH 5/9] Fix fmt --- docker_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_test.go b/docker_test.go index a748e33561..eba72120b3 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1287,7 +1287,7 @@ func TestDockerContainerCopyFileToContainer(t *testing.T) { t.Fatal(err) } copiedFilePath := "hello_copy.sh" - nginxC.CopyFileToContainer(ctx,"/", copiedFilePath, fileContent, 700) + nginxC.CopyFileToContainer(ctx, "/", copiedFilePath, fileContent, 700) c, err := nginxC.Exec(ctx, []string{"bash", copiedFilePath}) if err != nil { t.Fatal(err) From 635892e8cf75282ac17e0439ddacac2a79bd00b7 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Sun, 16 Aug 2020 11:38:09 -0400 Subject: [PATCH 6/9] Remove copyToContainer method --- container.go | 1 - docker.go | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/container.go b/container.go index f98ed064f1..de689d5dfb 100644 --- a/container.go +++ b/container.go @@ -49,7 +49,6 @@ type Container interface { NetworkAliases(context.Context) (map[string][]string, error) // get container network aliases for a network Exec(ctx context.Context, cmd []string) (int, error) ContainerIP(context.Context) (string, error) // get container ip - CopyToContainer(ctx context.Context, containerPath string, content io.Reader) error CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error } diff --git a/docker.go b/docker.go index a02f0a3f69..4870e0f0ba 100644 --- a/docker.go +++ b/docker.go @@ -307,10 +307,6 @@ func (c *DockerContainer) Exec(ctx context.Context, cmd []string) (int, error) { return exitCode, nil } -func (c *DockerContainer) CopyToContainer(ctx context.Context, containerPath string, content io.Reader) error { - return c.provider.client.CopyToContainer(ctx, c.ID, containerPath, content, types.CopyToContainerOptions{}) -} - func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error { buffer := &bytes.Buffer{} @@ -329,7 +325,7 @@ func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath return err } - return c.CopyToContainer(ctx, containerPath, buffer) + return c.provider.client.CopyToContainer(ctx, c.ID, containerPath, buffer, types.CopyToContainerOptions{}) } // StartLogProducer will start a concurrent process that will continuously read logs From e46cbf4c451f29c4be7460011f851fbbee44f724 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Thu, 20 Aug 2020 20:43:43 -0400 Subject: [PATCH 7/9] Simplied copyToContainer interface --- container.go | 2 +- docker.go | 12 +++++++++--- docker_test.go | 13 ++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/container.go b/container.go index de689d5dfb..1626e258e3 100644 --- a/container.go +++ b/container.go @@ -49,7 +49,7 @@ type Container interface { NetworkAliases(context.Context) (map[string][]string, error) // get container network aliases for a network Exec(ctx context.Context, cmd []string) (int, error) ContainerIP(context.Context) (string, error) // get container ip - CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error + CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error } // ImageBuildInfo defines what is needed to build an image diff --git a/docker.go b/docker.go index 4870e0f0ba..f537b50cd8 100644 --- a/docker.go +++ b/docker.go @@ -12,6 +12,7 @@ import ( "net/url" "os" "os/exec" + "path/filepath" "strings" "time" @@ -307,14 +308,19 @@ func (c *DockerContainer) Exec(ctx context.Context, cmd []string) (int, error) { return exitCode, nil } -func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath string, fileName string, fileContent []byte, fileMode int64) error { +func (c *DockerContainer) CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error { + fileContent, err := ioutil.ReadFile(hostFilePath) + if err != nil { + return err + } + buffer := &bytes.Buffer{} tw := tar.NewWriter(buffer) defer tw.Close() hdr := &tar.Header{ - Name: fileName, + Name: filepath.Base(containerFilePath), Mode: fileMode, Size: int64(len(fileContent)), } @@ -325,7 +331,7 @@ func (c *DockerContainer) CopyFileToContainer(ctx context.Context, containerPath return err } - return c.provider.client.CopyToContainer(ctx, c.ID, containerPath, buffer, types.CopyToContainerOptions{}) + return c.provider.client.CopyToContainer(ctx, c.ID, filepath.Dir(containerFilePath), buffer, types.CopyToContainerOptions{}) } // StartLogProducer will start a concurrent process that will continuously read logs diff --git a/docker_test.go b/docker_test.go index eba72120b3..ea90149cc3 100644 --- a/docker_test.go +++ b/docker_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "io/ioutil" "net/http" "path/filepath" "testing" @@ -1282,17 +1281,13 @@ func TestDockerContainerCopyFileToContainer(t *testing.T) { }) defer nginxC.Terminate(ctx) - fileContent, err := ioutil.ReadFile("./testresources/hello.sh") - if err != nil { - t.Fatal(err) - } - copiedFilePath := "hello_copy.sh" - nginxC.CopyFileToContainer(ctx, "/", copiedFilePath, fileContent, 700) - c, err := nginxC.Exec(ctx, []string{"bash", copiedFilePath}) + copiedFileName := "hello_copy.sh" + nginxC.CopyFileToContainer(ctx, "./testresources/hello.sh", "/" + copiedFileName, 700) + c, err := nginxC.Exec(ctx, []string{"bash", copiedFileName}) if err != nil { t.Fatal(err) } if c != 0 { - t.Fatalf("File %s should exist, expected return code 0, got %v", copiedFilePath, c) + t.Fatalf("File %s should exist, expected return code 0, got %v", copiedFileName, c) } } From 51c8e42742a036d9f433ec865b9050998a3e3066 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Thu, 20 Aug 2020 20:47:14 -0400 Subject: [PATCH 8/9] Update documentation --- docs/features/copy_file.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/features/copy_file.md b/docs/features/copy_file.md index 4b4e12bad1..b275a84d26 100644 --- a/docs/features/copy_file.md +++ b/docs/features/copy_file.md @@ -14,10 +14,6 @@ nginxC, err := GenericContainer(ctx, GenericContainerRequest{ Started: true, }) -fileContent, err := ioutil.ReadFile("./testresources/hello.sh") - if err != nil { - t.Fatal(err) - } -nginxC.CopyFileToContainer(ctx, "/", "hello_copy.sh", fileContent, 700) +nginxC.CopyFileToContainer(ctx, "./testresources/hello.sh", "/hello_copy.sh", fileContent, 700) ``` From e3a7202c464f26880c325e180972dc3bcdba36e7 Mon Sep 17 00:00:00 2001 From: Franklin Guimaraes Date: Thu, 20 Aug 2020 21:03:07 -0400 Subject: [PATCH 9/9] Fix checks --- container.go | 2 +- docker_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/container.go b/container.go index 1626e258e3..7c945ed94f 100644 --- a/container.go +++ b/container.go @@ -49,7 +49,7 @@ type Container interface { NetworkAliases(context.Context) (map[string][]string, error) // get container network aliases for a network Exec(ctx context.Context, cmd []string) (int, error) ContainerIP(context.Context) (string, error) // get container ip - CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error + CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error } // ImageBuildInfo defines what is needed to build an image diff --git a/docker_test.go b/docker_test.go index ea90149cc3..ccfc7c471a 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1282,7 +1282,7 @@ func TestDockerContainerCopyFileToContainer(t *testing.T) { defer nginxC.Terminate(ctx) copiedFileName := "hello_copy.sh" - nginxC.CopyFileToContainer(ctx, "./testresources/hello.sh", "/" + copiedFileName, 700) + nginxC.CopyFileToContainer(ctx, "./testresources/hello.sh", "/"+copiedFileName, 700) c, err := nginxC.Exec(ctx, []string{"bash", copiedFileName}) if err != nil { t.Fatal(err)