Skip to content

Commit

Permalink
buildinfo: add build attributes and frontend
Browse files Browse the repository at this point in the history
Signed-off-by: CrazyMax <[email protected]>
  • Loading branch information
crazy-max committed Nov 24, 2021
1 parent 859b0fb commit da5482f
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 64 deletions.
20 changes: 16 additions & 4 deletions docs/build-repro.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Build dependencies are generated when your image has been built. These
dependencies include versions of used images, git repositories and HTTP URLs
used by LLB `Source` operation.
used by LLB `Source` operation as well as build request attributes.

By default, the build dependencies are embedded in the image configuration and
also available in the solver response. The export mode can be refined with
Expand All @@ -23,6 +23,15 @@ The structure is base64 encoded and has the following format when decoded:

```json
{
"frontend": "dockerfile.v0",
"attrs": {
"build-arg:foo": "bar",
"cmdline": "crazymax/dockerfile:master",
"context": "https://github.com/crazy-max/buildkit-buildsources-test.git#master",
"filename": "Dockerfile",
"platform": "linux/amd64,linux/arm64",
"source": "crazymax/dockerfile:master"
},
"sources": [
{
"type": "docker-image",
Expand All @@ -48,9 +57,12 @@ The structure is base64 encoded and has the following format when decoded:
}
```

* `type` defines the source type (`docker-image`, `git` or `http`).
* `ref` is the reference of the source.
* `pin` is the source digest.
* `frontend` defines the frontend used to build.
* `attrs` defines build request attributes.
* `sources` defines build dependencies.
* `type` defines the source type (`docker-image`, `git` or `http`).
* `ref` is the reference of the source.
* `pin` is the source digest.

### Exporter response (metadata)

Expand Down
2 changes: 1 addition & 1 deletion frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
}
if !isScratch {
// if image not scratch set original image name as ref
// and actual reference as alias in BuildSource
// and actual reference as alias in binfotypes.Source
d.buildSource = &binfotypes.Source{
Type: binfotypes.SourceTypeDockerImage,
Ref: origName,
Expand Down
4 changes: 2 additions & 2 deletions solver/llbsolver/solver.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
}
inp.Ref = workerRef.ImmutableRef

dtbi, err := buildinfo.Merge(ctx, res.BuildSources(), inp.Metadata[exptypes.ExporterImageConfigKey])
dtbi, err := buildinfo.Get(ctx, req, res.BuildSources(), inp.Metadata[exptypes.ExporterImageConfigKey])
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -207,7 +207,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
}
m[k] = workerRef.ImmutableRef

dtbi, err := buildinfo.Merge(ctx, res.BuildSources(), inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k)])
dtbi, err := buildinfo.Get(ctx, req, res.BuildSources(), inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k)])
if err != nil {
return nil, err
}
Expand Down
66 changes: 57 additions & 9 deletions util/buildinfo/buildinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"encoding/base64"
"encoding/json"
"sort"
"strings"

"github.com/docker/distribution/reference"
"github.com/moby/buildkit/frontend"
"github.com/moby/buildkit/source"
binfotypes "github.com/moby/buildkit/util/buildinfo/types"
"github.com/moby/buildkit/util/urlutil"
Expand All @@ -23,14 +25,26 @@ func Decode(enc string) (bi binfotypes.BuildInfo, _ error) {
return bi, err
}

