From 996395111e1c3b0183ed91f1083c7aaeb210120b 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 | 16 ++++++++++++++++ pkg/build/build.go | 34 ++++++++++++++++++++++++++++++---- pkg/repository/repository.go | 12 ++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/cmd/medius/images/push.go b/cmd/medius/images/push.go index 3ad9f074..c0368510 100644 --- a/cmd/medius/images/push.go +++ b/cmd/medius/images/push.go @@ -134,6 +134,7 @@ func (b *buildAndPublish) Do(entry *common.Entry, timestamp time.Time) ([]string defer os.Remove(file) b.Log.Info("Building containerdisk ...") + // TODO: Fix arguments containerDisk, err := build.ContainerDisk(file, build.ContainerDiskConfig(artifactInfo.SHA256Sum, metadata.AdditionalLabels)) if err != nil { return nil, fmt.Errorf("error creating the containerdisk : %v", err) @@ -144,6 +145,7 @@ func (b *buildAndPublish) Do(entry *common.Entry, timestamp time.Time) ([]string names := prepareTags(timestamp, b.Options.PublishImagesOptions.TargetRegistry, entry, artifactInfo) for _, name := range names { + // TODO: Use b.pushImageIndex if err := b.pushImage(containerDisk, name); err != nil { return nil, err } @@ -261,6 +263,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..79600ec0 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -7,12 +7,13 @@ 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" + LabelShaSum = "shasum" + ImageOS = "linux" ) func ContainerDiskConfig(checksum string, additionalLabels map[string]string) v1.Config { @@ -34,7 +35,7 @@ func ContainerDiskConfig(checksum string, additionalLabels map[string]string) v1 return v1.Config{Labels: labels, Env: env} } -func ContainerDisk(imgPath string, config v1.Config) (v1.Image, error) { +func ContainerDisk(imgPath, imageArchitecture string, config v1.Config) (v1.Image, error) { img := empty.Image layer, err := tarball.LayerFromOpener(StreamLayerOpener(imgPath)) if err != nil { @@ -52,7 +53,8 @@ func ContainerDisk(imgPath string, config v1.Config) (v1.Image, error) { } // Modify the config file - cf.Architecture = ImageArchitecture + cf.Architecture = imageArchitecture + cf.OS = ImageOS cf.Config = config img, err = mutate.ConfigFile(img, cf) @@ -62,3 +64,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),