2017-06-19 20:39:00 +00:00
package client
import (
2017-12-05 23:32:52 +00:00
"archive/tar"
"bytes"
"compress/gzip"
2017-06-19 20:39:00 +00:00
"context"
2017-12-05 23:32:52 +00:00
"encoding/json"
2018-07-06 12:03:53 +00:00
"fmt"
2017-12-05 23:32:52 +00:00
"io"
2017-12-02 02:17:40 +00:00
"io/ioutil"
2017-12-04 03:38:37 +00:00
"net/http"
2017-12-02 02:17:40 +00:00
"os"
"path/filepath"
2017-07-12 05:08:53 +00:00
"runtime"
2017-12-05 23:32:52 +00:00
"strings"
2017-06-19 20:39:00 +00:00
"testing"
2017-12-04 03:38:37 +00:00
"time"
2017-06-19 20:39:00 +00:00
2017-12-05 23:32:52 +00:00
"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
2017-12-28 23:03:49 +00:00
"github.com/containerd/containerd/images"
2017-12-05 23:32:52 +00:00
"github.com/containerd/containerd/namespaces"
2017-12-28 23:03:49 +00:00
"github.com/containerd/containerd/snapshots"
2018-06-04 21:08:29 +00:00
"github.com/containerd/continuity/fs/fstest"
2017-06-22 20:15:46 +00:00
"github.com/moby/buildkit/client/llb"
2017-12-02 02:17:40 +00:00
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/testutil/httpserver"
2017-11-27 22:24:29 +00:00
"github.com/moby/buildkit/util/testutil/integration"
2017-12-05 23:32:52 +00:00
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
2017-12-02 02:17:40 +00:00
"github.com/stretchr/testify/require"
2018-07-06 12:03:53 +00:00
"golang.org/x/sync/errgroup"
2017-06-19 20:39:00 +00:00
)
2017-11-27 22:24:29 +00:00
func TestClientIntegration ( t * testing . T ) {
2017-11-30 02:49:04 +00:00
integration . Run ( t , [ ] integration . Test {
2018-05-22 00:07:08 +00:00
testRelativeWorkDir ,
2017-11-30 02:49:04 +00:00
testCallDiskUsage ,
testBuildMultiMount ,
2017-12-02 02:17:40 +00:00
testBuildHTTPSource ,
2017-12-05 23:32:52 +00:00
testBuildPushAndValidate ,
2017-12-11 02:18:18 +00:00
testResolveAndHosts ,
2017-12-11 21:17:07 +00:00
testUser ,
2017-12-13 05:55:16 +00:00
testOCIExporter ,
2018-02-09 19:03:12 +00:00
testWhiteoutParentDir ,
2018-02-13 19:18:18 +00:00
testDuplicateWhiteouts ,
2018-03-02 16:33:08 +00:00
testSchema1Image ,
2018-03-21 17:04:43 +00:00
testMountWithNoSource ,
2018-03-29 05:27:52 +00:00
testInvalidExporter ,
2018-03-26 13:51:08 +00:00
testReadonlyRootFS ,
2018-04-26 00:43:17 +00:00
testBasicCacheImportExport ,
2018-05-15 19:09:09 +00:00
testCachedMounts ,
2018-05-20 21:48:35 +00:00
testProxyEnv ,
2018-06-04 21:08:29 +00:00
testLocalSymlinkEscape ,
2018-06-08 05:28:52 +00:00
testTmpfsMounts ,
2018-06-18 20:57:36 +00:00
testSharedCacheMounts ,
testLockedCacheMounts ,
testDuplicateCacheMount ,
2018-07-09 22:42:34 +00:00
testParallelLocalBuilds ,
2017-11-30 02:49:04 +00:00
} )
2017-07-12 05:08:53 +00:00
}
2018-06-08 05:28:52 +00:00
func testTmpfsMounts ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
requiresLinux ( t )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-06-08 05:28:52 +00:00
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'mount | grep /foobar | grep "type tmpfs" && touch /foobar/test' ` ) , llb . AddMount ( "/foobar" , llb . Scratch ( ) , llb . Tmpfs ( ) ) )
def , err := st . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2018-06-04 21:08:29 +00:00
func testLocalSymlinkEscape ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
requiresLinux ( t )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-06-04 21:08:29 +00:00
require . NoError ( t , err )
defer c . Close ( )
2018-06-10 16:21:24 +00:00
test := [ ] byte ( ` set - ex
2018-06-04 21:08:29 +00:00
[ [ - L / mount / foo ] ]
[ [ - L / mount / sub / bar ] ]
[ [ - L / mount / bax ] ]
[ [ - f / mount / bay ] ]
2018-06-10 16:21:24 +00:00
[ [ - f / mount / sub / sub2 / file ] ]
2018-06-04 21:08:29 +00:00
[ [ ! - f / mount / baz ] ]
[ [ ! - f / mount / etc / passwd ] ]
[ [ ! - f / mount / etc / group ] ]
[ [ $ ( readlink / mount / foo ) == "/etc/passwd" ] ]
[ [ $ ( readlink / mount / sub / bar ) == "../../../etc/group" ] ]
` )
dir , err := tmpdir (
// point to absolute path that is not part of dir
fstest . Symlink ( "/etc/passwd" , "foo" ) ,
fstest . CreateDir ( "sub" , 0700 ) ,
// point outside of the dir
fstest . Symlink ( "../../../etc/group" , "sub/bar" ) ,
// regular valid symlink
fstest . Symlink ( "bay" , "bax" ) ,
// target for symlink (not requested)
fstest . CreateFile ( "bay" , [ ] byte { } , 0600 ) ,
2018-06-10 16:21:24 +00:00
// file with many subdirs
fstest . CreateDir ( "sub/sub2" , 0700 ) ,
fstest . CreateFile ( "sub/sub2/file" , [ ] byte { } , 0600 ) ,
2018-06-04 21:08:29 +00:00
// unused file that shouldn't be included
fstest . CreateFile ( "baz" , [ ] byte { } , 0600 ) ,
fstest . CreateFile ( "test.sh" , test , 0700 ) ,
)
require . NoError ( t , err )
defer os . RemoveAll ( dir )
local := llb . Local ( "mylocal" , llb . FollowPaths ( [ ] string {
2018-06-10 16:21:24 +00:00
"test.sh" , "foo" , "sub/bar" , "bax" , "sub/sub2/file" ,
2018-06-04 21:08:29 +00:00
} ) )
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh /mount/test.sh ` ) , llb . AddMount ( "/mount" , local , llb . Readonly ) )
def , err := st . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
LocalDirs : map [ string ] string {
"mylocal" : dir ,
} ,
} , nil )
require . NoError ( t , err )
}
2018-05-22 00:07:08 +00:00
func testRelativeWorkDir ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
requiresLinux ( t )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-05-22 00:07:08 +00:00
require . NoError ( t , err )
defer c . Close ( )
pwd := llb . Image ( "docker.io/library/busybox:latest" ) .
Dir ( "test1" ) .
Dir ( "test2" ) .
Run ( llb . Shlex ( ` sh -c "pwd > /out/pwd" ` ) ) .
AddMount ( "/out" , llb . Scratch ( ) )
def , err := pwd . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "pwd" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "/test1/test2\n" ) , dt )
}
2017-11-27 22:24:29 +00:00
func testCallDiskUsage ( t * testing . T , sb integration . Sandbox ) {
2017-12-09 02:19:08 +00:00
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
defer c . Close ( )
2017-06-19 20:39:00 +00:00
_ , err = c . DiskUsage ( context . TODO ( ) )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
2017-06-19 20:39:00 +00:00
}
2017-11-27 22:24:29 +00:00
func testBuildMultiMount ( t * testing . T , sb integration . Sandbox ) {
2017-06-19 20:39:00 +00:00
t . Parallel ( )
2017-12-09 02:19:08 +00:00
requiresLinux ( t )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
defer c . Close ( )
2017-06-19 20:39:00 +00:00
alpine := llb . Image ( "docker.io/library/alpine:latest" )
2017-06-21 21:48:21 +00:00
ls := alpine . Run ( llb . Shlex ( "/bin/ls -l" ) )
2017-06-19 20:39:00 +00:00
busybox := llb . Image ( "docker.io/library/busybox:latest" )
2017-06-21 21:48:21 +00:00
cp := ls . Run ( llb . Shlex ( "/bin/cp -a /busybox/etc/passwd baz" ) )
2017-06-19 20:39:00 +00:00
cp . AddMount ( "/busybox" , busybox )
2017-10-02 04:59:34 +00:00
def , err := cp . Marshal ( )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
2017-06-19 20:39:00 +00:00
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
2017-12-28 23:03:49 +00:00
checkAllReleasable ( t , c , sb , true )
2017-12-02 02:17:40 +00:00
}
func testBuildHTTPSource ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
defer c . Close ( )
2017-12-04 03:38:37 +00:00
modTime := time . Now ( ) . Add ( - 24 * time . Hour ) // avoid falso positive with current time
2017-12-02 02:17:40 +00:00
resp := httpserver . Response {
2017-12-04 03:38:37 +00:00
Etag : identity . NewID ( ) ,
Content : [ ] byte ( "content1" ) ,
LastModified : & modTime ,
2017-12-02 02:17:40 +00:00
}
server := httpserver . NewTestServer ( map [ string ] httpserver . Response {
"/foo" : resp ,
} )
defer server . Close ( )
// invalid URL first
st := llb . HTTP ( server . URL + "/bar" )
def , err := st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2017-12-02 02:17:40 +00:00
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "invalid response status 404" )
// first correct request
st = llb . HTTP ( server . URL + "/foo" )
def , err = st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2017-12-02 02:17:40 +00:00
require . NoError ( t , err )
require . Equal ( t , server . Stats ( "/foo" ) . AllRequests , 1 )
require . Equal ( t , server . Stats ( "/foo" ) . CachedRequests , 0 )
tmpdir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( tmpdir )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : tmpdir ,
2017-12-02 02:17:40 +00:00
} , nil )
require . NoError ( t , err )
require . Equal ( t , server . Stats ( "/foo" ) . AllRequests , 2 )
require . Equal ( t , server . Stats ( "/foo" ) . CachedRequests , 1 )
dt , err := ioutil . ReadFile ( filepath . Join ( tmpdir , "foo" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "content1" ) , dt )
2017-12-04 03:38:37 +00:00
// test extra options
st = llb . HTTP ( server . URL + "/foo" , llb . Filename ( "bar" ) , llb . Chmod ( 0741 ) , llb . Chown ( 1000 , 1000 ) )
def , err = st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : tmpdir ,
2017-12-04 03:38:37 +00:00
} , nil )
require . NoError ( t , err )
require . Equal ( t , server . Stats ( "/foo" ) . AllRequests , 3 )
require . Equal ( t , server . Stats ( "/foo" ) . CachedRequests , 1 )
dt , err = ioutil . ReadFile ( filepath . Join ( tmpdir , "bar" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "content1" ) , dt )
fi , err := os . Stat ( filepath . Join ( tmpdir , "bar" ) )
require . NoError ( t , err )
require . Equal ( t , fi . ModTime ( ) . Format ( http . TimeFormat ) , modTime . Format ( http . TimeFormat ) )
require . Equal ( t , int ( fi . Mode ( ) & 0777 ) , 0741 )
2017-12-28 23:03:49 +00:00
checkAllReleasable ( t , c , sb , true )
2017-12-02 02:17:40 +00:00
// TODO: check that second request was marked as cached
2017-06-19 20:39:00 +00:00
}
2017-11-27 22:24:29 +00:00
2017-12-11 02:18:18 +00:00
func testResolveAndHosts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-11 02:18:18 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
run ( ` sh -c "cp /etc/resolv.conf ." ` )
run ( ` sh -c "cp /etc/hosts ." ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
2017-12-11 02:18:18 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "resolv.conf" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "nameserver" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "hosts" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "127.0.0.1 localhost" )
}
2017-12-11 21:17:07 +00:00
func testUser ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-11 21:17:07 +00:00
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( ` sh -c "mkdir -m 0777 /wd" ` ) )
run := func ( user , cmd string ) {
st = st . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) , llb . User ( user ) )
}
run ( "daemon" , ` sh -c "id -nu > user" ` )
run ( "daemon:daemon" , ` sh -c "id -ng > group" ` )
run ( "daemon:nogroup" , ` sh -c "id -ng > nogroup" ` )
run ( "1:1" , ` sh -c "id -g > userone" ` )
st = st . Run ( llb . Shlex ( "cp -a /wd/. /out/" ) )
out := st . AddMount ( "/out" , llb . Scratch ( ) )
def , err := out . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
2017-12-11 21:17:07 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "user" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "daemon" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "group" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "daemon" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "nogroup" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "nogroup" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "userone" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "1" )
2017-12-28 23:03:49 +00:00
checkAllReleasable ( t , c , sb , true )
2017-12-11 21:17:07 +00:00
}
2017-12-13 05:55:16 +00:00
func testOCIExporter ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-13 05:55:16 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
run ( ` sh -c "echo -n first > foo" ` )
run ( ` sh -c "echo -n second > bar" ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
2017-12-18 00:20:19 +00:00
for _ , exp := range [ ] string { ExporterOCI , ExporterDocker } {
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
out := filepath . Join ( destDir , "out.tar" )
2018-03-27 04:16:32 +00:00
outW , err := os . Create ( out )
require . NoError ( t , err )
2017-12-18 00:20:19 +00:00
target := "example.com/buildkit/testoci:latest"
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2017-12-18 00:20:19 +00:00
Exporter : exp ,
ExporterAttrs : map [ string ] string {
2018-03-27 04:16:32 +00:00
"name" : target ,
2017-12-18 00:20:19 +00:00
} ,
2018-03-27 04:16:32 +00:00
ExporterOutput : outW ,
2017-12-18 00:20:19 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
m , err := readTarToMap ( dt , false )
require . NoError ( t , err )
_ , ok := m [ "oci-layout" ]
require . True ( t , ok )
var index ocispec . Index
err = json . Unmarshal ( m [ "index.json" ] . data , & index )
require . NoError ( t , err )
require . Equal ( t , 2 , index . SchemaVersion )
require . Equal ( t , 1 , len ( index . Manifests ) )
var mfst ocispec . Manifest
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . data , & mfst )
require . NoError ( t , err )
require . Equal ( t , 2 , len ( mfst . Layers ) )
var ociimg ocispec . Image
err = json . Unmarshal ( m [ "blobs/sha256/" + mfst . Config . Digest . Hex ( ) ] . data , & ociimg )
require . NoError ( t , err )
require . Equal ( t , "layers" , ociimg . RootFS . Type )
require . Equal ( t , 2 , len ( ociimg . RootFS . DiffIDs ) )
_ , ok = m [ "blobs/sha256/" + mfst . Layers [ 0 ] . Digest . Hex ( ) ]
require . True ( t , ok )
_ , ok = m [ "blobs/sha256/" + mfst . Layers [ 1 ] . Digest . Hex ( ) ]
require . True ( t , ok )
if exp != ExporterDocker {
continue
}
var dockerMfst [ ] struct {
Config string
RepoTags [ ] string
Layers [ ] string
}
err = json . Unmarshal ( m [ "manifest.json" ] . data , & dockerMfst )
require . NoError ( t , err )
require . Equal ( t , 1 , len ( dockerMfst ) )
_ , ok = m [ dockerMfst [ 0 ] . Config ]
require . True ( t , ok )
require . Equal ( t , 2 , len ( dockerMfst [ 0 ] . Layers ) )
require . Equal ( t , 1 , len ( dockerMfst [ 0 ] . RepoTags ) )
require . Equal ( t , target , dockerMfst [ 0 ] . RepoTags [ 0 ] )
for _ , l := range dockerMfst [ 0 ] . Layers {
_ , ok := m [ l ]
require . True ( t , ok )
}
}
2017-12-28 23:03:49 +00:00
checkAllReleasable ( t , c , sb , true )
2017-12-13 05:55:16 +00:00
}
2017-12-05 23:32:52 +00:00
func testBuildPushAndValidate ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
2018-06-18 20:57:36 +00:00
run ( ` sh -e -c "mkdir -p foo/sub; echo -n first > foo/sub/bar; chmod 0741 foo;" ` )
2017-12-08 22:55:23 +00:00
run ( ` true ` ) // this doesn't create a layer
2017-12-05 23:32:52 +00:00
run ( ` sh -c "echo -n second > foo/sub/baz" ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
registry , err := sb . NewRegistry ( )
if errors . Cause ( err ) == integration . ErrorRequirements {
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
target := registry + "/buildkit/testpush:latest"
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2017-12-05 23:32:52 +00:00
Exporter : ExporterImage ,
ExporterAttrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
} , nil )
require . NoError ( t , err )
// test existence of the image with next build
firstBuild := llb . Image ( target )
def , err = firstBuild . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
2017-12-13 05:55:16 +00:00
defer os . RemoveAll ( destDir )
2017-12-05 23:32:52 +00:00
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
2017-12-05 23:32:52 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "foo/sub/bar" ) )
require . NoError ( t , err )
require . Equal ( t , dt , [ ] byte ( "first" ) )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "foo/sub/baz" ) )
require . NoError ( t , err )
require . Equal ( t , dt , [ ] byte ( "second" ) )
fi , err := os . Stat ( filepath . Join ( destDir , "foo" ) )
require . NoError ( t , err )
require . Equal ( t , 0741 , int ( fi . Mode ( ) & 0777 ) )
2017-12-28 23:03:49 +00:00
checkAllReleasable ( t , c , sb , false )
2017-12-05 23:32:52 +00:00
// examine contents of exported tars (requires containerd)
var cdAddress string
if cd , ok := sb . ( interface {
ContainerdAddress ( ) string
} ) ; ! ok {
return
} else {
cdAddress = cd . ContainerdAddress ( )
}
// TODO: make public pull helper function so this can be checked for standalone as well
client , err := containerd . New ( cdAddress )
require . NoError ( t , err )
defer client . Close ( )
ctx := namespaces . WithNamespace ( context . Background ( ) , "buildkit" )
2017-12-28 23:03:49 +00:00
// check image in containerd
_ , err = client . ImageService ( ) . Get ( ctx , target )
require . NoError ( t , err )
// deleting image should release all content
err = client . ImageService ( ) . Delete ( ctx , target , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
2017-12-05 23:32:52 +00:00
img , err := client . Pull ( ctx , target )
require . NoError ( t , err )
desc , err := img . Config ( ctx )
require . NoError ( t , err )
2018-06-06 08:02:01 +00:00
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , desc )
2017-12-05 23:32:52 +00:00
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 . Equal ( t , 2 , len ( ociimg . RootFS . DiffIDs ) )
2018-01-05 18:51:32 +00:00
require . NotNil ( t , ociimg . Created )
require . True ( t , time . Since ( * ociimg . Created ) < 2 * time . Minute )
2017-12-05 23:32:52 +00:00
require . Condition ( t , func ( ) bool {
for _ , env := range ociimg . Config . Env {
if strings . HasPrefix ( env , "PATH=" ) {
return true
}
}
return false
} )
2017-12-08 22:55:23 +00:00
require . Equal ( t , 3 , len ( ociimg . History ) )
require . Contains ( t , ociimg . History [ 0 ] . CreatedBy , "foo/sub/bar" )
require . Contains ( t , ociimg . History [ 1 ] . CreatedBy , "true" )
require . Contains ( t , ociimg . History [ 2 ] . CreatedBy , "foo/sub/baz" )
require . False ( t , ociimg . History [ 0 ] . EmptyLayer )
require . True ( t , ociimg . History [ 1 ] . EmptyLayer )
require . False ( t , ociimg . History [ 2 ] . EmptyLayer )
2018-06-06 08:02:01 +00:00
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , img . Target ( ) )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
2018-06-26 22:24:33 +00:00
var mfst = struct {
MediaType string ` json:"mediaType,omitempty" `
ocispec . Manifest
} { }
2017-12-05 23:32:52 +00:00
err = json . Unmarshal ( dt , & mfst )
require . NoError ( t , err )
2018-06-26 22:24:33 +00:00
require . Equal ( t , images . MediaTypeDockerSchema2Manifest , mfst . MediaType )
2017-12-05 23:32:52 +00:00
require . Equal ( t , 2 , len ( mfst . Layers ) )
2018-06-06 08:02:01 +00:00
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , ocispec . Descriptor { Digest : mfst . Layers [ 0 ] . Digest } )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
2017-12-13 05:55:16 +00:00
m , err := readTarToMap ( dt , true )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
item , ok := m [ "foo/" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeDir )
require . Equal ( t , 0741 , int ( item . header . Mode & 0777 ) )
item , ok = m [ "foo/sub/" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeDir )
item , ok = m [ "foo/sub/bar" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "first" ) , item . data )
_ , ok = m [ "foo/sub/baz" ]
require . False ( t , ok )
2018-06-06 08:02:01 +00:00
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , ocispec . Descriptor { Digest : mfst . Layers [ 1 ] . Digest } )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
2017-12-13 05:55:16 +00:00
m , err = readTarToMap ( dt , true )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
item , ok = m [ "foo/sub/baz" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "second" ) , item . data )
2017-12-20 21:54:48 +00:00
item , ok = m [ "foo/" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeDir )
require . Equal ( t , 0741 , int ( item . header . Mode & 0777 ) )
item , ok = m [ "foo/sub/" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . header . Typeflag ) , tar . TypeDir )
_ , ok = m [ "foo/sub/bar" ]
require . False ( t , ok )
2017-12-05 23:32:52 +00:00
}
2018-04-26 00:43:17 +00:00
func testBasicCacheImportExport ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
registry , err := sb . NewRegistry ( )
if errors . Cause ( err ) == integration . ErrorRequirements {
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-04-26 00:43:17 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
run ( ` sh -c "echo -n foobar > const" ` )
run ( ` sh -c "cat /dev/urandom | head -c 100 | sha256sum > unique" ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
target := registry + "/buildkit/testexport:latest"
2018-04-25 17:49:15 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-04-26 00:43:17 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
ExportCache : target ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "const" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "foobar" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "unique" ) )
require . NoError ( t , err )
err = c . Prune ( context . TODO ( ) , nil )
require . NoError ( t , err )
checkAllRemoved ( t , c , sb )
destDir , err = ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
2018-04-25 17:49:15 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-04-26 00:43:17 +00:00
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
2018-04-25 17:49:15 +00:00
ImportCache : [ ] string { target } ,
2018-04-26 00:43:17 +00:00
} , nil )
require . NoError ( t , err )
dt2 , err := ioutil . ReadFile ( filepath . Join ( destDir , "const" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt2 ) , "foobar" )
dt2 , err = ioutil . ReadFile ( filepath . Join ( destDir , "unique" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , string ( dt2 ) )
}
2018-05-15 19:09:09 +00:00
func testCachedMounts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-05-15 19:09:09 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
// setup base for one of the cache sources
st := busybox . Run ( llb . Shlex ( ` sh -c "echo -n base > baz" ` ) , llb . Dir ( "/wd" ) )
base := st . AddMount ( "/wd" , llb . Scratch ( ) )
st = busybox . Run ( llb . Shlex ( ` sh -c "echo -n first > foo" ` ) , llb . Dir ( "/wd" ) )
2018-06-18 20:57:36 +00:00
st . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountShared ) )
2018-05-15 19:09:09 +00:00
st = st . Run ( llb . Shlex ( ` sh -c "cat foo && echo -n second > /wd2/bar" ` ) , llb . Dir ( "/wd" ) )
2018-06-18 20:57:36 +00:00
st . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountShared ) )
st . AddMount ( "/wd2" , base , llb . AsPersistentCacheDir ( "mycache2" , llb . CacheMountShared ) )
2018-05-15 19:09:09 +00:00
def , err := st . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
// repeat to make sure cache works
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
// second build using cache directories
st = busybox . Run ( llb . Shlex ( ` sh -c "cp /src0/foo . && cp /src1/bar . && cp /src1/baz ." ` ) , llb . Dir ( "/wd" ) )
out := st . AddMount ( "/wd" , llb . Scratch ( ) )
2018-06-18 20:57:36 +00:00
st . AddMount ( "/src0" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountShared ) )
st . AddMount ( "/src1" , base , llb . AsPersistentCacheDir ( "mycache2" , llb . CacheMountShared ) )
2018-05-15 19:09:09 +00:00
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
def , err = out . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "foo" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "first" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "bar" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "second" )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "baz" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "base" )
checkAllReleasable ( t , c , sb , true )
}
2018-06-18 20:57:36 +00:00
func testSharedCacheMounts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := busybox . Run ( llb . Shlex ( ` sh -e -c "touch one; while [[ ! -f two ]]; do ls -l; usleep 500000; done" ` ) , llb . Dir ( "/wd" ) )
st . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountShared ) )
st2 := busybox . Run ( llb . Shlex ( ` sh -e -c "touch two; while [[ ! -f one ]]; do ls -l; usleep 500000; done" ` ) , llb . Dir ( "/wd" ) )
st2 . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountShared ) )
out := busybox . Run ( llb . Shlex ( "true" ) )
out . AddMount ( "/m1" , st . Root ( ) )
out . AddMount ( "/m2" , st2 . Root ( ) )
def , err := out . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
func testLockedCacheMounts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := busybox . Run ( llb . Shlex ( ` sh -e -c "touch one; if [[ -f two ]]; then exit 0; fi; for i in $(seq 10); do if [[ -f two ]]; then exit 1; fi; usleep 200000; done" ` ) , llb . Dir ( "/wd" ) )
st . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
st2 := busybox . Run ( llb . Shlex ( ` sh -e -c "touch two; if [[ -f one ]]; then exit 0; fi; for i in $(seq 10); do if [[ -f one ]]; then exit 1; fi; usleep 200000; done" ` ) , llb . Dir ( "/wd" ) )
st2 . AddMount ( "/wd" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
out := busybox . Run ( llb . Shlex ( "true" ) )
out . AddMount ( "/m1" , st . Root ( ) )
out . AddMount ( "/m2" , st2 . Root ( ) )
def , err := out . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
func testDuplicateCacheMount ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
out := busybox . Run ( llb . Shlex ( ` sh -e -c "[[ ! -f /m2/foo ]]; touch /m1/foo; [[ -f /m2/foo ]];" ` ) )
out . AddMount ( "/m1" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
out . AddMount ( "/m2" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
def , err := out . Marshal ( )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2018-02-13 19:18:18 +00:00
// containerd/containerd#2119
func testDuplicateWhiteouts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-02-13 19:18:18 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
2018-06-18 20:57:36 +00:00
run ( ` sh -e -c "mkdir -p d0 d1; echo -n first > d1/bar;" ` )
2018-02-13 19:18:18 +00:00
run ( ` sh -c "rm -rf d0 d1" ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
out := filepath . Join ( destDir , "out.tar" )
2018-03-27 04:16:32 +00:00
outW , err := os . Create ( out )
require . NoError ( t , err )
2018-02-13 19:18:18 +00:00
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterOCI ,
ExporterOutput : outW ,
2018-02-13 19:18:18 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
m , err := readTarToMap ( dt , false )
require . NoError ( t , err )
var index ocispec . Index
err = json . Unmarshal ( m [ "index.json" ] . data , & index )
require . NoError ( t , err )
var mfst ocispec . Manifest
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . data , & mfst )
require . NoError ( t , err )
lastLayer := mfst . Layers [ len ( mfst . Layers ) - 1 ]
layer , ok := m [ "blobs/sha256/" + lastLayer . Digest . Hex ( ) ]
require . True ( t , ok )
m , err = readTarToMap ( layer . data , true )
require . NoError ( t , err )
_ , ok = m [ ".wh.d0" ]
require . True ( t , ok )
_ , ok = m [ ".wh.d1" ]
require . True ( t , ok )
// check for a bug that added whiteout for subfile
_ , ok = m [ "d1/.wh.bar" ]
require . True ( t , ! ok )
}
2018-02-09 19:03:12 +00:00
// #276
func testWhiteoutParentDir ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-02-09 19:03:12 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
st := llb . Scratch ( )
run := func ( cmd string ) {
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
}
run ( ` sh -c "mkdir -p foo; echo -n first > foo/bar;" ` )
run ( ` rm foo/bar ` )
def , err := st . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
out := filepath . Join ( destDir , "out.tar" )
2018-03-27 04:16:32 +00:00
outW , err := os . Create ( out )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-27 04:16:32 +00:00
Exporter : ExporterOCI ,
ExporterOutput : outW ,
2018-02-09 19:03:12 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
m , err := readTarToMap ( dt , false )
require . NoError ( t , err )
var index ocispec . Index
err = json . Unmarshal ( m [ "index.json" ] . data , & index )
require . NoError ( t , err )
var mfst ocispec . Manifest
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . data , & mfst )
require . NoError ( t , err )
lastLayer := mfst . Layers [ len ( mfst . Layers ) - 1 ]
layer , ok := m [ "blobs/sha256/" + lastLayer . Digest . Hex ( ) ]
require . True ( t , ok )
m , err = readTarToMap ( layer . data , true )
require . NoError ( t , err )
_ , ok = m [ "foo/.wh.bar" ]
require . True ( t , ok )
_ , ok = m [ "foo/" ]
require . True ( t , ok )
}
2018-03-02 16:33:08 +00:00
// #296
func testSchema1Image ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-03-02 16:33:08 +00:00
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "gcr.io/google_containers/pause:3.0@sha256:0d093c962a6c2dd8bb8727b661e2b5f13e9df884af9945b4cc7088d9350cd3ee" )
def , err := st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2018-03-02 16:33:08 +00:00
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
}
2018-03-21 17:04:43 +00:00
// #319
func testMountWithNoSource ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-03-21 17:04:43 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "docker.io/library/busybox:latest" )
st := llb . Scratch ( )
var nilState llb . State
// This should never actually be run, but we want to succeed
// if it was, because we expect an error below, or a daemon
// panic if the issue has regressed.
run := busybox . Run (
llb . Args ( [ ] string { "/bin/true" } ) ,
llb . AddMount ( "/nil" , nilState , llb . SourcePath ( "/" ) , llb . Readonly ) )
st = run . AddMount ( "/mnt" , st )
def , err := st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2018-06-07 20:54:04 +00:00
require . NoError ( t , err )
2018-03-21 17:04:43 +00:00
checkAllReleasable ( t , c , sb , true )
}
2018-03-26 13:51:08 +00:00
// #324
func testReadonlyRootFS ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-03-26 13:51:08 +00:00
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "docker.io/library/busybox:latest" )
st := llb . Scratch ( )
// The path /foo should be unwriteable.
run := busybox . Run (
llb . ReadonlyRootFS ( ) ,
llb . Args ( [ ] string { "/bin/touch" , "/foo" } ) )
st = run . AddMount ( "/mnt" , st )
def , err := st . Marshal ( )
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
2018-03-26 13:51:08 +00:00
require . Error ( t , err )
// Would prefer to detect more specifically "Read-only file
// system" but that isn't exposed here (it is on the stdio
// which we don't see).
require . Contains ( t , err . Error ( ) , "executor failed running [/bin/touch /foo]:" )
checkAllReleasable ( t , c , sb , true )
}
2018-05-20 21:48:35 +00:00
func testProxyEnv ( t * testing . T , sb integration . Sandbox ) {
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-05-20 21:48:35 +00:00
require . NoError ( t , err )
defer c . Close ( )
base := llb . Image ( "docker.io/library/busybox:latest" ) . Dir ( "/out" )
cmd := ` sh -c "echo -n $HTTP_PROXY-$HTTPS_PROXY-$NO_PROXY-$no_proxy > env" `
st := base . Run ( llb . Shlex ( cmd ) , llb . WithProxy ( llb . ProxyEnv {
HttpProxy : "httpvalue" ,
HttpsProxy : "httpsvalue" ,
NoProxy : "noproxyvalue" ,
} ) )
out := st . AddMount ( "/out" , llb . Scratch ( ) )
def , err := out . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "env" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "httpvalue-httpsvalue-noproxyvalue-noproxyvalue" )
// repeat to make sure proxy doesn't change cache
st = base . Run ( llb . Shlex ( cmd ) , llb . WithProxy ( llb . ProxyEnv {
HttpsProxy : "httpsvalue2" ,
NoProxy : "noproxyvalue2" ,
} ) )
out = st . AddMount ( "/out" , llb . Scratch ( ) )
def , err = out . Marshal ( )
require . NoError ( t , err )
destDir , err = ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
} , nil )
require . NoError ( t , err )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "env" ) )
require . NoError ( t , err )
require . Equal ( t , string ( dt ) , "httpvalue-httpsvalue-noproxyvalue-noproxyvalue" )
}
2017-11-27 22:24:29 +00:00
func requiresLinux ( t * testing . T ) {
if runtime . GOOS != "linux" {
t . Skipf ( "unsupported GOOS: %s" , runtime . GOOS )
}
}
2017-12-05 23:32:52 +00:00
type tarItem struct {
header * tar . Header
data [ ] byte
}
2017-12-13 05:55:16 +00:00
func readTarToMap ( dt [ ] byte , compressed bool ) ( map [ string ] * tarItem , error ) {
2017-12-05 23:32:52 +00:00
m := map [ string ] * tarItem { }
2017-12-13 05:55:16 +00:00
var r io . Reader = bytes . NewBuffer ( dt )
if compressed {
gz , err := gzip . NewReader ( r )
if err != nil {
return nil , err
}
defer gz . Close ( )
r = gz
2017-12-05 23:32:52 +00:00
}
2017-12-13 05:55:16 +00:00
tr := tar . NewReader ( r )
2017-12-05 23:32:52 +00:00
for {
2017-12-13 05:55:16 +00:00
h , err := tr . Next ( )
2017-12-05 23:32:52 +00:00
if err != nil {
if err == io . EOF {
return m , nil
}
return nil , err
}
2018-02-09 19:47:07 +00:00
if _ , ok := m [ h . Name ] ; ok {
return nil , errors . Errorf ( "duplicate entries for %s" , h . Name )
}
2017-12-05 23:32:52 +00:00
var dt [ ] byte
if h . Typeflag == tar . TypeReg {
2017-12-13 05:55:16 +00:00
dt , err = ioutil . ReadAll ( tr )
2017-12-05 23:32:52 +00:00
if err != nil {
return nil , err
}
}
m [ h . Name ] = & tarItem { header : h , data : dt }
}
}
2017-12-28 23:03:49 +00:00
2018-04-26 00:43:17 +00:00
func checkAllRemoved ( t * testing . T , c * Client , sb integration . Sandbox ) {
retries := 0
for {
require . True ( t , 20 > retries )
retries ++
du , err := c . DiskUsage ( context . TODO ( ) )
require . NoError ( t , err )
if len ( du ) > 0 {
time . Sleep ( 500 * time . Millisecond )
2018-04-27 19:02:07 +00:00
continue
2018-04-26 00:43:17 +00:00
}
break
}
}
2017-12-28 23:03:49 +00:00
func checkAllReleasable ( t * testing . T , c * Client , sb integration . Sandbox , checkContent bool ) {
2018-01-07 21:34:10 +00:00
retries := 0
loop0 :
for {
require . True ( t , 20 > retries )
retries ++
du , err := c . DiskUsage ( context . TODO ( ) )
require . NoError ( t , err )
for _ , d := range du {
if d . InUse {
time . Sleep ( 500 * time . Millisecond )
continue loop0
}
}
break
}
2017-12-28 23:03:49 +00:00
err := c . Prune ( context . TODO ( ) , nil )
require . NoError ( t , err )
du , err := c . DiskUsage ( context . TODO ( ) )
require . NoError ( t , err )
require . Equal ( t , 0 , len ( du ) )
// examine contents of exported tars (requires containerd)
var cdAddress string
if cd , ok := sb . ( interface {
ContainerdAddress ( ) string
} ) ; ! ok {
return
} else {
cdAddress = cd . ContainerdAddress ( )
}
// TODO: make public pull helper function so this can be checked for standalone as well
client , err := containerd . New ( cdAddress )
require . NoError ( t , err )
defer client . Close ( )
ctx := namespaces . WithNamespace ( context . Background ( ) , "buildkit" )
snapshotService := client . SnapshotService ( "overlayfs" )
2018-01-07 21:34:10 +00:00
retries = 0
2017-12-28 23:03:49 +00:00
for {
count := 0
err = snapshotService . Walk ( ctx , func ( context . Context , snapshots . Info ) error {
count ++
return nil
} )
require . NoError ( t , err )
if count == 0 {
break
}
require . True ( t , 20 > retries )
retries ++
time . Sleep ( 500 * time . Millisecond )
}
if ! checkContent {
return
}
retries = 0
for {
count := 0
err = client . ContentStore ( ) . Walk ( ctx , func ( content . Info ) error {
count ++
return nil
} )
require . NoError ( t , err )
if count == 0 {
break
}
require . True ( t , 20 > retries )
retries ++
time . Sleep ( 500 * time . Millisecond )
}
}
2018-03-29 05:27:52 +00:00
func testInvalidExporter ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
t . Parallel ( )
2018-06-06 10:52:53 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2018-03-29 05:27:52 +00:00
require . NoError ( t , err )
defer c . Close ( )
def , err := llb . Image ( "busybox:latest" ) . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
target := "example.com/buildkit/testoci:latest"
attrs := map [ string ] string {
"name" : target ,
}
for _ , exp := range [ ] string { ExporterOCI , ExporterDocker } {
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-29 05:27:52 +00:00
Exporter : exp ,
ExporterAttrs : attrs ,
} , nil )
// output file writer is required
require . Error ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-29 05:27:52 +00:00
Exporter : exp ,
ExporterAttrs : attrs ,
ExporterOutputDir : destDir ,
} , nil )
// output directory is not supported
require . Error ( t , err )
}
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-29 05:27:52 +00:00
Exporter : ExporterLocal ,
ExporterAttrs : attrs ,
} , nil )
// output directory is required
require . Error ( t , err )
f , err := os . Create ( filepath . Join ( destDir , "a" ) )
require . NoError ( t , err )
defer f . Close ( )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2018-03-29 05:27:52 +00:00
Exporter : ExporterLocal ,
ExporterAttrs : attrs ,
ExporterOutput : f ,
} , nil )
// output file writer is not supported
require . Error ( t , err )
checkAllReleasable ( t , c , sb , true )
}
2018-06-04 21:08:29 +00:00
2018-07-09 22:42:34 +00:00
// moby/buildkit#492
func testParallelLocalBuilds ( t * testing . T , sb integration . Sandbox ) {
2018-07-06 12:03:53 +00:00
t . Parallel ( )
ctx , cancel := context . WithCancel ( context . TODO ( ) )
defer cancel ( )
c , err := New ( ctx , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
eg , ctx := errgroup . WithContext ( ctx )
for i := 0 ; i < 3 ; i ++ {
2018-07-09 22:42:34 +00:00
func ( i int ) {
eg . Go ( func ( ) error {
fn := fmt . Sprintf ( "test%d" , i )
srcDir , err := tmpdir (
fstest . CreateFile ( fn , [ ] byte ( "contents" ) , 0600 ) ,
)
require . NoError ( t , err )
defer os . RemoveAll ( srcDir )
def , err := llb . Local ( "source" ) . Marshal ( )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( ctx , def , SolveOpt {
Exporter : ExporterLocal ,
ExporterOutputDir : destDir ,
LocalDirs : map [ string ] string {
"source" : srcDir ,
} ,
} , nil )
require . NoError ( t , err )
act , err := ioutil . ReadFile ( filepath . Join ( destDir , fn ) )
require . NoError ( t , err )
require . Equal ( t , "contents" , string ( act ) )
return nil
} )
} ( i )
2018-07-06 12:03:53 +00:00
}
err = eg . Wait ( )
require . NoError ( t , err )
}
2018-07-09 22:42:34 +00:00
func tmpdir ( appliers ... fstest . Applier ) ( string , error ) {
tmpdir , err := ioutil . TempDir ( "" , "buildkit-client" )
if err != nil {
return "" , err
}
if err := fstest . Apply ( appliers ... ) . Apply ( tmpdir ) ; err != nil {
return "" , err
}
return tmpdir , nil
}