From 9d6eb024d26386b1447d39dcfc50872e90832a66 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 1 Oct 2019 18:43:15 +0200 Subject: [PATCH] Bundle is not a command anymore Code moved to packager Signed-off-by: Nicolas De Loof --- Gopkg.lock | 13 +- Gopkg.toml | 4 +- e2e/build_test.go | 9 +- internal/commands/build.go | 186 ++++++++++-------- internal/commands/cnab.go | 2 +- internal/commands/push.go | 3 +- internal/{commands => packager}/bundle.go | 27 ++- .../{commands => packager}/bundle_test.go | 6 +- .../github.com/docker/buildx/build/build.go | 2 +- .../github.com/docker/buildx/build/output.go | 11 +- .../moby/buildkit/client/llb/exec.go | 14 +- .../moby/buildkit/client/llb/meta.go | 22 ++- .../moby/buildkit/client/llb/state.go | 8 +- .../github.com/moby/buildkit/client/solve.go | 4 +- .../frontend/gateway/grpcclient/client.go | 2 +- .../moby/buildkit/session/auth/auth.go | 5 +- .../moby/buildkit/session/content/caller.go | 25 ++- .../buildkit/session/filesync/diffcopy.go | 30 +-- .../buildkit/session/filesync/filesync.go | 53 +++-- .../moby/buildkit/session/secrets/secrets.go | 4 +- .../moby/buildkit/session/sshforward/copy.go | 16 +- .../moby/buildkit/session/sshforward/ssh.go | 15 +- .../sshforward/sshprovider/agentprovider.go | 2 +- .../moby/buildkit/session/upload/upload.go | 7 +- .../moby/buildkit/solver/pb/caps.go | 33 ++-- 25 files changed, 300 insertions(+), 203 deletions(-) rename internal/{commands => packager}/bundle.go (73%) rename internal/{commands => packager}/bundle_test.go (90%) diff --git a/Gopkg.lock b/Gopkg.lock index b84baa95..eceb1f3e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -236,7 +236,7 @@ version = "v0.3.2-beta1" [[projects]] - digest = "1:fc67ad7796e9571f4b9986e7ef73160304e69c3157929518a9ddfe9735322459" + digest = "1:6093483b2ea90f1c0c5ec0fd75778650031bc3da75526b1bd87309d22e1e7d6b" name = "github.com/docker/buildx" packages = [ "bake", @@ -248,7 +248,8 @@ "util/progress", ] pruneopts = "NUT" - revision = "96fb17b71125d4a11c904bd8a4298bac3b9e11e9" + revision = "6db68d029599c6710a32aa7adcba8e5a344795a7" + version = "v0.3.1" [[projects]] digest = "1:bc88d135d4f5d9a0968a213b3b2d786d1e216b9f10c30720f4d0d4976346732b" @@ -712,7 +713,7 @@ version = "v1.1.2" [[projects]] - digest = "1:4c3f5dc296bad571948333726a115427bab9caeeb732828d8f8f684a005557aa" + digest = "1:31d7e51628b4f5ed783d6923bac666dad0cad3ab6767477efc9c01c642a61f61" name = "github.com/moby/buildkit" packages = [ "api/services/control", @@ -748,7 +749,8 @@ "util/system", ] pruneopts = "NUT" - revision = "f238f1efb04f00bf0cc147141fda9ddb55c8bc49" + revision = "ae10b292fefb00e0fbf9fecd1419c5f252e58895" + version = "v0.6.2" [[projects]] digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" @@ -1459,10 +1461,11 @@ "github.com/docker/cli/cli/context/kubernetes", "github.com/docker/cli/cli/context/store", "github.com/docker/cli/cli/flags", + "github.com/docker/cli/cli/streams", "github.com/docker/cli/opts", "github.com/docker/cnab-to-oci/converter", "github.com/docker/cnab-to-oci/remotes", - "github.com/docker/distribution/manifest/manifestlist", + "github.com/docker/distribution/manifest/schema2", "github.com/docker/distribution/reference", "github.com/docker/docker/api/types", "github.com/docker/docker/api/types/container", diff --git a/Gopkg.toml b/Gopkg.toml index e33f462e..d2771356 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -23,11 +23,11 @@ required = ["github.com/wadey/gocovmerge"] [[constraint]] name = "github.com/docker/buildx" - revision = "96fb17b71125d4a11c904bd8a4298bac3b9e11e9" + version = "=v0.3.1" [[override]] name = "github.com/moby/buildkit" - revision = "f238f1efb04f00bf0cc147141fda9ddb55c8bc49" + version = "=v0.6.2" [[override]] name = "github.com/jaguilar/vt100" diff --git a/e2e/build_test.go b/e2e/build_test.go index ed1762b3..4276fa00 100644 --- a/e2e/build_test.go +++ b/e2e/build_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/deislabs/cnab-go/bundle" "gotest.tools/assert" + "gotest.tools/fs" "io/ioutil" - "os" "path" "testing" @@ -17,10 +17,9 @@ func TestBuild(t *testing.T) { defer cleanup() testDir := path.Join("testdata", "build") - tmp, err := ioutil.TempDir("","") - assert.NilError(t, err) - defer os.Remove(tmp) - f := path.Join(tmp, "bundle.json") + dir := fs.NewDir(t, "test-name") + defer dir.Remove() + f := dir.Join("bundle.json") cmd.Command = dockerCli.Command("app", "build", path.Join(testDir, "single"), "--output", f) icmd.RunCmd(cmd).Assert(t, icmd.Success) diff --git a/internal/commands/build.go b/internal/commands/build.go index df8f16a9..63b8402e 100644 --- a/internal/commands/build.go +++ b/internal/commands/build.go @@ -5,8 +5,11 @@ import ( "context" "encoding/json" "fmt" + "github.com/deislabs/cnab-go/bundle" "github.com/docker/app/internal/packager" + "github.com/docker/app/types" "github.com/docker/distribution/reference" + "github.com/moby/buildkit/client" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/auth/authprovider" "github.com/opencontainers/go-digest" @@ -26,7 +29,6 @@ import ( _ "github.com/docker/buildx/driver/docker" // required to get default driver registered, see driver/docker/factory.go:14 "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" - dockerclient "github.com/docker/docker/client" "github.com/moby/buildkit/util/appcontext" "github.com/spf13/cobra" ) @@ -45,7 +47,7 @@ func buildCmd(dockerCli command.Cli) *cobra.Command { Use: "build [APPLICATION]", Short: "Build service images for the application", Example: `$ docker app build myapp.dockerapp`, - Args: cli.RequiresRangeArgs(1, 1), + Args: cli.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { tag, err := runBuild(dockerCli, args[0], opts) if err == nil { @@ -73,33 +75,20 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe defer app.Cleanup() appname := app.Name - bundle, err := makeBundleFromApp(dockerCli, app, nil) + bundle, err := packager.MakeBundleFromApp(dockerCli, app, nil) if err != nil { return nil, err } - ctx := appcontext.Context() - - compose, err := bake.ParseCompose(app.Composes()[0]) // Fixme can have > 1 composes ? + targets, err := parseCompose(app) if err != nil { return nil, err } - targets := map[string]bake.Target{} - for _, n := range compose.ResolveGroup("default") { - t, err := compose.ResolveTarget(n) - if err != nil { - return nil, err - } - if t != nil { - targets[n] = *t - } - } - for service, t := range targets { if strings.HasPrefix(*t.Context, ".") { // Relative path in compose file under x.dockerapp refers to parent folder - // FIXME docker app init should maybe udate them ? + // FIXME docker app init should maybe update them ? path, err := filepath.Abs(appname + "/../" + (*t.Context)[1:]) if err != nil { return nil, err @@ -108,33 +97,19 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe targets[service] = t } } - - if logrus.IsLevelEnabled(logrus.DebugLevel) { - dt, err := json.MarshalIndent(targets, "", " ") - if err != nil { - return nil, err - } - logrus.Debug(string(dt)) - } + debugTargets(targets) buildopts, err := bake.TargetsToBuildOpt(targets, opt.noCache, opt.pull) if err != nil { return nil, err } - buildContext := bytes.NewBuffer(nil) - if err := packager.PackInvocationImageContext(dockerCli, app, buildContext); err != nil { + buildopts["invocation-image"], err = createInvocationImageBuildOptions(dockerCli, app) + if err != nil { return nil, err } - buildopts["invocation-image"] = build.Options{ - Inputs: build.Inputs{ - InStream: buildContext, - ContextPath: "-", - }, - Session: []session.Attachable{authprovider.NewDockerAuthProvider(os.Stderr)}, - } - + ctx := appcontext.Context() d, err := driver.GetDriver(ctx, "buildx_buildkit_default", nil, dockerCli.Client(), nil, "", nil) if err != nil { return nil, err @@ -146,23 +121,19 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe }, } - ctx2, cancel := context.WithCancel(context.TODO()) + ctx2, cancel := context.WithCancel(ctx) defer cancel() pw := progress.NewPrinter(ctx2, os.Stderr, opt.progress) - resp, err := build.Build(ctx2, driverInfo, buildopts, dockerAPI(dockerCli), dockerCli.ConfigFile(), pw) + + // We rely on buildx "docker" builder integrated in docker engine, so don't nee a DockerAPI here + resp, err := build.Build(ctx2, driverInfo, buildopts, nil, dockerCli.ConfigFile(), pw) if err != nil { return nil, err } fmt.Println("Successfully built service images") - if logrus.IsLevelEnabled(logrus.DebugLevel) { - dt, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, err - } - logrus.Debug(string(dt)) - } + debugSolveResponses(resp) for service, r := range resp { digest := r.ExporterResponse["containerimage.digest"] @@ -175,33 +146,21 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe image.Digest = digest bundle.Images[service] = image } - fmt.Printf(" - %s : %s\n", service, digest) - } - - if logrus.IsLevelEnabled(logrus.DebugLevel) { - dt, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, err - } - logrus.Debug(string(dt)) + fmt.Fprintf(dockerCli.Out(), " - %s : %s\n", service, digest) } + debugBundle(bundle) var ref reference.Named - ref, err = getNamedTagged(opt.tag) + ref, err = packager.GetNamedTagged(opt.tag) if err != nil { return nil, err } if ref == nil { - b := bytes.Buffer{} - _, err := bundle.WriteTo(&b) - if err != nil { + if ref, err = computeDigest(bundle); err != nil { return nil, err } - digest := digest.SHA256.FromBytes(b.Bytes()) - ref = sha{digest} } - if opt.out != "" { b, err := json.MarshalIndent(bundle, "", " ") if err != nil { @@ -215,45 +174,110 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe return ref, err } - if err := persistInBundleStore(ref, bundle); err != nil { + if err := packager.PersistInBundleStore(ref, bundle); err != nil { return ref, err } return ref, nil } +func computeDigest(bundle *bundle.Bundle) (reference.Named, error) { + b := bytes.Buffer{} + _, err := bundle.WriteTo(&b) + if err != nil { + return nil, err + } + digest := digest.SHA256.FromBytes(b.Bytes()) + ref := sha{digest} + return ref, nil +} + +func createInvocationImageBuildOptions(dockerCli command.Cli, app *types.App) (build.Options, error) { + buildContext := bytes.NewBuffer(nil) + if err := packager.PackInvocationImageContext(dockerCli, app, buildContext); err != nil { + return build.Options{}, err + } + return build.Options{ + Inputs: build.Inputs{ + InStream: buildContext, + ContextPath: "-", + }, + Session: []session.Attachable{authprovider.NewDockerAuthProvider(os.Stderr)}, + }, nil +} + +func debugTargets(targets map[string]bake.Target) { + if logrus.IsLevelEnabled(logrus.DebugLevel) { + dt, err := json.MarshalIndent(targets, "", " ") + if err != nil { + logrus.Debugf("Failed to marshal Buildx response: %s", err.Error()) + } else { + logrus.Debug(string(dt)) + } + } +} + +func debugBundle(bundle *bundle.Bundle) { + if logrus.IsLevelEnabled(logrus.DebugLevel) { + dt, err := json.MarshalIndent(bundle, "", " ") + if err != nil { + logrus.Debugf("Failed to marshal Bundle: %s", err.Error()) + } else { + logrus.Debug(string(dt)) + } + } +} + +func debugSolveResponses(resp map[string]*client.SolveResponse) { + if logrus.IsLevelEnabled(logrus.DebugLevel) { + dt, err := json.MarshalIndent(resp, "", " ") + if err != nil { + logrus.Debugf("Failed to marshal Buildx response: %s", err.Error()) + } else { + logrus.Debug(string(dt)) + } + } +} + +// parseCompose do parse app compose file and extract buildx targets +func parseCompose(app *types.App) (map[string]bake.Target, error) { + compose, err := bake.ParseCompose(app.Composes()[0]) + // Fixme can have > 1 composes ? + if err != nil { + return nil, err + } + targets := map[string]bake.Target{} + for _, n := range compose.ResolveGroup("default") { + t, err := compose.ResolveTarget(n) + if err != nil { + return nil, err + } + if t != nil { + targets[n] = *t + } + } + return targets, nil +} + + type sha struct { d digest.Digest } +var _ reference.Named = sha{""} +var _ reference.Digested = sha{""} +// Digest implement Digested.Digest() func (s sha) Digest() digest.Digest { return s.d } +// Digest implement Named.String() func (s sha) String() string { return s.d.String() } +// Digest implement Named.Name() func (s sha) Name() string { return s.d.String() } -var _ reference.Named = sha{""} -var _ reference.Digested = sha{""} - - -/// FIXME copy from vendor/github.com/docker/buildx/commands/util.go:318 could probably be made public -func dockerAPI(dockerCli command.Cli) *api { - return &api{dockerCli: dockerCli} -} - -type api struct { - dockerCli command.Cli -} - -func (a *api) DockerAPI(name string) (dockerclient.APIClient, error) { - if name == "" { - name = a.dockerCli.CurrentContext() - } - return nil, fmt.Errorf("Only support default context in this prototype") -} diff --git a/internal/commands/cnab.go b/internal/commands/cnab.go index 457b1c77..99d8f4cb 100644 --- a/internal/commands/cnab.go +++ b/internal/commands/cnab.go @@ -239,7 +239,7 @@ func extractAndLoadAppBasedBundle(dockerCli command.Cli, name string) (*bundle.B return nil, "", err } defer app.Cleanup() - bndl, err := makeBundleFromApp(dockerCli, app, nil) + bndl, err := packager.MakeBundleFromApp(dockerCli, app, nil) return bndl, "", err } diff --git a/internal/commands/push.go b/internal/commands/push.go index e3fefec0..a28898ff 100644 --- a/internal/commands/push.go +++ b/internal/commands/push.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "github.com/docker/app/internal/packager" "io" "io/ioutil" "os" @@ -202,7 +203,7 @@ func shouldRetagInvocationImage(meta metadata.AppMetadata, bndl *bundle.Bundle, imgName := tagOverride var err error if imgName == "" { - imgName, err = makeCNABImageName(meta.Name, meta.Version, "") + imgName, err = packager.MakeCNABImageName(meta.Name, meta.Version, "") if err != nil { return retagResult{}, err } diff --git a/internal/commands/bundle.go b/internal/packager/bundle.go similarity index 73% rename from internal/commands/bundle.go rename to internal/packager/bundle.go index 709397a4..bf49a435 100644 --- a/internal/commands/bundle.go +++ b/internal/packager/bundle.go @@ -1,11 +1,10 @@ -package commands +package packager import ( "bytes" "context" "fmt" "github.com/deislabs/cnab-go/bundle" - "github.com/docker/app/internal/packager" "github.com/docker/app/internal/store" "github.com/docker/app/types" "github.com/docker/app/types/metadata" @@ -19,16 +18,16 @@ import ( "io/ioutil" ) -func makeBundleFromApp(dockerCli command.Cli, app *types.App, refOverride reference.NamedTagged) (*bundle.Bundle, error) { +func MakeBundleFromApp(dockerCli command.Cli, app *types.App, refOverride reference.NamedTagged) (*bundle.Bundle, error) { logrus.Debug("Making app bundle") meta := app.Metadata() - invocationImageName, err := makeInvocationImageName(meta, refOverride) + invocationImageName, err := MakeInvocationImageName(meta, refOverride) if err != nil { return nil, err } buildContext := bytes.NewBuffer(nil) - if err := packager.PackInvocationImageContext(dockerCli, app, buildContext); err != nil { + if err := PackInvocationImageContext(dockerCli, app, buildContext); err != nil { return nil, err } @@ -46,23 +45,23 @@ func makeBundleFromApp(dockerCli command.Cli, app *types.App, refOverride refere if err := jsonmessage.DisplayJSONMessagesStream(buildResp.Body, ioutil.Discard, 0, false, func(jsonmessage.JSONMessage) {}); err != nil { // If the invocation image can't be found we will get an error of the form: // manifest for docker/cnab-app-base:v0.6.0-202-gbaf0b246c7 not found - if err.Error() == fmt.Sprintf("manifest for %s not found", packager.BaseInvocationImage(dockerCli)) { - return nil, fmt.Errorf("unable to resolve Docker App base image: %s", packager.BaseInvocationImage(dockerCli)) + if err.Error() == fmt.Sprintf("manifest for %s not found", BaseInvocationImage(dockerCli)) { + return nil, fmt.Errorf("unable to resolve Docker App base image: %s", BaseInvocationImage(dockerCli)) } return nil, err } - return packager.ToCNAB(app, invocationImageName) + return ToCNAB(app, invocationImageName) } -func makeInvocationImageName(meta metadata.AppMetadata, refOverride reference.NamedTagged) (string, error) { +func MakeInvocationImageName(meta metadata.AppMetadata, refOverride reference.NamedTagged) (string, error) { if refOverride != nil { - return makeCNABImageName(reference.FamiliarName(refOverride), refOverride.Tag(), "-invoc") + return MakeCNABImageName(reference.FamiliarName(refOverride), refOverride.Tag(), "-invoc") } - return makeCNABImageName(meta.Name, meta.Version, "-invoc") + return MakeCNABImageName(meta.Name, meta.Version, "-invoc") } -func makeCNABImageName(appName, appVersion, suffix string) (string, error) { +func MakeCNABImageName(appName, appVersion, suffix string) (string, error) { name := fmt.Sprintf("%s:%s%s", appName, appVersion, suffix) if _, err := reference.ParseNormalizedNamed(name); err != nil { return "", errors.Wrapf(err, "image name %q is invalid, please check name and version fields", name) @@ -70,7 +69,7 @@ func makeCNABImageName(appName, appVersion, suffix string) (string, error) { return name, nil } -func persistInBundleStore(ref reference.Named, bndle *bundle.Bundle) error { +func PersistInBundleStore(ref reference.Named, bndle *bundle.Bundle) error { if ref == nil { return nil } @@ -85,7 +84,7 @@ func persistInBundleStore(ref reference.Named, bndle *bundle.Bundle) error { return bundleStore.Store(ref, bndle) } -func getNamedTagged(tag string) (reference.NamedTagged, error) { +func GetNamedTagged(tag string) (reference.NamedTagged, error) { if tag == "" { return nil, nil } diff --git a/internal/commands/bundle_test.go b/internal/packager/bundle_test.go similarity index 90% rename from internal/commands/bundle_test.go rename to internal/packager/bundle_test.go index e134cef0..e9ae14ad 100644 --- a/internal/commands/bundle_test.go +++ b/internal/packager/bundle_test.go @@ -1,4 +1,4 @@ -package commands +package packager import ( "testing" @@ -34,9 +34,9 @@ func TestMakeInvocationImage(t *testing.T) { } for _, c := range testcases { t.Run(c.name, func(t *testing.T) { - ref, err := getNamedTagged(c.tag) + ref, err := GetNamedTagged(c.tag) assert.NilError(t, err) - actual, err := makeInvocationImageName(c.meta, ref) + actual, err := MakeInvocationImageName(c.meta, ref) if c.err != "" { assert.ErrorContains(t, err, c.err) assert.Equal(t, actual, "", "On "+c.meta.Name) diff --git a/vendor/github.com/docker/buildx/build/build.go b/vendor/github.com/docker/buildx/build/build.go index 9d60695f..72e32c71 100644 --- a/vendor/github.com/docker/buildx/build/build.go +++ b/vendor/github.com/docker/buildx/build/build.go @@ -400,7 +400,7 @@ func toSolveOpt(d driver.Driver, multiDriver bool, opt Options, dl dockerLoadCal return nil, nil, err } defers = append(defers, cancel) - opt.Exports[i].Output = w + opt.Exports[i].Output = wrapWriteCloser(w) } } else if !d.Features()[driver.DockerExporter] { return nil, nil, notSupported(d, driver.DockerExporter) diff --git a/vendor/github.com/docker/buildx/build/output.go b/vendor/github.com/docker/buildx/build/output.go index ac4d0ff5..b27db14c 100644 --- a/vendor/github.com/docker/buildx/build/output.go +++ b/vendor/github.com/docker/buildx/build/output.go @@ -2,6 +2,7 @@ package build import ( "encoding/csv" + "io" "os" "strings" @@ -81,7 +82,7 @@ func ParseOutputs(inp []string) ([]client.ExportEntry, error) { if _, err := console.ConsoleFromFile(os.Stdout); err == nil { return nil, errors.Errorf("output file is required for %s exporter. refusing to write to console", out.Type) } - out.Output = os.Stdout + out.Output = wrapWriteCloser(os.Stdout) } else if dest != "" { fi, err := os.Stat(dest) if err != nil && !os.IsNotExist(err) { @@ -94,7 +95,7 @@ func ParseOutputs(inp []string) ([]client.ExportEntry, error) { if err != nil { return nil, errors.Errorf("failed to open %s", err) } - out.Output = f + out.Output = wrapWriteCloser(f) } delete(out.Attrs, "dest") case "registry": @@ -106,3 +107,9 @@ func ParseOutputs(inp []string) ([]client.ExportEntry, error) { } return outs, nil } + +func wrapWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, error) { + return func(map[string]string) (io.WriteCloser, error) { + return wc, nil + } +} diff --git a/vendor/github.com/moby/buildkit/client/llb/exec.go b/vendor/github.com/moby/buildkit/client/llb/exec.go index 8e2d1d4c..ade99278 100644 --- a/vendor/github.com/moby/buildkit/client/llb/exec.go +++ b/vendor/github.com/moby/buildkit/client/llb/exec.go @@ -427,11 +427,13 @@ func Security(s pb.SecurityMode) RunOption { } func Shlex(str string) RunOption { - return Shlexf(str) + return runOptionFunc(func(ei *ExecInfo) { + ei.State = shlexf(str, false)(ei.State) + }) } func Shlexf(str string, v ...interface{}) RunOption { return runOptionFunc(func(ei *ExecInfo) { - ei.State = shlexf(str, v...)(ei.State) + ei.State = shlexf(str, true, v...)(ei.State) }) } @@ -442,7 +444,9 @@ func Args(a []string) RunOption { } func AddEnv(key, value string) RunOption { - return AddEnvf(key, value) + return runOptionFunc(func(ei *ExecInfo) { + ei.State = ei.State.AddEnv(key, value) + }) } func AddEnvf(key, value string, v ...interface{}) RunOption { @@ -458,7 +462,9 @@ func User(str string) RunOption { } func Dir(str string) RunOption { - return Dirf(str) + return runOptionFunc(func(ei *ExecInfo) { + ei.State = ei.State.Dir(str) + }) } func Dirf(str string, v ...interface{}) RunOption { return runOptionFunc(func(ei *ExecInfo) { diff --git a/vendor/github.com/moby/buildkit/client/llb/meta.go b/vendor/github.com/moby/buildkit/client/llb/meta.go index 78a24730..54b14c4c 100644 --- a/vendor/github.com/moby/buildkit/client/llb/meta.go +++ b/vendor/github.com/moby/buildkit/client/llb/meta.go @@ -24,19 +24,24 @@ var ( keySecurity = contextKeyT("llb.security") ) -func addEnvf(key, value string, v ...interface{}) StateOption { +func addEnvf(key, value string, replace bool, v ...interface{}) StateOption { + if replace { + value = fmt.Sprintf(value, v...) + } return func(s State) State { - return s.WithValue(keyEnv, getEnv(s).AddOrReplace(key, fmt.Sprintf(value, v...))) + return s.WithValue(keyEnv, getEnv(s).AddOrReplace(key, value)) } } func dir(str string) StateOption { - return dirf(str) + return dirf(str, false) } -func dirf(str string, v ...interface{}) StateOption { +func dirf(value string, replace bool, v ...interface{}) StateOption { + if replace { + value = fmt.Sprintf(value, v...) + } return func(s State) State { - value := fmt.Sprintf(str, v...) if !path.IsAbs(value) { prev := getDir(s) if prev == "" { @@ -100,9 +105,12 @@ func args(args ...string) StateOption { } } -func shlexf(str string, v ...interface{}) StateOption { +func shlexf(str string, replace bool, v ...interface{}) StateOption { + if replace { + str = fmt.Sprintf(str, v...) + } return func(s State) State { - arg, err := shlex.Split(fmt.Sprintf(str, v...)) + arg, err := shlex.Split(str) if err != nil { // TODO: handle error } diff --git a/vendor/github.com/moby/buildkit/client/llb/state.go b/vendor/github.com/moby/buildkit/client/llb/state.go index 928242af..ba8845e0 100644 --- a/vendor/github.com/moby/buildkit/client/llb/state.go +++ b/vendor/github.com/moby/buildkit/client/llb/state.go @@ -240,18 +240,18 @@ func (s State) File(a *FileAction, opts ...ConstraintsOpt) State { } func (s State) AddEnv(key, value string) State { - return s.AddEnvf(key, value) + return addEnvf(key, value, false)(s) } func (s State) AddEnvf(key, value string, v ...interface{}) State { - return addEnvf(key, value, v...)(s) + return addEnvf(key, value, true, v...)(s) } func (s State) Dir(str string) State { - return s.Dirf(str) + return dirf(str, false)(s) } func (s State) Dirf(str string, v ...interface{}) State { - return dirf(str, v...)(s) + return dirf(str, true, v...)(s) } func (s State) GetEnv(key string) (string, bool) { diff --git a/vendor/github.com/moby/buildkit/client/solve.go b/vendor/github.com/moby/buildkit/client/solve.go index 17b3810c..d09c5f76 100644 --- a/vendor/github.com/moby/buildkit/client/solve.go +++ b/vendor/github.com/moby/buildkit/client/solve.go @@ -46,8 +46,8 @@ type SolveOpt struct { type ExportEntry struct { Type string Attrs map[string]string - Output io.WriteCloser // for ExporterOCI and ExporterDocker - OutputDir string // for ExporterLocal + Output func(map[string]string) (io.WriteCloser, error) // for ExporterOCI and ExporterDocker + OutputDir string // for ExporterLocal } type CacheOptionsEntry struct { diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go b/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go index b39b2808..1a1ff075 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go @@ -128,7 +128,7 @@ func (c *grpcClient) Run(ctx context.Context, f client.BuildFunc) (retError erro } } if retError != nil { - st, _ := status.FromError(retError) + st, _ := status.FromError(errors.Cause(retError)) stp := st.Proto() req.Error = &rpc.Status{ Code: stp.Code, diff --git a/vendor/github.com/moby/buildkit/session/auth/auth.go b/vendor/github.com/moby/buildkit/session/auth/auth.go index 2b96a7ce..5717455f 100644 --- a/vendor/github.com/moby/buildkit/session/auth/auth.go +++ b/vendor/github.com/moby/buildkit/session/auth/auth.go @@ -4,6 +4,7 @@ import ( "context" "github.com/moby/buildkit/session" + "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -16,10 +17,10 @@ func CredentialsFunc(ctx context.Context, c session.Caller) func(string) (string Host: host, }) if err != nil { - if st, ok := status.FromError(err); ok && st.Code() == codes.Unimplemented { + if st, ok := status.FromError(errors.Cause(err)); ok && st.Code() == codes.Unimplemented { return "", "", nil } - return "", "", err + return "", "", errors.WithStack(err) } return resp.Username, resp.Secret, nil } diff --git a/vendor/github.com/moby/buildkit/session/content/caller.go b/vendor/github.com/moby/buildkit/session/content/caller.go index ef7a24ec..70e82130 100644 --- a/vendor/github.com/moby/buildkit/session/content/caller.go +++ b/vendor/github.com/moby/buildkit/session/content/caller.go @@ -9,6 +9,7 @@ import ( "github.com/moby/buildkit/session" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" "google.golang.org/grpc/metadata" ) @@ -31,47 +32,53 @@ func (cs *callerContentStore) choose(ctx context.Context) context.Context { func (cs *callerContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { ctx = cs.choose(ctx) - return cs.store.Info(ctx, dgst) + info, err := cs.store.Info(ctx, dgst) + return info, errors.WithStack(err) } func (cs *callerContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) { ctx = cs.choose(ctx) - return cs.store.Update(ctx, info, fieldpaths...) + info, err := cs.store.Update(ctx, info, fieldpaths...) + return info, errors.WithStack(err) } func (cs *callerContentStore) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error { ctx = cs.choose(ctx) - return cs.store.Walk(ctx, fn, fs...) + return errors.WithStack(cs.store.Walk(ctx, fn, fs...)) } func (cs *callerContentStore) Delete(ctx context.Context, dgst digest.Digest) error { ctx = cs.choose(ctx) - return cs.store.Delete(ctx, dgst) + return errors.WithStack(cs.store.Delete(ctx, dgst)) } func (cs *callerContentStore) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) { ctx = cs.choose(ctx) - return cs.store.ListStatuses(ctx, fs...) + resp, err := cs.store.ListStatuses(ctx, fs...) + return resp, errors.WithStack(err) } func (cs *callerContentStore) Status(ctx context.Context, ref string) (content.Status, error) { ctx = cs.choose(ctx) - return cs.store.Status(ctx, ref) + st, err := cs.store.Status(ctx, ref) + return st, errors.WithStack(err) } func (cs *callerContentStore) Abort(ctx context.Context, ref string) error { ctx = cs.choose(ctx) - return cs.store.Abort(ctx, ref) + return errors.WithStack(cs.store.Abort(ctx, ref)) } func (cs *callerContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) { ctx = cs.choose(ctx) - return cs.store.Writer(ctx, opts...) + w, err := cs.store.Writer(ctx, opts...) + return w, errors.WithStack(err) } func (cs *callerContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) { ctx = cs.choose(ctx) - return cs.store.ReaderAt(ctx, desc) + ra, err := cs.store.ReaderAt(ctx, desc) + return ra, errors.WithStack(err) } // NewCallerStore creates content.Store from session.Caller with specified storeID diff --git a/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go b/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go index 6934f946..f1d7d78e 100644 --- a/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go +++ b/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go @@ -14,7 +14,7 @@ import ( ) func sendDiffCopy(stream grpc.Stream, fs fsutil.FS, progress progressCb) error { - return fsutil.Send(stream.Context(), stream, fs, progress) + return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress)) } func newStreamWriter(stream grpc.ClientStream) io.WriteCloser { @@ -29,7 +29,7 @@ type bufferedWriteCloser struct { func (bwc *bufferedWriteCloser) Close() error { if err := bwc.Writer.Flush(); err != nil { - return err + return errors.WithStack(err) } return bwc.Closer.Close() } @@ -40,19 +40,25 @@ type streamWriterCloser struct { func (wc *streamWriterCloser) Write(dt []byte) (int, error) { if err := wc.ClientStream.SendMsg(&BytesMessage{Data: dt}); err != nil { - return 0, err + // SendMsg return EOF on remote errors + if errors.Cause(err) == io.EOF { + if err := errors.WithStack(wc.ClientStream.RecvMsg(struct{}{})); err != nil { + return 0, err + } + } + return 0, errors.WithStack(err) } return len(dt), nil } func (wc *streamWriterCloser) Close() error { if err := wc.ClientStream.CloseSend(); err != nil { - return err + return errors.WithStack(err) } // block until receiver is done var bm BytesMessage if err := wc.ClientStream.RecvMsg(&bm); err != io.EOF { - return err + return errors.WithStack(err) } return nil } @@ -69,19 +75,19 @@ func recvDiffCopy(ds grpc.Stream, dest string, cu CacheUpdater, progress progres cf = cu.HandleChange ch = cu.ContentHasher() } - return fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{ + return errors.WithStack(fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{ NotifyHashed: cf, ContentHasher: ch, ProgressCb: progress, Filter: fsutil.FilterFunc(filter), - }) + })) } func syncTargetDiffCopy(ds grpc.Stream, dest string) error { if err := os.MkdirAll(dest, 0700); err != nil { - return err + return errors.Wrapf(err, "failed to create synctarget dest dir %s", dest) } - return fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{ + return errors.WithStack(fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{ Merge: true, Filter: func() func(string, *fstypes.Stat) bool { uid := os.Getuid() @@ -92,7 +98,7 @@ func syncTargetDiffCopy(ds grpc.Stream, dest string) error { return true } }(), - }) + })) } func writeTargetFile(ds grpc.Stream, wc io.WriteCloser) error { @@ -102,10 +108,10 @@ func writeTargetFile(ds grpc.Stream, wc io.WriteCloser) error { if errors.Cause(err) == io.EOF { return nil } - return err + return errors.WithStack(err) } if _, err := wc.Write(bm.Data); err != nil { - return err + return errors.WithStack(err) } } } diff --git a/vendor/github.com/moby/buildkit/session/filesync/filesync.go b/vendor/github.com/moby/buildkit/session/filesync/filesync.go index de5237b1..a45abe02 100644 --- a/vendor/github.com/moby/buildkit/session/filesync/filesync.go +++ b/vendor/github.com/moby/buildkit/session/filesync/filesync.go @@ -18,11 +18,12 @@ import ( ) const ( - keyOverrideExcludes = "override-excludes" - keyIncludePatterns = "include-patterns" - keyExcludePatterns = "exclude-patterns" - keyFollowPaths = "followpaths" - keyDirName = "dir-name" + keyOverrideExcludes = "override-excludes" + keyIncludePatterns = "include-patterns" + keyExcludePatterns = "exclude-patterns" + keyFollowPaths = "followpaths" + keyDirName = "dir-name" + keyExporterMetaPrefix = "exporter-md-" ) type fsSyncProvider struct { @@ -238,16 +239,16 @@ func NewFSSyncTargetDir(outdir string) session.Attachable { } // NewFSSyncTarget allows writing into an io.WriteCloser -func NewFSSyncTarget(w io.WriteCloser) session.Attachable { +func NewFSSyncTarget(f func(map[string]string) (io.WriteCloser, error)) session.Attachable { p := &fsSyncTarget{ - outfile: w, + f: f, } return p } type fsSyncTarget struct { - outdir string - outfile io.WriteCloser + outdir string + f func(map[string]string) (io.WriteCloser, error) } func (sp *fsSyncTarget) Register(server *grpc.Server) { @@ -258,11 +259,26 @@ func (sp *fsSyncTarget) DiffCopy(stream FileSend_DiffCopyServer) error { if sp.outdir != "" { return syncTargetDiffCopy(stream, sp.outdir) } - if sp.outfile == nil { + + if sp.f == nil { return errors.New("empty outfile and outdir") } - defer sp.outfile.Close() - return writeTargetFile(stream, sp.outfile) + opts, _ := metadata.FromIncomingContext(stream.Context()) // if no metadata continue with empty object + md := map[string]string{} + for k, v := range opts { + if strings.HasPrefix(k, keyExporterMetaPrefix) { + md[strings.TrimPrefix(k, keyExporterMetaPrefix)] = strings.Join(v, ",") + } + } + wc, err := sp.f(md) + if err != nil { + return err + } + if wc == nil { + return status.Errorf(codes.AlreadyExists, "target already exists") + } + defer wc.Close() + return writeTargetFile(stream, wc) } func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress func(int, bool)) error { @@ -275,13 +291,13 @@ func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress cc, err := client.DiffCopy(ctx) if err != nil { - return err + return errors.WithStack(err) } return sendDiffCopy(cc, fs, progress) } -func CopyFileWriter(ctx context.Context, c session.Caller) (io.WriteCloser, error) { +func CopyFileWriter(ctx context.Context, md map[string]string, c session.Caller) (io.WriteCloser, error) { method := session.MethodURL(_FileSend_serviceDesc.ServiceName, "diffcopy") if !c.Supports(method) { return nil, errors.Errorf("method %s not supported by the client", method) @@ -289,9 +305,16 @@ func CopyFileWriter(ctx context.Context, c session.Caller) (io.WriteCloser, erro client := NewFileSendClient(c.Conn()) + opts := make(map[string][]string, len(md)) + for k, v := range md { + opts[keyExporterMetaPrefix+k] = []string{v} + } + + ctx = metadata.NewOutgoingContext(ctx, opts) + cc, err := client.DiffCopy(ctx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return newStreamWriter(cc), nil diff --git a/vendor/github.com/moby/buildkit/session/secrets/secrets.go b/vendor/github.com/moby/buildkit/session/secrets/secrets.go index 6cfda18b..3f3bb644 100644 --- a/vendor/github.com/moby/buildkit/session/secrets/secrets.go +++ b/vendor/github.com/moby/buildkit/session/secrets/secrets.go @@ -21,10 +21,10 @@ func GetSecret(ctx context.Context, c session.Caller, id string) ([]byte, error) ID: id, }) if err != nil { - if st, ok := status.FromError(err); ok && (st.Code() == codes.Unimplemented || st.Code() == codes.NotFound) { + if st, ok := status.FromError(errors.Cause(err)); ok && (st.Code() == codes.Unimplemented || st.Code() == codes.NotFound) { return nil, errors.Wrapf(ErrNotFound, "secret %s not found", id) } - return nil, err + return nil, errors.WithStack(err) } return resp.Data, nil } diff --git a/vendor/github.com/moby/buildkit/session/sshforward/copy.go b/vendor/github.com/moby/buildkit/session/sshforward/copy.go index c101f3b4..85366f19 100644 --- a/vendor/github.com/moby/buildkit/session/sshforward/copy.go +++ b/vendor/github.com/moby/buildkit/session/sshforward/copy.go @@ -3,23 +3,24 @@ package sshforward import ( io "io" + "github.com/pkg/errors" context "golang.org/x/net/context" "golang.org/x/sync/errgroup" "google.golang.org/grpc" ) -func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream) error { +func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream, closeStream func() error) error { g, ctx := errgroup.WithContext(ctx) g.Go(func() (retErr error) { p := &BytesMessage{} for { if err := stream.RecvMsg(p); err != nil { + conn.Close() if err == io.EOF { return nil } - conn.Close() - return err + return errors.WithStack(err) } select { case <-ctx.Done(): @@ -29,7 +30,7 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream) erro } if _, err := conn.Write(p.Data); err != nil { conn.Close() - return err + return errors.WithStack(err) } p.Data = p.Data[:0] } @@ -41,9 +42,12 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream) erro n, err := conn.Read(buf) switch { case err == io.EOF: + if closeStream != nil { + closeStream() + } return nil case err != nil: - return err + return errors.WithStack(err) } select { case <-ctx.Done(): @@ -52,7 +56,7 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream) erro } p := &BytesMessage{Data: buf[:n]} if err := stream.SendMsg(p); err != nil { - return err + return errors.WithStack(err) } } }) diff --git a/vendor/github.com/moby/buildkit/session/sshforward/ssh.go b/vendor/github.com/moby/buildkit/session/sshforward/ssh.go index a4effef6..0001f59b 100644 --- a/vendor/github.com/moby/buildkit/session/sshforward/ssh.go +++ b/vendor/github.com/moby/buildkit/session/sshforward/ssh.go @@ -7,6 +7,7 @@ import ( "path/filepath" "github.com/moby/buildkit/session" + "github.com/pkg/errors" context "golang.org/x/net/context" "golang.org/x/sync/errgroup" "google.golang.org/grpc/metadata" @@ -48,7 +49,7 @@ func (s *server) run(ctx context.Context, l net.Listener, id string) error { return err } - go Copy(ctx, conn, stream) + go Copy(ctx, conn, stream, stream.CloseSend) } }) @@ -65,7 +66,7 @@ type SocketOpt struct { func MountSSHSocket(ctx context.Context, c session.Caller, opt SocketOpt) (sockPath string, closer func() error, err error) { dir, err := ioutil.TempDir("", ".buildkit-ssh-sock") if err != nil { - return "", nil, err + return "", nil, errors.WithStack(err) } defer func() { @@ -78,16 +79,16 @@ func MountSSHSocket(ctx context.Context, c session.Caller, opt SocketOpt) (sockP l, err := net.Listen("unix", sockPath) if err != nil { - return "", nil, err + return "", nil, errors.WithStack(err) } if err := os.Chown(sockPath, opt.UID, opt.GID); err != nil { l.Close() - return "", nil, err + return "", nil, errors.WithStack(err) } if err := os.Chmod(sockPath, os.FileMode(opt.Mode)); err != nil { l.Close() - return "", nil, err + return "", nil, errors.WithStack(err) } s := &server{caller: c} @@ -102,12 +103,12 @@ func MountSSHSocket(ctx context.Context, c session.Caller, opt SocketOpt) (sockP return sockPath, func() error { err := l.Close() os.RemoveAll(sockPath) - return err + return errors.WithStack(err) }, nil } func CheckSSHID(ctx context.Context, c session.Caller, id string) error { client := NewSSHClient(c.Conn()) _, err := client.CheckAgent(ctx, &CheckAgentRequest{ID: id}) - return err + return errors.WithStack(err) } diff --git a/vendor/github.com/moby/buildkit/session/sshforward/sshprovider/agentprovider.go b/vendor/github.com/moby/buildkit/session/sshforward/sshprovider/agentprovider.go index 009a91b7..7aa3e3df 100644 --- a/vendor/github.com/moby/buildkit/session/sshforward/sshprovider/agentprovider.go +++ b/vendor/github.com/moby/buildkit/session/sshforward/sshprovider/agentprovider.go @@ -114,7 +114,7 @@ func (sp *socketProvider) ForwardAgent(stream sshforward.SSH_ForwardAgentServer) eg.Go(func() error { defer s1.Close() - return sshforward.Copy(ctx, s2, stream) + return sshforward.Copy(ctx, s2, stream, nil) }) return eg.Wait() diff --git a/vendor/github.com/moby/buildkit/session/upload/upload.go b/vendor/github.com/moby/buildkit/session/upload/upload.go index 8d69bde2..c739b92d 100644 --- a/vendor/github.com/moby/buildkit/session/upload/upload.go +++ b/vendor/github.com/moby/buildkit/session/upload/upload.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/moby/buildkit/session" + "github.com/pkg/errors" "google.golang.org/grpc/metadata" ) @@ -26,7 +27,7 @@ func New(ctx context.Context, c session.Caller, url *url.URL) (*Upload, error) { cc, err := client.Pull(ctx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &Upload{cc: cc}, nil @@ -44,12 +45,12 @@ func (u *Upload) WriteTo(w io.Writer) (int, error) { if err == io.EOF { return n, nil } - return n, err + return n, errors.WithStack(err) } nn, err := w.Write(bm.Data) n += nn if err != nil { - return n, err + return n, errors.WithStack(err) } } } diff --git a/vendor/github.com/moby/buildkit/solver/pb/caps.go b/vendor/github.com/moby/buildkit/solver/pb/caps.go index 7ff0358e..7649ce7d 100644 --- a/vendor/github.com/moby/buildkit/solver/pb/caps.go +++ b/vendor/github.com/moby/buildkit/solver/pb/caps.go @@ -30,19 +30,20 @@ const ( CapBuildOpLLBFileName apicaps.CapID = "source.buildop.llbfilename" - CapExecMetaBase apicaps.CapID = "exec.meta.base" - CapExecMetaProxy apicaps.CapID = "exec.meta.proxyenv" - CapExecMetaNetwork apicaps.CapID = "exec.meta.network" - CapExecMetaSecurity apicaps.CapID = "exec.meta.security" - CapExecMetaSetsDefaultPath apicaps.CapID = "exec.meta.setsdefaultpath" - CapExecMountBind apicaps.CapID = "exec.mount.bind" - CapExecMountCache apicaps.CapID = "exec.mount.cache" - CapExecMountCacheSharing apicaps.CapID = "exec.mount.cache.sharing" - CapExecMountSelector apicaps.CapID = "exec.mount.selector" - CapExecMountTmpfs apicaps.CapID = "exec.mount.tmpfs" - CapExecMountSecret apicaps.CapID = "exec.mount.secret" - CapExecMountSSH apicaps.CapID = "exec.mount.ssh" - CapExecCgroupsMounted apicaps.CapID = "exec.cgroup" + CapExecMetaBase apicaps.CapID = "exec.meta.base" + CapExecMetaProxy apicaps.CapID = "exec.meta.proxyenv" + CapExecMetaNetwork apicaps.CapID = "exec.meta.network" + CapExecMetaSecurity apicaps.CapID = "exec.meta.security" + CapExecMetaSetsDefaultPath apicaps.CapID = "exec.meta.setsdefaultpath" + CapExecMountBind apicaps.CapID = "exec.mount.bind" + CapExecMountBindReadWriteNoOuput apicaps.CapID = "exec.mount.bind.readwrite-nooutput" + CapExecMountCache apicaps.CapID = "exec.mount.cache" + CapExecMountCacheSharing apicaps.CapID = "exec.mount.cache.sharing" + CapExecMountSelector apicaps.CapID = "exec.mount.selector" + CapExecMountTmpfs apicaps.CapID = "exec.mount.tmpfs" + CapExecMountSecret apicaps.CapID = "exec.mount.secret" + CapExecMountSSH apicaps.CapID = "exec.mount.ssh" + CapExecCgroupsMounted apicaps.CapID = "exec.cgroup" CapFileBase apicaps.CapID = "file.base" @@ -193,6 +194,12 @@ func init() { Status: apicaps.CapStatusExperimental, }) + Caps.Init(apicaps.Cap{ + ID: CapExecMountBindReadWriteNoOuput, + Enabled: true, + Status: apicaps.CapStatusExperimental, + }) + Caps.Init(apicaps.Cap{ ID: CapExecMountCache, Enabled: true,