Merge pull request #188 from tonistiigi/empty-config
dockerfile: return valid empty image config for scratchdocker-18.09
commit
81551b56a9
|
@ -32,6 +32,9 @@ type blobmapper interface {
|
|||
}
|
||||
|
||||
func GetDiffPairs(ctx context.Context, contentStore content.Store, snapshotter snapshot.Snapshotter, differ diff.Differ, ref cache.ImmutableRef) ([]DiffPair, error) {
|
||||
if ref == nil {
|
||||
return nil, nil
|
||||
}
|
||||
blobmap, ok := snapshotter.(blobmapper)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("image exporter requires snapshotter with blobs mapping support")
|
||||
|
|
|
@ -52,6 +52,9 @@ func (s State) Marshal() (*Definition, error) {
|
|||
def := &Definition{
|
||||
Metadata: make(map[digest.Digest]OpMetadata, 0),
|
||||
}
|
||||
if s.Output() == nil {
|
||||
return def, nil
|
||||
}
|
||||
def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{})
|
||||
if err != nil {
|
||||
return def, err
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/moby/buildkit/cache"
|
||||
|
@ -56,21 +58,31 @@ func (e *localExporterInstance) Name() string {
|
|||
}
|
||||
|
||||
func (e *localExporterInstance) Export(ctx context.Context, ref cache.ImmutableRef, opt map[string][]byte) error {
|
||||
mount, err := ref.Mount(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var src string
|
||||
var err error
|
||||
if ref == nil {
|
||||
src, err = ioutil.TempDir("", "buildkit")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(src)
|
||||
} else {
|
||||
mount, err := ref.Mount(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
|
||||
dest, err := lm.Mount()
|
||||
if err != nil {
|
||||
return err
|
||||
src, err = lm.Mount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lm.Unmount()
|
||||
}
|
||||
defer lm.Unmount()
|
||||
|
||||
progress := newProgressHandler(ctx, "copying files")
|
||||
return filesync.CopyToCaller(ctx, dest, e.caller, progress)
|
||||
return filesync.CopyToCaller(ctx, src, e.caller, progress)
|
||||
}
|
||||
|
||||
func newProgressHandler(ctx context.Context, id string) func(int, bool) {
|
||||
|
|
|
@ -91,6 +91,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
if d.base == nil {
|
||||
if d.stage.BaseName == emptyImageName {
|
||||
d.state = llb.Scratch()
|
||||
d.image = emptyImage()
|
||||
continue
|
||||
}
|
||||
func(i int, d *dispatchState) {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dockerfile2llb
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/moby/buildkit/util/system"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
|
@ -58,3 +60,16 @@ func clone(src Image) Image {
|
|||
img.Config.Entrypoint = append([]string{}, src.Config.Entrypoint...)
|
||||
return img
|
||||
}
|
||||
|
||||
func emptyImage() Image {
|
||||
img := Image{
|
||||
Image: ocispec.Image{
|
||||
Architecture: runtime.GOARCH,
|
||||
OS: runtime.GOOS,
|
||||
},
|
||||
}
|
||||
img.RootFS.Type = "layers"
|
||||
img.Config.WorkingDir = "/"
|
||||
img.Config.Env = []string{"PATH=" + system.DefaultPathEnv}
|
||||
return img
|
||||
}
|
||||
|
|
|
@ -4,18 +4,26 @@ import (
|
|||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/fs/fstest"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/util/testutil/httpserver"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -25,6 +33,7 @@ func TestIntegration(t *testing.T) {
|
|||
testDockerfileInvalidCommand,
|
||||
testDockerfileADDFromURL,
|
||||
testDockerfileAddArchive,
|
||||
testDockerfileScratchConfig,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -342,6 +351,71 @@ ADD %s /
|
|||
require.Equal(t, buf2.Bytes(), dt)
|
||||
}
|
||||
|
||||
func testDockerfileScratchConfig(t *testing.T, sb integration.Sandbox) {
|
||||
var cdAddress string
|
||||
if cd, ok := sb.(interface {
|
||||
ContainerdAddress() string
|
||||
}); !ok {
|
||||
t.Skip("only for containerd worker")
|
||||
} else {
|
||||
cdAddress = cd.ContainerdAddress()
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
ENV foo=bar
|
||||
`)
|
||||
|
||||
dir, err := tmpdir(
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
args, trace := dfCmdArgs(dir, dir)
|
||||
defer os.RemoveAll(trace)
|
||||
|
||||
target := "example.com/moby/dockerfilescratch:test"
|
||||
cmd := sb.Cmd(args + " --exporter=image --exporter-opt=name=" + target)
|
||||
err = cmd.Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
client, err := containerd.New(cdAddress)
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), "buildkit")
|
||||
|
||||
img, err := client.ImageService().Get(ctx, target)
|
||||
require.NoError(t, err)
|
||||
|
||||
desc, err := img.Config(ctx, client.ContentStore(), platforms.Default())
|
||||
require.NoError(t, err)
|
||||
|
||||
dt, err := content.ReadBlob(ctx, client.ContentStore(), desc.Digest)
|
||||
require.NoError(t, err)
|
||||
|
||||
var ociimg ocispec.Image
|
||||
err = json.Unmarshal(dt, &ociimg)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, "", ociimg.OS)
|
||||
require.NotEqual(t, "", ociimg.Architecture)
|
||||
require.NotEqual(t, "", ociimg.Config.WorkingDir)
|
||||
require.Equal(t, "layers", ociimg.RootFS.Type)
|
||||
|
||||
require.Contains(t, ociimg.Config.Env, "foo=bar")
|
||||
require.Condition(t, func() bool {
|
||||
for _, env := range ociimg.Config.Env {
|
||||
if strings.HasPrefix(env, "PATH=") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func tmpdir(appliers ...fstest.Applier) (string, error) {
|
||||
tmpdir, err := ioutil.TempDir("", "buildkit-dockerfile")
|
||||
if err != nil {
|
||||
|
|
|
@ -156,15 +156,21 @@ func (s *Solver) Solve(ctx context.Context, id string, req SolveRequest) error {
|
|||
}
|
||||
|
||||
defer func() {
|
||||
go ref.Release(context.TODO())
|
||||
if ref != nil {
|
||||
go ref.Release(context.TODO())
|
||||
}
|
||||
}()
|
||||
|
||||
immutable, ok := toImmutableRef(ref)
|
||||
if !ok {
|
||||
return errors.Errorf("invalid reference for exporting: %T", ref)
|
||||
}
|
||||
if err := immutable.Finalize(ctx); err != nil {
|
||||
return err
|
||||
var immutable cache.ImmutableRef
|
||||
if ref != nil {
|
||||
var ok bool
|
||||
immutable, ok = toImmutableRef(ref)
|
||||
if !ok {
|
||||
return errors.Errorf("invalid reference for exporting: %T", ref)
|
||||
}
|
||||
if err := immutable.Finalize(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if exp := req.Exporter; exp != nil {
|
||||
|
@ -788,6 +794,10 @@ func (s *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (cache
|
|||
if !ok {
|
||||
return nil, nil, errors.Errorf("invalid frontend: %s", req.Frontend)
|
||||
}
|
||||
} else {
|
||||
if req.Definition == nil || req.Definition.Def == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
}
|
||||
ref, exp, err := s.solve(ctx, s.job, SolveRequest{
|
||||
Definition: req.Definition,
|
||||
|
|
Loading…
Reference in New Issue