From db0aa5a7d2e47bf5441005d2f240abcc04537996 Mon Sep 17 00:00:00 2001 From: "zhuangbowei.zbw" Date: Wed, 28 Feb 2024 12:52:50 +0800 Subject: [PATCH] convertor: support multi-arch images Signed-off-by: zhuangbowei.zbw --- cmd/convertor/builder/builder.go | 274 +++++++++++++++++---- cmd/convertor/builder/builder_engine.go | 20 +- cmd/convertor/builder/builder_test.go | 6 +- cmd/convertor/builder/overlaybd_builder.go | 4 +- cmd/convertor/builder/turboOCI_builder.go | 6 +- cmd/convertor/main.go | 53 ++-- docs/BUILDING.md | 4 +- docs/USERSPACE_CONVERTOR.md | 1 + go.mod | 6 +- go.sum | 12 +- 10 files changed, 281 insertions(+), 105 deletions(-) diff --git a/cmd/convertor/builder/builder.go b/cmd/convertor/builder/builder.go index e13f9a18..6dd76009 100644 --- a/cmd/convertor/builder/builder.go +++ b/cmd/convertor/builder/builder.go @@ -20,28 +20,33 @@ import ( "context" "crypto/tls" "crypto/x509" + "encoding/json" "fmt" + "io" "net" "net/http" "os" "path/filepath" "runtime" "strings" + "sync" + "sync/atomic" "time" "github.com/containerd/accelerated-container-image/cmd/convertor/database" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/reference" + "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" + "github.com/opencontainers/go-digest" v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) -type Builder interface { - Build(ctx context.Context) error -} - type BuilderOptions struct { Ref string TargetRef string @@ -57,18 +62,214 @@ type BuilderOptions struct { Reserve bool NoUpload bool DumpManifest bool + + // ConcurrencyLimit limits the number of manifests that can be built at once + // 0 means no limit + ConcurrencyLimit int } -type overlaybdBuilder struct { - layers int - config v1.Image - engine builderEngine +type graphBuilder struct { + // required + Resolver remotes.Resolver + + // options + BuilderOptions + + // private + fetcher remotes.Fetcher + pusher remotes.Pusher + tagPusher remotes.Pusher + group *errgroup.Group + sem chan struct{} + id atomic.Int32 +} + +func (b *graphBuilder) Build(ctx context.Context) error { + fetcher, err := b.Resolver.Fetcher(ctx, b.Ref) + if err != nil { + return fmt.Errorf("failed to obtain new fetcher: %w", err) + } + pusher, err := b.Resolver.Pusher(ctx, b.TargetRef+"@") // append '@' to avoid tag + if err != nil { + return fmt.Errorf("failed to obtain new pusher: %w", err) + } + tagPusher, err := b.Resolver.Pusher(ctx, b.TargetRef) // append '@' to avoid tag + if err != nil { + return fmt.Errorf("failed to obtain new tag pusher: %w", err) + } + b.fetcher = fetcher + b.pusher = pusher + b.tagPusher = tagPusher + _, src, err := b.Resolver.Resolve(ctx, b.Ref) + if err != nil { + return fmt.Errorf("failed to resolve: %w", err) + } + + g, gctx := errgroup.WithContext(ctx) + b.group = g + if b.ConcurrencyLimit > 0 { + b.sem = make(chan struct{}, b.ConcurrencyLimit) + } + g.Go(func() error { + target, err := b.process(gctx, src, true) + if err != nil { + return fmt.Errorf("failed to build %q: %w", src.Digest, err) + } + log.G(gctx).Infof("converted to %q, digest: %q", b.TargetRef, target.Digest) + return nil + }) + return g.Wait() } -func NewOverlayBDBuilder(ctx context.Context, opt BuilderOptions) (Builder, error) { +func (b *graphBuilder) process(ctx context.Context, src v1.Descriptor, tag bool) (v1.Descriptor, error) { + switch src.MediaType { + case v1.MediaTypeImageManifest, images.MediaTypeDockerSchema2Manifest: + return b.buildOne(ctx, src, tag) + case v1.MediaTypeImageIndex, images.MediaTypeDockerSchema2ManifestList: + var index v1.Index + rc, err := b.fetcher.Fetch(ctx, src) + if err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to fetch index: %w", err) + } + defer rc.Close() + indexBytes, err := io.ReadAll(rc) + if err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to read index: %w", err) + } + if err := json.Unmarshal(indexBytes, &index); err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to unmarshal index: %w", err) + } + var wg sync.WaitGroup + for _i, _m := range index.Manifests { + i := _i + m := _m + wg.Add(1) + b.group.Go(func() error { + defer wg.Done() + target, err := b.process(ctx, m, false) + if err != nil { + return fmt.Errorf("failed to build %q: %w", m.Digest, err) + } + index.Manifests[i] = target + return nil + }) + } + wg.Wait() + if ctx.Err() != nil { + return v1.Descriptor{}, ctx.Err() + } + + // upload index + indexBytes, err = json.Marshal(index) + if err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to marshal index: %w", err) + } + expected := src + expected.Digest = digest.FromBytes(indexBytes) + expected.Size = int64(len(indexBytes)) + var pusher remotes.Pusher + if tag { + pusher = b.tagPusher + } else { + pusher = b.pusher + } + if err := uploadBytes(ctx, pusher, expected, indexBytes); err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to upload index: %w", err) + } + return expected, nil + default: + return v1.Descriptor{}, fmt.Errorf("unsupported media type %q", src.MediaType) + } +} + +func (b *graphBuilder) buildOne(ctx context.Context, src v1.Descriptor, tag bool) (v1.Descriptor, error) { + if b.sem != nil { + select { + case <-ctx.Done(): + return v1.Descriptor{}, ctx.Err() + case b.sem <- struct{}{}: + } + } + defer func() { + if b.sem != nil { + select { + case <-ctx.Done(): + case <-b.sem: + } + } + }() + id := b.id.Add(1) + + var platform string + if src.Platform == nil { + platform = "" + } else { + platform = platforms.Format(*src.Platform) + ctx = log.WithLogger(ctx, log.G(ctx).WithField("platform", platform)) + } + workdir := filepath.Join(b.WorkDir, fmt.Sprintf("%d-%s-%s", id, strings.ReplaceAll(platform, "/", "_"), src.Digest.Encoded())) + log.G(ctx).Infof("building %s ...", workdir) + + // init build engine + manifest, config, err := fetchManifestAndConfig(ctx, b.fetcher, src) + if err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to fetch manifest and config: %w", err) + } + var pusher remotes.Pusher + if tag { + pusher = b.tagPusher + } else { + pusher = b.pusher + } + engineBase := &builderEngineBase{ + resolver: b.Resolver, + fetcher: b.fetcher, + pusher: pusher, + manifest: *manifest, + config: *config, + inputDesc: src, + } + engineBase.workDir = workdir + engineBase.oci = b.OCI + engineBase.mkfs = b.Mkfs + engineBase.vsize = b.Vsize + engineBase.db = b.DB + refspec, err := reference.Parse(b.Ref) + if err != nil { + return v1.Descriptor{}, err + } + engineBase.host = refspec.Hostname() + engineBase.repository = strings.TrimPrefix(refspec.Locator, engineBase.host+"/") + engineBase.reserve = b.Reserve + engineBase.noUpload = b.NoUpload + engineBase.dumpManifest = b.DumpManifest + + var engine builderEngine + switch b.Engine { + case Overlaybd: + engine = NewOverlayBDBuilderEngine(engineBase) + case TurboOCI: + engine = NewTurboOCIBuilderEngine(engineBase) + } + + // build + builder := &overlaybdBuilder{ + layers: len(engineBase.manifest.Layers), + engine: engine, + } + desc, err := builder.Build(ctx) + if err != nil { + return v1.Descriptor{}, fmt.Errorf("failed to build %s: %w", workdir, err) + } + src.Digest = desc.Digest + src.Size = desc.Size + return src, nil +} + +func Build(ctx context.Context, opt BuilderOptions) error { tlsConfig, err := loadTLSConfig(opt.CertOption) if err != nil { - return nil, fmt.Errorf("failed to load certifications: %w", err) + return fmt.Errorf("failed to load certifications: %w", err) } transport := &http.Transport{ DialContext: (&net.Dialer{ @@ -106,41 +307,21 @@ func NewOverlayBDBuilder(ctx context.Context, opt BuilderOptions) (Builder, erro }), ), }) - engineBase, err := getBuilderEngineBase(ctx, resolver, opt.Ref, opt.TargetRef) - if err != nil { - return nil, err - } - engineBase.workDir = opt.WorkDir - engineBase.oci = opt.OCI - engineBase.mkfs = opt.Mkfs - engineBase.vsize = opt.Vsize - engineBase.db = opt.DB - refspec, err := reference.Parse(opt.Ref) - if err != nil { - return nil, err - } - engineBase.host = refspec.Hostname() - engineBase.repository = strings.TrimPrefix(refspec.Locator, engineBase.host+"/") - engineBase.reserve = opt.Reserve - engineBase.noUpload = opt.NoUpload - engineBase.dumpManifest = opt.DumpManifest + return (&graphBuilder{ + Resolver: resolver, + BuilderOptions: opt, + }).Build(ctx) +} - var engine builderEngine - switch opt.Engine { - case Overlaybd: - engine = NewOverlayBDBuilderEngine(engineBase) - case TurboOCI: - engine = NewTurboOCIBuilderEngine(engineBase) - } - return &overlaybdBuilder{ - layers: len(engineBase.manifest.Layers), - engine: engine, - config: engineBase.config, - }, nil +type overlaybdBuilder struct { + layers int + engine builderEngine } -func (b *overlaybdBuilder) Build(ctx context.Context) error { +// Build return a descriptor of the converted target, as the caller may need it +// to tag or compose an index +func (b *overlaybdBuilder) Build(ctx context.Context) (v1.Descriptor, error) { defer b.engine.Cleanup() alreadyConverted := make([]chan *v1.Descriptor, b.layers) downloaded := make([]chan error, b.layers) @@ -150,7 +331,7 @@ func (b *overlaybdBuilder) Build(ctx context.Context) error { // when errors are encountered fallback to regular conversion if convertedDesc, err := b.engine.CheckForConvertedManifest(ctx); err == nil && convertedDesc.Digest != "" { logrus.Infof("Image found already converted in registry with digest %s", convertedDesc.Digest) - return nil + return convertedDesc, nil } // Errgroups will close the context after wait returns so the operations need their own @@ -244,15 +425,16 @@ func (b *overlaybdBuilder) Build(ctx context.Context) error { }) } if err := g.Wait(); err != nil { - return err + return v1.Descriptor{}, err } - if err := b.engine.UploadImage(ctx); err != nil { - return errors.Wrap(err, "failed to upload manifest or config") + targetDesc, err := b.engine.UploadImage(ctx) + if err != nil { + return v1.Descriptor{}, errors.Wrap(err, "failed to upload manifest or config") } b.engine.StoreConvertedManifestDetails(ctx) logrus.Info("convert finished") - return nil + return targetDesc, nil } // block until ctx.Done() or sent diff --git a/cmd/convertor/builder/builder_engine.go b/cmd/convertor/builder/builder_engine.go index 4b6c5365..b664a3f3 100644 --- a/cmd/convertor/builder/builder_engine.go +++ b/cmd/convertor/builder/builder_engine.go @@ -48,8 +48,8 @@ type builderEngine interface { UploadLayer(ctx context.Context, idx int) error - // UploadImage upload new manifest and config - UploadImage(ctx context.Context) error + // UploadImage upload new manifest and config, return the descriptor of the manifest + UploadImage(ctx context.Context) (specs.Descriptor, error) // Cleanup removes workdir Cleanup() @@ -149,10 +149,10 @@ func (e *builderEngineBase) mediaTypeImageLayer() string { } } -func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) error { +func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) (specs.Descriptor, error) { cbuf, err := json.Marshal(e.config) if err != nil { - return err + return specs.Descriptor{}, err } e.manifest.Config = specs.Descriptor{ MediaType: e.mediaTypeConfig(), @@ -161,14 +161,14 @@ func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) error { } if !e.noUpload { if err = uploadBytes(ctx, e.pusher, e.manifest.Config, cbuf); err != nil { - return errors.Wrapf(err, "failed to upload config") + return specs.Descriptor{}, errors.Wrapf(err, "failed to upload config") } logrus.Infof("config uploaded") } if e.dumpManifest { confPath := path.Join(e.workDir, "config.json") if err := continuity.AtomicWriteFile(confPath, cbuf, 0644); err != nil { - return err + return specs.Descriptor{}, err } logrus.Infof("config dumped") } @@ -176,7 +176,7 @@ func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) error { e.manifest.MediaType = e.mediaTypeManifest() cbuf, err = json.Marshal(e.manifest) if err != nil { - return err + return specs.Descriptor{}, err } manifestDesc := specs.Descriptor{ MediaType: e.mediaTypeManifest(), @@ -185,7 +185,7 @@ func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) error { } if !e.noUpload { if err = uploadBytes(ctx, e.pusher, manifestDesc, cbuf); err != nil { - return errors.Wrapf(err, "failed to upload manifest") + return specs.Descriptor{}, errors.Wrapf(err, "failed to upload manifest") } e.outputDesc = manifestDesc logrus.Infof("manifest uploaded") @@ -193,11 +193,11 @@ func (e *builderEngineBase) uploadManifestAndConfig(ctx context.Context) error { if e.dumpManifest { descPath := path.Join(e.workDir, "manifest.json") if err := continuity.AtomicWriteFile(descPath, cbuf, 0644); err != nil { - return err + return specs.Descriptor{}, err } logrus.Infof("manifest dumped") } - return nil + return manifestDesc, nil } func getBuilderEngineBase(ctx context.Context, resolver remotes.Resolver, ref, targetRef string) (*builderEngineBase, error) { diff --git a/cmd/convertor/builder/builder_test.go b/cmd/convertor/builder/builder_test.go index 6118dba6..75ed2236 100644 --- a/cmd/convertor/builder/builder_test.go +++ b/cmd/convertor/builder/builder_test.go @@ -97,11 +97,11 @@ func (e *mockFuzzBuilderEngine) UploadLayer(ctx context.Context, idx int) error return nil } -func (e *mockFuzzBuilderEngine) UploadImage(ctx context.Context) error { +func (e *mockFuzzBuilderEngine) UploadImage(ctx context.Context) (specs.Descriptor, error) { if e.fixedRand.Float64() < failRate { - return fmt.Errorf("random error on UploadImage") + return specs.Descriptor{}, fmt.Errorf("random error on UploadImage") } - return nil + return specs.Descriptor{}, nil } func (e *mockFuzzBuilderEngine) CheckForConvertedLayer(ctx context.Context, idx int) (specs.Descriptor, error) { diff --git a/cmd/convertor/builder/overlaybd_builder.go b/cmd/convertor/builder/overlaybd_builder.go index fef8ca14..09a8c4f1 100644 --- a/cmd/convertor/builder/overlaybd_builder.go +++ b/cmd/convertor/builder/overlaybd_builder.go @@ -158,7 +158,7 @@ func (e *overlaybdBuilderEngine) UploadLayer(ctx context.Context, idx int) error return nil } -func (e *overlaybdBuilderEngine) UploadImage(ctx context.Context) error { +func (e *overlaybdBuilderEngine) UploadImage(ctx context.Context) (specs.Descriptor, error) { for idx := range e.manifest.Layers { e.manifest.Layers[idx] = e.overlaybdLayers[idx].desc e.config.RootFS.DiffIDs[idx] = e.overlaybdLayers[idx].desc.Digest @@ -166,7 +166,7 @@ func (e *overlaybdBuilderEngine) UploadImage(ctx context.Context) error { if !e.mkfs { baseDesc, err := e.uploadBaseLayer(ctx) if err != nil { - return err + return specs.Descriptor{}, err } e.manifest.Layers = append([]specs.Descriptor{baseDesc}, e.manifest.Layers...) e.config.RootFS.DiffIDs = append([]digest.Digest{baseDesc.Digest}, e.config.RootFS.DiffIDs...) diff --git a/cmd/convertor/builder/turboOCI_builder.go b/cmd/convertor/builder/turboOCI_builder.go index 47d96fe5..83ffeeb9 100644 --- a/cmd/convertor/builder/turboOCI_builder.go +++ b/cmd/convertor/builder/turboOCI_builder.go @@ -167,12 +167,12 @@ func (e *turboOCIBuilderEngine) UploadLayer(ctx context.Context, idx int) error return nil } -func (e *turboOCIBuilderEngine) UploadImage(ctx context.Context) error { +func (e *turboOCIBuilderEngine) UploadImage(ctx context.Context) (specs.Descriptor, error) { for idx := range e.manifest.Layers { layerDir := e.getLayerDir(idx) uncompress, err := getFileDesc(path.Join(layerDir, tociLayerTar), true) if err != nil { - return errors.Wrapf(err, "failed to get uncompressed descriptor for layer %d", idx) + return specs.Descriptor{}, errors.Wrapf(err, "failed to get uncompressed descriptor for layer %d", idx) } e.manifest.Layers[idx] = e.tociLayers[idx] e.config.RootFS.DiffIDs[idx] = uncompress.Digest @@ -189,7 +189,7 @@ func (e *turboOCIBuilderEngine) UploadImage(ctx context.Context) error { } if !e.mkfs { if err := uploadBlob(ctx, e.pusher, overlaybdBaseLayer, baseDesc); err != nil { - return errors.Wrapf(err, "failed to upload baselayer %q", overlaybdBaseLayer) + return specs.Descriptor{}, errors.Wrapf(err, "failed to upload baselayer %q", overlaybdBaseLayer) } e.manifest.Layers = append([]specs.Descriptor{baseDesc}, e.manifest.Layers...) e.config.RootFS.DiffIDs = append([]digest.Digest{baseDesc.Digest}, e.config.RootFS.DiffIDs...) diff --git a/cmd/convertor/main.go b/cmd/convertor/main.go index 1d491c0f..374412a6 100644 --- a/cmd/convertor/main.go +++ b/cmd/convertor/main.go @@ -31,21 +31,22 @@ import ( ) var ( - repo string - user string - plain bool - tagInput string - tagOutput string - dir string - oci bool - mkfs bool - verbose bool - vsize int - fastoci string - turboOCI string - overlaybd string - dbstr string - dbType string + repo string + user string + plain bool + tagInput string + tagOutput string + dir string + oci bool + mkfs bool + verbose bool + vsize int + fastoci string + turboOCI string + overlaybd string + dbstr string + dbType string + concurrencyLimit int // certification certDirs []string @@ -95,9 +96,10 @@ var ( ClientCerts: clientCerts, Insecure: insecure, }, - Reserve: reserve, - NoUpload: noUpload, - DumpManifest: dumpManifest, + Reserve: reserve, + NoUpload: noUpload, + DumpManifest: dumpManifest, + ConcurrencyLimit: concurrencyLimit, } if overlaybd != "" { logrus.Info("building [Overlaybd - Native] image...") @@ -121,12 +123,7 @@ var ( logrus.Warnf("falling back to no deduplication") } - builder, err := builder.NewOverlayBDBuilder(ctx, opt) - if err != nil { - logrus.Errorf("failed to create overlaybd builder: %v", err) - os.Exit(1) - } - if err := builder.Build(ctx); err != nil { + if err := builder.Build(ctx, opt); err != nil { logrus.Errorf("failed to build overlaybd: %v", err) os.Exit(1) } @@ -136,12 +133,7 @@ var ( logrus.Info("building [Overlaybd - Turbo OCIv1] image...") opt.Engine = builder.TurboOCI opt.TargetRef = repo + ":" + tb - builder, err := builder.NewOverlayBDBuilder(ctx, opt) - if err != nil { - logrus.Errorf("failed to create TurboOCI builder: %v", err) - os.Exit(1) - } - if err := builder.Build(ctx); err != nil { + if err := builder.Build(ctx, opt); err != nil { logrus.Errorf("failed to build TurboOCIv1 image: %v", err) os.Exit(1) } @@ -168,6 +160,7 @@ func init() { rootCmd.Flags().StringVar(&overlaybd, "overlaybd", "", "build overlaybd format") rootCmd.Flags().StringVar(&dbstr, "db-str", "", "db str for overlaybd conversion") rootCmd.Flags().StringVar(&dbType, "db-type", "", "type of db to use for conversion deduplication. Available: mysql. Default none") + rootCmd.Flags().IntVar(&concurrencyLimit, "concurrency-limit", 4, "the number of manifests that can be built at the same time, used for multi-arch images, 0 means no limit") // certification rootCmd.Flags().StringArrayVar(&certDirs, "cert-dir", nil, "In these directories, root CA should be named as *.crt and client cert should be named as *.cert, *.key") diff --git a/docs/BUILDING.md b/docs/BUILDING.md index e39b3780..c82bf8da 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -11,7 +11,7 @@ This doc includes: ## Requirements -* Install Go >= 1.16.x +* Install Go >= 1.19.x * Install runc >= 1.0 * Install containerd >= 1.4.x (1.6.x is preferred) * See [Downloads at containerd.io](https://containerd.io/downloads/). @@ -61,4 +61,4 @@ sudo bin/overlaybd-snapshotter # restart containerd sudo systemctl restart containerd -``` \ No newline at end of file +``` diff --git a/docs/USERSPACE_CONVERTOR.md b/docs/USERSPACE_CONVERTOR.md index afdec708..d0b35dd7 100644 --- a/docs/USERSPACE_CONVERTOR.md +++ b/docs/USERSPACE_CONVERTOR.md @@ -49,6 +49,7 @@ Flags: --overlaybd string build overlaybd format --db-str string db str for overlaybd conversion --db-type string type of db to use for conversion deduplication. Available: mysql. Default none + --concurrency-limit int the number of manifests that can be built at the same time, used for multi-arch images, 0 means no limit (default 4) --cert-dir stringArray In these directories, root CA should be named as *.crt and client cert should be named as *.cert, *.key --root-ca stringArray root CA certificates --client-cert stringArray client cert certificates, should form in ${cert-file}:${key-file} diff --git a/go.mod b/go.mod index 1d117866..a84e2cbe 100644 --- a/go.mod +++ b/go.mod @@ -10,17 +10,17 @@ require ( github.com/moby/locker v1.0.1 github.com/moby/sys/mountinfo v0.6.2 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b + github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/runtime-spec v1.1.0-rc.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.1.3 github.com/urfave/cli v1.22.12 - golang.org/x/sync v0.3.0 + golang.org/x/sync v0.4.0 golang.org/x/sys v0.13.0 google.golang.org/grpc v1.58.3 - oras.land/oras-go/v2 v2.1.0 + oras.land/oras-go/v2 v2.3.1 ) require ( diff --git a/go.sum b/go.sum index aef9dbab..a290498c 100644 --- a/go.sum +++ b/go.sum @@ -609,8 +609,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -930,8 +930,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1268,8 +1268,8 @@ k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -oras.land/oras-go/v2 v2.1.0 h1:1nS8BIeEP6CBVQifwxrsth2bkuD+cYfjp7Hf7smUcS8= -oras.land/oras-go/v2 v2.1.0/go.mod h1:v5ZSAPIMEJYnZjZ6rTGPAyaonH+rCFmbE95IAzCTeGU= +oras.land/oras-go/v2 v2.3.1 h1:lUC6q8RkeRReANEERLfH86iwGn55lbSWP20egdFHVec= +oras.land/oras-go/v2 v2.3.1/go.mod h1:5AQXVEu1X/FKp1F9DMOb5ZItZBOa0y5dha0yCm4NR9c= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=