// Merge combines and fixes build sources from image config
// key binfotypes.ImageConfigField.
func Merge(ctx context.Context, buildSources map[string]string, imageConfig []byte) ([]byte, error) {
// Get returns build info.
func Get(ctx context.Context, solveReq frontend.SolveRequest, buildSources map[string]string, imageConfig []byte) ([]byte, error) {
icbi, err := FromImageConfig(imageConfig)
if err != nil {
return nil, err
}
srcs, err := mergeSources(ctx, buildSources, icbi)
if err != nil {
return nil, err
}
return json.Marshal(binfotypes.BuildInfo{
Frontend: solveReq.Frontend,
Attrs: filterAttrs(solveReq.FrontendOpt),
Sources: srcs,
})
}

// mergeSources combines and fixes build sources from image config
// key binfotypes.ImageConfigField.
func mergeSources(ctx context.Context, buildSources map[string]string, imageConfigBuildInfo binfotypes.BuildInfo) ([]binfotypes.Source, error) {
// Iterate and combine build sources
mbs := map[string]binfotypes.Source{}
for buildSource, pin := range buildSources {
Expand All @@ -40,7 +54,7 @@ func Merge(ctx context.Context, buildSources map[string]string, imageConfig []by
}
switch sourceID := src.(type) {
case *source.ImageIdentifier:
for i, ics := range icbi.Sources {
for i, ics := range imageConfigBuildInfo.Sources {
// Use original user input from image config
if ics.Type == binfotypes.SourceTypeDockerImage && ics.Alias == sourceID.Reference.String() {
if _, ok := mbs[ics.Alias]; !ok {
Expand All @@ -53,7 +67,7 @@ func Merge(ctx context.Context, buildSources map[string]string, imageConfig []by
Ref: reference.TagNameOnly(parsed).String(),
Pin: pin,
}
icbi.Sources = append(icbi.Sources[:i], icbi.Sources[i+1:]...)
imageConfigBuildInfo.Sources = append(imageConfigBuildInfo.Sources[:i], imageConfigBuildInfo.Sources[i+1:]...)
}
break
}
Expand Down Expand Up @@ -94,7 +108,7 @@ func Merge(ctx context.Context, buildSources map[string]string, imageConfig []by
// Leftovers build deps in image config. Mostly duplicated ones we
// don't need but there is an edge case if no instruction except sources
// one is defined (e.g. FROM ...) that can be valid so take it into account.
for _, ics := range icbi.Sources {
for _, ics := range imageConfigBuildInfo.Sources {
if ics.Type != binfotypes.SourceTypeDockerImage {
continue
}
Expand All @@ -119,9 +133,7 @@ func Merge(ctx context.Context, buildSources map[string]string, imageConfig []by
return srcs[i].Ref < srcs[j].Ref
})

return json.Marshal(binfotypes.BuildInfo{
Sources: srcs,
})
return srcs, nil
}

// FromImageConfig returns build dependencies from image config.
Expand All @@ -141,3 +153,39 @@ func FromImageConfig(imageConfig []byte) (bi binfotypes.BuildInfo, _ error) {
}
return bi, nil
}

var knownAttrs = []string{
"cmdline",
"context",
"filename",
"source",

//"add-hosts",
//"cgroup-parent",
//"force-network-mode",
//"hostname",
//"image-resolve-mode",
"platform",
"shm-size",
"target",
"ulimit",
}

// filterAttrs filters frontent opt by picking only those that
// could effectively change the build result.
func filterAttrs(attrs map[string]string) map[string]string {
filtered := make(map[string]string)
for k, v := range attrs {
if strings.HasPrefix(k, "build-arg:") || strings.HasPrefix(k, "label:") {
filtered[k] = v
continue
}
for _, knownAttr := range knownAttrs {
if knownAttr == k {
filtered[k] = v
break
}
}
}
return filtered
}
83 changes: 35 additions & 48 deletions util/buildinfo/buildinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package buildinfo

import (
"context"
"encoding/base64"
"encoding/json"
"testing"

binfotypes "github.com/moby/buildkit/util/buildinfo/types"
Expand All @@ -17,7 +15,7 @@ func TestDecode(t *testing.T) {
assert.Equal(t, 6, len(bi.Sources))
}

func TestMerge(t *testing.T) {
func TestMergeSources(t *testing.T) {
buildSourcesLLB := map[string]string{
"docker-image://docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0": "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
"docker-image://docker.io/library/alpine:3.13@sha256:1d30d1ba3cb90962067e9b29491fbd56997979d54376f23f01448b5c5cd8b462": "sha256:1d30d1ba3cb90962067e9b29491fbd56997979d54376f23f01448b5c5cd8b462",
Expand All @@ -27,7 +25,7 @@ func TestMerge(t *testing.T) {
"https://raw.githubusercontent.com/moby/moby/master/README.md": "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c",
}

buildInfoImageConfig, err := json.Marshal(binfotypes.BuildInfo{
buildInfo := binfotypes.BuildInfo{
Sources: []binfotypes.Source{
{
Type: binfotypes.SourceTypeDockerImage,
Expand All @@ -54,52 +52,41 @@ func TestMerge(t *testing.T) {
Pin: "sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04",
},
},
})
require.NoError(t, err)

bic, err := json.Marshal(binfotypes.ImageConfig{
BuildInfo: buildInfoImageConfig,
})
require.NoError(t, err)

ret, err := Merge(context.Background(), buildSourcesLLB, bic)
require.NoError(t, err)
}

dec, err := Decode(base64.StdEncoding.EncodeToString(ret))
srcs, err := mergeSources(context.Background(), buildSourcesLLB, buildInfo)
require.NoError(t, err)

assert.Equal(t, binfotypes.BuildInfo{
Sources: []binfotypes.Source{
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
Pin: "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/library/alpine:3.13",
Pin: "sha256:1d30d1ba3cb90962067e9b29491fbd56997979d54376f23f01448b5c5cd8b462",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/moby/buildkit:v0.9.0",
Pin: "sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/tonistiigi/xx@sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04",
Pin: "sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04",
},
{
Type: binfotypes.SourceTypeGit,
Ref: "https://github.com/crazy-max/buildkit-buildsources-test.git#master",
Pin: "259a5aa5aa5bb3562d12cc631fe399f4788642c1",
},
{
Type: binfotypes.SourceTypeHTTP,
Ref: "https://raw.githubusercontent.com/moby/moby/master/README.md",
Pin: "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c",
},
assert.Equal(t, []binfotypes.Source{
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
Pin: "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/library/alpine:3.13",
Pin: "sha256:1d30d1ba3cb90962067e9b29491fbd56997979d54376f23f01448b5c5cd8b462",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/moby/buildkit:v0.9.0",
Pin: "sha256:8dc668e7f66db1c044aadbed306020743516a94848793e0f81f94a087ee78cab",
},
{
Type: binfotypes.SourceTypeDockerImage,
Ref: "docker.io/tonistiigi/xx@sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04",
Pin: "sha256:21a61be4744f6531cb5f33b0e6f40ede41fa3a1b8c82d5946178f80cc84bfc04",
},
{
Type: binfotypes.SourceTypeGit,
Ref: "https://github.com/crazy-max/buildkit-buildsources-test.git#master",
Pin: "259a5aa5aa5bb3562d12cc631fe399f4788642c1",
},
{
Type: binfotypes.SourceTypeHTTP,
Ref: "https://raw.githubusercontent.com/moby/moby/master/README.md",
Pin: "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c",
},
}, dec)
}, srcs)
}
4 changes: 4 additions & 0 deletions util/buildinfo/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ type ImageConfig struct {
// ImageConfigField key and returned in solver ExporterResponse as
// exptypes.ExporterBuildInfo key.
type BuildInfo struct {
// Frontend defines the frontend used to build.
Frontend string `json:"frontend,omitempty"`
// Attrs defines build request attributes.
Attrs map[string]string `json:"attrs,omitempty"`
// Sources defines build dependencies.
Sources []Source `json:"sources,omitempty"`
}
Expand Down

0 comments on commit da5482f

Please sign in to comment.