From 68ae67720a973450a0d56f925a56a6fcc2ef4393 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Fri, 26 May 2023 00:20:29 -0700 Subject: [PATCH] build: fix writing correct image ID with -q Container driver wrote manifest digest that had a mismatch with --iidfile output. When --iidfile was set the --metadata-file was not written. Signed-off-by: Tonis Tiigi --- commands/build.go | 17 +++++++++----- tests/build.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/commands/build.go b/commands/build.go index 3467e463..f575f91e 100644 --- a/commands/build.go +++ b/commands/build.go @@ -274,14 +274,12 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) { } if options.quiet { - fmt.Println(resp.ExporterResponse[exptypes.ExporterImageDigestKey]) + fmt.Println(getImageID(resp.ExporterResponse)) } if options.imageIDFile != "" { - dgst := resp.ExporterResponse[exptypes.ExporterImageDigestKey] - if v, ok := resp.ExporterResponse[exptypes.ExporterImageConfigDigestKey]; ok { - dgst = v + if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse)), 0644); err != nil { + return errors.Wrap(err, "writing image ID file") } - return os.WriteFile(options.imageIDFile, []byte(dgst), 0644) } if options.metadataFile != "" { if err := writeMetadataFile(options.metadataFile, decodeExporterResponse(resp.ExporterResponse)); err != nil { @@ -296,6 +294,15 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) { return nil } +// getImageID returns the image ID - the digest of the image config +func getImageID(resp map[string]string) string { + dgst := resp[exptypes.ExporterImageDigestKey] + if v, ok := resp[exptypes.ExporterImageConfigDigestKey]; ok { + dgst = v + } + return dgst +} + func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) { resp, _, err := cbuild.RunBuild(ctx, dockerCli, *opts, os.Stdin, printer, false) return resp, err diff --git a/tests/build.go b/tests/build.go index c3aa0d5f..71908546 100644 --- a/tests/build.go +++ b/tests/build.go @@ -1,9 +1,13 @@ package tests import ( + "bytes" + "encoding/json" "errors" "fmt" "os" + "path/filepath" + "strings" "testing" "github.com/containerd/containerd/platforms" @@ -11,6 +15,7 @@ import ( "github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil/integration" + "github.com/opencontainers/go-digest" "github.com/stretchr/testify/require" ) @@ -23,6 +28,7 @@ func buildCmd(sb integration.Sandbox, args ...string) (string, error) { var buildTests = []func(t *testing.T, sb integration.Sandbox){ testBuild, + testImageIDOutput, testBuildLocalExport, testBuildRegistryExport, testBuildTarExport, @@ -83,6 +89,56 @@ func testBuildRegistryExport(t *testing.T, sb integration.Sandbox) { require.Equal(t, img.Layers[0]["bar"].Data, []byte("foo")) } +func testImageIDOutput(t *testing.T, sb integration.Sandbox) { + dockerfile := []byte(`FROM busybox:latest`) + + dir, err := tmpdir(t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + require.NoError(t, err) + + targetDir := t.TempDir() + + outFlag := "--output=type=docker" + + if sb.Name() == "remote" { + // there is no Docker atm to load the image + outFlag += ",dest=" + targetDir + "/image.tar" + } + + cmd := buildxCmd(sb, "build", "-q", outFlag, "--iidfile", filepath.Join(targetDir, "iid.txt"), "--metadata-file", filepath.Join(targetDir, "md.json"), dir) + stdout := bytes.NewBuffer(nil) + cmd.Stdout = stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + + require.NoError(t, err) + + dt, err := os.ReadFile(filepath.Join(targetDir, "iid.txt")) + require.NoError(t, err) + + imageID := string(dt) + require.NotEmpty(t, imageID) + + dgst, err := digest.Parse(string(dt)) + require.NoError(t, err) + + require.Equal(t, dgst.String(), strings.TrimSpace(stdout.String())) + + dt, err = os.ReadFile(filepath.Join(targetDir, "md.json")) + require.NoError(t, err) + + type mdT struct { + ConfigDigest string `json:"containerimage.config.digest"` + } + var md mdT + err = json.Unmarshal(dt, &md) + require.NoError(t, err) + + require.NotEmpty(t, md.ConfigDigest) + require.Equal(t, dgst, digest.Digest(md.ConfigDigest)) +} + func createTestProject(t *testing.T) string { dockerfile := []byte(` FROM busybox:latest AS base