diff --git a/cmd/util.go b/cmd/util.go index ad8085152..634dd699c 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -120,6 +120,7 @@ func NewUnpackCommand() *cobra.Command { server, _ := cmd.Flags().GetString("auth-server-address") identity, _ := cmd.Flags().GetString("auth-identity-token") registryToken, _ := cmd.Flags().GetString("auth-registry-token") + platform, _ := cmd.Flags().GetString("platform") util.DefaultContext.Info("Downloading", image, "to", destination) auth := ®istrytypes.AuthConfig{ @@ -132,7 +133,7 @@ func NewUnpackCommand() *cobra.Command { } if !local && !strings.HasPrefix(image, filePrefix) { - info, err := docker.DownloadAndExtractDockerImage(util.DefaultContext, image, destination, auth, verify) + info, err := docker.DownloadAndExtractDockerImage(util.DefaultContext, image, destination, auth, verify, platform) if err != nil { util.DefaultContext.Error(err.Error()) os.Exit(1) @@ -140,7 +141,7 @@ func NewUnpackCommand() *cobra.Command { util.DefaultContext.Info(fmt.Sprintf("Pulled: %s %s", info.Target.Digest, info.Name)) util.DefaultContext.Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.Target.Size)))) } else { - info, err := docker.ExtractDockerImage(util.DefaultContext, image, destination) + info, err := docker.ExtractDockerImage(util.DefaultContext, image, destination, platform) if err != nil { util.DefaultContext.Error(err.Error()) os.Exit(1) @@ -158,6 +159,7 @@ func NewUnpackCommand() *cobra.Command { c.Flags().String("auth-registry-token", "", "Authentication registry token") c.Flags().Bool("verify", false, "Verify signed images to notary before to pull") c.Flags().Bool("local", false, "Unpack local image") + c.Flags().String("platform", "", "Platform to unpack (e.g., linux/amd64, linux/arm64, linux/amd64/v3) ") return c } diff --git a/pkg/helpers/docker/docker.go b/pkg/helpers/docker/docker.go index 705cce41e..7b7c52284 100644 --- a/pkg/helpers/docker/docker.go +++ b/pkg/helpers/docker/docker.go @@ -22,24 +22,22 @@ import ( "os" "strings" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/tarball" - "github.com/containerd/containerd/images" - luetimages "github.com/mudler/luet/pkg/api/core/image" - luettypes "github.com/mudler/luet/pkg/api/core/types" - - fileHelper "github.com/mudler/luet/pkg/helpers/file" - - "github.com/docker/cli/cli/trust" "github.com/docker/distribution/reference" registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/docker/registry" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/daemon" + "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/mudler/luet/pkg/api/core/bus" + luetimages "github.com/mudler/luet/pkg/api/core/image" + luettypes "github.com/mudler/luet/pkg/api/core/types" + + fileHelper "github.com/mudler/luet/pkg/helpers/file" + + "github.com/docker/cli/cli/trust" "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -138,7 +136,7 @@ type UnpackEventData struct { } // DownloadAndExtractDockerImage extracts a container image natively. It supports privileged/unprivileged mode -func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, auth *registrytypes.AuthConfig, verify bool) (*images.Image, error) { +func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, auth *registrytypes.AuthConfig, verify bool, platform string) (*images.Image, error) { if verify { img, err := verifyImage(image, auth) if err != nil { @@ -158,7 +156,16 @@ func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, au return nil, err } - img, err := remote.Image(ref, remote.WithAuth(staticAuth{auth}), remote.WithTransport(http.DefaultTransport)) + opts := []remote.Option{remote.WithAuth(staticAuth{auth}), remote.WithTransport(http.DefaultTransport)} + if platform != "" { + p, err := v1.ParsePlatform(platform) + if err != nil { + return nil, err + } + opts = append(opts, remote.WithPlatform(*p)) + } + + img, err := remote.Image(ref, opts...) if err != nil { return nil, err } @@ -204,7 +211,7 @@ func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, au }, nil } -func ExtractDockerImage(ctx luettypes.Context, local, dest string) (*images.Image, error) { +func ExtractDockerImage(ctx luettypes.Context, local, dest, platform string) (*images.Image, error) { var img v1.Image if !fileHelper.Exists(dest) { if err := os.MkdirAll(dest, os.ModePerm); err != nil { @@ -223,7 +230,15 @@ func ExtractDockerImage(ctx luettypes.Context, local, dest string) (*images.Imag if err != nil { return nil, err } - img, err = daemon.Image(ref) + if platform != "" { + p, err := v1.ParsePlatform(platform) + if err != nil { + return nil, err + } + img, err = remote.Image(ref, remote.WithPlatform(*p)) + } else { + img, err = remote.Image(ref) + } } if err != nil { return nil, err diff --git a/pkg/installer/client/docker.go b/pkg/installer/client/docker.go index 483031957..a90882f56 100644 --- a/pkg/installer/client/docker.go +++ b/pkg/installer/client/docker.go @@ -97,8 +97,7 @@ func (c *DockerClient) DownloadArtifact(a *artifact.PackageArtifact) (*artifact. imageName := fmt.Sprintf("%s:%s", uri, a.CompileSpec.GetPackage().ImageID()) c.context.Info("Downloading image", imageName) - // imageName := fmt.Sprintf("%s/%s", uri, artifact.GetCompileSpec().GetPackage().GetPackageImageName()) - info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify) + info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify, "") if err != nil { c.context.Warning(fmt.Sprintf(errImageDownloadMsg, imageName, err.Error())) continue @@ -158,7 +157,7 @@ func (c *DockerClient) DownloadFile(name string) (string, error) { imageName := fmt.Sprintf("%s:%s", uri, helpers.SanitizeImageString(name)) c.context.Info("Downloading", imageName) - info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify) + info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify, "") if err != nil { c.context.Warning(fmt.Sprintf(errImageDownloadMsg, imageName, err.Error())) continue