2017-06-19 20:39:00 +00:00
package client
import (
2017-12-05 23:32:52 +00:00
"archive/tar"
2020-03-30 06:25:49 +00:00
"bytes"
2017-06-19 20:39:00 +00:00
"context"
2018-09-06 21:39:56 +00:00
"crypto/rand"
"crypto/rsa"
2018-09-06 22:25:45 +00:00
"crypto/x509"
2017-12-05 23:32:52 +00:00
"encoding/json"
2018-09-06 22:25:45 +00:00
"encoding/pem"
2018-07-06 12:03:53 +00:00
"fmt"
2018-08-16 10:44:25 +00:00
"io"
2017-12-02 02:17:40 +00:00
"io/ioutil"
2018-08-01 23:59:32 +00:00
"net"
2017-12-04 03:38:37 +00:00
"net/http"
2017-12-02 02:17:40 +00:00
"os"
2020-08-24 06:40:04 +00:00
"os/exec"
2017-12-02 02:17:40 +00:00
"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"
2020-05-28 20:46:33 +00:00
ctderrdefs "github.com/containerd/containerd/errdefs"
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"
2018-08-16 10:44:25 +00:00
gateway "github.com/moby/buildkit/frontend/gateway/client"
2017-12-02 02:17:40 +00:00
"github.com/moby/buildkit/identity"
2018-07-20 00:14:28 +00:00
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/secrets/secretsprovider"
2018-09-06 21:39:56 +00:00
"github.com/moby/buildkit/session/sshforward/sshprovider"
2020-05-19 19:59:15 +00:00
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb"
2019-03-18 23:00:48 +00:00
"github.com/moby/buildkit/util/contentutil"
2019-02-02 00:20:18 +00:00
"github.com/moby/buildkit/util/entitlements"
2018-07-17 22:17:51 +00:00
"github.com/moby/buildkit/util/testutil"
2019-07-10 23:55:04 +00:00
"github.com/moby/buildkit/util/testutil/echoserver"
2017-12-02 02:17:40 +00:00
"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-09-06 21:39:56 +00:00
"golang.org/x/crypto/ssh/agent"
2018-07-06 12:03:53 +00:00
"golang.org/x/sync/errgroup"
2017-06-19 20:39:00 +00:00
)
2019-03-22 06:49:08 +00:00
func init ( ) {
2019-09-09 13:47:18 +00:00
if os . Getenv ( "TEST_DOCKERD" ) == "1" {
integration . InitDockerdWorker ( )
} else {
integration . InitOCIWorker ( )
integration . InitContainerdWorker ( )
}
2019-03-22 06:49:08 +00:00
}
2018-08-16 10:44:25 +00:00
type nopWriteCloser struct {
io . Writer
}
func ( nopWriteCloser ) Close ( ) error { return nil }
2019-08-08 00:50:00 +00:00
func TestIntegration ( t * testing . T ) {
2019-02-02 00:20:18 +00:00
mirrors := integration . WithMirroredImages ( integration . OfficialImages ( "busybox:latest" , "alpine:latest" ) )
2017-11-30 02:49:04 +00:00
integration . Run ( t , [ ] integration . Test {
2020-03-03 06:35:29 +00:00
testCacheExportCacheKeyLoop ,
2018-05-22 00:07:08 +00:00
testRelativeWorkDir ,
2019-02-27 22:40:45 +00:00
testFileOpMkdirMkfile ,
testFileOpCopyRm ,
2019-10-30 21:25:00 +00:00
testFileOpRmWildcard ,
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 ,
2019-11-30 11:46:11 +00:00
testBuildExportWithUncompressed ,
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-08-30 13:52:19 +00:00
testFrontendImageNaming ,
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-09-11 08:02:46 +00:00
testBasicRegistryCacheImportExport ,
testBasicLocalCacheImportExport ,
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 ,
2021-04-14 15:34:04 +00:00
testRunCacheWithMounts ,
2018-07-09 22:42:34 +00:00
testParallelLocalBuilds ,
2018-07-20 00:14:28 +00:00
testSecretMounts ,
2018-08-01 23:59:32 +00:00
testExtraHosts ,
2018-08-04 19:42:01 +00:00
testNetworkMode ,
2018-08-16 10:44:25 +00:00
testFrontendMetadataReturn ,
2019-12-09 20:50:21 +00:00
testFrontendUseSolveResults ,
2018-09-06 21:39:56 +00:00
testSSHMount ,
2018-09-11 21:21:40 +00:00
testStdinClosed ,
2018-10-03 00:25:33 +00:00
testHostnameLookup ,
2020-10-10 13:10:34 +00:00
testHostnameSpecifying ,
2019-03-18 23:00:48 +00:00
testPushByDigest ,
2019-01-18 22:49:08 +00:00
testBasicInlineCacheImportExport ,
2019-03-19 02:12:34 +00:00
testExportBusyboxLocal ,
2019-07-10 23:55:04 +00:00
testBridgeNetworking ,
2019-07-25 21:13:13 +00:00
testCacheMountNoCache ,
2019-07-30 01:02:36 +00:00
testExporterTargetExists ,
2019-08-21 00:17:12 +00:00
testTarExporterWithSocket ,
2020-07-18 00:17:23 +00:00
testTarExporterWithSocketCopy ,
2020-03-30 06:25:49 +00:00
testTarExporterSymlink ,
2019-08-29 22:21:17 +00:00
testMultipleRegistryCacheImportExport ,
2020-05-19 19:59:15 +00:00
testSourceMap ,
testSourceMapFromRef ,
2020-05-28 20:46:33 +00:00
testLazyImagePush ,
2020-08-24 06:40:04 +00:00
testStargzLazyPull ,
2021-02-04 05:59:25 +00:00
testFileOpInputSwap ,
2021-05-26 18:08:56 +00:00
testRelativeMountpoint ,
2019-02-02 00:20:18 +00:00
} , mirrors )
integration . Run ( t , [ ] integration . Test {
2019-01-10 02:24:25 +00:00
testSecurityMode ,
2019-07-18 15:52:47 +00:00
testSecurityModeSysfs ,
2019-02-02 00:20:18 +00:00
testSecurityModeErrors ,
2018-09-12 23:13:06 +00:00
} ,
2019-02-02 00:20:18 +00:00
mirrors ,
integration . WithMatrix ( "secmode" , map [ string ] interface { } {
"sandbox" : securitySandbox ,
"insecure" : securityInsecure ,
} ) ,
2018-09-12 23:13:06 +00:00
)
2019-07-10 23:55:04 +00:00
integration . Run ( t , [ ] integration . Test {
testHostNetworking ,
} ,
mirrors ,
integration . WithMatrix ( "netmode" , map [ string ] interface { } {
"default" : defaultNetwork ,
"host" : hostNetwork ,
} ) ,
)
2017-07-12 05:08:53 +00:00
}
2018-08-23 07:59:41 +00:00
func newContainerd ( cdAddress string ) ( * containerd . Client , error ) {
2020-01-05 17:13:15 +00:00
return containerd . New ( cdAddress , containerd . WithTimeout ( 60 * time . Second ) )
2018-08-23 07:59:41 +00:00
}
2020-03-03 06:35:29 +00:00
// moby/buildkit#1336
func testCacheExportCacheKeyLoop ( t * testing . T , sb integration . Sandbox ) {
2020-02-27 14:27:13 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
tmpdir , err := ioutil . TempDir ( "" , "buildkit-buildctl" )
require . NoError ( t , err )
defer os . RemoveAll ( tmpdir )
err = ioutil . WriteFile ( filepath . Join ( tmpdir , "foo" ) , [ ] byte ( "foodata" ) , 0600 )
require . NoError ( t , err )
2020-03-03 06:35:29 +00:00
for _ , mode := range [ ] bool { false , true } {
func ( mode bool ) {
t . Run ( fmt . Sprintf ( "mode=%v" , mode ) , func ( t * testing . T ) {
buildbase := llb . Image ( "alpine:latest" ) . File ( llb . Copy ( llb . Local ( "mylocal" ) , "foo" , "foo" ) )
if mode { // same cache keys with a separating node go to different code-path
buildbase = buildbase . Run ( llb . Shlex ( "true" ) ) . Root ( )
}
intermed := llb . Image ( "alpine:latest" ) . File ( llb . Copy ( buildbase , "foo" , "foo" ) )
final := llb . Scratch ( ) . File ( llb . Copy ( intermed , "foo" , "foooooo" ) )
2020-03-25 22:39:32 +00:00
def , err := final . Marshal ( context . TODO ( ) )
2020-03-03 06:35:29 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
CacheExports : [ ] CacheOptionsEntry {
{
Type : "local" ,
Attrs : map [ string ] string {
"dest" : filepath . Join ( tmpdir , "cache" ) ,
} ,
} ,
} ,
LocalDirs : map [ string ] string {
"mylocal" : tmpdir ,
} ,
} , nil )
require . NoError ( t , err )
} )
} ( mode )
}
2020-02-27 14:27:13 +00:00
}
2019-07-10 23:55:04 +00:00
func testBridgeNetworking ( t * testing . T , sb integration . Sandbox ) {
if os . Getenv ( "BUILDKIT_RUN_NETWORK_INTEGRATION_TESTS" ) == "" {
t . SkipNow ( )
}
if sb . Rootless ( ) {
t . SkipNow ( )
}
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
s , err := echoserver . NewTestServer ( "foo" )
require . NoError ( t , err )
addrParts := strings . Split ( s . Addr ( ) . String ( ) , ":" )
2020-03-25 22:39:32 +00:00
def , err := llb . Image ( "busybox" ) . Run ( llb . Shlexf ( "sh -c 'nc 127.0.0.1 %s | grep foo'" , addrParts [ len ( addrParts ) - 1 ] ) ) . Marshal ( context . TODO ( ) )
2019-07-10 23:55:04 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
}
func testHostNetworking ( t * testing . T , sb integration . Sandbox ) {
if os . Getenv ( "BUILDKIT_RUN_NETWORK_INTEGRATION_TESTS" ) == "" {
t . SkipNow ( )
}
netMode := sb . Value ( "netmode" )
var allowedEntitlements [ ] entitlements . Entitlement
if netMode == hostNetwork {
allowedEntitlements = [ ] entitlements . Entitlement { entitlements . EntitlementNetworkHost }
}
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
s , err := echoserver . NewTestServer ( "foo" )
require . NoError ( t , err )
addrParts := strings . Split ( s . Addr ( ) . String ( ) , ":" )
2020-03-25 22:39:32 +00:00
def , err := llb . Image ( "busybox" ) . Run ( llb . Shlexf ( "sh -c 'nc 127.0.0.1 %s | grep foo'" , addrParts [ len ( addrParts ) - 1 ] ) , llb . Network ( llb . NetModeHost ) ) . Marshal ( context . TODO ( ) )
2019-07-10 23:55:04 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
AllowedEntitlements : allowedEntitlements ,
} , nil )
if netMode == hostNetwork {
require . NoError ( t , err )
} else {
require . Error ( t , err )
}
}
2019-03-19 02:12:34 +00:00
// #877
func testExportBusyboxLocal ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
2020-03-25 22:39:32 +00:00
def , err := llb . Image ( "busybox" ) . Marshal ( context . TODO ( ) )
2019-03-19 02:12:34 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
} , nil )
require . NoError ( t , err )
fi , err := os . Stat ( filepath . Join ( destDir , "bin/busybox" ) )
require . NoError ( t , err )
fi2 , err := os . Stat ( filepath . Join ( destDir , "bin/vi" ) )
require . NoError ( t , err )
2020-07-27 16:38:29 +00:00
require . True ( t , os . SameFile ( fi , fi2 ) )
2019-03-19 02:12:34 +00:00
}
2018-10-03 00:25:33 +00:00
func testHostnameLookup ( t * testing . T , sb integration . Sandbox ) {
if sb . Rootless ( ) {
t . SkipNow ( )
}
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( ` sh -c "ping -c 1 $(hostname)" ` ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-10-03 00:25:33 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2020-10-10 13:10:34 +00:00
// moby/buildkit#1301
func testHostnameSpecifying ( t * testing . T , sb integration . Sandbox ) {
if sb . Rootless ( ) {
t . SkipNow ( )
}
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
hostname := "testtest"
st := llb . Image ( "busybox:latest" ) . With ( llb . Hostname ( hostname ) ) .
Run ( llb . Shlexf ( "sh -c 'echo $HOSTNAME | grep %s'" , hostname ) ) .
Run ( llb . Shlexf ( "sh -c 'echo $(hostname) | grep %s'" , hostname ) )
def , err := st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
FrontendAttrs : map [ string ] string { "hostname" : hostname } ,
} , nil )
require . NoError ( t , err )
}
2018-09-11 21:21:40 +00:00
// moby/buildkit#614
func testStdinClosed ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( "cat" ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-09-11 21:21:40 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2018-09-06 21:39:56 +00:00
func testSSHMount ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
a := agent . NewKeyring ( )
k , err := rsa . GenerateKey ( rand . Reader , 2048 )
require . NoError ( t , err )
err = a . Add ( agent . AddedKey { PrivateKey : k } )
require . NoError ( t , err )
sockPath , clean , err := makeSSHAgentSock ( a )
require . NoError ( t , err )
defer clean ( )
ssh , err := sshprovider . NewSSHAgentProvider ( [ ] sshprovider . AgentConfig { {
2018-09-06 22:25:45 +00:00
Paths : [ ] string { sockPath } ,
2018-09-06 21:39:56 +00:00
} } )
require . NoError ( t , err )
// no ssh exposed
st := llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( ` nosuchcmd ` ) , llb . AddSSHSocket ( ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-09-06 21:39:56 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
2018-10-05 22:50:07 +00:00
require . Contains ( t , err . Error ( ) , "no SSH key " )
2018-09-06 21:39:56 +00:00
// custom ID not exposed
st = llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( ` nosuchcmd ` ) , llb . AddSSHSocket ( llb . SSHID ( "customID" ) ) )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2018-09-06 21:39:56 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { ssh } ,
} , nil )
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "unset ssh forward key customID" )
// missing custom ID ignored on optional
st = llb . Image ( "busybox:latest" ) . Run ( llb . Shlex ( ` ls ` ) , llb . AddSSHSocket ( llb . SSHID ( "customID" ) , llb . SSHOptional ) )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2018-09-06 21:39:56 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { ssh } ,
} , nil )
require . NoError ( t , err )
// valid socket
st = llb . Image ( "alpine:latest" ) .
Run ( llb . Shlex ( ` apk add --no-cache openssh ` ) ) .
Run ( llb . Shlex ( ` sh -c 'echo -n $SSH_AUTH_SOCK > /out/sock && ssh-add -l > /out/out' ` ) ,
llb . AddSSHSocket ( ) )
out := st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2018-09-06 21:39:56 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
Session : [ ] session . Attachable { ssh } ,
2018-09-06 21:39:56 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "sock" ) )
require . NoError ( t , err )
require . Equal ( t , "/run/buildkit/ssh_agent.0" , string ( dt ) )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "out" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "2048" )
require . Contains ( t , string ( dt ) , "(RSA)" )
// forbidden command
st = llb . Image ( "alpine:latest" ) .
Run ( llb . Shlex ( ` apk add --no-cache openssh ` ) ) .
Run ( llb . Shlex ( ` sh -c 'ssh-keygen -f /tmp/key -N "" && ssh-add -k /tmp/key 2> /out/out || true' ` ) ,
llb . AddSSHSocket ( ) )
out = st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2018-09-06 21:39:56 +00:00
require . NoError ( t , err )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
Session : [ ] session . Attachable { ssh } ,
2018-09-06 21:39:56 +00:00
} , nil )
require . NoError ( t , err )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "out" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "agent refused operation" )
2018-09-06 22:25:45 +00:00
// valid socket from key on disk
st = llb . Image ( "alpine:latest" ) .
Run ( llb . Shlex ( ` apk add --no-cache openssh ` ) ) .
Run ( llb . Shlex ( ` sh -c 'ssh-add -l > /out/out' ` ) ,
llb . AddSSHSocket ( ) )
out = st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2018-09-06 22:25:45 +00:00
require . NoError ( t , err )
k , err = rsa . GenerateKey ( rand . Reader , 1024 )
require . NoError ( t , err )
dt = pem . EncodeToMemory (
& pem . Block {
Type : "RSA PRIVATE KEY" ,
Bytes : x509 . MarshalPKCS1PrivateKey ( k ) ,
} ,
)
tmpDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( tmpDir )
err = ioutil . WriteFile ( filepath . Join ( tmpDir , "key" ) , dt , 0600 )
require . NoError ( t , err )
ssh , err = sshprovider . NewSSHAgentProvider ( [ ] sshprovider . AgentConfig { {
Paths : [ ] string { filepath . Join ( tmpDir , "key" ) } ,
} } )
require . NoError ( t , err )
destDir , err = ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
Session : [ ] session . Attachable { ssh } ,
2018-09-06 22:25:45 +00:00
} , nil )
require . NoError ( t , err )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "out" ) )
require . NoError ( t , err )
require . Contains ( t , string ( dt ) , "1024" )
require . Contains ( t , string ( dt ) , "(RSA)" )
2018-09-06 21:39:56 +00:00
}
2018-08-01 23:59:32 +00:00
func testExtraHosts ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'cat /etc/hosts | grep myhost | grep 1.2.3.4' ` ) , llb . AddExtraHost ( "myhost" , net . ParseIP ( "1.2.3.4" ) ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-08-01 23:59:32 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2018-08-04 19:42:01 +00:00
func testNetworkMode ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'wget https://example.com 2>&1 | grep "wget: bad address"' ` ) , llb . Network ( llb . NetModeNone ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-08-04 19:42:01 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
st2 := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` ifconfig ` ) , llb . Network ( llb . NetModeHost ) )
2020-03-25 22:39:32 +00:00
def , err = st2 . Marshal ( context . TODO ( ) )
2018-08-04 19:42:01 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
// Currently disabled globally by default
// AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementNetworkHost},
} , nil )
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "network.host is not allowed" )
}
2019-03-18 23:00:48 +00:00
func testPushByDigest ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-03-18 23:00:48 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2019-03-18 23:00:48 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
st := llb . Scratch ( ) . File ( llb . Mkfile ( "foo" , 0600 , [ ] byte ( "data" ) ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-03-18 23:00:48 +00:00
require . NoError ( t , err )
name := registry + "/foo/bar"
resp , err := c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : "image" ,
Attrs : map [ string ] string {
"name" : name ,
"push" : "true" ,
"push-by-digest" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
_ , _ , err = contentutil . ProviderFromRef ( name + ":latest" )
require . Error ( t , err )
desc , _ , err := contentutil . ProviderFromRef ( name + "@" + resp . ExporterResponse [ "containerimage.digest" ] )
require . NoError ( t , err )
require . Equal ( t , resp . ExporterResponse [ "containerimage.digest" ] , desc . Digest . String ( ) )
require . Equal ( t , images . MediaTypeDockerSchema2Manifest , desc . MediaType )
require . True ( t , desc . Size > 0 )
}
2019-01-10 02:24:25 +00:00
func testSecurityMode ( t * testing . T , sb integration . Sandbox ) {
2019-02-02 00:20:18 +00:00
var command string
mode := llb . SecurityModeSandbox
var allowedEntitlements [ ] entitlements . Entitlement
secMode := sb . Value ( "secmode" )
if secMode == securitySandbox {
/ *
$ capsh -- decode = 00000000 a80425fb
0x00000000a80425fb = cap_chown , cap_dac_override , cap_fowner , cap_fsetid , cap_kill , cap_setgid , cap_setuid , cap_setpcap ,
cap_net_bind_service , cap_net_raw , cap_sys_chroot , cap_mknod , cap_audit_write , cap_setfcap
* /
command = ` sh -c 'cat /proc/self/status | grep CapEff | grep "00000000a80425fb"' `
allowedEntitlements = [ ] entitlements . Entitlement { }
} else {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-02-02 00:20:18 +00:00
/ *
$ capsh -- decode = 0000003 fffffffff
0x0000003fffffffff = cap_chown , cap_dac_override , cap_dac_read_search , cap_fowner , cap_fsetid , cap_kill , cap_setgid ,
cap_setuid , cap_setpcap , cap_linux_immutable , cap_net_bind_service , cap_net_broadcast , cap_net_admin , cap_net_raw ,
cap_ipc_lock , cap_ipc_owner , cap_sys_module , cap_sys_rawio , cap_sys_chroot , cap_sys_ptrace , cap_sys_pacct , cap_sys_admin ,
cap_sys_boot , cap_sys_nice , cap_sys_resource , cap_sys_time , cap_sys_tty_config , cap_mknod , cap_lease , cap_audit_write ,
cap_audit_control , cap_setfcap , cap_mac_override , cap_mac_admin , cap_syslog , cap_wake_alarm , cap_block_suspend , cap_audit_read
* /
command = ` sh -c 'cat /proc/self/status | grep CapEff | grep "0000003fffffffff"' `
mode = llb . SecurityModeInsecure
allowedEntitlements = [ ] entitlements . Entitlement { entitlements . EntitlementSecurityInsecure }
}
2019-01-10 02:24:25 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) .
2019-02-02 00:20:18 +00:00
Run ( llb . Shlex ( command ) ,
llb . Security ( mode ) )
2019-01-10 02:24:25 +00:00
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-01-10 02:24:25 +00:00
require . NoError ( t , err )
2019-02-02 00:20:18 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
AllowedEntitlements : allowedEntitlements ,
} , nil )
2019-01-10 02:24:25 +00:00
require . NoError ( t , err )
2019-02-02 00:20:18 +00:00
}
2019-01-10 02:24:25 +00:00
2019-07-18 15:52:47 +00:00
func testSecurityModeSysfs ( t * testing . T , sb integration . Sandbox ) {
2019-07-18 19:50:53 +00:00
if sb . Rootless ( ) {
t . SkipNow ( )
}
2019-07-18 15:52:47 +00:00
mode := llb . SecurityModeSandbox
var allowedEntitlements [ ] entitlements . Entitlement
secMode := sb . Value ( "secmode" )
if secMode == securitySandbox {
allowedEntitlements = [ ] entitlements . Entitlement { }
} else {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-07-18 15:52:47 +00:00
mode = llb . SecurityModeInsecure
allowedEntitlements = [ ] entitlements . Entitlement { entitlements . EntitlementSecurityInsecure }
}
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
command := ` mkdir /sys/fs/cgroup/cpuset/securitytest `
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( command ) ,
llb . Security ( mode ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-07-18 15:52:47 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
AllowedEntitlements : allowedEntitlements ,
} , nil )
2019-07-18 19:50:53 +00:00
if secMode == securitySandbox {
2019-07-18 15:52:47 +00:00
require . Error ( t , err )
2019-08-05 22:52:13 +00:00
require . Contains ( t , err . Error ( ) , "executor failed running" )
require . Contains ( t , err . Error ( ) , "mkdir /sys/fs/cgroup/cpuset/securitytest" )
2019-07-18 15:52:47 +00:00
} else {
require . NoError ( t , err )
}
}
2019-02-02 00:20:18 +00:00
func testSecurityModeErrors ( t * testing . T , sb integration . Sandbox ) {
2019-01-10 02:24:25 +00:00
2019-02-02 00:20:18 +00:00
c , err := New ( context . TODO ( ) , sb . Address ( ) )
2019-01-10 02:24:25 +00:00
require . NoError ( t , err )
2019-02-02 00:20:18 +00:00
defer c . Close ( )
secMode := sb . Value ( "secmode" )
if secMode == securitySandbox {
2019-01-10 02:24:25 +00:00
2019-02-02 00:20:18 +00:00
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'echo sandbox' ` ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-02-02 00:20:18 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
AllowedEntitlements : [ ] entitlements . Entitlement { entitlements . EntitlementSecurityInsecure } ,
} , nil )
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "security.insecure is not allowed" )
}
if secMode == securityInsecure {
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'echo insecure' ` ) , llb . Security ( llb . SecurityModeInsecure ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-02-02 00:20:18 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "security.insecure is not allowed" )
}
2019-01-10 02:24:25 +00:00
}
2018-08-30 13:52:19 +00:00
func testFrontendImageNaming ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-08-15 15:11:37 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2018-08-15 15:11:37 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
2018-08-31 09:54:41 +00:00
checkImageName := map [ string ] func ( out , imageName string , exporterResponse map [ string ] string ) {
ExporterOCI : func ( out , imageName string , exporterResponse map [ string ] string ) {
2018-08-15 15:11:37 +00:00
// Nothing to check
return
} ,
2018-08-31 09:54:41 +00:00
ExporterDocker : func ( out , imageName string , exporterResponse map [ string ] string ) {
require . Contains ( t , exporterResponse , "image.name" )
require . Equal ( t , exporterResponse [ "image.name" ] , "docker.io/library/" + imageName )
2018-08-15 15:11:37 +00:00
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
m , err := testutil . 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 dockerMfst [ ] struct {
RepoTags [ ] string
}
err = json . Unmarshal ( m [ "manifest.json" ] . Data , & dockerMfst )
require . NoError ( t , err )
require . Equal ( t , 1 , len ( dockerMfst ) )
require . Equal ( t , 1 , len ( dockerMfst [ 0 ] . RepoTags ) )
2019-08-05 22:52:13 +00:00
require . Equal ( t , imageName , dockerMfst [ 0 ] . RepoTags [ 0 ] )
2018-08-15 15:11:37 +00:00
} ,
2018-08-31 09:54:41 +00:00
ExporterImage : func ( _ , imageName string , exporterResponse map [ string ] string ) {
require . Contains ( t , exporterResponse , "image.name" )
require . Equal ( t , exporterResponse [ "image.name" ] , imageName )
2018-08-15 15:11:37 +00:00
// check if we can pull (requires containerd)
2020-06-21 01:35:25 +00:00
cdAddress := sb . ContainerdAddress ( )
if cdAddress == "" {
2018-08-15 15:11:37 +00:00
return
}
// 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" )
// check image in containerd
_ , err = client . ImageService ( ) . Get ( ctx , imageName )
require . NoError ( t , err )
// deleting image should release all content
err = client . ImageService ( ) . Delete ( ctx , imageName , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
_ , err = client . Pull ( ctx , imageName )
require . NoError ( t , err )
err = client . ImageService ( ) . Delete ( ctx , imageName , images . SynchronousDelete ( ) )
require . NoError ( t , err )
} ,
}
2018-08-30 14:59:12 +00:00
// A caller provided name takes precedence over one returned by the frontend. Iterate over both options.
for _ , winner := range [ ] string { "frontend" , "caller" } {
2018-08-30 15:27:04 +00:00
winner := winner // capture loop variable.
// The double layer of `t.Run` here is required so
// that the inner-most tests (with the actual
// functionality) have definitely completed before the
// sandbox and registry cleanups (defered above) are run.
t . Run ( winner , func ( t * testing . T ) {
for _ , exp := range [ ] string { ExporterOCI , ExporterDocker , ExporterImage } {
exp := exp // capture loop variable.
t . Run ( exp , func ( t * testing . T ) {
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
so := SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : exp ,
Attrs : map [ string ] string { } ,
} ,
} ,
2018-08-30 15:27:04 +00:00
}
out := filepath . Join ( destDir , "out.tar" )
imageName := "image-" + exp + "-fe:latest"
switch exp {
2018-08-31 10:19:04 +00:00
case ExporterOCI :
t . Skip ( "oci exporter does not support named images" )
case ExporterDocker :
2018-08-30 15:27:04 +00:00
outW , err := os . Create ( out )
require . NoError ( t , err )
2019-07-30 00:50:54 +00:00
so . Exports [ 0 ] . Output = fixedWriteCloser ( outW )
2018-08-30 15:27:04 +00:00
case ExporterImage :
imageName = registry + "/" + imageName
2019-01-31 16:30:39 +00:00
so . Exports [ 0 ] . Attrs [ "push" ] = "true"
2018-08-30 15:27:04 +00:00
}
feName := imageName
switch winner {
case "caller" :
feName = "loser:latest"
2019-01-31 16:30:39 +00:00
so . Exports [ 0 ] . Attrs [ "name" ] = imageName
2018-08-30 15:27:04 +00:00
case "frontend" :
2019-01-31 16:30:39 +00:00
so . Exports [ 0 ] . Attrs [ "name" ] = "*"
2018-08-30 15:27:04 +00:00
}
frontend := func ( ctx context . Context , c gateway . Client ) ( * gateway . Result , error ) {
res := gateway . NewResult ( )
res . AddMeta ( "image.name" , [ ] byte ( feName ) )
return res , nil
}
2018-08-31 09:54:41 +00:00
resp , err := c . Build ( context . TODO ( ) , so , "" , frontend , nil )
2018-08-30 15:27:04 +00:00
require . NoError ( t , err )
2018-08-31 09:54:41 +00:00
checkImageName [ exp ] ( out , imageName , resp . ExporterResponse )
2018-08-30 15:27:04 +00:00
} )
2018-08-15 15:11:37 +00:00
}
2018-08-30 15:27:04 +00:00
} )
2018-08-15 15:11:37 +00:00
}
checkAllReleasable ( t , c , sb , true )
}
2018-07-20 00:14:28 +00:00
func testSecretMounts ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` sh -c 'mount | grep mysecret | grep "type tmpfs" && [ "$(cat /run/secrets/mysecret)" = 'foo-secret' ]' ` ) , llb . AddSecret ( "/run/secrets/mysecret" ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-07-20 00:14:28 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { secretsprovider . FromMap ( map [ string ] [ ] byte {
"/run/secrets/mysecret" : [ ] byte ( "foo-secret" ) ,
} ) } ,
} , nil )
require . NoError ( t , err )
// test optional
st = llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` echo secret2 ` ) , llb . AddSecret ( "/run/secrets/mysecret2" , llb . SecretOptional ) )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2018-07-20 00:14:28 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { secretsprovider . FromMap ( map [ string ] [ ] byte { } ) } ,
} , nil )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
st = llb . Image ( "busybox:latest" ) .
Run ( llb . Shlex ( ` echo secret3 ` ) , llb . AddSecret ( "/run/secrets/mysecret3" ) )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2018-07-20 00:14:28 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { secretsprovider . FromMap ( map [ string ] [ ] byte { } ) } ,
} , nil )
require . Error ( t , err )
// test id,perm,uid
st = llb . Image ( "busybox:latest" ) .
2019-07-01 22:32:04 +00:00
Run ( llb . Shlex ( ` sh -c '[ "$(stat -c "%u %g %f" /run/secrets/mysecret4)" = "1 1 81ff" ]' ` ) , llb . AddSecret ( "/run/secrets/mysecret4" , llb . SecretID ( "mysecret" ) , llb . SecretFileOpt ( 1 , 1 , 0777 ) ) )
2018-07-20 00:14:28 +00:00
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2018-07-20 00:14:28 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Session : [ ] session . Attachable { secretsprovider . FromMap ( map [ string ] [ ] byte {
"mysecret" : [ ] byte ( "pw" ) ,
} ) } ,
} , nil )
require . NoError ( t , err )
}
2018-06-08 05:28:52 +00:00
func testTmpfsMounts ( t * testing . T , sb integration . Sandbox ) {
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 ( ) ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-06-08 05:28:52 +00:00
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 ) {
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 ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-06-04 21:08:29 +00:00
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 ) {
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 ( ) )
2020-03-25 22:39:32 +00:00
def , err := pwd . Marshal ( context . TODO ( ) )
2018-05-22 00:07:08 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2018-05-22 00:07:08 +00:00
} , 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 )
}
2019-02-27 22:40:45 +00:00
func testFileOpMkdirMkfile ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Scratch ( ) .
File ( llb . Mkdir ( "/foo" , 0700 ) . Mkfile ( "bar" , 0600 , [ ] byte ( "contents" ) ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-02-27 22:40:45 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-03-09 00:15:42 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2019-02-27 22:40:45 +00:00
} , nil )
require . NoError ( t , err )
fi , err := os . Stat ( filepath . Join ( destDir , "foo" ) )
require . NoError ( t , err )
require . Equal ( t , true , fi . IsDir ( ) )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "bar" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "contents" ) , dt )
}
func testFileOpCopyRm ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
dir , err := tmpdir (
fstest . CreateFile ( "myfile" , [ ] byte ( "data0" ) , 0600 ) ,
fstest . CreateDir ( "sub" , 0700 ) ,
fstest . CreateFile ( "sub/foo" , [ ] byte ( "foo0" ) , 0600 ) ,
fstest . CreateFile ( "sub/bar" , [ ] byte ( "bar0" ) , 0600 ) ,
)
require . NoError ( t , err )
defer os . RemoveAll ( dir )
dir2 , err := tmpdir (
fstest . CreateFile ( "file2" , [ ] byte ( "file2" ) , 0600 ) ,
)
require . NoError ( t , err )
defer os . RemoveAll ( dir )
st := llb . Scratch ( ) .
File (
llb . Copy ( llb . Local ( "mylocal" ) , "myfile" , "myfile2" ) .
Copy ( llb . Local ( "mylocal" ) , "sub" , "out" ) .
Rm ( "out/foo" ) .
Copy ( llb . Local ( "mylocal2" ) , "file2" , "/" ) )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-02-27 22:40:45 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-03-09 00:15:42 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2019-02-27 22:40:45 +00:00
LocalDirs : map [ string ] string {
"mylocal" : dir ,
"mylocal2" : dir2 ,
} ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "myfile2" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "data0" ) , dt )
fi , err := os . Stat ( filepath . Join ( destDir , "out" ) )
require . NoError ( t , err )
require . Equal ( t , true , fi . IsDir ( ) )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "out/bar" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "bar0" ) , dt )
_ , err = os . Stat ( filepath . Join ( destDir , "out/foo" ) )
2020-04-19 05:17:47 +00:00
require . Equal ( t , true , errors . Is ( err , os . ErrNotExist ) )
2019-02-27 22:40:45 +00:00
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "file2" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "file2" ) , dt )
2021-02-04 05:59:25 +00:00
}
// testFileOpInputSwap is a regression test that cache is invalidated when subset of fileop is built
func testFileOpInputSwap ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
2019-02-27 22:40:45 +00:00
2021-02-04 05:59:25 +00:00
base := llb . Scratch ( ) . File ( llb . Mkfile ( "/foo" , 0600 , [ ] byte ( "foo" ) ) )
src := llb . Scratch ( ) . File ( llb . Mkfile ( "/bar" , 0600 , [ ] byte ( "bar" ) ) )
st := base . File ( llb . Copy ( src , "/bar" , "/baz" ) )
def , err := st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
// bar does not exist in base but index of all inputs remains the same
st = base . File ( llb . Copy ( base , "/bar" , "/baz" ) )
def , err = st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , "bar: no such file" )
2019-02-27 22:40:45 +00:00
}
2019-10-30 21:25:00 +00:00
func testFileOpRmWildcard ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
dir , err := tmpdir (
fstest . CreateDir ( "foo" , 0700 ) ,
fstest . CreateDir ( "bar" , 0700 ) ,
fstest . CreateFile ( "foo/target" , [ ] byte ( "foo0" ) , 0600 ) ,
fstest . CreateFile ( "bar/target" , [ ] byte ( "bar0" ) , 0600 ) ,
fstest . CreateFile ( "bar/remaining" , [ ] byte ( "bar1" ) , 0600 ) ,
)
require . NoError ( t , err )
defer os . RemoveAll ( dir )
st := llb . Scratch ( ) . File (
llb . Copy ( llb . Local ( "mylocal" ) , "foo" , "foo" ) .
Copy ( llb . Local ( "mylocal" ) , "bar" , "bar" ) ,
) . File (
llb . Rm ( "*/target" , llb . WithAllowWildcard ( true ) ) ,
)
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-10-30 21:25:00 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
LocalDirs : map [ string ] string {
"mylocal" : dir ,
} ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "bar/remaining" ) )
require . NoError ( t , err )
require . Equal ( t , [ ] byte ( "bar1" ) , dt )
fi , err := os . Stat ( filepath . Join ( destDir , "foo" ) )
require . NoError ( t , err )
require . Equal ( t , true , fi . IsDir ( ) )
_ , err = os . Stat ( filepath . Join ( destDir , "foo/target" ) )
2020-04-19 05:17:47 +00:00
require . Equal ( t , true , errors . Is ( err , os . ErrNotExist ) )
2019-10-30 21:25:00 +00:00
_ , err = os . Stat ( filepath . Join ( destDir , "bar/target" ) )
2020-04-19 05:17:47 +00:00
require . Equal ( t , true , errors . Is ( err , os . ErrNotExist ) )
2019-10-30 21:25:00 +00:00
}
2017-11-27 22:24:29 +00:00
func testCallDiskUsage ( t * testing . T , sb integration . Sandbox ) {
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-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 )
2020-03-25 22:39:32 +00:00
def , err := cp . Marshal ( context . TODO ( ) )
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 ) {
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" )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2017-12-02 02:17:40 +00:00
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" )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2017-12-02 02:17:40 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : 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 ) )
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2017-12-04 03:38:37 +00:00
require . NoError ( t , err )
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : 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 )
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 ." ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2017-12-11 02:18:18 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : 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 )
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" ` )
2020-09-12 06:18:19 +00:00
run ( "daemon:nobody" , ` sh -c "id -ng > nobody" ` )
2017-12-11 21:17:07 +00:00
run ( "1:1" , ` sh -c "id -g > userone" ` )
st = st . Run ( llb . Shlex ( "cp -a /wd/. /out/" ) )
out := st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2017-12-11 21:17:07 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : 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" )
2020-09-12 06:18:19 +00:00
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "nobody" ) )
2017-12-11 21:17:07 +00:00
require . NoError ( t , err )
2020-09-12 06:18:19 +00:00
require . Contains ( t , string ( dt ) , "nobody" )
2017-12-11 21:17:07 +00:00
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 ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2017-12-13 05:55:16 +00:00
requiresLinux ( t )
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" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2017-12-13 05:55:16 +00:00
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-08-31 10:19:04 +00:00
attrs := map [ string ] string { }
if exp == ExporterDocker {
attrs [ "name" ] = target
}
2018-05-03 00:35:07 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : exp ,
Attrs : attrs ,
2019-07-30 00:50:54 +00:00
Output : fixedWriteCloser ( outW ) ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2017-12-18 00:20:19 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
2018-07-17 22:17:51 +00:00
m , err := testutil . ReadTarToMap ( dt , false )
2017-12-18 00:20:19 +00:00
require . NoError ( t , err )
_ , ok := m [ "oci-layout" ]
require . True ( t , ok )
var index ocispec . Index
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "index.json" ] . Data , & index )
2017-12-18 00:20:19 +00:00
require . NoError ( t , err )
require . Equal ( t , 2 , index . SchemaVersion )
require . Equal ( t , 1 , len ( index . Manifests ) )
var mfst ocispec . Manifest
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . Data , & mfst )
2017-12-18 00:20:19 +00:00
require . NoError ( t , err )
require . Equal ( t , 2 , len ( mfst . Layers ) )
var ociimg ocispec . Image
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "blobs/sha256/" + mfst . Config . Digest . Hex ( ) ] . Data , & ociimg )
2017-12-18 00:20:19 +00:00
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
}
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "manifest.json" ] . Data , & dockerMfst )
2017-12-18 00:20:19 +00:00
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
}
2018-08-16 10:44:25 +00:00
func testFrontendMetadataReturn ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-08-16 10:44:25 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
frontend := func ( ctx context . Context , c gateway . Client ) ( * gateway . Result , error ) {
res := gateway . NewResult ( )
res . AddMeta ( "frontend.returned" , [ ] byte ( "true" ) )
res . AddMeta ( "not-frontend.not-returned" , [ ] byte ( "false" ) )
res . AddMeta ( "frontendnot.returned.either" , [ ] byte ( "false" ) )
return res , nil
}
res , err := c . Build ( context . TODO ( ) , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterOCI ,
Attrs : map [ string ] string { } ,
2019-07-30 00:50:54 +00:00
Output : fixedWriteCloser ( nopWriteCloser { ioutil . Discard } ) ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2018-08-16 10:44:25 +00:00
} , "" , frontend , nil )
require . NoError ( t , err )
require . Contains ( t , res . ExporterResponse , "frontend.returned" )
require . Equal ( t , res . ExporterResponse [ "frontend.returned" ] , "true" )
require . NotContains ( t , res . ExporterResponse , "not-frontend.not-returned" )
require . NotContains ( t , res . ExporterResponse , "frontendnot.returned.either" )
checkAllReleasable ( t , c , sb , true )
}
2019-12-09 20:50:21 +00:00
func testFrontendUseSolveResults ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
frontend := func ( ctx context . Context , c gateway . Client ) ( * gateway . Result , error ) {
st := llb . Scratch ( ) . File (
llb . Mkfile ( "foo" , 0600 , [ ] byte ( "data" ) ) ,
)
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-12-09 20:50:21 +00:00
if err != nil {
return nil , err
}
res , err := c . Solve ( ctx , gateway . SolveRequest {
Definition : def . ToPB ( ) ,
} )
if err != nil {
return nil , err
}
ref , err := res . SingleRef ( )
if err != nil {
return nil , err
}
2020-01-23 19:30:45 +00:00
st2 , err := ref . ToState ( )
if err != nil {
return nil , err
}
2019-12-09 20:50:21 +00:00
st = llb . Scratch ( ) . File (
2020-01-23 19:30:45 +00:00
llb . Copy ( st2 , "foo" , "foo2" ) ,
2019-12-09 20:50:21 +00:00
)
2020-03-25 22:39:32 +00:00
def , err = st . Marshal ( context . TODO ( ) )
2019-12-09 20:50:21 +00:00
if err != nil {
return nil , err
}
return c . Solve ( ctx , gateway . SolveRequest {
Definition : def . ToPB ( ) ,
} )
}
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Build ( context . TODO ( ) , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
} , "" , frontend , nil )
require . NoError ( t , err )
2020-01-23 19:30:45 +00:00
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "foo2" ) )
2019-12-09 20:50:21 +00:00
require . NoError ( t , err )
require . Equal ( t , dt , [ ] byte ( "data" ) )
}
2019-09-09 13:47:18 +00:00
func skipDockerd ( t * testing . T , sb integration . Sandbox ) {
// TODO: remove me once dockerd supports the image and exporter.
t . Helper ( )
if os . Getenv ( "TEST_DOCKERD" ) == "1" {
t . Skip ( "dockerd missing a required exporter, cache exporter, or entitlement" )
}
}
2019-07-30 01:02:36 +00:00
func testExporterTargetExists ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-07-30 01:02:36 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
st := llb . Image ( "busybox:latest" )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-07-30 01:02:36 +00:00
require . NoError ( t , err )
var mdDgst string
res , err := c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterOCI ,
Attrs : map [ string ] string { } ,
Output : func ( m map [ string ] string ) ( io . WriteCloser , error ) {
mdDgst = m [ "containerimage.digest" ]
return nil , nil
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
dgst := res . ExporterResponse [ "containerimage.digest" ]
require . True ( t , strings . HasPrefix ( dgst , "sha256:" ) )
require . Equal ( t , dgst , mdDgst )
2020-12-14 21:25:34 +00:00
require . True ( t , strings . HasPrefix ( res . ExporterResponse [ "containerimage.config.digest" ] , "sha256:" ) )
2019-07-30 01:02:36 +00:00
}
2019-08-21 00:17:12 +00:00
func testTarExporterWithSocket ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
if os . Getenv ( "TEST_DOCKERD" ) == "1" {
t . Skip ( "tar exporter is temporarily broken on dockerd" )
}
2019-08-21 00:17:12 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
alpine := llb . Image ( "docker.io/library/alpine:latest" )
2020-03-25 22:39:32 +00:00
def , err := alpine . Run ( llb . Args ( [ ] string { "sh" , "-c" , "nc -l -s local:/socket.sock & usleep 100000; kill %1" } ) ) . Marshal ( context . TODO ( ) )
2019-08-21 00:17:12 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterTar ,
Attrs : map [ string ] string { } ,
Output : func ( m map [ string ] string ) ( io . WriteCloser , error ) {
return nopWriteCloser { ioutil . Discard } , nil
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
}
2020-07-18 00:17:23 +00:00
func testTarExporterWithSocketCopy ( t * testing . T , sb integration . Sandbox ) {
if os . Getenv ( "TEST_DOCKERD" ) == "1" {
t . Skip ( "tar exporter is temporarily broken on dockerd" )
}
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
alpine := llb . Image ( "docker.io/library/alpine:latest" )
state := alpine . Run ( llb . Args ( [ ] string { "sh" , "-c" , "nc -l -s local:/root/socket.sock & usleep 100000; kill %1" } ) ) . Root ( )
fa := llb . Copy ( state , "/root" , "/roo2" , & llb . CopyInfo { } )
scratchCopy := llb . Scratch ( ) . File ( fa )
def , err := scratchCopy . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2020-03-30 06:25:49 +00:00
// moby/buildkit#1418
func testTarExporterSymlink ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
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;ln -s foo bar" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2020-03-30 06:25:49 +00:00
require . NoError ( t , err )
var buf bytes . Buffer
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterTar ,
Output : fixedWriteCloser ( & nopWriteCloser { & buf } ) ,
} ,
} ,
} , nil )
require . NoError ( t , err )
m , err := testutil . ReadTarToMap ( buf . Bytes ( ) , false )
require . NoError ( t , err )
item , ok := m [ "foo" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "first" ) , item . Data )
item , ok = m [ "bar" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeSymlink )
require . Equal ( t , "foo" , item . Header . Linkname )
}
2019-11-30 11:46:11 +00:00
func testBuildExportWithUncompressed ( t * testing . T , sb integration . Sandbox ) {
2020-04-08 19:06:42 +00:00
if os . Getenv ( "TEST_DOCKERD" ) == "1" {
t . Skip ( "image exporter is missing in dockerd" )
}
2019-11-30 11:46:11 +00:00
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
busybox := llb . Image ( "busybox:latest" )
2020-06-21 22:29:23 +00:00
cmd := ` sh -e -c "echo -n uncompressed > data" `
2019-11-30 11:46:11 +00:00
st := llb . Scratch ( )
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , st )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-11-30 11:46:11 +00:00
require . NoError ( t , err )
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2019-11-30 11:46:11 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
target := registry + "/buildkit/build/exporter:withnocompressed"
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
"compression" : "uncompressed" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
2020-06-23 18:23:53 +00:00
ctx := namespaces . WithNamespace ( context . Background ( ) , "buildkit" )
cdAddress := sb . ContainerdAddress ( )
var client * containerd . Client
if cdAddress != "" {
client , err = newContainerd ( cdAddress )
require . NoError ( t , err )
defer client . Close ( )
img , err := client . GetImage ( ctx , target )
require . NoError ( t , err )
mfst , err := images . Manifest ( ctx , client . ContentStore ( ) , img . Target ( ) , nil )
require . NoError ( t , err )
require . Equal ( t , 1 , len ( mfst . Layers ) )
require . Equal ( t , images . MediaTypeDockerSchema2Layer , mfst . Layers [ 0 ] . MediaType )
}
2019-11-30 11:46:11 +00:00
// new layer with gzip compression
targetImg := llb . Image ( target )
2020-06-21 22:29:23 +00:00
cmd = ` sh -e -c "echo -n gzip > data" `
st = busybox . Run ( llb . Shlex ( cmd ) , llb . Dir ( "/wd" ) ) . AddMount ( "/wd" , targetImg )
2019-11-30 11:46:11 +00:00
2020-06-21 22:29:23 +00:00
def , err = st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
compressedTarget := registry + "/buildkit/build/exporter:withcompressed"
2019-11-30 11:46:11 +00:00
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
2020-06-21 22:29:23 +00:00
"name" : compressedTarget ,
2019-11-30 11:46:11 +00:00
"push" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
2020-06-21 01:35:25 +00:00
if cdAddress == "" {
t . Skip ( "rest of test requires containerd worker" )
2019-11-30 11:46:11 +00:00
}
err = client . ImageService ( ) . Delete ( ctx , target , images . SynchronousDelete ( ) )
require . NoError ( t , err )
2020-06-21 22:29:23 +00:00
err = client . ImageService ( ) . Delete ( ctx , compressedTarget , images . SynchronousDelete ( ) )
require . NoError ( t , err )
2019-11-30 11:46:11 +00:00
checkAllReleasable ( t , c , sb , true )
2020-06-21 22:29:23 +00:00
img , err := client . Pull ( ctx , compressedTarget )
2019-11-30 11:46:11 +00:00
require . NoError ( t , err )
dt , err := content . ReadBlob ( ctx , img . ContentStore ( ) , img . Target ( ) )
require . NoError ( t , err )
var mfst = struct {
MediaType string ` json:"mediaType,omitempty" `
ocispec . Manifest
} { }
err = json . Unmarshal ( dt , & mfst )
require . NoError ( t , err )
require . Equal ( t , 2 , len ( mfst . Layers ) )
require . Equal ( t , images . MediaTypeDockerSchema2Layer , mfst . Layers [ 0 ] . MediaType )
require . Equal ( t , images . MediaTypeDockerSchema2LayerGzip , mfst . Layers [ 1 ] . MediaType )
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , ocispec . Descriptor { Digest : mfst . Layers [ 0 ] . Digest } )
require . NoError ( t , err )
m , err := testutil . ReadTarToMap ( dt , false )
require . NoError ( t , err )
item , ok := m [ "data" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "uncompressed" ) , item . Data )
dt , err = content . ReadBlob ( ctx , img . ContentStore ( ) , ocispec . Descriptor { Digest : mfst . Layers [ 1 ] . Digest } )
require . NoError ( t , err )
m , err = testutil . ReadTarToMap ( dt , true )
require . NoError ( t , err )
item , ok = m [ "data" ]
require . True ( t , ok )
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "gzip" ) , item . Data )
}
2017-12-05 23:32:52 +00:00
func testBuildPushAndValidate ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2017-12-05 23:32:52 +00:00
requiresLinux ( t )
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" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2017-12-05 23:32:52 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
} ,
2017-12-05 23:32:52 +00:00
} ,
} , nil )
require . NoError ( t , err )
// test existence of the image with next build
firstBuild := llb . Image ( target )
2020-03-25 22:39:32 +00:00
def , err = firstBuild . Marshal ( context . TODO ( ) )
2017-12-05 23:32:52 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : 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)
2020-06-21 01:35:25 +00:00
cdAddress := sb . ContainerdAddress ( )
if cdAddress == "" {
t . Skip ( "rest of test requires containerd worker" )
2017-12-05 23:32:52 +00:00
}
// TODO: make public pull helper function so this can be checked for standalone as well
2018-08-23 07:59:41 +00:00
client , err := newContainerd ( cdAddress )
2017-12-05 23:32:52 +00:00
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 ) )
2019-11-30 11:46:11 +00:00
require . Equal ( t , images . MediaTypeDockerSchema2LayerGzip , mfst . Layers [ 0 ] . MediaType )
require . Equal ( t , images . MediaTypeDockerSchema2LayerGzip , mfst . Layers [ 1 ] . MediaType )
2017-12-05 23:32:52 +00:00
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 )
2018-07-17 22:17:51 +00:00
m , err := testutil . ReadTarToMap ( dt , true )
2017-12-05 23:32:52 +00:00
require . NoError ( t , err )
item , ok := m [ "foo/" ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeDir )
require . Equal ( t , 0741 , int ( item . Header . Mode & 0777 ) )
2017-12-05 23:32:52 +00:00
item , ok = m [ "foo/sub/" ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeDir )
2017-12-05 23:32:52 +00:00
item , ok = m [ "foo/sub/bar" ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "first" ) , item . Data )
2017-12-05 23:32:52 +00:00
_ , 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 )
2018-07-17 22:17:51 +00:00
m , err = testutil . 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 )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeReg )
require . Equal ( t , [ ] byte ( "second" ) , item . Data )
2017-12-05 23:32:52 +00:00
2017-12-20 21:54:48 +00:00
item , ok = m [ "foo/" ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeDir )
require . Equal ( t , 0741 , int ( item . Header . Mode & 0777 ) )
2017-12-20 21:54:48 +00:00
item , ok = m [ "foo/sub/" ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
require . Equal ( t , int32 ( item . Header . Typeflag ) , tar . TypeDir )
2017-12-20 21:54:48 +00:00
_ , ok = m [ "foo/sub/bar" ]
require . False ( t , ok )
2017-12-05 23:32:52 +00:00
}
2020-08-24 06:40:04 +00:00
func testStargzLazyPull ( t * testing . T , sb integration . Sandbox ) {
skipDockerd ( t , sb )
requiresLinux ( t )
cdAddress := sb . ContainerdAddress ( )
2020-09-03 05:40:57 +00:00
if cdAddress == "" || sb . Snapshotter ( ) != "stargz" {
2020-08-24 06:40:04 +00:00
t . Skip ( "test requires containerd worker with stargz snapshotter" )
}
client , err := newContainerd ( cdAddress )
require . NoError ( t , err )
defer client . Close ( )
registry , err := sb . NewRegistry ( )
if errors . Is ( err , integration . ErrorRequirements ) {
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
2021-02-12 01:43:14 +00:00
var (
imageService = client . ImageService ( )
contentStore = client . ContentStore ( )
ctx = namespaces . WithNamespace ( context . Background ( ) , "buildkit" )
)
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
2020-08-24 06:40:04 +00:00
// Prepare stargz image
2021-02-12 01:43:14 +00:00
orgImage := "docker.io/library/alpine:latest"
2020-08-24 06:40:04 +00:00
sgzImage := registry + "/stargz/alpine:latest"
2021-02-12 01:43:14 +00:00
ctrRemoteCommonArg := [ ] string { "--namespace" , "buildkit" , "--address" , cdAddress }
err = exec . Command ( "ctr-remote" , append ( ctrRemoteCommonArg , "i" , "pull" , orgImage ) ... ) . Run ( )
require . NoError ( t , err )
err = exec . Command ( "ctr-remote" , append ( ctrRemoteCommonArg , "i" , "optimize" , "--oci" , "--period=1" , orgImage , sgzImage ) ... ) . Run ( )
require . NoError ( t , err )
err = exec . Command ( "ctr-remote" , append ( ctrRemoteCommonArg , "i" , "push" , "--plain-http" , sgzImage ) ... ) . Run ( )
2020-08-24 06:40:04 +00:00
require . NoError ( t , err )
2021-02-12 01:43:14 +00:00
// clear all local state out
err = imageService . Delete ( ctx , orgImage , images . SynchronousDelete ( ) )
2020-08-24 06:40:04 +00:00
require . NoError ( t , err )
2021-02-12 01:43:14 +00:00
err = imageService . Delete ( ctx , sgzImage , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
2020-08-24 06:40:04 +00:00
// stargz layers should be lazy even for executing something on them
def , err := llb . Image ( sgzImage ) .
Run ( llb . Args ( [ ] string { "/bin/touch" , "/foo" } ) ) .
Marshal ( context . TODO ( ) )
require . NoError ( t , err )
target := registry + "/buildkit/testlazyimage:latest"
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
img , err := imageService . Get ( ctx , target )
require . NoError ( t , err )
manifest , err := images . Manifest ( ctx , contentStore , img . Target , nil )
require . NoError ( t , err )
// Check if image layers are lazy.
// The topmost(last) layer created by `Run` isn't lazy so we skip the check for the layer.
var sgzLayers [ ] ocispec . Descriptor
for _ , layer := range manifest . Layers [ : len ( manifest . Layers ) - 1 ] {
_ , err = contentStore . Info ( ctx , layer . Digest )
require . True ( t , errors . Is ( err , ctderrdefs . ErrNotFound ) , "unexpected error %v" , err )
sgzLayers = append ( sgzLayers , layer )
}
require . NotEqual ( t , 0 , len ( sgzLayers ) , "no layer can be used for checking lazypull" )
// The topmost(last) layer created by `Run` shouldn't be lazy
_ , err = contentStore . Info ( ctx , manifest . Layers [ len ( manifest . Layers ) - 1 ] . Digest )
require . NoError ( t , err )
// clear all local state out
err = imageService . Delete ( ctx , img . Name , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
// stargz layers should be exportable
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
out := filepath . Join ( destDir , "out.tar" )
outW , err := os . Create ( out )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterOCI ,
Output : fixedWriteCloser ( outW ) ,
} ,
} ,
} , nil )
require . NoError ( t , err )
// Check if image layers are un-lazied
for _ , layer := range sgzLayers {
_ , err = contentStore . Info ( ctx , layer . Digest )
require . NoError ( t , err )
}
err = c . Prune ( context . TODO ( ) , nil , PruneAll )
require . NoError ( t , err )
checkAllRemoved ( t , c , sb )
}
2020-05-28 20:46:33 +00:00
func testLazyImagePush ( t * testing . T , sb integration . Sandbox ) {
skipDockerd ( t , sb )
requiresLinux ( t )
cdAddress := sb . ContainerdAddress ( )
if cdAddress == "" {
t . Skip ( "test requires containerd worker" )
}
client , err := newContainerd ( cdAddress )
require . NoError ( t , err )
defer client . Close ( )
ctx := namespaces . WithNamespace ( context . Background ( ) , "buildkit" )
registry , err := sb . NewRegistry ( )
if errors . Is ( err , integration . ErrorRequirements ) {
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
// push the busybox image to the mutable registry
sourceImage := "busybox:latest"
def , err := llb . Image ( sourceImage ) . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
targetNoTag := registry + "/buildkit/testlazyimage:"
target := targetNoTag + "latest"
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
imageService := client . ImageService ( )
contentStore := client . ContentStore ( )
img , err := imageService . Get ( ctx , target )
require . NoError ( t , err )
manifest , err := images . Manifest ( ctx , contentStore , img . Target , nil )
require . NoError ( t , err )
for _ , layer := range manifest . Layers {
_ , err = contentStore . Info ( ctx , layer . Digest )
require . NoError ( t , err )
}
// clear all local state out
err = imageService . Delete ( ctx , img . Name , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
// retag the image we just pushed with no actual changes, which
// should not result in the image getting un-lazied
def , err = llb . Image ( target ) . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
target2 := targetNoTag + "newtag"
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target2 ,
"push" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
img , err = imageService . Get ( ctx , target2 )
require . NoError ( t , err )
manifest , err = images . Manifest ( ctx , contentStore , img . Target , nil )
require . NoError ( t , err )
for _ , layer := range manifest . Layers {
_ , err = contentStore . Info ( ctx , layer . Digest )
require . True ( t , errors . Is ( err , ctderrdefs . ErrNotFound ) , "unexpected error %v" , err )
}
// clear all local state out again
err = imageService . Delete ( ctx , img . Name , images . SynchronousDelete ( ) )
require . NoError ( t , err )
checkAllReleasable ( t , c , sb , true )
// try a cross-repo push to same registry, which should still result in the
// image remaining lazy
target3 := registry + "/buildkit/testlazycrossrepo:latest"
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target3 ,
"push" : "true" ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
img , err = imageService . Get ( ctx , target3 )
require . NoError ( t , err )
manifest , err = images . Manifest ( ctx , contentStore , img . Target , nil )
require . NoError ( t , err )
for _ , layer := range manifest . Layers {
_ , err = contentStore . Info ( ctx , layer . Digest )
require . True ( t , errors . Is ( err , ctderrdefs . ErrNotFound ) , "unexpected error %v" , err )
}
// check that a subsequent build can use the previously lazy image in an exec
def , err = llb . Image ( target2 ) . Run ( llb . Args ( [ ] string { "true" } ) ) . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2019-08-29 22:21:17 +00:00
func testBasicCacheImportExport ( t * testing . T , sb integration . Sandbox , cacheOptionsEntryImport , cacheOptionsEntryExport [ ] CacheOptionsEntry ) {
2018-04-26 00:43:17 +00:00
requiresLinux ( t )
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" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-04-26 00:43:17 +00:00
require . NoError ( t , err )
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2019-08-29 22:21:17 +00:00
CacheExports : cacheOptionsEntryExport ,
2018-04-26 00:43:17 +00:00
} , 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 )
2018-07-26 22:31:35 +00:00
err = c . Prune ( context . TODO ( ) , nil , PruneAll )
2018-04-26 00:43:17 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} } ,
2019-08-29 22:21:17 +00:00
CacheImports : cacheOptionsEntryImport ,
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-09-11 08:02:46 +00:00
func testBasicRegistryCacheImportExport ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-09-11 08:02:46 +00:00
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2018-09-11 08:02:46 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
target := registry + "/buildkit/testexport:latest"
o := CacheOptionsEntry {
Type : "registry" ,
Attrs : map [ string ] string {
"ref" : target ,
} ,
}
2019-08-29 22:21:17 +00:00
testBasicCacheImportExport ( t , sb , [ ] CacheOptionsEntry { o } , [ ] CacheOptionsEntry { o } )
}
func testMultipleRegistryCacheImportExport ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-08-29 22:21:17 +00:00
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2019-08-29 22:21:17 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
target := registry + "/buildkit/testexport:latest"
o := CacheOptionsEntry {
Type : "registry" ,
Attrs : map [ string ] string {
"ref" : target ,
} ,
}
o2 := CacheOptionsEntry {
Type : "registry" ,
Attrs : map [ string ] string {
"ref" : target + "notexist" ,
} ,
}
testBasicCacheImportExport ( t , sb , [ ] CacheOptionsEntry { o , o2 } , [ ] CacheOptionsEntry { o } )
2018-09-11 08:02:46 +00:00
}
func testBasicLocalCacheImportExport ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-09-11 08:02:46 +00:00
dir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( dir )
2019-01-31 16:30:39 +00:00
im := CacheOptionsEntry {
2018-09-11 08:02:46 +00:00
Type : "local" ,
Attrs : map [ string ] string {
2019-01-31 16:30:39 +00:00
"src" : dir ,
2018-09-11 08:02:46 +00:00
} ,
}
2019-01-31 16:30:39 +00:00
ex := CacheOptionsEntry {
Type : "local" ,
Attrs : map [ string ] string {
"dest" : dir ,
} ,
}
2019-08-29 22:21:17 +00:00
testBasicCacheImportExport ( t , sb , [ ] CacheOptionsEntry { im } , [ ] CacheOptionsEntry { ex } )
2018-09-11 08:02:46 +00:00
}
2019-01-18 22:49:08 +00:00
func testBasicInlineCacheImportExport ( t * testing . T , sb integration . Sandbox ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2019-01-18 22:49:08 +00:00
requiresLinux ( t )
registry , err := sb . NewRegistry ( )
2020-04-19 05:17:47 +00:00
if errors . Is ( err , integration . ErrorRequirements ) {
2019-01-18 22:49:08 +00:00
t . Skip ( err . Error ( ) )
}
require . NoError ( t , err )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
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" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2019-01-18 22:49:08 +00:00
require . NoError ( t , err )
target := registry + "/buildkit/testexportinline:latest"
resp , err := c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
} ,
2019-01-18 22:49:08 +00:00
} ,
CacheExports : [ ] CacheOptionsEntry {
{
Type : "inline" ,
} ,
} ,
} , nil )
require . NoError ( t , err )
dgst , ok := resp . ExporterResponse [ "containerimage.digest" ]
require . Equal ( t , ok , true )
2019-06-10 21:16:16 +00:00
unique , err := readFileInImage ( c , target + "@" + dgst , "/unique" )
2019-02-22 15:51:26 +00:00
require . NoError ( t , err )
2019-01-18 22:49:08 +00:00
err = c . Prune ( context . TODO ( ) , nil , PruneAll )
require . NoError ( t , err )
checkAllRemoved ( t , c , sb )
resp , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-02-22 15:51:26 +00:00
// specifying inline cache exporter is needed for reproducing containerimage.digest
// (not needed for reproducing rootfs/unique)
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
2019-06-10 21:16:16 +00:00
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2019-01-18 22:49:08 +00:00
CacheExports : [ ] CacheOptionsEntry {
{
Type : "inline" ,
} ,
} ,
CacheImports : [ ] CacheOptionsEntry {
{
Type : "registry" ,
Attrs : map [ string ] string {
"ref" : target ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
dgst2 , ok := resp . ExporterResponse [ "containerimage.digest" ]
require . Equal ( t , ok , true )
require . Equal ( t , dgst , dgst2 )
2019-02-22 15:51:26 +00:00
err = c . Prune ( context . TODO ( ) , nil , PruneAll )
require . NoError ( t , err )
checkAllRemoved ( t , c , sb )
resp , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterImage ,
2019-06-10 21:16:16 +00:00
Attrs : map [ string ] string {
"name" : target ,
"push" : "true" ,
} ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2019-02-22 15:51:26 +00:00
CacheImports : [ ] CacheOptionsEntry {
{
Type : "registry" ,
Attrs : map [ string ] string {
"ref" : target ,
} ,
} ,
} ,
} , nil )
require . NoError ( t , err )
dgst3 , ok := resp . ExporterResponse [ "containerimage.digest" ]
require . Equal ( t , ok , true )
// dgst3 != dgst, because inline cache is not exported for dgst3
2019-06-10 21:16:16 +00:00
unique3 , err := readFileInImage ( c , target + "@" + dgst3 , "/unique" )
2019-02-22 15:51:26 +00:00
require . NoError ( t , err )
require . EqualValues ( t , unique , unique3 )
}
func readFileInImage ( c * Client , ref , path string ) ( [ ] byte , error ) {
2020-03-25 22:39:32 +00:00
def , err := llb . Image ( ref ) . Marshal ( context . TODO ( ) )
2019-02-22 15:51:26 +00:00
if err != nil {
return nil , err
}
destDir , err := ioutil . TempDir ( "" , "buildkit" )
if err != nil {
return nil , err
}
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2019-02-22 15:51:26 +00:00
} , nil )
if err != nil {
return nil , err
}
return ioutil . ReadFile ( filepath . Join ( destDir , filepath . Clean ( path ) ) )
2019-01-18 22:49:08 +00:00
}
2018-05-15 19:09:09 +00:00
func testCachedMounts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
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
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-05-15 19:09:09 +00:00
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 )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2018-05-15 19:09:09 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2018-05-15 19:09:09 +00:00
} , 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 )
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 ( ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2018-06-18 20:57:36 +00:00
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 )
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 ( ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2018-06-18 20:57:36 +00:00
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 )
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 ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2018-06-18 20:57:36 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
}
2021-04-14 15:34:04 +00:00
func testRunCacheWithMounts ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
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 /m1/sbin/apk ]]" ` ) )
out . AddMount ( "/m1" , llb . Image ( "alpine:latest" ) , llb . Readonly )
def , err := out . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
out = busybox . Run ( llb . Shlex ( ` sh -e -c "[[ -f /m1/sbin/apk ]]" ` ) )
out . AddMount ( "/m1" , llb . Image ( "busybox:latest" ) , llb . Readonly )
def , err = out . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
}
2019-07-25 21:13:13 +00:00
func testCacheMountNoCache ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
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 "touch /m1/foo; touch /m2/bar" ` ) )
out . AddMount ( "/m1" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
out . AddMount ( "/m2" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache2" , llb . CacheMountLocked ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2019-07-25 21:13:13 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
out = busybox . Run ( llb . Shlex ( ` sh -e -c "[[ ! -f /m1/foo ]]; touch /m1/foo2;" ` ) , llb . IgnoreCache )
out . AddMount ( "/m1" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2019-07-25 21:13:13 +00:00
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . NoError ( t , err )
out = busybox . Run ( llb . Shlex ( ` sh -e -c "[[ -f /m1/foo2 ]]; [[ -f /m2/bar ]];" ` ) )
out . AddMount ( "/m1" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache1" , llb . CacheMountLocked ) )
out . AddMount ( "/m2" , llb . Scratch ( ) , llb . AsPersistentCacheDir ( "mycache2" , llb . CacheMountLocked ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2019-07-25 21:13:13 +00:00
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 ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-02-13 19:18:18 +00:00
requiresLinux ( t )
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" ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-02-13 19:18:18 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterOCI ,
2019-07-30 00:50:54 +00:00
Output : fixedWriteCloser ( outW ) ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2018-02-13 19:18:18 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
2018-07-17 22:17:51 +00:00
m , err := testutil . ReadTarToMap ( dt , false )
2018-02-13 19:18:18 +00:00
require . NoError ( t , err )
var index ocispec . Index
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "index.json" ] . Data , & index )
2018-02-13 19:18:18 +00:00
require . NoError ( t , err )
var mfst ocispec . Manifest
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . Data , & mfst )
2018-02-13 19:18:18 +00:00
require . NoError ( t , err )
lastLayer := mfst . Layers [ len ( mfst . Layers ) - 1 ]
layer , ok := m [ "blobs/sha256/" + lastLayer . Digest . Hex ( ) ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
m , err = testutil . ReadTarToMap ( layer . Data , true )
2018-02-13 19:18:18 +00:00
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 ) {
2019-09-09 13:47:18 +00:00
skipDockerd ( t , sb )
2018-02-09 19:03:12 +00:00
requiresLinux ( t )
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 ` )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-02-09 19:03:12 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterOCI ,
2019-07-30 00:50:54 +00:00
Output : fixedWriteCloser ( outW ) ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2018-02-09 19:03:12 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( out )
require . NoError ( t , err )
2018-07-17 22:17:51 +00:00
m , err := testutil . ReadTarToMap ( dt , false )
2018-02-09 19:03:12 +00:00
require . NoError ( t , err )
var index ocispec . Index
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "index.json" ] . Data , & index )
2018-02-09 19:03:12 +00:00
require . NoError ( t , err )
var mfst ocispec . Manifest
2018-07-17 22:17:51 +00:00
err = json . Unmarshal ( m [ "blobs/sha256/" + index . Manifests [ 0 ] . Digest . Hex ( ) ] . Data , & mfst )
2018-02-09 19:03:12 +00:00
require . NoError ( t , err )
lastLayer := mfst . Layers [ len ( mfst . Layers ) - 1 ]
layer , ok := m [ "blobs/sha256/" + lastLayer . Digest . Hex ( ) ]
require . True ( t , ok )
2018-07-17 22:17:51 +00:00
m , err = testutil . ReadTarToMap ( layer . Data , true )
2018-02-09 19:03:12 +00:00
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 ) {
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" )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-03-02 16:33:08 +00:00
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 ) {
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 )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-03-21 17:04:43 +00:00
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 ) {
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 )
2020-03-25 22:39:32 +00:00
def , err := st . Marshal ( context . TODO ( ) )
2018-03-26 13:51:08 +00:00
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 )
}
2020-05-19 19:59:15 +00:00
func testSourceMap ( t * testing . T , sb integration . Sandbox ) {
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
2020-05-20 23:44:57 +00:00
sm1 := llb . NewSourceMap ( nil , "foo" , [ ] byte ( "data1" ) )
sm2 := llb . NewSourceMap ( nil , "bar" , [ ] byte ( "data2" ) )
2020-05-19 19:59:15 +00:00
2020-05-20 23:44:57 +00:00
st := llb . Scratch ( ) . Run (
llb . Shlex ( "not-exist" ) ,
sm1 . Location ( [ ] * pb . Range { { Start : pb . Position { Line : 7 } } } ) ,
sm2 . Location ( [ ] * pb . Range { { Start : pb . Position { Line : 8 } } } ) ,
2020-05-21 01:48:09 +00:00
sm1 . Location ( [ ] * pb . Range { { Start : pb . Position { Line : 9 } } } ) ,
2020-05-20 23:44:57 +00:00
)
2020-05-19 19:59:15 +00:00
def , err := st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt { } , nil )
require . Error ( t , err )
srcs := errdefs . Sources ( err )
2020-05-21 01:48:09 +00:00
require . Equal ( t , 3 , len ( srcs ) )
2020-05-19 19:59:15 +00:00
2020-05-20 23:44:57 +00:00
// Source errors are wrapped in the order provided as llb.ConstraintOpts, so
// when they are unwrapped, the first unwrapped error is the last location
// provided.
2020-05-21 01:48:09 +00:00
require . Equal ( t , "foo" , srcs [ 0 ] . Info . Filename )
require . Equal ( t , [ ] byte ( "data1" ) , srcs [ 0 ] . Info . Data )
2020-05-19 19:59:15 +00:00
require . Nil ( t , srcs [ 0 ] . Info . Definition )
2020-05-21 02:04:08 +00:00
require . Equal ( t , 1 , len ( srcs [ 0 ] . Ranges ) )
require . Equal ( t , int32 ( 9 ) , srcs [ 0 ] . Ranges [ 0 ] . Start . Line )
require . Equal ( t , int32 ( 0 ) , srcs [ 0 ] . Ranges [ 0 ] . Start . Character )
2020-05-20 23:44:57 +00:00
2020-05-21 01:48:09 +00:00
require . Equal ( t , "bar" , srcs [ 1 ] . Info . Filename )
require . Equal ( t , [ ] byte ( "data2" ) , srcs [ 1 ] . Info . Data )
2020-05-20 23:44:57 +00:00
require . Nil ( t , srcs [ 1 ] . Info . Definition )
require . Equal ( t , 1 , len ( srcs [ 1 ] . Ranges ) )
2020-05-21 01:48:09 +00:00
require . Equal ( t , int32 ( 8 ) , srcs [ 1 ] . Ranges [ 0 ] . Start . Line )
2020-05-20 23:44:57 +00:00
require . Equal ( t , int32 ( 0 ) , srcs [ 1 ] . Ranges [ 0 ] . Start . Character )
2020-05-21 01:48:09 +00:00
require . Equal ( t , "foo" , srcs [ 2 ] . Info . Filename )
require . Equal ( t , [ ] byte ( "data1" ) , srcs [ 2 ] . Info . Data )
require . Nil ( t , srcs [ 2 ] . Info . Definition )
require . Equal ( t , 1 , len ( srcs [ 2 ] . Ranges ) )
require . Equal ( t , int32 ( 7 ) , srcs [ 2 ] . Ranges [ 0 ] . Start . Line )
require . Equal ( t , int32 ( 0 ) , srcs [ 2 ] . Ranges [ 0 ] . Start . Character )
2020-05-19 19:59:15 +00:00
}
func testSourceMapFromRef ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
srcState := llb . Scratch ( ) . File (
llb . Mkfile ( "foo" , 0600 , [ ] byte ( "data" ) ) )
sm := llb . NewSourceMap ( & srcState , "bar" , [ ] byte ( "bardata" ) )
frontend := func ( ctx context . Context , c gateway . Client ) ( * gateway . Result , error ) {
st := llb . Scratch ( ) . File (
llb . Mkdir ( "foo/bar" , 0600 ) , //fails because /foo doesn't exist
sm . Location ( [ ] * pb . Range { { Start : pb . Position { Line : 3 , Character : 1 } } } ) ,
)
def , err := st . Marshal ( context . TODO ( ) )
if err != nil {
return nil , err
}
res , err := c . Solve ( ctx , gateway . SolveRequest {
Definition : def . ToPB ( ) ,
} )
if err != nil {
return nil , err
}
ref , err := res . SingleRef ( )
if err != nil {
return nil , err
}
st2 , err := ref . ToState ( )
if err != nil {
return nil , err
}
st = llb . Scratch ( ) . File (
llb . Copy ( st2 , "foo" , "foo2" ) ,
)
def , err = st . Marshal ( context . TODO ( ) )
if err != nil {
return nil , err
}
return c . Solve ( ctx , gateway . SolveRequest {
Definition : def . ToPB ( ) ,
} )
}
_ , err = c . Build ( context . TODO ( ) , SolveOpt { } , "" , frontend , nil )
require . Error ( t , err )
srcs := errdefs . Sources ( err )
require . Equal ( t , 1 , len ( srcs ) )
require . Equal ( t , "bar" , srcs [ 0 ] . Info . Filename )
require . Equal ( t , [ ] byte ( "bardata" ) , srcs [ 0 ] . Info . Data )
require . NotNil ( t , srcs [ 0 ] . Info . Definition )
2020-05-20 23:44:57 +00:00
require . Equal ( t , 1 , len ( srcs [ 0 ] . Ranges ) )
require . Equal ( t , int32 ( 3 ) , srcs [ 0 ] . Ranges [ 0 ] . Start . Line )
require . Equal ( t , int32 ( 1 ) , srcs [ 0 ] . Ranges [ 0 ] . Start . Character )
2020-05-19 19:59:15 +00:00
}
2018-05-20 21:48:35 +00:00
func testProxyEnv ( t * testing . T , sb integration . Sandbox ) {
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" )
2021-04-24 16:12:47 +00:00
cmd := ` sh -c "echo -n $HTTP_PROXY-$HTTPS_PROXY-$NO_PROXY-$no_proxy-$ALL_PROXY-$all_proxy > env" `
2018-05-20 21:48:35 +00:00
st := base . Run ( llb . Shlex ( cmd ) , llb . WithProxy ( llb . ProxyEnv {
2020-07-18 16:11:39 +00:00
HTTPProxy : "httpvalue" ,
HTTPSProxy : "httpsvalue" ,
2018-05-20 21:48:35 +00:00
NoProxy : "noproxyvalue" ,
2021-04-24 16:12:47 +00:00
AllProxy : "allproxyvalue" ,
2018-05-20 21:48:35 +00:00
} ) )
out := st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err := out . Marshal ( context . TODO ( ) )
2018-05-20 21:48:35 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2018-05-20 21:48:35 +00:00
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "env" ) )
require . NoError ( t , err )
2021-04-24 16:12:47 +00:00
require . Equal ( t , string ( dt ) , "httpvalue-httpsvalue-noproxyvalue-noproxyvalue-allproxyvalue-allproxyvalue" )
2018-05-20 21:48:35 +00:00
// repeat to make sure proxy doesn't change cache
st = base . Run ( llb . Shlex ( cmd ) , llb . WithProxy ( llb . ProxyEnv {
2020-07-18 16:11:39 +00:00
HTTPSProxy : "httpsvalue2" ,
2018-05-20 21:48:35 +00:00
NoProxy : "noproxyvalue2" ,
} ) )
out = st . AddMount ( "/out" , llb . Scratch ( ) )
2020-03-25 22:39:32 +00:00
def , err = out . Marshal ( context . TODO ( ) )
2018-05-20 21:48:35 +00:00
require . NoError ( t , err )
destDir , err = ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2018-05-20 21:48:35 +00:00
} , nil )
require . NoError ( t , err )
dt , err = ioutil . ReadFile ( filepath . Join ( destDir , "env" ) )
require . NoError ( t , err )
2021-04-24 16:12:47 +00:00
require . Equal ( t , string ( dt ) , "httpvalue-httpsvalue-noproxyvalue-noproxyvalue-allproxyvalue-allproxyvalue" )
2018-05-20 21:48:35 +00:00
}
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
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
}
2018-07-26 22:31:35 +00:00
err := c . Prune ( context . TODO ( ) , nil , PruneAll )
2017-12-28 23:03:49 +00:00
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)
2020-06-21 01:35:25 +00:00
cdAddress := sb . ContainerdAddress ( )
if cdAddress == "" {
2020-06-24 16:56:20 +00:00
t . Logf ( "checkAllReleasable: skipping check for exported tars in non-containerd test" )
2017-12-28 23:03:49 +00:00
return
}
// TODO: make public pull helper function so this can be checked for standalone as well
2018-08-23 07:59:41 +00:00
client , err := newContainerd ( cdAddress )
2017-12-28 23:03:49 +00:00
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 )
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 ( )
2020-03-25 22:39:32 +00:00
def , err := llb . Image ( "busybox:latest" ) . Marshal ( context . TODO ( ) )
2018-03-29 05:27:52 +00:00
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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : exp ,
Attrs : attrs ,
} ,
} ,
2018-03-29 05:27:52 +00:00
} , 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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : exp ,
Attrs : attrs ,
OutputDir : destDir ,
} ,
} ,
2018-03-29 05:27:52 +00:00
} , 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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
Attrs : attrs ,
} ,
} ,
2018-03-29 05:27:52 +00:00
} , 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 {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
Attrs : attrs ,
2019-07-30 00:50:54 +00:00
Output : fixedWriteCloser ( f ) ,
2019-01-31 16:30:39 +00:00
} ,
} ,
2018-03-29 05:27:52 +00:00
} , 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
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 )
2020-03-25 22:39:32 +00:00
def , err := llb . Local ( "source" ) . Marshal ( context . TODO ( ) )
2018-07-09 22:42:34 +00:00
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( ctx , def , SolveOpt {
2019-01-31 16:30:39 +00:00
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
2018-07-09 22:42:34 +00:00
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
2021-05-26 18:08:56 +00:00
// testRelativeMountpoint is a test that relative paths for mountpoints don't
// fail when runc is upgraded to at least rc95, which introduces an error when
// mountpoints are not absolute. Relative paths should be transformed to
// absolute points based on the llb.State's current working directory.
func testRelativeMountpoint ( t * testing . T , sb integration . Sandbox ) {
requiresLinux ( t )
c , err := New ( context . TODO ( ) , sb . Address ( ) )
require . NoError ( t , err )
defer c . Close ( )
id := identity . NewID ( )
st := llb . Image ( "busybox:latest" ) . Dir ( "/root" ) . Run (
llb . Shlexf ( "sh -c 'echo -n %s > /root/relpath/data'" , id ) ,
) . AddMount ( "relpath" , llb . Scratch ( ) )
def , err := st . Marshal ( context . TODO ( ) )
require . NoError ( t , err )
destDir , err := ioutil . TempDir ( "" , "buildkit" )
require . NoError ( t , err )
defer os . RemoveAll ( destDir )
_ , err = c . Solve ( context . TODO ( ) , def , SolveOpt {
Exports : [ ] ExportEntry {
{
Type : ExporterLocal ,
OutputDir : destDir ,
} ,
} ,
} , nil )
require . NoError ( t , err )
dt , err := ioutil . ReadFile ( filepath . Join ( destDir , "data" ) )
require . NoError ( t , err )
require . Equal ( t , dt , [ ] byte ( id ) )
}
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
}
2018-09-06 21:39:56 +00:00
func makeSSHAgentSock ( agent agent . Agent ) ( p string , cleanup func ( ) error , err error ) {
tmpDir , err := ioutil . TempDir ( "" , "buildkit" )
if err != nil {
return "" , nil , err
}
defer func ( ) {
if err != nil {
os . RemoveAll ( tmpDir )
}
} ( )
sockPath := filepath . Join ( tmpDir , "ssh_auth_sock" )
l , err := net . Listen ( "unix" , sockPath )
if err != nil {
return "" , nil , err
}
s := & server { l : l }
go s . run ( agent )
return sockPath , func ( ) error {
l . Close ( )
return os . RemoveAll ( tmpDir )
} , nil
}
type server struct {
l net . Listener
}
func ( s * server ) run ( a agent . Agent ) error {
for {
c , err := s . l . Accept ( )
if err != nil {
return err
}
go agent . ServeAgent ( a , c )
}
}
2019-02-02 00:20:18 +00:00
type secModeSandbox struct { }
func ( * secModeSandbox ) UpdateConfigFile ( in string ) string {
return in
}
type secModeInsecure struct { }
func ( * secModeInsecure ) UpdateConfigFile ( in string ) string {
return in + "\n\ninsecure-entitlements = [\"security.insecure\"]\n"
}
var securitySandbox integration . ConfigUpdater = & secModeSandbox { }
var securityInsecure integration . ConfigUpdater = & secModeInsecure { }
2019-07-10 23:55:04 +00:00
type netModeHost struct { }
func ( * netModeHost ) UpdateConfigFile ( in string ) string {
return in + "\n\ninsecure-entitlements = [\"network.host\"]\n"
}
type netModeDefault struct { }
func ( * netModeDefault ) UpdateConfigFile ( in string ) string {
return in
}
var hostNetwork integration . ConfigUpdater = & netModeHost { }
var defaultNetwork integration . ConfigUpdater = & netModeDefault { }
2019-07-30 00:50:54 +00:00
func fixedWriteCloser ( wc io . WriteCloser ) func ( map [ string ] string ) ( io . WriteCloser , error ) {
return func ( map [ string ] string ) ( io . WriteCloser , error ) {
return wc , nil
}
}