From 22a7f7e7bd917e443aa47aaa9eaa5dac03a5a10b Mon Sep 17 00:00:00 2001 From: Vishwas Siravara Date: Fri, 26 May 2023 12:32:59 -0700 Subject: [PATCH] feat: Tests for bind mounts (#66) Issue #, if available: *Description of changes:* Test functioning of nested bind mounts with and without $DOCKER_COMAPT set. 1. Without $FINCH_DOCKER_COMAPT. ``` # fails when nested directories are mounted first followed by parent directory finch finch run -it -v /Users/siravara/outer/nest/://Users/siravara/outer/nest/ -v /Users/siravara/temp_home/:/Users/siravara/outer public.ecr.aws/amazonlinux/amazonlinux:2 sh -c "ls /Users/siravara/outer/nest/" # passes when parent directory is mounted first followed by nested directories finch finch run -it -v /Users/siravara/temp_home/:/Users/siravara/outer -v /Users/siravara/outer/nest/://Users/siravara/outer/nest/ public.ecr.aws/amazonlinux/amazonlinux:2 sh -c "ls /Users/siravara/outer/nest/" ``` 2. With $FINCH_DOCKER_COMAT set ``` # passes when nested directories are mounted first followed by parent directory finch finch run -it -v /Users/siravara/outer/nest/://Users/siravara/outer/nest/ -v /Users/siravara/temp_home/:/Users/siravara/outer public.ecr.aws/amazonlinux/amazonlinux:2 sh -c "ls /Users/siravara/outer/nest/" # passes when parent directory is mounted first followed by nested directories finch finch run -it -v /Users/siravara/temp_home/:/Users/siravara/outer -v /Users/siravara/outer/nest/://Users/siravara/outer/nest/ public.ecr.aws/amazonlinux/amazonlinux:2 sh -c "ls /Users/siravara/outer/nest/" ``` *Testing done:* Yes locally. - [X] I've reviewed the guidance in CONTRIBUTING.md #### License Acceptance By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: Vishwas Siravara --- fenv/get.go | 15 ++++++++++ ffs/create.go | 17 ++++++++++++ tests/run.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 fenv/get.go diff --git a/fenv/get.go b/fenv/get.go new file mode 100644 index 0000000..40249c9 --- /dev/null +++ b/fenv/get.go @@ -0,0 +1,15 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package fenv Package path implements utility routines for working with environment variables +package fenv + +import ( + "os" +) + +// GetEnv retrieves the value of an environment variable. +// It returns an empty string if the variable is not set. +func GetEnv(key string) string { + return os.Getenv(key) +} diff --git a/ffs/create.go b/ffs/create.go index f131f78..9347243 100644 --- a/ffs/create.go +++ b/ffs/create.go @@ -60,3 +60,20 @@ func CreateTempDir(directoryPrefix string) string { gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) return tempDir } + +// CreateNestedDir creates a nested directory and returns the path of the created directory. +// It is the caller's responsibility to remove the directory when it is no longer needed. +func CreateNestedDir(dirPath string) string { + homeDir, err := os.UserHomeDir() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + fullPath := filepath.Join(homeDir, dirPath) + err = os.MkdirAll(fullPath, 0o740) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + return fullPath +} + +// DeleteDirectory deletes the directory including nested directories. +func DeleteDirectory(directoryPath string) { + err := os.RemoveAll(directoryPath) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) +} diff --git a/tests/run.go b/tests/run.go index 8ded813..42b284b 100644 --- a/tests/run.go +++ b/tests/run.go @@ -16,6 +16,7 @@ import ( "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" + "github.com/runfinch/common-tests/fenv" "github.com/runfinch/common-tests/command" "github.com/runfinch/common-tests/ffs" @@ -446,6 +447,81 @@ func Run(o *RunOption) { verifyMountsInfo(actualMount, expectedMount) }) + // TODO: Remove FINCH_DOCKER_COMPAT=1 check when FINCH_DOCKER_COMPAT flag is removed in finch + ginkgo.It("should create nested bind mounts within a container when FINCH_DOCKER_COMPAT is not set", func() { + const ( + outerDir = "/outer" + nestedDir = "/outer/nested" + ) + + if fenv.GetEnv("FINCH_DOCKER_COMPAT") == "1" { + ginkgo.Skip("Skipping test: FINCH_DOCKER_COMPAT is set to 1") + } + // Create the nested directory on the host + hostDirectory := ffs.CreateNestedDir(outerDir) + nestedDirectory := ffs.CreateNestedDir(nestedDir) + defer ffs.DeleteDirectory(hostDirectory) + + // Directory on host to be mounted at hostDirectory in container + tempDir := ffs.CreateTempDir("some_dir") + defer ffs.DeleteDirectory(tempDir) + // Write a file to the nested directory + nestedFilePath := filepath.Join(nestedDirectory, "file1.txt") + ffs.WriteFile(nestedFilePath, "test") + + // Mount nested directory first followed by parent directory + // Upstream issue: https://github.com/containerd/nerdctl/issues/2254 + command.RunWithoutSuccessfulExit(o.BaseOpt, "run", "--rm", "--name", testContainerName, + "-v", nestedDirectory+":"+nestedDirectory, + "-v", tempDir+":"+hostDirectory, + defaultImage, "sh", "-c", "ls "+nestedDirectory) + + // Mount parent directory first followed by nested + output := command.StdoutStr(o.BaseOpt, "run", "--rm", "--name", testContainerName2, + "-v", tempDir+":"+hostDirectory, + "-v", nestedDirectory+":"+nestedDirectory, + defaultImage, "sh", "-c", "ls "+nestedDirectory) + gomega.Expect(output).Should(gomega.ContainSubstring("file1.txt")) + }) + + // TODO: Remove FINCH_DOCKER_COMPAT=1 check when FINCH_DOCKER_COMPAT flag is removed in finch + // https://github.com/runfinch/finch/pull/417/files + + ginkgo.It("should create nested bind mounts within a container when FINCH_DOCKER_COMPAT is set", func() { + const ( + outerDir = "/outer" + nestedDir = "/outer/nested" + ) + if fenv.GetEnv("FINCH_DOCKER_COMPAT") != "1" { + ginkgo.Skip("Skipping test: FINCH_DOCKER_COMPAT is not set to 1") + } + // Create the nested directory on the host + hostDirectory := ffs.CreateNestedDir(outerDir) + nestedDirectory := ffs.CreateNestedDir(nestedDir) + defer ffs.DeleteDirectory(hostDirectory) + + // Directory on host to be mounted at hostDirectory in container + tempDir := ffs.CreateTempDir("some_dir") + defer ffs.DeleteDirectory(tempDir) + // Write a file to the nested directory + nestedFilePath := filepath.Join(nestedDirectory, "file1.txt") + ffs.WriteFile(nestedFilePath, "test") + + // Mount nested directory first followed by parent directory + output := command.StdoutStr(o.BaseOpt, "run", "--rm", "--name", testContainerName, + "-v", nestedDirectory+":"+nestedDirectory, + "-v", tempDir+":"+hostDirectory, + defaultImage, "sh", "-c", "ls "+nestedDirectory) + gomega.Expect(output).Should(gomega.ContainSubstring("file1.txt")) + + // Mount parent directory first followed by nested + output = command.StdoutStr(o.BaseOpt, "run", "--rm", "--name", testContainerName2, + "-v", tempDir+":"+hostDirectory, + "-v", nestedDirectory+":"+nestedDirectory, + defaultImage, "sh", "-c", "ls "+nestedDirectory) + gomega.Expect(output).Should(gomega.ContainSubstring("file1.txt")) + }) + ginkgo.It("should create a tmpfs mount using --mount type=tmpfs flag", func() { tmpfsDir := "/tmpfsDir" command.Run(o.BaseOpt, "run", "-d", "--name", testContainerName, "--mount",