Merge pull request #1402 from ktock/remote-snapshotter

Support stargz snapshotter for dev stages
v0.8
Erik Sipsma 2020-08-31 10:41:11 -07:00 committed by GitHub
commit a57f8a2dcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 381 additions and 31 deletions

View File

@ -11,6 +11,7 @@ ARG ROOTLESSKIT_VERSION=v0.9.5
ARG CNI_VERSION=v0.8.6
ARG SHADOW_VERSION=4.8.1
ARG FUSEOVERLAYFS_VERSION=v1.1.2
ARG STARGZ_SNAPSHOTTER_VERSION=5aca593bd474015005b8832cf9763685d9d4db61
# git stage is used for checking out remote repository sources
FROM --platform=$BUILDPLATFORM alpine AS git
@ -173,6 +174,15 @@ RUN --mount=target=/root/.cache,type=cache \
CGO_ENABLED=0 go build -o /rootlesskit ./cmd/rootlesskit && \
file /rootlesskit | grep "statically linked"
FROM gobuild-base AS stargz-snapshotter
RUN git clone https://github.com/containerd/stargz-snapshotter.git /go/src/github.com/containerd/stargz-snapshotter
WORKDIR /go/src/github.com/containerd/stargz-snapshotter
ARG STARGZ_SNAPSHOTTER_VERSION
RUN git checkout -q "$STARGZ_SNAPSHOTTER_VERSION" && \
mkdir /out && CGO_ENABLED=0 PREFIX=/out/ make && \
file /out/containerd-stargz-grpc | grep "statically linked" && \
file /out/ctr-remote | grep "statically linked"
FROM --platform=$BUILDPLATFORM alpine AS fuse-overlayfs
RUN apk add --no-cache curl
ARG FUSEOVERLAYFS_VERSION
@ -225,7 +235,7 @@ RUN curl -Ls https://github.com/containernetworking/plugins/releases/download/$C
FROM buildkit-base AS integration-tests-base
ENV BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR="1000:1000"
RUN apt-get --no-install-recommends install -y uidmap sudo vim iptables \
RUN apt-get --no-install-recommends install -y uidmap sudo vim iptables fuse \
&& useradd --create-home --home-dir /home/user --uid 1000 -s /bin/sh user \
&& echo "XDG_RUNTIME_DIR=/run/user/1000; export XDG_RUNTIME_DIR" >> /home/user/.profile \
&& mkdir -m 0700 -p /run/user/1000 \
@ -233,6 +243,8 @@ RUN apt-get --no-install-recommends install -y uidmap sudo vim iptables \
&& update-alternatives --set iptables /usr/sbin/iptables-legacy
# musl is needed to directly use the registry binary that is built on alpine
ENV BUILDKIT_INTEGRATION_CONTAINERD_EXTRA="containerd-1.3=/opt/containerd-alt/bin"
ENV BUILDKIT_INTEGRATION_CONTAINERD_STARGZ=1
COPY --from=stargz-snapshotter /out/* /usr/bin/
COPY --from=rootlesskit /rootlesskit /usr/bin/
COPY --from=containerd-alt /out/containerd* /opt/containerd-alt/bin/
COPY --from=registry /bin/registry /usr/bin

22
cache/manager.go vendored
View File

@ -385,12 +385,17 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, opts ...RefOpt
}
return nil, err
}
// parent refs are possibly lazy so keep it hold the description handlers.
var dhs DescHandlers
if mutable.parent != nil {
dhs = mutable.parent.descHandlers
}
rec := &cacheRecord{
mu: &sync.Mutex{},
cm: cm,
refs: make(map[ref]struct{}),
// mutable refs are always non-lazy, so we can set parent desc handlers to nil
parent: mutable.parentRef(false, nil),
mu: &sync.Mutex{},
cm: cm,
refs: make(map[ref]struct{}),
parent: mutable.parentRef(false, dhs),
md: md,
equalMutable: &mutableRef{cacheRecord: mutable},
}
@ -535,7 +540,12 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
cm.records[id] = rec // TODO: save to db
return rec.mref(true, nil), nil
// parent refs are possibly lazy so keep it hold the description handlers.
var dhs DescHandlers
if parent != nil {
dhs = parent.descHandlers
}
return rec.mref(true, dhs), nil
}
func (cm *cacheManager) GetMutable(ctx context.Context, id string, opts ...RefOption) (MutableRef, error) {

5
cache/opts.go vendored
View File

@ -9,8 +9,9 @@ import (
)
type DescHandler struct {
Provider content.Provider
Progress progress.Controller
Provider content.Provider
Progress progress.Controller
SnapshotLabels map[string]string
}
type DescHandlers map[digest.Digest]*DescHandler

58
cache/refs.go vendored
View File

@ -391,15 +391,69 @@ func (sr *immutableRef) Extract(ctx context.Context) (rerr error) {
ctx = winlayers.UseWindowsLayerMode(ctx)
}
if _, err := sr.prepareRemoteSnapshots(ctx, sr.descHandlers); err != nil {
return err
}
return sr.extract(ctx, sr.descHandlers)
}
func (sr *immutableRef) prepareRemoteSnapshots(ctx context.Context, dhs DescHandlers) (bool, error) {
ok, err := sr.sizeG.Do(ctx, sr.ID()+"-prepare-remote-snapshot", func(ctx context.Context) (_ interface{}, rerr error) {
snapshotID := getSnapshotID(sr.md)
if _, err := sr.cm.Snapshotter.Stat(ctx, snapshotID); err == nil {
return true, nil
}
desc, err := sr.ociDesc()
if err != nil {
return false, err
}
dh := dhs[desc.Digest]
if dh == nil {
return false, nil
}
parentID := ""
if sr.parent != nil {
if ok, err := sr.parent.prepareRemoteSnapshots(ctx, dhs); !ok {
return false, err
}
parentID = getSnapshotID(sr.parent.md)
}
// Hint labels to the snapshotter
labels := dh.SnapshotLabels
if labels == nil {
labels = make(map[string]string)
}
labels["containerd.io/snapshot.ref"] = snapshotID
opt := snapshots.WithLabels(labels)
// Try to preapre the remote snapshot
key := fmt.Sprintf("tmp-%s %s", identity.NewID(), sr.Info().ChainID)
if err = sr.cm.Snapshotter.Prepare(ctx, key, parentID, opt); err != nil {
if errdefs.IsAlreadyExists(err) {
// Check if the targeting snapshot ID has been prepared as a remote
// snapshot in the snapshotter.
if _, err := sr.cm.Snapshotter.Stat(ctx, snapshotID); err == nil {
// We can use this remote snapshot without unlazying.
// Try the next layer as well.
return true, nil
}
}
}
// This layer cannot be prepared without unlazying.
return false, nil
})
return ok.(bool), err
}
func (sr *immutableRef) extract(ctx context.Context, dhs DescHandlers) error {
_, err := sr.sizeG.Do(ctx, sr.ID()+"-extract", func(ctx context.Context) (_ interface{}, rerr error) {
snapshotID := getSnapshotID(sr.md)
if _, err := sr.cm.Snapshotter.Stat(ctx, snapshotID); err == nil {
queueBlobOnly(sr.md, false)
return nil, sr.md.Commit()
return nil, nil
}
eg, egctx := errgroup.WithContext(ctx)

9
cache/remote.go vendored
View File

@ -35,7 +35,7 @@ func (sr *immutableRef) GetRemote(ctx context.Context, createIfNeeded bool, comp
return nil, err
}
mprovider := lazyMultiProvider{mprovider: contentutil.NewMultiProvider(nil)}
mprovider := &lazyMultiProvider{mprovider: contentutil.NewMultiProvider(nil)}
remote := &solver.Remote{
Provider: mprovider,
}
@ -115,18 +115,19 @@ type lazyMultiProvider struct {
plist []lazyRefProvider
}
func (mp lazyMultiProvider) Add(p lazyRefProvider) {
func (mp *lazyMultiProvider) Add(p lazyRefProvider) {
mp.mprovider.Add(p.desc.Digest, p)
mp.plist = append(mp.plist, p)
}
func (mp lazyMultiProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
func (mp *lazyMultiProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
return mp.mprovider.ReaderAt(ctx, desc)
}
func (mp lazyMultiProvider) Unlazy(ctx context.Context) error {
func (mp *lazyMultiProvider) Unlazy(ctx context.Context) error {
eg, egctx := errgroup.WithContext(ctx)
for _, p := range mp.plist {
p := p
eg.Go(func() error {
return p.Unlazy(egctx)
})

View File

@ -15,6 +15,7 @@ import (
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@ -119,6 +120,7 @@ func TestIntegration(t *testing.T) {
testSourceMap,
testSourceMapFromRef,
testLazyImagePush,
testStargzLazyPull,
}, mirrors)
integration.Run(t, []integration.Test{
@ -2049,6 +2051,112 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
require.False(t, ok)
}
func testStargzLazyPull(t *testing.T, sb integration.Sandbox) {
skipDockerd(t, sb)
requiresLinux(t)
cdAddress := sb.ContainerdAddress()
if cdAddress == "" || !sb.Stargz() {
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)
// Prepare stargz image
sgzImage := registry + "/stargz/alpine:latest"
err = exec.Command("ctr-remote", "image", "optimize",
"--period=1", "alpine:latest", sgzImage).Run()
require.NoError(t, err)
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
// 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)
var (
imageService = client.ImageService()
contentStore = client.ContentStore()
ctx = namespaces.WithNamespace(context.Background(), "buildkit")
)
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)
}
func testLazyImagePush(t *testing.T, sb integration.Sandbox) {
skipDockerd(t, sb)
requiresLinux(t)

View File

@ -102,7 +102,11 @@ func testBuildContainerdExporter(t *testing.T, sb integration.Sandbox) {
require.NoError(t, err)
// NOTE: by default, it is overlayfs
ok, err := img.IsUnpacked(ctx, "overlayfs")
snapshotter := "overlayfs"
if sb.Stargz() {
snapshotter = "stargz"
}
ok, err := img.IsUnpacked(ctx, snapshotter)
require.NoError(t, err)
require.Equal(t, ok, true)
}

View File

@ -78,7 +78,8 @@ type OCIConfig struct {
// incomplete and the intention is to make it default without config.
UserRemapUnsupported string `toml:"userRemapUnsupported"`
// For use in storing the OCI worker binary name that will replace buildkit-runc
Binary string `toml:"binary"`
Binary string `toml:"binary"`
ProxySnapshotterPath string `toml:"proxySnapshotterPath"`
}
type ContainerdConfig struct {
@ -89,6 +90,7 @@ type ContainerdConfig struct {
Namespace string `toml:"namespace"`
GCConfig
NetworkConfig
Snapshotter string `toml:"snapshotter"`
}
type GCPolicy struct {

View File

@ -86,6 +86,11 @@ func init() {
Usage: "path of cni binary files",
Value: defaultConf.Workers.Containerd.NetworkConfig.CNIBinaryPath,
},
cli.StringFlag{
Name: "containerd-worker-snapshotter",
Usage: "snapshotter name to use",
Value: ctd.DefaultSnapshotter,
},
}
if defaultConf.Workers.Containerd.GC == nil || *defaultConf.Workers.Containerd.GC {
@ -184,6 +189,9 @@ func applyContainerdFlags(c *cli.Context, cfg *config.Config) error {
if c.GlobalIsSet("containerd-cni-binary-dir") {
cfg.Workers.Containerd.NetworkConfig.CNIBinaryPath = c.GlobalString("containerd-cni-binary-dir")
}
if c.GlobalIsSet("containerd-worker-snapshotter") {
cfg.Workers.Containerd.Snapshotter = c.GlobalString("containerd-worker-snapshotter")
}
return nil
}
@ -210,7 +218,11 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
},
}
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, ctd.DefaultSnapshotter, cfg.Namespace, cfg.Labels, dns, nc, ctd.WithTimeout(60*time.Second))
snapshotter := ctd.DefaultSnapshotter
if cfg.Snapshotter != "" {
snapshotter = cfg.Snapshotter
}
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Labels, dns, nc, ctd.WithTimeout(60*time.Second))
if err != nil {
return nil, err
}

View File

@ -6,11 +6,16 @@ import (
"os"
"os/exec"
"strconv"
"time"
fuseoverlayfs "github.com/AkihiroSuda/containerd-fuse-overlayfs"
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
"github.com/containerd/containerd/defaults"
"github.com/containerd/containerd/pkg/dialer"
ctdsnapshot "github.com/containerd/containerd/snapshots"
"github.com/containerd/containerd/snapshots/native"
"github.com/containerd/containerd/snapshots/overlay"
snproxy "github.com/containerd/containerd/snapshots/proxy"
"github.com/containerd/containerd/sys"
"github.com/moby/buildkit/cmd/buildkitd/config"
"github.com/moby/buildkit/executor/oci"
@ -22,6 +27,8 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
)
func init() {
@ -50,9 +57,13 @@ func init() {
},
cli.StringFlag{
Name: "oci-worker-snapshotter",
Usage: "name of snapshotter (overlayfs or native)",
Usage: "name of snapshotter (overlayfs, native, etc.)",
Value: defaultConf.Workers.OCI.Snapshotter,
},
cli.StringFlag{
Name: "oci-worker-proxy-snapshotter-path",
Usage: "address of proxy snapshotter socket (do not include 'unix://' prefix)",
},
cli.StringSliceFlag{
Name: "oci-worker-platform",
Usage: "override supported platforms for worker",
@ -193,6 +204,9 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
if c.GlobalIsSet("oci-worker-binary") {
cfg.Workers.OCI.Binary = c.GlobalString("oci-worker-binary")
}
if c.GlobalIsSet("oci-worker-proxy-snapshotter-path") {
cfg.Workers.OCI.ProxySnapshotterPath = c.GlobalString("oci-worker-proxy-snapshotter-path")
}
return nil
}
@ -213,7 +227,7 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
return nil, err
}
snFactory, err := snapshotterFactory(common.config.Root, cfg.Snapshotter)
snFactory, err := snapshotterFactory(common.config.Root, cfg.Snapshotter, cfg.ProxySnapshotterPath)
if err != nil {
return nil, err
}
@ -266,7 +280,36 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
return []worker.Worker{w}, nil
}
func snapshotterFactory(commonRoot, name string) (runc.SnapshotterFactory, error) {
func snapshotterFactory(commonRoot, name, address string) (runc.SnapshotterFactory, error) {
if address != "" {
snFactory := runc.SnapshotterFactory{
Name: name,
}
if _, err := os.Stat(address); os.IsNotExist(err) {
return snFactory, errors.Wrapf(err, "snapshotter doesn't exist on %q (Do not include 'unix://' prefix)", address)
}
snFactory.New = func(root string) (ctdsnapshot.Snapshotter, error) {
backoffConfig := backoff.DefaultConfig
backoffConfig.MaxDelay = 3 * time.Second
connParams := grpc.ConnectParams{
Backoff: backoffConfig,
}
gopts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithConnectParams(connParams),
grpc.WithContextDialer(dialer.ContextDialer),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
}
conn, err := grpc.Dial(dialer.DialAddress(address), gopts...)
if err != nil {
return nil, errors.Wrapf(err, "failed to dial %q", address)
}
return snproxy.NewSnapshotter(snapshotsapi.NewSnapshotsClient(conn), name), nil
}
return snFactory, nil
}
if name == "auto" {
if err := overlay.Supported(commonRoot); err == nil {
name = "overlayfs"

View File

@ -3,7 +3,9 @@ package containerimage
import (
"context"
"encoding/json"
"fmt"
"runtime"
"strings"
"sync"
"time"
@ -13,6 +15,7 @@ import (
"github.com/containerd/containerd/leases"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/snapshots"
"github.com/docker/docker/errdefs"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/client/llb"
@ -203,14 +206,29 @@ func (p *puller) CacheKey(ctx context.Context, g session.Group, index int) (cach
progressController.Name = p.vtx.Name()
}
descHandler := &cache.DescHandler{
Provider: p.manifest.Remote.Provider,
Progress: progressController,
var layers string
for _, desc := range p.manifest.Remote.Descriptors {
layers += fmt.Sprintf("%s,", desc.Digest.String())
}
layers = strings.TrimSuffix(layers, ",")
p.descHandlers = cache.DescHandlers(make(map[digest.Digest]*cache.DescHandler))
for _, desc := range p.manifest.Remote.Descriptors {
p.descHandlers[desc.Digest] = descHandler
// Hints for remote/stargz snapshotter for searching for remote snapshots
labels := snapshots.FilterInheritedLabels(desc.Annotations)
if labels == nil {
labels = make(map[string]string)
}
labels["containerd.io/snapshot/remote/stargz.reference"] = p.manifest.Ref
labels["containerd.io/snapshot/remote/stargz.digest"] = desc.Digest.String()
labels["containerd.io/snapshot/remote/stargz.layers"] = layers
p.descHandlers[desc.Digest] = &cache.DescHandler{
Provider: p.manifest.Remote.Provider,
Progress: progressController,
SnapshotLabels: labels,
}
}
}

View File

@ -37,12 +37,22 @@ func InitContainerdWorker() {
})
}
}
if s := os.Getenv("BUILDKIT_INTEGRATION_CONTAINERD_STARGZ"); s == "1" {
Register(&containerd{
name: "containerd-stargz",
containerd: "containerd",
containerdShim: "containerd-shim-runc-v2",
stargzSnapshotter: "containerd-stargz-grpc",
})
}
}
type containerd struct {
name string
containerd string
containerdShim string
name string
containerd string
containerdShim string
stargzSnapshotter string
}
func (c *containerd) Name() string {
@ -98,6 +108,26 @@ disabled_plugins = ["cri"]
[plugins.linux]
shim = %q
`, filepath.Join(tmpdir, "root"), filepath.Join(tmpdir, "state"), address, filepath.Join(tmpdir, "debug.sock"), c.containerdShim)
var snBuildkitdArgs []string
if c.stargzSnapshotter != "" {
snPath, snCl, err := runStargzSnapshotter(cfg, c.stargzSnapshotter)
if err != nil {
return nil, nil, err
}
deferF.append(snCl)
config = fmt.Sprintf(`%s
[proxy_plugins]
[proxy_plugins.stargz]
type = "snapshot"
address = %q
`, config, snPath)
snBuildkitdArgs = append(snBuildkitdArgs, "--containerd-worker-snapshotter=stargz")
}
configFile := filepath.Join(tmpdir, "config.toml")
if err := ioutil.WriteFile(configFile, []byte(config), 0644); err != nil {
return nil, nil, err
@ -109,19 +139,19 @@ disabled_plugins = ["cri"]
if err != nil {
return nil, nil, err
}
if err := waitUnix(address, 5*time.Second); err != nil {
if err := waitUnix(address, 10*time.Second); err != nil {
ctdStop()
return nil, nil, errors.Wrapf(err, "containerd did not start up: %s", formatLogs(cfg.Logs))
}
deferF.append(ctdStop)
buildkitdArgs := []string{"buildkitd",
buildkitdArgs := append([]string{"buildkitd",
"--oci-worker=false",
"--containerd-worker-gc=false",
"--containerd-worker=true",
"--containerd-worker-addr", address,
"--containerd-worker-labels=org.mobyproject.buildkit.worker.sandbox=true", // Include use of --containerd-worker-labels to trigger https://github.com/moby/buildkit/pull/603
}
}, snBuildkitdArgs...)
buildkitdSock, stop, err := runBuildkitd(cfg, buildkitdArgs, cfg.Logs, 0, 0)
if err != nil {
@ -134,6 +164,7 @@ disabled_plugins = ["cri"]
address: buildkitdSock,
containerdAddress: address,
rootless: false,
stargz: c.stargzSnapshotter != "",
}, cl, nil
}

View File

@ -21,6 +21,7 @@ import (
"github.com/gofrs/flock"
"github.com/moby/buildkit/util/contentutil"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sync/semaphore"
@ -37,6 +38,7 @@ type Backend interface {
Address() string
ContainerdAddress() string
Rootless() bool
Stargz() bool
}
type Sandbox interface {
@ -371,3 +373,50 @@ func prepareValueMatrix(tc testConf) []matrixValue {
}
return m
}
func runStargzSnapshotter(cfg *BackendConfig, binary string) (address string, cl func() error, err error) {
if err := lookupBinary(binary); err != nil {
return "", nil, err
}
deferF := &multiCloser{}
cl = deferF.F()
defer func() {
if err != nil {
deferF.F()()
cl = nil
}
}()
tmpStargzDir, err := ioutil.TempDir("", "bktest_containerd_stargz_grpc")
if err != nil {
return "", nil, err
}
deferF.append(func() error { return os.RemoveAll(tmpStargzDir) })
config := `insecure = ["127.0.0.1", "localhost"]`
configFile := filepath.Join(tmpStargzDir, "config.toml")
if err = ioutil.WriteFile(configFile, []byte(config), 0644); err != nil {
return "", nil, err
}
address = filepath.Join(tmpStargzDir, "containerd-stargz-grpc.sock")
stargzRootDir := filepath.Join(tmpStargzDir, "root")
cmd := exec.Command(binary,
"--log-level", "debug",
"--address", address,
"--root", stargzRootDir,
"--config", configFile)
snStop, err := startCmd(cmd, cfg.Logs)
if err != nil {
return "", nil, err
}
if err = waitUnix(address, 10*time.Second); err != nil {
snStop()
return "", nil, errors.Wrapf(err, "containerd-stargz-grpc did not start up: %s", formatLogs(cfg.Logs))
}
deferF.append(snStop)
return
}

View File

@ -24,6 +24,7 @@ type backend struct {
address string
containerdAddress string
rootless bool
stargz bool
}
func (b backend) Address() string {
@ -38,6 +39,10 @@ func (b backend) Rootless() bool {
return b.rootless
}
func (b backend) Stargz() bool {
return b.stargz
}
type sandbox struct {
Backend