From f0ab230aee409e492298baad0d408a7e934f5ca4 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Wed, 12 Jun 2024 19:21:37 +0000 Subject: [PATCH 1/9] Add tests to verify embed binary image --- integration/integration_test.go | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/integration/integration_test.go b/integration/integration_test.go index 4b0e82e8..1d392900 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -1354,6 +1354,45 @@ COPY --from=a /root/date.txt /date.txt`, testImageAlpine, testImageAlpine), }) } +func TestEmbedBinaryImage(t *testing.T) { + t.Parallel() + + srv := createGitServer(t, gitServerOptions{ + files: map[string]string{ + ".devcontainer/Dockerfile": fmt.Sprintf("FROM %s\nRUN date --utc > /root/date.txt", testImageAlpine), + ".devcontainer/devcontainer.json": `{ + "name": "Test", + "build": { + "dockerfile": "Dockerfile" + }, + }`, + }, + }) + + testReg := setupInMemoryRegistry(t, setupInMemoryRegistryOpts{}) + testRepo := testReg + "/test" + ref, err := name.ParseReference(testRepo + ":latest") + require.NoError(t, err) + + _, err = runEnvbuilder(t, options{env: []string{ + envbuilderEnv("GIT_URL", srv.URL), + envbuilderEnv("CACHE_REPO", testRepo), + envbuilderEnv("PUSH_IMAGE", "1"), + }}) + require.NoError(t, err) + + _, err = remote.Image(ref) + require.NoError(t, err, "expected image to be present after build + push") + + ctr, err := runEnvbuilder(t, options{env: []string{ + envbuilderEnv("FALLBACK_IMAGE", ref.String()), + }}) + require.NoError(t, err) + + out := execContainer(t, ctr, "[[ -f \"/.envbuilder/bin/envbuilder\" ]] && echo \"exists\"") + require.Equal(t, "exists", strings.TrimSpace(out)) +} + type setupInMemoryRegistryOpts struct { Username string Password string From 0cab914e621525e0d500bb36967261d50b6508a2 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Thu, 13 Jun 2024 09:07:18 +0000 Subject: [PATCH 2/9] update test to check built image --- integration/integration_test.go | 40 ++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/integration/integration_test.go b/integration/integration_test.go index 1d392900..83a9d3fd 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -30,6 +30,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/image" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/go-git/go-billy/v5/memfs" @@ -1370,7 +1371,7 @@ func TestEmbedBinaryImage(t *testing.T) { }) testReg := setupInMemoryRegistry(t, setupInMemoryRegistryOpts{}) - testRepo := testReg + "/test" + testRepo := testReg + "/test-embed-binary-image" ref, err := name.ParseReference(testRepo + ":latest") require.NoError(t, err) @@ -1384,13 +1385,42 @@ func TestEmbedBinaryImage(t *testing.T) { _, err = remote.Image(ref) require.NoError(t, err, "expected image to be present after build + push") - ctr, err := runEnvbuilder(t, options{env: []string{ - envbuilderEnv("FALLBACK_IMAGE", ref.String()), - }}) + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + require.NoError(t, err) + t.Cleanup(func() { + cli.Close() + }) + + // Pull the image we just built + rc, err := cli.ImagePull(ctx, ref.String(), image.PullOptions{}) + require.NoError(t, err) + t.Cleanup(func() { _ = rc.Close() }) + _, err = io.ReadAll(rc) + require.NoError(t, err) + + // Run it + ctr, err := cli.ContainerCreate(ctx, &container.Config{ + Image: ref.String(), + Cmd: []string{"sleep", "infinity"}, + Labels: map[string]string{ + testContainerLabel: "true", + }, + }, nil, nil, nil, "") + require.NoError(t, err) + t.Cleanup(func() { + _ = cli.ContainerRemove(ctx, ctr.ID, container.RemoveOptions{ + RemoveVolumes: true, + Force: true, + }) + }) + err = cli.ContainerStart(ctx, ctr.ID, container.StartOptions{}) require.NoError(t, err) - out := execContainer(t, ctr, "[[ -f \"/.envbuilder/bin/envbuilder\" ]] && echo \"exists\"") + out := execContainer(t, ctr.ID, "[[ -f \"/.envbuilder/bin/envbuilder\" ]] && echo \"exists\"") require.Equal(t, "exists", strings.TrimSpace(out)) + out = execContainer(t, ctr.ID, "cat /root/date.txt") + require.NotEmpty(t, strings.TrimSpace(out)) } type setupInMemoryRegistryOpts struct { From cecd6621325f7f5cfee9f44b26b2e623cceb2d50 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Thu, 13 Jun 2024 17:24:17 +0000 Subject: [PATCH 3/9] Update ctx and copy .envbuilder to image --- envbuilder.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/envbuilder.go b/envbuilder.go index 307a55dd..7389755f 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -342,6 +342,11 @@ func Run(ctx context.Context, options Options) error { } } + if options.PushImage { + buildParams.DockerfileContent = buildParams.DockerfileContent + "\n" + + "COPY .envbuilder .envbuilder" + } + HijackLogrus(func(entry *logrus.Entry) { for _, line := range strings.Split(entry.Message, "\r") { options.Logger(notcodersdk.LogLevelInfo, "#%d: %s", stageNumber, color.HiBlackString(line)) @@ -521,7 +526,7 @@ func Run(ctx context.Context, options Options) error { // https://github.com/coder/envbuilder/pull/114 RegistryMirrors: registryMirror, }, - SrcContext: buildParams.BuildContext, + SrcContext: "/", // For cached image utilization, produce reproducible builds. Reproducible: options.PushImage, From 3eb42174acc651873931d18e687023ef767a48e5 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 14 Jun 2024 12:58:15 +0000 Subject: [PATCH 4/9] Try to copy bin to .devcontainer to include it in build context --- envbuilder.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/envbuilder.go b/envbuilder.go index 7389755f..0fc1110a 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -27,6 +27,7 @@ import ( "github.com/kballard/go-shellquote" "github.com/mattn/go-isatty" + cp "github.com/otiai10/copy" "github.com/GoogleContainerTools/kaniko/pkg/config" "github.com/GoogleContainerTools/kaniko/pkg/creds" @@ -343,8 +344,14 @@ func Run(ctx context.Context, options Options) error { } if options.PushImage { + // Copy the envbuilder binary into the build context. + binPath := filepath.Join(MagicDir, "bin", "envbuilder") + err := cp.Copy(binPath, filepath.Join(buildParams.BuildContext, binPath)) + if err != nil { + return err + } buildParams.DockerfileContent = buildParams.DockerfileContent + "\n" + - "COPY .envbuilder .envbuilder" + "COPY " + binPath + " " + binPath } HijackLogrus(func(entry *logrus.Entry) { @@ -526,7 +533,7 @@ func Run(ctx context.Context, options Options) error { // https://github.com/coder/envbuilder/pull/114 RegistryMirrors: registryMirror, }, - SrcContext: "/", + SrcContext: buildParams.BuildContext, // For cached image utilization, produce reproducible builds. Reproducible: options.PushImage, From 4138dc5d8c7855b87bae3bc20b0444e41ae5d13c Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 14 Jun 2024 16:02:53 +0200 Subject: [PATCH 5/9] Simple copy file operation --- envbuilder.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/envbuilder.go b/envbuilder.go index 0fc1110a..df560fe5 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "io/fs" + "log" "maps" "net" "net/http" @@ -27,7 +28,6 @@ import ( "github.com/kballard/go-shellquote" "github.com/mattn/go-isatty" - cp "github.com/otiai10/copy" "github.com/GoogleContainerTools/kaniko/pkg/config" "github.com/GoogleContainerTools/kaniko/pkg/creds" @@ -345,13 +345,17 @@ func Run(ctx context.Context, options Options) error { if options.PushImage { // Copy the envbuilder binary into the build context. + buildParams.DockerfileContent = buildParams.DockerfileContent + "\n" + + fmt.Sprintf("COPY %s %s", ".envbuilder", "/.envbuilder") + + log.Println("FIXME show me the Dockerfile now: " + buildParams.DockerfileContent) + binPath := filepath.Join(MagicDir, "bin", "envbuilder") - err := cp.Copy(binPath, filepath.Join(buildParams.BuildContext, binPath)) + dst := filepath.Join(buildParams.BuildContext, binPath) + err := copyFile(binPath, dst) if err != nil { - return err + return fmt.Errorf("aaa : %v", err) } - buildParams.DockerfileContent = buildParams.DockerfileContent + "\n" + - "COPY " + binPath + " " + binPath } HijackLogrus(func(entry *logrus.Entry) { @@ -1171,3 +1175,21 @@ func maybeDeleteFilesystem(log LoggerFunc, force bool) error { return util.DeleteFilesystem() } + +func copyFile(src, dst string) error { + content, err := os.ReadFile(src) + if err != nil { + return xerrors.Errorf("read file failed: %w", err) + } + + err = os.MkdirAll(filepath.Dir(dst), 0755) + if err != nil { + return xerrors.Errorf("mkdir all failed: %w", err) + } + + err = os.WriteFile(dst, content, 0644) + if err != nil { + return xerrors.Errorf("write file failed: %w", err) + } + return nil +} From 19b235dff042744a72369bcc5be6d402aa1dad77 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Sun, 23 Jun 2024 13:37:16 +0100 Subject: [PATCH 6/9] use feature added in coder/kaniko#16 --- envbuilder.go | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/envbuilder.go b/envbuilder.go index df560fe5..be33c349 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "io/fs" - "log" "maps" "net" "net/http" @@ -343,21 +342,6 @@ func Run(ctx context.Context, options Options) error { } } - if options.PushImage { - // Copy the envbuilder binary into the build context. - buildParams.DockerfileContent = buildParams.DockerfileContent + "\n" + - fmt.Sprintf("COPY %s %s", ".envbuilder", "/.envbuilder") - - log.Println("FIXME show me the Dockerfile now: " + buildParams.DockerfileContent) - - binPath := filepath.Join(MagicDir, "bin", "envbuilder") - dst := filepath.Join(buildParams.BuildContext, binPath) - err := copyFile(binPath, dst) - if err != nil { - return fmt.Errorf("aaa : %v", err) - } - } - HijackLogrus(func(entry *logrus.Entry) { for _, line := range strings.Split(entry.Message, "\r") { options.Logger(notcodersdk.LogLevelInfo, "#%d: %s", stageNumber, color.HiBlackString(line)) @@ -421,9 +405,29 @@ func Run(ctx context.Context, options Options) error { util.AddToDefaultIgnoreList(util.IgnoreListEntry{ Path: ignorePath, PrefixMatchOnly: false, + AllowedPaths: map[string]struct{}{}, }) } + // In order to allow 'resuming' envbuilder, embed the binary into the image + // if it is being pushed + if options.PushImage { + exePath, err := os.Executable() + if err != nil { + return xerrors.Errorf("get exe path: %w", err) + } + // Add an exception for the current running binary in kaniko ignore list + if err := util.AddAllowedPathToDefaultIgnoreList(exePath); err != nil { + return xerrors.Errorf("add exe path to ignore list: %w", err) + } + // Copy the envbuilder binary into the build context. + buildParams.DockerfileContent += fmt.Sprintf("\nCOPY %s %s", exePath, exePath) + dst := filepath.Join(buildParams.BuildContext, exePath) + if err := copyFile(exePath, dst); err != nil { + return xerrors.Errorf("copy running binary to build context: %w", err) + } + } + // temp move of all ro mounts tempRemountDest := filepath.Join("/", MagicDir, "mnt") ignorePrefixes := []string{tempRemountDest, "/proc", "/sys"} From f2c69124451eb34d7d8c4841ee7e736ec748b051 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Sun, 23 Jun 2024 13:38:46 +0100 Subject: [PATCH 7/9] update kaniko fork in go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 74d3b3d2..a6c71b9b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.22.3 // There are a few options we need added to Kaniko! // See: https://github.com/GoogleContainerTools/kaniko/compare/main...coder:kaniko:main -replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20240612094751-9d2f7eaa733c +replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko c36d9e29c8b540658ba4f56e534c0fc9f1d9e691 require ( cdr.dev/slog v1.6.2-0.20240126064726-20367d4aede6 From baef8fc0ff58b02e975238b63988c7892f169727 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Sun, 23 Jun 2024 13:42:40 +0100 Subject: [PATCH 8/9] fmt --- envbuilder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/envbuilder.go b/envbuilder.go index 2c3e09e7..aa58d800 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -1209,12 +1209,12 @@ func copyFile(src, dst string) error { return xerrors.Errorf("read file failed: %w", err) } - err = os.MkdirAll(filepath.Dir(dst), 0755) + err = os.MkdirAll(filepath.Dir(dst), 0o755) if err != nil { return xerrors.Errorf("mkdir all failed: %w", err) } - err = os.WriteFile(dst, content, 0644) + err = os.WriteFile(dst, content, 0o644) if err != nil { return xerrors.Errorf("write file failed: %w", err) } From a250901153c3d7a51da2b446d6dce4dbc1bc89be Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Mon, 24 Jun 2024 10:24:36 +0100 Subject: [PATCH 9/9] AllowedPaths is now a slice --- envbuilder.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/envbuilder.go b/envbuilder.go index aa58d800..889db1e4 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -404,7 +404,7 @@ func Run(ctx context.Context, options Options) error { util.AddToDefaultIgnoreList(util.IgnoreListEntry{ Path: ignorePath, PrefixMatchOnly: false, - AllowedPaths: map[string]struct{}{}, + AllowedPaths: nil, }) } diff --git a/go.mod b/go.mod index 2c7c334d..c831fdfc 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.22.3 // There are a few options we need added to Kaniko! // See: https://github.com/GoogleContainerTools/kaniko/compare/main...coder:kaniko:main -replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20240623122900-c36d9e29c8b5 +replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20240624091120-7208a49f5b15 require ( cdr.dev/slog v1.6.2-0.20240126064726-20367d4aede6 diff --git a/go.sum b/go.sum index 13475cfd..ee16941c 100644 --- a/go.sum +++ b/go.sum @@ -126,8 +126,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/coder/kaniko v0.0.0-20240623122900-c36d9e29c8b5 h1:Le7TE50D8g3A/fAuXmFsDPw3ne0fh9+ZjYLZFxD6cOA= -github.com/coder/kaniko v0.0.0-20240623122900-c36d9e29c8b5/go.mod h1:YMK7BlxerzLlMwihGxNWUaFoN9LXCij4P+w/8/fNlcM= +github.com/coder/kaniko v0.0.0-20240624091120-7208a49f5b15 h1:Rne2frxrqtLEQ/v4f/wS550Yp/WXLCRFzDuxg8b9woM= +github.com/coder/kaniko v0.0.0-20240624091120-7208a49f5b15/go.mod h1:YMK7BlxerzLlMwihGxNWUaFoN9LXCij4P+w/8/fNlcM= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc= github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc=