From 5eafd3b73bf020cdf7ae8e413645c8481e4e9f5c Mon Sep 17 00:00:00 2001 From: Radu M Date: Tue, 8 Oct 2019 22:11:50 +0300 Subject: [PATCH] Update cnab-to-oci to v0.2.0-beta1 (#639) Signed-off-by: Radu M --- Gopkg.lock | 7 +- Gopkg.toml | 3 +- pkg/cnab/cnab-to-oci/registry.go | 6 +- .../docker/cnab-to-oci/converter/convert.go | 215 ++++++++---------- .../docker/cnab-to-oci/converter/types.go | 51 ++--- .../docker/cnab-to-oci/relocation/types.go | 4 + .../docker/cnab-to-oci/remotes/fixup.go | 84 ++++--- .../cnab-to-oci/remotes/fixuphelpers.go | 6 +- .../cnab-to-oci/remotes/fixupoptions.go | 9 + .../docker/cnab-to-oci/remotes/pull.go | 47 ++-- .../docker/cnab-to-oci/remotes/push.go | 54 +++-- 11 files changed, 260 insertions(+), 226 deletions(-) create mode 100644 vendor/github.com/docker/cnab-to-oci/relocation/types.go diff --git a/Gopkg.lock b/Gopkg.lock index 3251a74f3..4b84b6977 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -330,15 +330,16 @@ revision = "f95ca8e1ba6c22c9abcdbf65e8dcc39c53958bba" [[projects]] - branch = "master" - digest = "1:a9d1406d7380d50675fddc88442cecdbfbdd069bc24191171ae901719cd4c79b" + digest = "1:51fef110ff737b08bebfa091471714db028ebcbeda6a3cad8ca4512b39b34581" name = "github.com/docker/cnab-to-oci" packages = [ "converter", + "relocation", "remotes", ] pruneopts = "NUT" - revision = "85061934a54630aec0dd4adbe6427c10bd09a658" + revision = "c33e316902ce0e44adc6e14731c7241286d17d8e" + version = "v0.2.0-beta1" [[projects]] digest = "1:95f17095fc25ae7c9de6adbe34c048ea6102b0a3999c6fcf03fc663ab536c602" diff --git a/Gopkg.toml b/Gopkg.toml index 8132ff6cc..e21191aaf 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -7,10 +7,9 @@ version = "v0.5.0-beta1" -# Using master until there is a release of cnab-to-oci [[constraint]] name = "github.com/docker/cnab-to-oci" - branch = "master" + version = "v0.2.0-beta1" [[constraint]] name = "github.com/carolynvs/datetime-printer" diff --git a/pkg/cnab/cnab-to-oci/registry.go b/pkg/cnab/cnab-to-oci/registry.go index 81b98a277..68a3bc647 100644 --- a/pkg/cnab/cnab-to-oci/registry.go +++ b/pkg/cnab/cnab-to-oci/registry.go @@ -43,7 +43,7 @@ func (r *Registry) PullBundle(tag string, insecureRegistry bool) (*bundle.Bundle insecureRegistries = append(insecureRegistries, reg) } - bun, err := remotes.Pull(context.Background(), ref, r.createResolver(insecureRegistries)) + bun, _, err := remotes.Pull(context.Background(), ref, r.createResolver(insecureRegistries)) if err != nil { return nil, errors.Wrap(err, "unable to pull remote bundle") } @@ -63,11 +63,11 @@ func (r *Registry) PushBundle(bun *bundle.Bundle, tag string, insecureRegistry b resolver := r.createResolver(insecureRegistries) - err = remotes.FixupBundle(context.Background(), bun, ref, resolver, remotes.WithEventCallback(r.displayEvent)) + rm, err := remotes.FixupBundle(context.Background(), bun, ref, resolver, remotes.WithEventCallback(r.displayEvent), remotes.WithAutoBundleUpdate()) if err != nil { return err } - d, err := remotes.Push(context.Background(), bun, ref, resolver, true) + d, err := remotes.Push(context.Background(), bun, rm, ref, resolver, true) if err != nil { return err } diff --git a/vendor/github.com/docker/cnab-to-oci/converter/convert.go b/vendor/github.com/docker/cnab-to-oci/converter/convert.go index 59dc017cb..35a5f8307 100644 --- a/vendor/github.com/docker/cnab-to-oci/converter/convert.go +++ b/vendor/github.com/docker/cnab-to-oci/converter/convert.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/images" "github.com/deislabs/cnab-go/bundle" + "github.com/docker/cnab-to-oci/relocation" "github.com/docker/distribution/reference" ocischema "github.com/opencontainers/image-spec/specs-go" ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -60,12 +61,13 @@ func GetBundleConfigManifestDescriptor(ix *ocischemav1.Index) (ocischemav1.Descr } // ConvertBundleToOCIIndex converts a CNAB bundle into an OCI Index representation -func ConvertBundleToOCIIndex(b *bundle.Bundle, targetRef reference.Named, bundleConfigManifestRef ocischemav1.Descriptor) (*ocischemav1.Index, error) { +func ConvertBundleToOCIIndex(b *bundle.Bundle, targetRef reference.Named, + bundleConfigManifestRef ocischemav1.Descriptor, relocationMap relocation.ImageRelocationMap) (*ocischemav1.Index, error) { annotations, err := makeAnnotations(b) if err != nil { return nil, err } - manifests, err := makeManifests(b, targetRef, bundleConfigManifestRef) + manifests, err := makeManifests(b, targetRef, bundleConfigManifestRef, relocationMap) if err != nil { return nil, err } @@ -79,24 +81,59 @@ func ConvertBundleToOCIIndex(b *bundle.Bundle, targetRef reference.Named, bundle return &result, nil } -// ConvertOCIIndexToBundle converts an OCI index to a CNAB bundle representation -func ConvertOCIIndexToBundle(ix *ocischemav1.Index, config *BundleConfig, originRepo reference.Named) (*bundle.Bundle, error) { - b := &bundle.Bundle{ - SchemaVersion: CNABVersion, - Actions: config.Actions, - Credentials: config.Credentials, - Definitions: config.Definitions, - Parameters: config.Parameters, - Outputs: config.Outputs, - Custom: config.Custom, - } - if err := parseTopLevelAnnotations(ix.Annotations, b); err != nil { - return nil, err - } - if err := parseManifests(ix.Manifests, b, originRepo); err != nil { - return nil, err +// GenerateRelocationMap generates the bundle relocation map +func GenerateRelocationMap(ix *ocischemav1.Index, b *bundle.Bundle, originRepo reference.Named) (relocation.ImageRelocationMap, error) { + relocationMap := relocation.ImageRelocationMap{} + + for _, d := range ix.Manifests { + switch d.MediaType { + case ocischemav1.MediaTypeImageManifest, ocischemav1.MediaTypeImageIndex: + case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList: + default: + return nil, fmt.Errorf("unsupported manifest descriptor %q with mediatype %q", d.Digest, d.MediaType) + } + descriptorType, ok := d.Annotations[CNABDescriptorTypeAnnotation] + if !ok { + return nil, fmt.Errorf("manifest descriptor %q has no CNAB descriptor type annotation %q", d.Digest, CNABDescriptorTypeAnnotation) + } + if descriptorType == CNABDescriptorTypeConfig { + continue + } + // strip tag/digest from originRepo + originRepo, err := reference.ParseNormalizedNamed(originRepo.Name()) + if err != nil { + return nil, fmt.Errorf("failed to create a digested reference for manifest descriptor %q: %s", d.Digest, err) + } + ref, err := reference.WithDigest(originRepo, d.Digest) + if err != nil { + return nil, fmt.Errorf("failed to create a digested reference for manifest descriptor %q: %s", d.Digest, err) + } + refFamiliar := reference.FamiliarString(ref) + switch descriptorType { + // The current descriptor is an invocation image + case CNABDescriptorTypeInvocation: + if len(b.InvocationImages) == 0 { + return nil, fmt.Errorf("unknown invocation image: %q", d.Digest) + } + relocationMap[b.InvocationImages[0].Image] = refFamiliar + + // The current descriptor is a component image + case CNABDescriptorTypeComponent: + componentName, ok := d.Annotations[CNABDescriptorComponentNameAnnotation] + if !ok { + return nil, fmt.Errorf("component name missing in descriptor %q", d.Digest) + } + c, ok := b.Images[componentName] + if !ok { + return nil, fmt.Errorf("component %q not found in bundle", componentName) + } + relocationMap[c.Image] = refFamiliar + default: + return nil, fmt.Errorf("invalid CNAB descriptor type %q in descriptor %q", descriptorType, d.Digest) + } } - return b, nil + + return relocationMap, nil } func makeAnnotations(b *bundle.Bundle) (map[string]string, error) { @@ -124,29 +161,8 @@ func makeAnnotations(b *bundle.Bundle) (map[string]string, error) { return result, nil } -func parseTopLevelAnnotations(annotations map[string]string, into *bundle.Bundle) error { - var ok bool - if into.Name, ok = annotations[ocischemav1.AnnotationTitle]; !ok { - return errors.New("manifest is missing title annotation " + ocischemav1.AnnotationTitle) - } - if into.Version, ok = annotations[ocischemav1.AnnotationVersion]; !ok { - return errors.New("manifest is missing version annotation " + ocischemav1.AnnotationVersion) - } - into.Description = annotations[ocischemav1.AnnotationDescription] - if maintainersJSON, ok := annotations[ocischemav1.AnnotationAuthors]; ok { - if err := json.Unmarshal([]byte(maintainersJSON), &into.Maintainers); err != nil { - return fmt.Errorf("unable to parse maintainers: %s", err) - } - } - if keywordsJSON, ok := annotations[CNABKeywordsAnnotation]; ok { - if err := json.Unmarshal([]byte(keywordsJSON), &into.Keywords); err != nil { - return fmt.Errorf("unable to parse keywords: %s", err) - } - } - return nil -} - -func makeManifests(b *bundle.Bundle, targetReference reference.Named, bundleConfigManifestReference ocischemav1.Descriptor) ([]ocischemav1.Descriptor, error) { +func makeManifests(b *bundle.Bundle, targetReference reference.Named, + bundleConfigManifestReference ocischemav1.Descriptor, relocationMap relocation.ImageRelocationMap) ([]ocischemav1.Descriptor, error) { if len(b.InvocationImages) != 1 { return nil, errors.New("only one invocation image supported") } @@ -155,7 +171,7 @@ func makeManifests(b *bundle.Bundle, targetReference reference.Named, bundleConf } bundleConfigManifestReference.Annotations[CNABDescriptorTypeAnnotation] = CNABDescriptorTypeConfig manifests := []ocischemav1.Descriptor{bundleConfigManifestReference} - invocationImage, err := makeDescriptor(b.InvocationImages[0].BaseImage, targetReference) + invocationImage, err := makeDescriptor(b.InvocationImages[0].BaseImage, targetReference, relocationMap) if err != nil { return nil, fmt.Errorf("invalid invocation image: %s", err) } @@ -166,7 +182,7 @@ func makeManifests(b *bundle.Bundle, targetReference reference.Named, bundleConf images := makeSortedImages(b.Images) for _, name := range images { img := b.Images[name] - image, err := makeDescriptor(img.BaseImage, targetReference) + image, err := makeDescriptor(img.BaseImage, targetReference, relocationMap) if err != nil { return nil, fmt.Errorf("invalid image: %s", err) } @@ -188,92 +204,57 @@ func makeSortedImages(images map[string]bundle.Image) []string { return result } -func parseManifests(descriptors []ocischemav1.Descriptor, into *bundle.Bundle, originRepo reference.Named) error { - for _, d := range descriptors { - var imageType string - switch d.MediaType { - case ocischemav1.MediaTypeImageManifest, ocischemav1.MediaTypeImageIndex: - imageType = "oci" - case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList: - imageType = "docker" - default: - return fmt.Errorf("unsupported manifest descriptor %q with mediatype %q", d.Digest, d.MediaType) - } - descriptorType, ok := d.Annotations[CNABDescriptorTypeAnnotation] - if !ok { - return fmt.Errorf("manifest descriptor %q has no CNAB descriptor type annotation %q", d.Digest, CNABDescriptorTypeAnnotation) - } - if descriptorType == CNABDescriptorTypeConfig { - continue - } - // strip tag/digest from originRepo - originRepo, err := reference.ParseNormalizedNamed(originRepo.Name()) - if err != nil { - return fmt.Errorf("failed to create a digested reference for manifest descriptor %q: %s", d.Digest, err) - } - ref, err := reference.WithDigest(originRepo, d.Digest) - if err != nil { - return fmt.Errorf("failed to create a digested reference for manifest descriptor %q: %s", d.Digest, err) - } - refFamiliar := reference.FamiliarString(ref) - switch descriptorType { - // The current descriptor is an invocation image - case CNABDescriptorTypeInvocation: - into.InvocationImages = append(into.InvocationImages, bundle.InvocationImage{ - BaseImage: bundle.BaseImage{ - Image: refFamiliar, - ImageType: imageType, - MediaType: d.MediaType, - Size: uint64(d.Size), - }, - }) - // The current descriptor is a component image - case CNABDescriptorTypeComponent: - componentName, ok := d.Annotations[CNABDescriptorComponentNameAnnotation] - if !ok { - return fmt.Errorf("component name missing in descriptor %q", d.Digest) - } - if into.Images == nil { - into.Images = make(map[string]bundle.Image) - } - into.Images[componentName] = bundle.Image{ - BaseImage: bundle.BaseImage{ - Image: refFamiliar, - ImageType: imageType, - MediaType: d.MediaType, - Size: uint64(d.Size), - }, - } - default: - return fmt.Errorf("invalid CNAB descriptor type %q in descriptor %q", descriptorType, d.Digest) - } +func makeDescriptor(baseImage bundle.BaseImage, targetReference reference.Named, relocationMap relocation.ImageRelocationMap) (ocischemav1.Descriptor, error) { + relocatedImage, ok := relocationMap[baseImage.Image] + if !ok { + return ocischemav1.Descriptor{}, fmt.Errorf("image %q not present in the relocation map", baseImage.Image) } - return nil -} -func makeDescriptor(baseImage bundle.BaseImage, targetReference reference.Named) (ocischemav1.Descriptor, error) { - named, err := reference.ParseNormalizedNamed(baseImage.Image) + named, err := reference.ParseNormalizedNamed(relocatedImage) if err != nil { - return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not a valid image reference: %s", baseImage.Image, err) + return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not a valid image reference: %s", relocatedImage, err) } if named.Name() != targetReference.Name() { - return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not in the same repository as %q", baseImage.Image, targetReference.String()) + return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not in the same repository as %q", relocatedImage, targetReference.String()) } digested, ok := named.(reference.Digested) if !ok { - return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not a digested reference", baseImage.Image) + return ocischemav1.Descriptor{}, fmt.Errorf("image %q is not a digested reference", relocatedImage) + } + mediaType, err := getMediaType(baseImage, relocatedImage) + if err != nil { + return ocischemav1.Descriptor{}, err + } + if baseImage.Size == 0 { + return ocischemav1.Descriptor{}, fmt.Errorf("image %q size is not set", relocatedImage) + } + + return ocischemav1.Descriptor{ + Digest: digested.Digest(), + MediaType: mediaType, + Size: int64(baseImage.Size), + }, nil +} + +func getMediaType(baseImage bundle.BaseImage, relocatedImage string) (string, error) { + mediaType := baseImage.MediaType + if mediaType == "" { + switch baseImage.ImageType { + case "docker": + mediaType = images.MediaTypeDockerSchema2Manifest + case "oci": + mediaType = ocischemav1.MediaTypeImageManifest + default: + return "", fmt.Errorf("unsupported image type %q for image %q", baseImage.ImageType, relocatedImage) + } } - switch baseImage.MediaType { + switch mediaType { case ocischemav1.MediaTypeImageManifest: case images.MediaTypeDockerSchema2Manifest: case ocischemav1.MediaTypeImageIndex: case images.MediaTypeDockerSchema2ManifestList: default: - return ocischemav1.Descriptor{}, fmt.Errorf("unsupported media type %q for image %q", baseImage.MediaType, baseImage.Image) + return "", fmt.Errorf("unsupported media type %q for image %q", baseImage.MediaType, relocatedImage) } - return ocischemav1.Descriptor{ - Digest: digested.Digest(), - MediaType: baseImage.MediaType, - Size: int64(baseImage.Size), - }, nil + return mediaType, nil } diff --git a/vendor/github.com/docker/cnab-to-oci/converter/types.go b/vendor/github.com/docker/cnab-to-oci/converter/types.go index 637bb936f..177022123 100644 --- a/vendor/github.com/docker/cnab-to-oci/converter/types.go +++ b/vendor/github.com/docker/cnab-to-oci/converter/types.go @@ -1,13 +1,10 @@ package converter import ( - "encoding/json" - - "github.com/deislabs/cnab-go/bundle/definition" - "github.com/deislabs/cnab-go/bundle" "github.com/docker/distribution" "github.com/docker/distribution/manifest/schema2" + "github.com/docker/go/canonical/json" digest "github.com/opencontainers/go-digest" ocischema "github.com/opencontainers/image-spec/specs-go" ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -18,17 +15,6 @@ const ( CNABConfigMediaType = "application/vnd.cnab.config.v1+json" ) -// BundleConfig describes a cnab bundle runtime config -type BundleConfig struct { - SchemaVersion string `json:"schemaVersion" mapstructure:"schemaVersion"` - Actions map[string]bundle.Action `json:"actions,omitempty" mapstructure:"actions,omitempty"` - Definitions definition.Definitions `json:"definitions" mapstructure:"definitions"` - Parameters map[string]bundle.Parameter `json:"parameters" mapstructure:"parameters"` - Outputs map[string]bundle.Output `json:"outputs" mapstructure:"outputs"` - Credentials map[string]bundle.Credential `json:"credentials" mapstructure:"credentials"` - Custom map[string]interface{} `json:"custom,omitempty" mapstructure:"custom"` -} - // PreparedBundleConfig contains the config blob, image manifest (and fallback), and descriptors for a CNAB config type PreparedBundleConfig struct { ConfigBlob []byte @@ -38,22 +24,9 @@ type PreparedBundleConfig struct { Fallback *PreparedBundleConfig } -// CreateBundleConfig creates a bundle config from a CNAB -func CreateBundleConfig(b *bundle.Bundle) *BundleConfig { - return &BundleConfig{ - SchemaVersion: CNABVersion, - Actions: b.Actions, - Definitions: b.Definitions, - Parameters: b.Parameters, - Outputs: b.Outputs, - Credentials: b.Credentials, - Custom: b.Custom, - } -} - // PrepareForPush serializes a bundle config, generates its image manifest, and its manifest descriptor -func (c *BundleConfig) PrepareForPush() (*PreparedBundleConfig, error) { - blob, err := json.Marshal(c) +func PrepareForPush(b *bundle.Bundle) (*PreparedBundleConfig, error) { + blob, err := json.MarshalCanonical(b) if err != nil { return nil, err } @@ -109,14 +82,24 @@ func prepareOCIBundleConfig(mediaType string) bundleConfigPreparer { } } +func nonOCIDescriptorOf(blob []byte) distribution.Descriptor { + return distribution.Descriptor{ + MediaType: schema2.MediaTypeImageConfig, + Size: int64(len(blob)), + Digest: digest.FromBytes(blob), + } +} + func prepareNonOCIBundleConfig(blob []byte) (*PreparedBundleConfig, error) { + desc := nonOCIDescriptorOf(blob) man, err := schema2.FromStruct(schema2.Manifest{ Versioned: schema2.SchemaVersion, - Config: distribution.Descriptor{ - MediaType: schema2.MediaTypeImageConfig, - Size: int64(len(blob)), - Digest: digest.FromBytes(blob), + // Add a descriptor for the configuration because some registries + // require the layers property to be defined and non-empty + Layers: []distribution.Descriptor{ + desc, }, + Config: desc, }) if err != nil { return nil, err diff --git a/vendor/github.com/docker/cnab-to-oci/relocation/types.go b/vendor/github.com/docker/cnab-to-oci/relocation/types.go new file mode 100644 index 000000000..ffe4ea78f --- /dev/null +++ b/vendor/github.com/docker/cnab-to-oci/relocation/types.go @@ -0,0 +1,4 @@ +package relocation + +// ImageRelocationMap stores the mapping between the original image reference as key, and the relocated reference as a value. +type ImageRelocationMap map[string]string diff --git a/vendor/github.com/docker/cnab-to-oci/remotes/fixup.go b/vendor/github.com/docker/cnab-to-oci/remotes/fixup.go index cf811ca81..4403940a0 100644 --- a/vendor/github.com/docker/cnab-to-oci/remotes/fixup.go +++ b/vendor/github.com/docker/cnab-to-oci/remotes/fixup.go @@ -11,20 +11,21 @@ import ( "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" "github.com/deislabs/cnab-go/bundle" + "github.com/docker/cnab-to-oci/relocation" "github.com/docker/distribution/reference" ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" ) // FixupBundle checks that all the references are present in the referenced repository, otherwise it will mount all // the manifests to that repository. The bundle is then patched with the new digested references. -func FixupBundle(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver remotes.Resolver, opts ...FixupOption) error { +func FixupBundle(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver remotes.Resolver, opts ...FixupOption) (relocation.ImageRelocationMap, error) { logger := log.G(ctx) logger.Debugf("Fixing up bundle %s", ref) - // Configure the fixup and the even loop + // Configure the fixup and the event loop cfg, err := newFixupConfig(b, ref, resolver, opts...) if err != nil { - return err + return nil, err } events := make(chan FixupEvent) @@ -43,37 +44,64 @@ func FixupBundle(ctx context.Context, b *bundle.Bundle, ref reference.Named, res // Fixup invocation images if len(b.InvocationImages) != 1 { - return fmt.Errorf("only one invocation image supported for bundle %q", ref) + return nil, fmt.Errorf("only one invocation image supported for bundle %q", ref) } - if b.InvocationImages[0].BaseImage, err = fixupImage(ctx, b.InvocationImages[0].BaseImage, cfg, events, cfg.invocationImagePlatformFilter); err != nil { - return err + + relocationMap := relocation.ImageRelocationMap{} + if err := fixupImage(ctx, &b.InvocationImages[0].BaseImage, relocationMap, cfg, events, cfg.invocationImagePlatformFilter); err != nil { + return nil, err } // Fixup images for name, original := range b.Images { - if original.BaseImage, err = fixupImage(ctx, original.BaseImage, cfg, events, cfg.componentImagePlatformFilter); err != nil { - return err + if err := fixupImage(ctx, &original.BaseImage, relocationMap, cfg, events, cfg.componentImagePlatformFilter); err != nil { + return nil, err } b.Images[name] = original } logger.Debug("Bundle fixed") - return nil + return relocationMap, nil } -func fixupImage(ctx context.Context, baseImage bundle.BaseImage, cfg fixupConfig, events chan<- FixupEvent, platformFilter platforms.Matcher) (bundle.BaseImage, error) { - log.G(ctx).Debugf("Fixing image %s", baseImage.Image) +func fixupImage(ctx context.Context, baseImage *bundle.BaseImage, relocationMap relocation.ImageRelocationMap, cfg fixupConfig, events chan<- FixupEvent, platformFilter platforms.Matcher) error { + log.G(ctx).Debugf("Updating entry in relocation map for %q", baseImage.Image) ctx = withMutedContext(ctx) notifyEvent, progress := makeEventNotifier(events, baseImage.Image, cfg.targetRef) notifyEvent(FixupEventTypeCopyImageStart, "", nil) // Fixup Base image - fixupInfo, err := fixupBaseImage(ctx, &baseImage, cfg.targetRef, cfg.resolver) + fixupInfo, err := fixupBaseImage(ctx, baseImage, cfg.targetRef, cfg.resolver) if err != nil { return notifyError(notifyEvent, err) } + // Update the relocation map with the original image name and the digested reference of the image pushed inside the bundle repository + newRef, err := reference.WithDigest(fixupInfo.targetRepo, fixupInfo.resolvedDescriptor.Digest) + if err != nil { + return err + } + + relocationMap[baseImage.Image] = newRef.String() + + // if the autoUpdateBundle flag is passed, mutate the bundle with the resolved digest, mediaType, and size + if cfg.autoBundleUpdate { + baseImage.Digest = fixupInfo.resolvedDescriptor.Digest.String() + baseImage.Size = uint64(fixupInfo.resolvedDescriptor.Size) + baseImage.MediaType = fixupInfo.resolvedDescriptor.MediaType + } else { + if baseImage.Digest != fixupInfo.resolvedDescriptor.Digest.String() { + return fmt.Errorf("image %q digest differs %q after fixup: %q", baseImage.Image, baseImage.Digest, fixupInfo.resolvedDescriptor.Digest.String()) + } + if baseImage.Size != uint64(fixupInfo.resolvedDescriptor.Size) { + return fmt.Errorf("image %q size differs %d after fixup: %d", baseImage.Image, baseImage.Size, fixupInfo.resolvedDescriptor.Size) + } + if baseImage.MediaType != fixupInfo.resolvedDescriptor.MediaType { + return fmt.Errorf("image %q media type differs %q after fixup: %q", baseImage.Image, baseImage.MediaType, fixupInfo.resolvedDescriptor.MediaType) + } + } + if fixupInfo.sourceRef.Name() == fixupInfo.targetRepo.Name() { notifyEvent(FixupEventTypeCopyImageEnd, "Nothing to do: image reference is already present in repository"+fixupInfo.targetRepo.String(), nil) - return baseImage, nil + return nil } sourceFetcher, err := makeSourceFetcher(ctx, cfg.resolver, fixupInfo.sourceRef.Name()) @@ -82,7 +110,7 @@ func fixupImage(ctx context.Context, baseImage bundle.BaseImage, cfg fixupConfig } // Fixup platforms - if err := fixupPlatforms(ctx, &baseImage, &fixupInfo, sourceFetcher, platformFilter); err != nil { + if err := fixupPlatforms(ctx, baseImage, relocationMap, &fixupInfo, sourceFetcher, platformFilter); err != nil { return notifyError(notifyEvent, err) } @@ -97,12 +125,21 @@ func fixupImage(ctx context.Context, baseImage bundle.BaseImage, cfg fixupConfig } notifyEvent(FixupEventTypeCopyImageEnd, "", nil) - return baseImage, nil + return nil } -func fixupPlatforms(ctx context.Context, baseImage *bundle.BaseImage, fixupInfo *imageFixupInfo, sourceFetcher sourceFetcherAdder, filter platforms.Matcher) error { +func fixupPlatforms(ctx context.Context, + baseImage *bundle.BaseImage, + relocationMap relocation.ImageRelocationMap, + fixupInfo *imageFixupInfo, + sourceFetcher sourceFetcherAdder, + filter platforms.Matcher) error { + + logger := log.G(ctx) + logger.Debugf("Fixup platforms for image %v, with relocation map %v", baseImage, relocationMap) if filter == nil || - (fixupInfo.resolvedDescriptor.MediaType != ocischemav1.MediaTypeImageIndex && fixupInfo.resolvedDescriptor.MediaType != images.MediaTypeDockerSchema2ManifestList) { + (fixupInfo.resolvedDescriptor.MediaType != ocischemav1.MediaTypeImageIndex && + fixupInfo.resolvedDescriptor.MediaType != images.MediaTypeDockerSchema2ManifestList) { // no platform filter if platform is empty, or if the descriptor is not an OCI Index / Docker Manifest list return nil } @@ -140,11 +177,7 @@ func fixupPlatforms(ctx context.Context, baseImage *bundle.BaseImage, fixupInfo descriptor.Digest = d descriptor.Size = int64(len(manifestBytes)) fixupInfo.resolvedDescriptor = descriptor - newRef, err := reference.WithDigest(fixupInfo.targetRepo, d) - if err != nil { - return err - } - baseImage.Image = newRef.String() + return nil } @@ -172,13 +205,6 @@ func fixupBaseImage(ctx context.Context, if err != nil { return imageFixupInfo{}, fmt.Errorf("failed to resolve %q, push the image to the registry before pushing the bundle: %s", sourceImageRef, err) } - digested, err := reference.WithDigest(targetRepoOnly, descriptor.Digest) - if err != nil { - return imageFixupInfo{}, err - } - baseImage.Image = reference.FamiliarString(digested) - baseImage.MediaType = descriptor.MediaType - baseImage.Size = uint64(descriptor.Size) return imageFixupInfo{ resolvedDescriptor: descriptor, sourceRef: sourceImageRef, diff --git a/vendor/github.com/docker/cnab-to-oci/remotes/fixuphelpers.go b/vendor/github.com/docker/cnab-to-oci/remotes/fixuphelpers.go index 980a52267..0255b319d 100644 --- a/vendor/github.com/docker/cnab-to-oci/remotes/fixuphelpers.go +++ b/vendor/github.com/docker/cnab-to-oci/remotes/fixuphelpers.go @@ -97,9 +97,9 @@ func makeManifestWalker(ctx context.Context, sourceFetcher remotes.Fetcher, return walker.walk(scheduler.ctx(), fixupInfo.resolvedDescriptor, nil), cleaner, nil } -func notifyError(notifyEvent eventNotifier, err error) (bundle.BaseImage, error) { +func notifyError(notifyEvent eventNotifier, err error) error { notifyEvent(FixupEventTypeCopyImageEnd, "", err) - return bundle.BaseImage{}, err + return err } func checkBaseImage(baseImage *bundle.BaseImage) error { @@ -119,7 +119,7 @@ func checkBaseImage(baseImage *bundle.BaseImage) error { case images.MediaTypeDockerSchema2ManifestList: case "": default: - return fmt.Errorf("image media type %q is not supported", baseImage.ImageType) + return fmt.Errorf("image media type %q is not supported", baseImage.MediaType) } return nil diff --git a/vendor/github.com/docker/cnab-to-oci/remotes/fixupoptions.go b/vendor/github.com/docker/cnab-to-oci/remotes/fixupoptions.go index 698fd3db8..118bbb3aa 100644 --- a/vendor/github.com/docker/cnab-to-oci/remotes/fixupoptions.go +++ b/vendor/github.com/docker/cnab-to-oci/remotes/fixupoptions.go @@ -25,6 +25,7 @@ type fixupConfig struct { resolver remotes.Resolver invocationImagePlatformFilter platforms.Matcher componentImagePlatformFilter platforms.Matcher + autoBundleUpdate bool } // FixupOption is a helper for configuring a FixupBundle @@ -105,3 +106,11 @@ func WithParallelism(maxConcurrentJobs int, jobsBufferLength int) FixupOption { return nil } } + +// WithAutoBundleUpdate updates the bundle with content digests and size provided by the registry +func WithAutoBundleUpdate() FixupOption { + return func(cfg *fixupConfig) error { + cfg.autoBundleUpdate = true + return nil + } +} diff --git a/vendor/github.com/docker/cnab-to-oci/remotes/pull.go b/vendor/github.com/docker/cnab-to-oci/remotes/pull.go index 143b4cc54..a212b8428 100644 --- a/vendor/github.com/docker/cnab-to-oci/remotes/pull.go +++ b/vendor/github.com/docker/cnab-to-oci/remotes/pull.go @@ -12,23 +12,28 @@ import ( "github.com/deislabs/cnab-go/bundle" "github.com/docker/cli/opts" "github.com/docker/cnab-to-oci/converter" + "github.com/docker/cnab-to-oci/relocation" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/client/auth" ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" ) // Pull pulls a bundle from an OCI Image Index manifest -func Pull(ctx context.Context, ref reference.Named, resolver remotes.Resolver) (*bundle.Bundle, error) { +func Pull(ctx context.Context, ref reference.Named, resolver remotes.Resolver) (*bundle.Bundle, relocation.ImageRelocationMap, error) { log.G(ctx).Debugf("Pulling CNAB Bundle %s", ref) index, err := getIndex(ctx, ref, resolver) if err != nil { - return nil, err + return nil, nil, err } - config, err := getConfig(ctx, ref, resolver, index) + b, err := getBundle(ctx, ref, resolver, index) if err != nil { - return nil, err + return nil, nil, err + } + relocationMap, err := converter.GenerateRelocationMap(&index, b, ref) + if err != nil { + return nil, nil, err } - return converter.ConvertOCIIndexToBundle(&index, &config, ref) + return b, relocationMap, nil } func getIndex(ctx context.Context, ref auth.Scope, resolver remotes.Resolver) (ocischemav1.Index, error) { @@ -58,25 +63,25 @@ func getIndex(ctx context.Context, ref auth.Scope, resolver remotes.Resolver) (o return index, nil } -func getConfig(ctx context.Context, ref opts.NamedOption, resolver remotes.Resolver, index ocischemav1.Index) (converter.BundleConfig, error) { +func getBundle(ctx context.Context, ref opts.NamedOption, resolver remotes.Resolver, index ocischemav1.Index) (*bundle.Bundle, error) { repoOnly, err := reference.ParseNormalizedNamed(ref.Name()) if err != nil { - return converter.BundleConfig{}, fmt.Errorf("invalid bundle config manifest reference name %q: %s", ref, err) + return nil, fmt.Errorf("invalid bundle manifest reference name %q: %s", ref, err) } // config is wrapped in an image manifest. So we first pull the manifest // and then the config blob within it configManifestDescriptor, err := getConfigManifestDescriptor(ctx, ref, index) if err != nil { - return converter.BundleConfig{}, err + return nil, err } manifest, err := getConfigManifest(ctx, ref, repoOnly, resolver, configManifestDescriptor) if err != nil { - return converter.BundleConfig{}, err + return nil, err } - // Pull now the config itself + // Pull now the bundle itself return getBundleConfig(ctx, ref, repoOnly, resolver, manifest) } @@ -114,13 +119,13 @@ func getConfigManifest(ctx context.Context, ref opts.NamedOption, repoOnly refer return manifest, err } -func getBundleConfig(ctx context.Context, ref opts.NamedOption, repoOnly reference.Named, resolver remotes.Resolver, manifest ocischemav1.Manifest) (converter.BundleConfig, error) { +func getBundleConfig(ctx context.Context, ref opts.NamedOption, repoOnly reference.Named, resolver remotes.Resolver, manifest ocischemav1.Manifest) (*bundle.Bundle, error) { logger := log.G(ctx) - logger.Debugf("Fetching Bundle Config %s", manifest.Config.Digest) + logger.Debugf("Fetching Bundle %s", manifest.Config.Digest) configRef, err := reference.WithDigest(repoOnly, manifest.Config.Digest) if err != nil { - return converter.BundleConfig{}, fmt.Errorf("invalid bundle config reference name %q: %s", ref, err) + return nil, fmt.Errorf("invalid bundle reference name %q: %s", ref, err) } configPayload, err := pullPayload(ctx, resolver, configRef.String(), ocischemav1.Descriptor{ Digest: manifest.Config.Digest, @@ -128,15 +133,15 @@ func getBundleConfig(ctx context.Context, ref opts.NamedOption, repoOnly referen Size: manifest.Config.Size, }) if err != nil { - return converter.BundleConfig{}, fmt.Errorf("failed to pull bundle config %q: %s", ref, err) + return nil, fmt.Errorf("failed to pull bundle %q: %s", ref, err) } - var config converter.BundleConfig - if err := json.Unmarshal(configPayload, &config); err != nil { - return converter.BundleConfig{}, fmt.Errorf("failed to pull bundle config %q: %s", ref, err) + var b bundle.Bundle + if err := json.Unmarshal(configPayload, &b); err != nil { + return nil, fmt.Errorf("failed to pull bundle %q: %s", ref, err) } - logPayload(logger, config) + logPayload(logger, b) - return config, nil + return &b, nil } func pullPayload(ctx context.Context, resolver remotes.Resolver, reference string, descriptor ocischemav1.Descriptor) ([]byte, error) { @@ -150,5 +155,7 @@ func pullPayload(ctx context.Context, resolver remotes.Resolver, reference strin return nil, err } defer reader.Close() - return ioutil.ReadAll(reader) + + result, err := ioutil.ReadAll(reader) + return result, err } diff --git a/vendor/github.com/docker/cnab-to-oci/remotes/push.go b/vendor/github.com/docker/cnab-to-oci/remotes/push.go index 7645a2c02..d72c4343d 100644 --- a/vendor/github.com/docker/cnab-to-oci/remotes/push.go +++ b/vendor/github.com/docker/cnab-to-oci/remotes/push.go @@ -11,6 +11,7 @@ import ( "github.com/containerd/containerd/remotes" "github.com/deislabs/cnab-go/bundle" "github.com/docker/cnab-to-oci/converter" + "github.com/docker/cnab-to-oci/relocation" "github.com/docker/distribution/reference" "github.com/opencontainers/go-digest" ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -21,7 +22,13 @@ import ( type ManifestOption func(*ocischemav1.Index) error // Push pushes a bundle as an OCI Image Index manifest -func Push(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver remotes.Resolver, allowFallbacks bool, options ...ManifestOption) (ocischemav1.Descriptor, error) { +func Push(ctx context.Context, + b *bundle.Bundle, + relocationMap relocation.ImageRelocationMap, + ref reference.Named, + resolver remotes.Resolver, + allowFallbacks bool, + options ...ManifestOption) (ocischemav1.Descriptor, error) { log.G(ctx).Debugf("Pushing CNAB Bundle %s", ref) confManifestDescriptor, err := pushConfig(ctx, b, ref, resolver, allowFallbacks) @@ -29,7 +36,7 @@ func Push(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver r return ocischemav1.Descriptor{}, err } - indexDescriptor, err := pushIndex(ctx, b, ref, resolver, allowFallbacks, confManifestDescriptor, options...) + indexDescriptor, err := pushIndex(ctx, b, relocationMap, ref, resolver, allowFallbacks, confManifestDescriptor, options...) if err != nil { return ocischemav1.Descriptor{}, err } @@ -46,7 +53,7 @@ func pushConfig(ctx context.Context, logger := log.G(ctx) logger.Debugf("Pushing CNAB Bundle Config") - bundleConfig, err := converter.CreateBundleConfig(b).PrepareForPush() + bundleConfig, err := converter.PrepareForPush(b) if err != nil { return ocischemav1.Descriptor{}, err } @@ -59,12 +66,12 @@ func pushConfig(ctx context.Context, return confManifestDescriptor, nil } -func pushIndex(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver remotes.Resolver, allowFallbacks bool, +func pushIndex(ctx context.Context, b *bundle.Bundle, relocationMap relocation.ImageRelocationMap, ref reference.Named, resolver remotes.Resolver, allowFallbacks bool, confManifestDescriptor ocischemav1.Descriptor, options ...ManifestOption) (ocischemav1.Descriptor, error) { logger := log.G(ctx) logger.Debug("Pushing CNAB Index") - indexDescriptor, indexPayload, err := prepareIndex(b, ref, confManifestDescriptor, options...) + indexDescriptor, indexPayload, err := prepareIndex(b, relocationMap, ref, confManifestDescriptor, options...) if err != nil { return ocischemav1.Descriptor{}, err } @@ -76,21 +83,23 @@ func pushIndex(ctx context.Context, b *bundle.Bundle, ref reference.Named, resol if err := pushPayload(ctx, resolver, ref.String(), indexDescriptor, indexPayload); err != nil { if !allowFallbacks { + logger.Debug("Not using fallbacks, giving up") return ocischemav1.Descriptor{}, err } + logger.Debugf("Unable to push OCI Index: %v", err) // retry with a docker manifestlist - return pushDockerManifestList(ctx, b, ref, resolver, confManifestDescriptor, options...) + return pushDockerManifestList(ctx, b, relocationMap, ref, resolver, confManifestDescriptor, options...) } logger.Debugf("CNAB Index pushed") return indexDescriptor, nil } -func pushDockerManifestList(ctx context.Context, b *bundle.Bundle, ref reference.Named, resolver remotes.Resolver, +func pushDockerManifestList(ctx context.Context, b *bundle.Bundle, relocationMap relocation.ImageRelocationMap, ref reference.Named, resolver remotes.Resolver, confManifestDescriptor ocischemav1.Descriptor, options ...ManifestOption) (ocischemav1.Descriptor, error) { logger := log.G(ctx) - indexDescriptor, indexPayload, err := prepareIndexNonOCI(b, ref, confManifestDescriptor, options...) + indexDescriptor, indexPayload, err := prepareIndexNonOCI(b, relocationMap, ref, confManifestDescriptor, options...) if err != nil { return ocischemav1.Descriptor{}, err } @@ -99,14 +108,21 @@ func pushDockerManifestList(ctx context.Context, b *bundle.Bundle, ref reference logger.Debug("Manifest list Descriptor") logPayload(logger, indexDescriptor) - if err := pushPayload(ctx, resolver, ref.String(), indexDescriptor, indexPayload); err != nil { + if err := pushPayload(ctx, + resolver, ref.String(), + indexDescriptor, + indexPayload); err != nil { return ocischemav1.Descriptor{}, err } return indexDescriptor, nil } -func prepareIndex(b *bundle.Bundle, ref reference.Named, confDescriptor ocischemav1.Descriptor, options ...ManifestOption) (ocischemav1.Descriptor, []byte, error) { - ix, err := convertIndexAndApplyOptions(b, ref, confDescriptor, options...) +func prepareIndex(b *bundle.Bundle, + relocationMap relocation.ImageRelocationMap, + ref reference.Named, + confDescriptor ocischemav1.Descriptor, + options ...ManifestOption) (ocischemav1.Descriptor, []byte, error) { + ix, err := convertIndexAndApplyOptions(b, relocationMap, ref, confDescriptor, options...) if err != nil { return ocischemav1.Descriptor{}, nil, err } @@ -127,8 +143,12 @@ type ociIndexWrapper struct { MediaType string `json:"mediaType,omitempty"` } -func convertIndexAndApplyOptions(b *bundle.Bundle, ref reference.Named, confDescriptor ocischemav1.Descriptor, options ...ManifestOption) (*ocischemav1.Index, error) { - ix, err := converter.ConvertBundleToOCIIndex(b, ref, confDescriptor) +func convertIndexAndApplyOptions(b *bundle.Bundle, + relocationMap relocation.ImageRelocationMap, + ref reference.Named, + confDescriptor ocischemav1.Descriptor, + options ...ManifestOption) (*ocischemav1.Index, error) { + ix, err := converter.ConvertBundleToOCIIndex(b, ref, confDescriptor, relocationMap) if err != nil { return nil, err } @@ -140,8 +160,12 @@ func convertIndexAndApplyOptions(b *bundle.Bundle, ref reference.Named, confDesc return ix, nil } -func prepareIndexNonOCI(b *bundle.Bundle, ref reference.Named, confDescriptor ocischemav1.Descriptor, options ...ManifestOption) (ocischemav1.Descriptor, []byte, error) { - ix, err := convertIndexAndApplyOptions(b, ref, confDescriptor, options...) +func prepareIndexNonOCI(b *bundle.Bundle, + relocationMap relocation.ImageRelocationMap, + ref reference.Named, + confDescriptor ocischemav1.Descriptor, + options ...ManifestOption) (ocischemav1.Descriptor, []byte, error) { + ix, err := convertIndexAndApplyOptions(b, relocationMap, ref, confDescriptor, options...) if err != nil { return ocischemav1.Descriptor{}, nil, err }