Skip to content

Commit

Permalink
image exporter: return image descriptor in response
Browse files Browse the repository at this point in the history
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
  • Loading branch information
crazy-max committed Feb 8, 2022
1 parent fb38dd3 commit 254b272
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 2 deletions.
40 changes: 40 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
Expand Down Expand Up @@ -143,6 +144,7 @@ func TestIntegration(t *testing.T) {
testMergeOpCacheMax,
testRmSymlink,
testMoveParentDir,
testExporterImageDescriptor,
)
tests = append(tests, diffOpTestCases()...)
integration.Run(t, tests, mirrors)
Expand Down Expand Up @@ -4860,6 +4862,44 @@ func testRelativeMountpoint(t *testing.T, sb integration.Sandbox) {
require.Equal(t, dt, []byte(id))
}

func testExporterImageDescriptor(t *testing.T, sb integration.Sandbox) {
skipDockerd(t, sb)
requiresLinux(t)
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

st := llb.Image("busybox:latest")
def, err := st.Marshal(sb.Context())
require.NoError(t, err)

res, err := c.Solve(sb.Context(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterOCI,
Attrs: map[string]string{},
Output: func(m map[string]string) (io.WriteCloser, error) {
return nil, nil
},
},
},
}, nil)
require.NoError(t, err)

require.Contains(t, res.ExporterResponse, exptypes.ExporterImageDescriptorKey)
dt, err := base64.StdEncoding.DecodeString(res.ExporterResponse[exptypes.ExporterImageDescriptorKey])
require.NoError(t, err)

var desc *ocispecs.Descriptor
err = json.Unmarshal(dt, &desc)
require.NoError(t, err)

require.NotEmpty(t, desc.MediaType)
require.NotEmpty(t, desc.Digest.String())
require.True(t, strings.HasPrefix(desc.Digest.String(), "sha256:"))
require.Equal(t, res.ExporterResponse[exptypes.ExporterImageDigestKey], desc.Digest.String())
}

func tmpdir(appliers ...fstest.Applier) (string, error) {
tmpdir, err := ioutil.TempDir("", "buildkit-client")
if err != nil {
Expand Down
17 changes: 16 additions & 1 deletion cmd/buildctl/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/base64"
"encoding/json"
"io"
"os"
Expand Down Expand Up @@ -315,7 +316,21 @@ func buildAction(clicontext *cli.Context) error {
}

func writeMetadataFile(filename string, exporterResponse map[string]string) error {
b, err := json.Marshal(exporterResponse)
out := make(map[string]interface{})
for k, v := range exporterResponse {
dt, err := base64.StdEncoding.DecodeString(v)
if err != nil {
out[k] = v
continue
}
var raw json.RawMessage
if json.Unmarshal(dt, &raw) != nil {
out[k] = v
continue
}
out[k] = raw
}
b, err := json.Marshal(out)
if err != nil {
return err
}
Expand Down
14 changes: 13 additions & 1 deletion cmd/buildctl/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/util/testutil/integration"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -142,15 +143,26 @@ func testBuildMetadataFile(t *testing.T, sb integration.Sandbox) {
metadataBytes, err := ioutil.ReadFile(metadataFile)
require.NoError(t, err)

var metadata map[string]string
var metadata map[string]interface{}
err = json.Unmarshal(metadataBytes, &metadata)
require.NoError(t, err)

require.Contains(t, metadata, "image.name")
require.Equal(t, imageName, metadata["image.name"])

require.Contains(t, metadata, exptypes.ExporterImageDigestKey)
digest := metadata[exptypes.ExporterImageDigestKey]
require.NotEmpty(t, digest)

require.Contains(t, metadata, exptypes.ExporterImageDescriptorKey)
var desc *ocispecs.Descriptor
dtdesc, err := json.Marshal(metadata[exptypes.ExporterImageDescriptorKey])
require.NoError(t, err)
err = json.Unmarshal(dtdesc, &desc)
require.NoError(t, err)
require.NotEmpty(t, desc.MediaType)
require.NotEmpty(t, desc.Digest.String())

cdAddress := sb.ContainerdAddress()
if cdAddress == "" {
t.Log("no containerd worker, skipping digest verification")
Expand Down
9 changes: 9 additions & 0 deletions exporter/containerimage/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package containerimage

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -347,6 +349,13 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
if v, ok := desc.Annotations[exptypes.ExporterConfigDigestKey]; ok {
resp[exptypes.ExporterImageConfigDigestKey] = v
}

dtdesc, err := json.Marshal(desc)
if err != nil {
return nil, err
}
resp[exptypes.ExporterImageDescriptorKey] = base64.StdEncoding.EncodeToString(dtdesc)

return resp, nil
}

Expand Down
1 change: 1 addition & 0 deletions exporter/containerimage/exptypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
ExporterImageDigestKey = "containerimage.digest"
ExporterImageConfigKey = "containerimage.config"
ExporterImageConfigDigestKey = "containerimage.config.digest"
ExporterImageDescriptorKey = "containerimage.descriptor"
ExporterInlineCache = "containerimage.inlinecache"
ExporterBuildInfo = "containerimage.buildinfo"
ExporterPlatformsKey = "refs.platforms"
Expand Down
9 changes: 9 additions & 0 deletions exporter/oci/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package oci

import (
"context"
"encoding/base64"
"encoding/json"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -208,6 +210,13 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
desc.Annotations[ocispecs.AnnotationCreated] = time.Now().UTC().Format(time.RFC3339)

resp := make(map[string]string)

dtdesc, err := json.Marshal(desc)
if err != nil {
return nil, err
}
resp[exptypes.ExporterImageDescriptorKey] = base64.StdEncoding.EncodeToString(dtdesc)

resp[exptypes.ExporterImageDigestKey] = desc.Digest.String()
if v, ok := desc.Annotations[exptypes.ExporterConfigDigestKey]; ok {
resp[exptypes.ExporterImageConfigDigestKey] = v
Expand Down

0 comments on commit 254b272

Please sign in to comment.