From 407d324ec1a5d9242114971e9e18e8469538924c Mon Sep 17 00:00:00 2001 From: Seunghyun Hwang Date: Tue, 5 Apr 2022 03:01:13 +0900 Subject: [PATCH] implement volume mount for container job (#1101) * implement volume mount for container job * Update pkg/runner/run_context.go Co-authored-by: Ryan * add tests for container volume mount options * remove unused code * prefer if-else instead of if-continue * remove continue * add some tests Co-authored-by: Ryan Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- pkg/model/testdata/container-volumes/push.yml | 19 ++++++++++ pkg/model/workflow_test.go | 9 +++++ pkg/runner/run_context.go | 15 ++++++++ pkg/runner/run_context_test.go | 38 +++++++++++++++++++ pkg/runner/runner_test.go | 1 + 5 files changed, 82 insertions(+) create mode 100644 pkg/model/testdata/container-volumes/push.yml diff --git a/pkg/model/testdata/container-volumes/push.yml b/pkg/model/testdata/container-volumes/push.yml new file mode 100644 index 0000000..1ed27f2 --- /dev/null +++ b/pkg/model/testdata/container-volumes/push.yml @@ -0,0 +1,19 @@ +name: Job Container +on: push + +jobs: + with-volumes: + runs-on: ubuntu-latest + container: + image: node:16-buster-slim + volumes: + - my_docker_volume:/path/to/volume + - /path/to/nonexist/directory + - /proc/sys/kernel/random/boot_id:/current/boot_id + steps: + - run: | + set -e + test -d /path/to/volume + test "$(cat /proc/sys/kernel/random/boot_id)" = "$(cat /current/boot_id)" + test -d /path/to/nonexist/directory + \ No newline at end of file diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index a3b08e4..f15d570 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -112,6 +112,10 @@ jobs: password: registry-password env: HOME: /home/user + volumes: + - my_docker_volume:/volume_mount + - /data/my_data + - /source/directory:/destination/directory runs-on: ubuntu-latest steps: - uses: ./actions/docker-url @@ -127,6 +131,11 @@ jobs: assert.Contains(t, container.Env["HOME"], "/home/user") assert.Contains(t, container.Credentials["username"], "registry-username") assert.Contains(t, container.Credentials["password"], "registry-password") + assert.ElementsMatch(t, container.Volumes, []string{ + "my_docker_volume:/volume_mount", + "/data/my_data", + "/source/directory:/destination/directory", + }) } func TestReadWorkflow_StepsTypes(t *testing.T) { diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index bbc2d14..06c0740 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -102,6 +102,21 @@ func (rc *RunContext) GetBindsAndMounts() ([]string, map[string]string) { name + "-env": ActPath, } + if job := rc.Run.Job(); job != nil { + if container := job.Container(); container != nil { + for _, v := range container.Volumes { + if !strings.Contains(v, ":") || filepath.IsAbs(v) { + // Bind anonymous volume or host file. + binds = append(binds, v) + } else { + // Mount existing volume. + paths := strings.SplitN(v, ":", 2) + mounts[paths[0]] = paths[1] + } + } + } + } + if rc.Config.BindWorkdir { bindModifiers := "" if runtime.GOOS == "darwin" { diff --git a/pkg/runner/run_context_test.go b/pkg/runner/run_context_test.go index ca85930..9aced90 100644 --- a/pkg/runner/run_context_test.go +++ b/pkg/runner/run_context_test.go @@ -293,6 +293,44 @@ func TestRunContext_GetBindsAndMounts(t *testing.T) { } } } + + t.Run("ContainerVolumeMountTest", func(t *testing.T) { + tests := []struct { + name string + volumes []string + wantbind string + wantmount map[string]string + }{ + {"BindAnonymousVolume", []string{"/volume"}, "/volume", map[string]string{}}, + {"BindHostFile", []string{"/path/to/file/on/host:/volume"}, "/path/to/file/on/host:/volume", map[string]string{}}, + {"MountExistingVolume", []string{"volume-id:/volume"}, "", map[string]string{"volume-id": "/volume"}}, + } + + for _, testcase := range tests { + t.Run(testcase.name, func(t *testing.T) { + job := &model.Job{} + err := job.RawContainer.Encode(map[string][]string{ + "volumes": testcase.volumes, + }) + assert.NoError(t, err) + + rc := rctemplate.Clone() + rc.Run.JobID = "job1" + rc.Run.Workflow.Jobs = map[string]*model.Job{"job1": job} + + gotbind, gotmount := rc.GetBindsAndMounts() + + if len(testcase.wantbind) > 0 { + assert.Contains(t, gotbind, testcase.wantbind) + } + + for k, v := range testcase.wantmount { + assert.Contains(t, gotmount, k) + assert.Equal(t, gotmount[k], v) + } + }) + } + }) } func TestGetGitHubContext(t *testing.T) { diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 1dcded3..a318827 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -141,6 +141,7 @@ func TestRunEvent(t *testing.T) { {"testdata", "evalmatrix-merge-array", "push", "", platforms, ""}, {"../model/testdata", "strategy", "push", "", platforms, ""}, // TODO: move all testdata into pkg so we can validate it with planner and runner // {"testdata", "issue-228", "push", "", platforms, ""}, // TODO [igni]: Remove this once everything passes + {"../model/testdata", "container-volumes", "push", "", platforms, ""}, // single test for different architecture: linux/arm64 {"testdata", "basic", "push", "", platforms, "linux/arm64"},