From a4f4ac881a4848532f8ca4c30b03c286cbba12f8 Mon Sep 17 00:00:00 2001 From: Ben Oukhanov Date: Wed, 21 Feb 2024 14:23:57 +0000 Subject: [PATCH] feat: arm containerdisks Build and push multiple containerdisks with different CPU architectures (x64 or aarch64). Jira-Url: https://issues.redhat.com/browse/CNV-38597 Signed-off-by: Ben Oukhanov --- cmd/medius/images/push.go | 22 +++++++++++++++++++++- pkg/build/build.go | 27 +++++++++++++++++++++++++++ pkg/repository/repository.go | 12 ++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/cmd/medius/images/push.go b/cmd/medius/images/push.go index 3ad9f074..42f76397 100644 --- a/cmd/medius/images/push.go +++ b/cmd/medius/images/push.go @@ -142,9 +142,15 @@ func (b *buildAndPublish) Do(entry *common.Entry, timestamp time.Time) ([]string return nil, b.Ctx.Err() } + b.Log.Info("Building containerdisk index ...") + containerDiskIndex, err := build.ContainerDiskIndex([]v1.Image{containerDisk}) + if err != nil { + return nil, fmt.Errorf("error creating the containerdisk index : %v", err) + } + names := prepareTags(timestamp, b.Options.PublishImagesOptions.TargetRegistry, entry, artifactInfo) for _, name := range names { - if err := b.pushImage(containerDisk, name); err != nil { + if err := b.pushImageIndex(containerDiskIndex, name); err != nil { return nil, err } if errors.Is(b.Ctx.Err(), context.Canceled) { @@ -261,6 +267,20 @@ func (b *buildAndPublish) pushImage(containerDisk v1.Image, name string) error { return nil } +func (b *buildAndPublish) pushImageIndex(containerDiskIndex v1.ImageIndex, name string) error { + if !b.Options.DryRun { + b.Log.Infof("Pushing %s image index", name) + if err := b.Repo.PushImageIndex(b.Ctx, containerDiskIndex, name); err != nil { + b.Log.WithError(err).Error("Failed to push image image") + return err + } + } else { + b.Log.Infof("Dry run enabled, not pushing %s image index", name) + } + + return nil +} + func prepareTags(timestamp time.Time, registry string, entry *common.Entry, artifactDetails *api.ArtifactDetails) []string { metadata := entry.Artifact.Metadata() imageName := path.Join(registry, metadata.Describe()) diff --git a/pkg/build/build.go b/pkg/build/build.go index 161ed577..a24045b1 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -7,12 +7,14 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/tarball" ) const ( LabelShaSum = "shasum" ImageArchitecture = "amd64" + ImageOS = "linux" ) func ContainerDiskConfig(checksum string, additionalLabels map[string]string) v1.Config { @@ -53,6 +55,7 @@ func ContainerDisk(imgPath string, config v1.Config) (v1.Image, error) { // Modify the config file cf.Architecture = ImageArchitecture + cf.OS = ImageOS cf.Config = config img, err = mutate.ConfigFile(img, cf) @@ -62,3 +65,27 @@ func ContainerDisk(imgPath string, config v1.Config) (v1.Image, error) { return img, nil } + +func ContainerDiskIndex(images []v1.Image) (v1.ImageIndex, error) { + indexAddendum := make([]mutate.IndexAddendum, 0, len(images)) + + for _, image := range images { + configFile, err := image.ConfigFile() + if err != nil { + return nil, err + } + + descriptor, err := partial.Descriptor(image) + if err != nil { + return nil, err + } + descriptor.Platform = configFile.Platform() + + indexAddendum = append(indexAddendum, mutate.IndexAddendum{ + Add: image, + Descriptor: *descriptor, + }) + } + + return mutate.AppendManifests(empty.Index, indexAddendum...), nil +} diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go index d1b2c63f..64736284 100644 --- a/pkg/repository/repository.go +++ b/pkg/repository/repository.go @@ -12,7 +12,9 @@ import ( "github.com/docker/distribution/registry/api/errcode" v2 "github.com/docker/distribution/registry/api/v2" "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/pkg/errors" ) @@ -30,6 +32,7 @@ type ImageInfo struct { type Repository interface { ImageMetadata(imgRef string, insecure bool) (*ImageInfo, error) PushImage(ctx context.Context, img v1.Image, imgRef string) error + PushImageIndex(ctx context.Context, img v1.ImageIndex, imgRef string) error CopyImage(ctx context.Context, srcRef, dstRef string, insecure bool) error } @@ -82,6 +85,15 @@ func (r RepositoryImpl) PushImage(ctx context.Context, img v1.Image, imgRef stri return crane.Push(img, imgRef, crane.WithContext(ctx)) } +func (r RepositoryImpl) PushImageIndex(ctx context.Context, imageIndex v1.ImageIndex, imageRef string) error { + ref, err := name.ParseReference(imageRef) + if err != nil { + return err + } + + return remote.WriteIndex(ref, imageIndex, remote.WithContext(ctx)) +} + func (r RepositoryImpl) CopyImage(ctx context.Context, srcRef, dstRef string, insecure bool) error { options := []crane.Option{ crane.WithContext(ctx),