Merge pull request #687 from tonistiigi/dockerfile-testing

dockerfile: add testing external dockerfile features
docker-18.09
Akihiro Suda 2018-10-16 15:58:55 +09:00 committed by GitHub
commit 0d80bd17a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 250 additions and 74 deletions

View File

@ -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

View File

@ -1,4 +1,4 @@
// +build !dfrunmount,!dfextall
// +build !dfrunmount
package dockerfile2llb

View File

@ -1,4 +1,4 @@
// +build dfrunmount dfextall
// +build dfrunmount
package dockerfile2llb

View File

@ -1,4 +1,4 @@
// +build dfsecrets dfextall
// +build dfsecrets
package dockerfile2llb

View File

@ -1,4 +1,4 @@
// +build dfssh dfextall
// +build dfssh
package dockerfile2llb

View File

@ -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)
}

View File

@ -37,6 +37,51 @@ import (
"github.com/stretchr/testify/require"
)
var allTests = []integration.Test{
testNoSnapshotLeak,
testCmdShell,
testGlobalArg,
testDockerfileDirs,
testDockerfileInvalidCommand,
testDockerfileADDFromURL,
testDockerfileAddArchive,
testDockerfileScratchConfig,
testExportedHistory,
testExposeExpansion,
testUser,
testDockerignore,
testDockerignoreInvalid,
testDockerfileFromGit,
testCopyChown,
testCopyWildcards,
testCopyOverrideFiles,
testMultiStageImplicitFrom,
testCopyVarSubstitution,
testMultiStageCaseInsensitive,
testLabels,
testCacheImportExport,
testReproducibleIDs,
testImportExportReproducibleIDs,
testNoCache,
testDockerfileFromHTTP,
testBuiltinArgs,
testPullScratch,
testSymlinkDestination,
testHTTPDockerfile,
testNoSnapshotLeak,
testCopySymlinks,
testContextChangeDirToFile,
testPlatformArgsImplicit,
testPlatformArgsExplicit,
testExportMultiPlatform,
testQuotedMetaArgs,
testIgnoreEntrypoint,
testCopyThroughSymlinkContext,
testCopyThroughSymlinkMultiStage,
testCopyChownCreateDest,
testEmptyDestDir,
}
var opts []integration.TestOpt
type frontend interface {
@ -73,50 +118,7 @@ func init() {
}
func TestIntegration(t *testing.T) {
integration.Run(t, []integration.Test{
testNoSnapshotLeak,
testCmdShell,
testGlobalArg,
testDockerfileDirs,
testDockerfileInvalidCommand,
testDockerfileADDFromURL,
testDockerfileAddArchive,
testDockerfileScratchConfig,
testExportedHistory,
testExposeExpansion,
testUser,
testDockerignore,
testDockerignoreInvalid,
testDockerfileFromGit,
testCopyChown,
testCopyWildcards,
testCopyOverrideFiles,
testMultiStageImplicitFrom,
testCopyVarSubstitution,
testMultiStageCaseInsensitive,
testLabels,
testCacheImportExport,
testReproducibleIDs,
testImportExportReproducibleIDs,
testNoCache,
testDockerfileFromHTTP,
testBuiltinArgs,
testPullScratch,
testSymlinkDestination,
testHTTPDockerfile,
testNoSnapshotLeak,
testCopySymlinks,
testContextChangeDirToFile,
testPlatformArgsImplicit,
testPlatformArgsExplicit,
testExportMultiPlatform,
testQuotedMetaArgs,
testIgnoreEntrypoint,
testCopyThroughSymlinkContext,
testCopyThroughSymlinkMultiStage,
testCopyChownCreateDest,
testEmptyDestDir,
}, opts...)
integration.Run(t, allTests, opts...)
}
func testEmptyDestDir(t *testing.T, sb integration.Sandbox) {

View File

@ -1,4 +1,4 @@
// +build !dfsecrets,!dfextall
// +build !dfsecrets
package instructions

View File

@ -1,4 +1,4 @@
// +build !dfssh,!dfextall
// +build !dfssh
package instructions

View File

@ -1,4 +1,4 @@
// +build dfrunmount dfextall
// +build dfrunmount
package instructions

View File

@ -1,4 +1,4 @@
// +build dfsecrets dfextall
// +build dfsecrets
package instructions

View File

@ -1,4 +1,4 @@
// +build dfssh dfextall
// +build dfssh
package instructions

View File

@ -0,0 +1 @@
dfrunmount dfsecrets dfssh

View File

@ -0,0 +1 @@
dfrunmount

View File

@ -0,0 +1 @@
dfrunmount dfsecrets

View File

@ -0,0 +1 @@
dfrunmount dfssh

View File

@ -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

View File

@ -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 \

View File

@ -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"
@ -87,4 +119,4 @@ case $buildmode in
"legacy")
rm "$iidfile"
;;
esac
esac

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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,9 +187,23 @@ func copyImagesLocal(t *testing.T, host string, images map[string]string) error
}
localImageCache[host][to] = struct{}{}
desc, provider, err := contentutil.ProviderFromRef(from)
if err != nil {
return err
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 {