Merge pull request #687 from tonistiigi/dockerfile-testing
dockerfile: add testing external dockerfile featuresdocker-18.09
commit
0d80bd17a3
|
@ -1,10 +1,15 @@
|
|||
FROM --platform=$BUILDPLATFORM golang:1.11-alpine AS builder
|
||||
# syntax = tonistiigi/dockerfile:runmount20181002
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.11 AS builder
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends file
|
||||
ARG BUILDTAGS=""
|
||||
COPY . /go/src/github.com/moby/buildkit
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ENV GOOS=$TARGETOS GOARCH=$TARGETARCH
|
||||
RUN CGO_ENABLED=0 go build -o /dockerfile-frontend -tags "$BUILDTAGS" --ldflags '-extldflags "-static"' github.com/moby/buildkit/frontend/dockerfile/cmd/dockerfile-frontend
|
||||
WORKDIR /go/src/github.com/moby/buildkit
|
||||
RUN --mount=target=. --mount=type=cache,target=/root/.cache \
|
||||
CGO_ENABLED=0 go build -o /dockerfile-frontend -tags "$BUILDTAGS" --ldflags '-extldflags "-static"' ./frontend/dockerfile/cmd/dockerfile-frontend && \
|
||||
file /dockerfile-frontend | grep "statically linked"
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /dockerfile-frontend /bin/dockerfile-frontend
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !dfrunmount,!dfextall
|
||||
// +build !dfrunmount
|
||||
|
||||
package dockerfile2llb
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfrunmount dfextall
|
||||
// +build dfrunmount
|
||||
|
||||
package dockerfile2llb
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfsecrets dfextall
|
||||
// +build dfsecrets
|
||||
|
||||
package dockerfile2llb
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfssh dfextall
|
||||
// +build dfssh
|
||||
|
||||
package dockerfile2llb
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// +build dfrunmount
|
||||
|
||||
package dockerfile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/builder"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var mountTests = []integration.Test{
|
||||
testMountContext,
|
||||
}
|
||||
|
||||
func init() {
|
||||
allTests = append(allTests, mountTests...)
|
||||
}
|
||||
|
||||
func testMountContext(t *testing.T, sb integration.Sandbox) {
|
||||
f := getFrontend(t, sb)
|
||||
|
||||
dockerfile := []byte(`
|
||||
FROM busybox
|
||||
RUN --mount=target=/context [ "$(cat /context/testfile)" == "contents0" ]
|
||||
`)
|
||||
|
||||
dir, err := tmpdir(
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("testfile", []byte("contents0"), 0600),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
c, err := client.New(context.TODO(), sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
_, err = f.Solve(context.TODO(), c, client.SolveOpt{
|
||||
LocalDirs: map[string]string{
|
||||
builder.LocalNameDockerfile: dir,
|
||||
builder.LocalNameContext: dir,
|
||||
},
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
|
@ -37,43 +37,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var opts []integration.TestOpt
|
||||
|
||||
type frontend interface {
|
||||
Solve(context.Context, *client.Client, client.SolveOpt, chan *client.SolveStatus) (*client.SolveResponse, error)
|
||||
DFCmdArgs(string, string) (string, string)
|
||||
RequiresBuildctl(t *testing.T)
|
||||
}
|
||||
|
||||
func init() {
|
||||
frontends := map[string]interface{}{}
|
||||
|
||||
opts = []integration.TestOpt{
|
||||
integration.WithMirroredImages(integration.OfficialImages("busybox:latest")),
|
||||
integration.WithMirroredImages(map[string]string{
|
||||
"tonistiigi/copy:v0.1.7": "docker.io/" + dockerfile2llb.DefaultCopyImage,
|
||||
}),
|
||||
integration.WithMatrix("frontend", frontends),
|
||||
}
|
||||
|
||||
if os.Getenv("FRONTEND_BUILTIN_ONLY") == "1" {
|
||||
frontends["builtin"] = &builtinFrontend{}
|
||||
} else if os.Getenv("FRONTEND_CLIENT_ONLY") == "1" {
|
||||
frontends["client"] = &clientFrontend{}
|
||||
} else if gw := os.Getenv("FRONTEND_GATEWAY_ONLY"); gw != "" {
|
||||
name := "buildkit_test/" + identity.NewID() + ":latest"
|
||||
opts = append(opts, integration.WithMirroredImages(map[string]string{
|
||||
name: gw,
|
||||
}))
|
||||
frontends["gateway"] = &gatewayFrontend{gw: name}
|
||||
} else {
|
||||
frontends["builtin"] = &builtinFrontend{}
|
||||
frontends["client"] = &clientFrontend{}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
integration.Run(t, []integration.Test{
|
||||
var allTests = []integration.Test{
|
||||
testNoSnapshotLeak,
|
||||
testCmdShell,
|
||||
testGlobalArg,
|
||||
|
@ -116,7 +80,45 @@ func TestIntegration(t *testing.T) {
|
|||
testCopyThroughSymlinkMultiStage,
|
||||
testCopyChownCreateDest,
|
||||
testEmptyDestDir,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
var opts []integration.TestOpt
|
||||
|
||||
type frontend interface {
|
||||
Solve(context.Context, *client.Client, client.SolveOpt, chan *client.SolveStatus) (*client.SolveResponse, error)
|
||||
DFCmdArgs(string, string) (string, string)
|
||||
RequiresBuildctl(t *testing.T)
|
||||
}
|
||||
|
||||
func init() {
|
||||
frontends := map[string]interface{}{}
|
||||
|
||||
opts = []integration.TestOpt{
|
||||
integration.WithMirroredImages(integration.OfficialImages("busybox:latest")),
|
||||
integration.WithMirroredImages(map[string]string{
|
||||
"tonistiigi/copy:v0.1.7": "docker.io/" + dockerfile2llb.DefaultCopyImage,
|
||||
}),
|
||||
integration.WithMatrix("frontend", frontends),
|
||||
}
|
||||
|
||||
if os.Getenv("FRONTEND_BUILTIN_ONLY") == "1" {
|
||||
frontends["builtin"] = &builtinFrontend{}
|
||||
} else if os.Getenv("FRONTEND_CLIENT_ONLY") == "1" {
|
||||
frontends["client"] = &clientFrontend{}
|
||||
} else if gw := os.Getenv("FRONTEND_GATEWAY_ONLY"); gw != "" {
|
||||
name := "buildkit_test/" + identity.NewID() + ":latest"
|
||||
opts = append(opts, integration.WithMirroredImages(map[string]string{
|
||||
name: gw,
|
||||
}))
|
||||
frontends["gateway"] = &gatewayFrontend{gw: name}
|
||||
} else {
|
||||
frontends["builtin"] = &builtinFrontend{}
|
||||
frontends["client"] = &clientFrontend{}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
integration.Run(t, allTests, opts...)
|
||||
}
|
||||
|
||||
func testEmptyDestDir(t *testing.T, sb integration.Sandbox) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !dfsecrets,!dfextall
|
||||
// +build !dfsecrets
|
||||
|
||||
package instructions
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !dfssh,!dfextall
|
||||
// +build !dfssh
|
||||
|
||||
package instructions
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfrunmount dfextall
|
||||
// +build dfrunmount
|
||||
|
||||
package instructions
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfsecrets dfextall
|
||||
// +build dfsecrets
|
||||
|
||||
package instructions
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build dfssh dfextall
|
||||
// +build dfssh
|
||||
|
||||
package instructions
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
dfrunmount dfsecrets dfssh
|
|
@ -0,0 +1 @@
|
|||
dfrunmount
|
|
@ -0,0 +1 @@
|
|||
dfrunmount dfsecrets
|
|
@ -0,0 +1 @@
|
|||
dfrunmount dfssh
|
|
@ -4,7 +4,7 @@ ARG CONTAINERD_VERSION=v1.2.0-rc.1
|
|||
ARG CONTAINERD10_VERSION=v1.0.3
|
||||
# available targets: buildkitd, buildkitd.oci_only, buildkitd.containerd_only
|
||||
ARG BUILDKIT_TARGET=buildkitd
|
||||
ARG REGISTRY_VERSION=2.6
|
||||
ARG REGISTRY_VERSION=v2.7.0-rc.0
|
||||
ARG ROOTLESSKIT_VERSION=4f7ae4607d626f0a22fb495056d55b17cce8c01b
|
||||
|
||||
# The `buildkitd` stage and the `buildctl` stage are placed here
|
||||
|
@ -74,7 +74,7 @@ FROM buildkit-base AS buildkitd.containerd_only
|
|||
ENV CGO_ENABLED=0
|
||||
RUN go build -ldflags "$(cat .tmp/ldflags) -d" -o /usr/bin/buildkitd.containerd_only -tags no_oci_worker ./cmd/buildkitd
|
||||
|
||||
FROM registry:$REGISTRY_VERSION AS registry
|
||||
FROM tonistiigi/registry:$REGISTRY_VERSION AS registry
|
||||
|
||||
FROM gobuild-base AS rootlesskit-base
|
||||
RUN git clone https://github.com/rootless-containers/rootlesskit.git /go/src/github.com/rootless-containers/rootlesskit
|
||||
|
|
|
@ -6,7 +6,7 @@ ARG CONTAINERD_VERSION=v1.2.0-rc.1
|
|||
ARG CONTAINERD10_VERSION=v1.0.3
|
||||
# available targets: buildkitd, buildkitd.oci_only, buildkitd.containerd_only
|
||||
ARG BUILDKIT_TARGET=buildkitd
|
||||
ARG REGISTRY_VERSION=2.6
|
||||
ARG REGISTRY_VERSION=v2.7.0-rc.0
|
||||
ARG ROOTLESSKIT_VERSION=4f7ae4607d626f0a22fb495056d55b17cce8c01b
|
||||
ARG ROOTLESS_BASE_MODE=external
|
||||
|
||||
|
@ -149,7 +149,7 @@ RUN --mount=from=containerd-src,src=/usr/src/containerd,readwrite --mount=target
|
|||
&& make bin/containerd-shim \
|
||||
&& mv bin /out
|
||||
|
||||
FROM registry:$REGISTRY_VERSION AS registry
|
||||
FROM tonistiigi/registry:$REGISTRY_VERSION AS registry
|
||||
|
||||
FROM gobuild-base AS rootlesskit
|
||||
ARG ROOTLESSKIT_VERSION
|
||||
|
@ -188,7 +188,7 @@ ENTRYPOINT ["containerd"]
|
|||
|
||||
FROM buildkit-base AS integration-tests
|
||||
ENV BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR="1000:1000"
|
||||
RUN apt-get install -y --no-install-recommends uidmap sudo musl \
|
||||
RUN apt-get install -y --no-install-recommends uidmap sudo \
|
||||
&& useradd --create-home --home-dir /home/user --uid 1000 -s /bin/sh user \
|
||||
&& echo "XDG_RUNTIME_DIR=/run/user/1000; export XDG_RUNTIME_DIR" >> /home/user/.profile \
|
||||
&& mkdir -m 0700 -p /run/user/1000 \
|
||||
|
|
46
hack/test
46
hack/test
|
@ -6,7 +6,9 @@ set -eu -o pipefail
|
|||
: ${TEST_INTEGRATION=}
|
||||
: ${TEST_GATEWAY=}
|
||||
: ${TEST_DOCKERFILE=}
|
||||
: ${DOCKERFILE_RELEASES=}
|
||||
: ${CONTINUOUS_INTEGRATION=}
|
||||
: ${BUILDKIT_REGISTRY_MIRROR_DIR=}
|
||||
|
||||
progressFlag=""
|
||||
if [ "$CONTINUOUS_INTEGRATION" == "true" ]; then progressFlag="--progress=plain"; fi
|
||||
|
@ -32,7 +34,6 @@ while test $# -gt 0
|
|||
shift
|
||||
done
|
||||
|
||||
|
||||
iid="buildkit-tests"
|
||||
iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
|
||||
set -x
|
||||
|
@ -61,8 +62,10 @@ case $buildmode in
|
|||
;;
|
||||
esac
|
||||
|
||||
cacheVolume=$(docker create -v /root/.cache -v /root/.cache/registry alpine)
|
||||
|
||||
if [ "$TEST_INTEGRATION" == 1 ]; then
|
||||
docker run --rm -v /tmp --privileged $iid go test ${TESTFLAGS:--v} ${TESTPKGS:-./...}
|
||||
docker run --rm -v /tmp --volumes-from=$cacheVolume -e BUILDKIT_REGISTRY_MIRROR_DIR=/root/.cache/registry --privileged $iid go test ${TESTFLAGS:--v} ${TESTPKGS:-./...}
|
||||
fi
|
||||
|
||||
|
||||
|
@ -72,13 +75,42 @@ fi
|
|||
|
||||
|
||||
if [ "$TEST_DOCKERFILE" == 1 ]; then
|
||||
docker run --rm $iid go build ./frontend/dockerfile/cmd/dockerfile-frontend
|
||||
docker run --rm $iid go build -tags dfrunmount ./frontend/dockerfile/cmd/dockerfile-frontend
|
||||
docker run --rm $iid go build -tags "dfrunmount dfsecrets" ./frontend/dockerfile/cmd/dockerfile-frontend
|
||||
docker run --rm $iid go build -tags "dfrunmount dfssh" ./frontend/dockerfile/cmd/dockerfile-frontend
|
||||
docker run --rm $iid go build -tags dfextall ./frontend/dockerfile/cmd/dockerfile-frontend
|
||||
if [ -z $DOCKERFILE_RELEASES ]; then
|
||||
DOCKERFILE_RELEASES="mainline experimental mounts secrets ssh"
|
||||
fi
|
||||
|
||||
|
||||
for release in $DOCKERFILE_RELEASES; do
|
||||
buildtags=$(cat ./frontend/dockerfile/release/$release/tags)
|
||||
tarout=$(mktemp -t dockerfile-frontend.XXXXXXXXXX)
|
||||
case $buildmode in
|
||||
"buildkit")
|
||||
buildctl build $progressFlag --frontend=dockerfile.v0 --local context=. --local dockerfile=. \
|
||||
--frontend-opt filename=./frontend/dockerfile/cmd/dockerfile-frontend/Dockerfile \
|
||||
--frontend-opt build-arg:BUILDTAGS="$buildtags" \
|
||||
--exporter=oci --exporter-opt output=$tarout
|
||||
;;
|
||||
"docker-buildkit")
|
||||
dfiidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
|
||||
docker build --iidfile=$dfiidfile -f ./frontend/dockerfile/cmd/dockerfile-frontend/Dockerfile --build-arg BUILDTAGS="$buildtags" .
|
||||
dfiid=$(cat $dfiidfile)
|
||||
docker save -o $tarout $dfiid
|
||||
docker rmi $dfiid
|
||||
rm $dfiidfile
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -s $tarout ]; then
|
||||
cid=$(docker create -v /tmp --rm --privileged --volumes-from=$cacheVolume -e BUILDKIT_REGISTRY_MIRROR_DIR=/root/.cache/registry -e BUILDKIT_WORKER_RANDOM=1 -e FRONTEND_GATEWAY_ONLY=local:/$release.tar -e EXTERNAL_DF_FRONTEND=/dockerfile-frontend $iid go test --count=1 -tags "$buildtags" ${TESTFLAGS:--v} ./frontend/dockerfile)
|
||||
docker cp $tarout $cid:/$release.tar
|
||||
docker start -a $cid
|
||||
fi
|
||||
rm $tarout
|
||||
done
|
||||
fi
|
||||
|
||||
docker rm -v $cacheVolume
|
||||
|
||||
case $buildmode in
|
||||
"docker-buildkit")
|
||||
rm "$iidfile"
|
||||
|
|
|
@ -72,6 +72,7 @@ func (w *ingester) Writer(ctx context.Context, opts ...content.WriterOpt) (conte
|
|||
}
|
||||
writer, err := w.pusher.Push(ctx, wo.Desc)
|
||||
if err != nil {
|
||||
unlock()
|
||||
return nil, err
|
||||
}
|
||||
return &lockedWriter{unlock: unlock, Writer: writer}, nil
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/content/local"
|
||||
"github.com/containerd/containerd/images/archive"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
func providerFromBinary(fn string) (_ ocispec.Descriptor, _ content.Provider, _ func(), err error) {
|
||||
ctx := context.TODO()
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "buildkit-state")
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
close := func() {
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
close()
|
||||
}
|
||||
}()
|
||||
// can't use contentutil.Buffer because ImportIndex takes content.Store even though only requires Provider/Ingester
|
||||
c, err := local.NewStore(tmpDir)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
|
||||
f, err := os.Open(fn)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
desc, err := archive.ImportIndex(ctx, c, f)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
|
||||
var idx ocispec.Index
|
||||
dt, err := content.ReadBlob(ctx, c, desc)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
if err := json.Unmarshal(dt, &idx); err != nil {
|
||||
return ocispec.Descriptor{}, nil, nil, err
|
||||
}
|
||||
|
||||
return idx.Manifests[0], c, close, nil
|
||||
}
|
|
@ -58,7 +58,7 @@ http:
|
|||
}
|
||||
|
||||
cmd := exec.Command("registry", "serve", filepath.Join(dir, "config.yaml"))
|
||||
rc, err := cmd.StdoutPipe()
|
||||
rc, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -14,8 +15,11 @@ import (
|
|||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/moby/buildkit/util/contentutil"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -123,7 +127,13 @@ func Run(t *testing.T, testCases []Test, opt ...TestOpt) {
|
|||
|
||||
matrix := prepareValueMatrix(tc)
|
||||
|
||||
for _, br := range List() {
|
||||
list := List()
|
||||
if os.Getenv("BUILDKIT_WORKER_RANDOM") == "1" && len(list) > 0 {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
list = []Worker{list[rand.Intn(len(list))]}
|
||||
}
|
||||
|
||||
for _, br := range list {
|
||||
for _, tc := range testCases {
|
||||
for _, mv := range matrix {
|
||||
fn := getFunctionName(tc)
|
||||
|
@ -177,10 +187,24 @@ func copyImagesLocal(t *testing.T, host string, images map[string]string) error
|
|||
}
|
||||
localImageCache[host][to] = struct{}{}
|
||||
|
||||
desc, provider, err := contentutil.ProviderFromRef(from)
|
||||
var desc ocispec.Descriptor
|
||||
var provider content.Provider
|
||||
var err error
|
||||
if strings.HasPrefix(from, "local:") {
|
||||
var closer func()
|
||||
desc, provider, closer, err = providerFromBinary(strings.TrimPrefix(from, "local:"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if closer != nil {
|
||||
defer closer()
|
||||
}
|
||||
} else {
|
||||
desc, provider, err = contentutil.ProviderFromRef(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ingester, err := contentutil.IngesterFromRef(host + "/" + to)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Reference in New Issue