mirror of https://github.com/knative/func.git
76 lines
2.2 KiB
Go
76 lines
2.2 KiB
Go
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/containerd/platforms"
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
|
gcrTypes "github.com/google/go-containerregistry/pkg/v1/types"
|
|
)
|
|
|
|
// GetPlatformImage returns image reference for specific platform.
|
|
// If the image is not multi-arch it returns ref argument directly (provided platform matches).
|
|
// If the image is multi-arch it returns digest based reference (provided the platform is part of the multi-arch image).
|
|
func GetPlatformImage(ref, platform string) (string, error) {
|
|
|
|
plat, err := platforms.Parse(platform)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot parse platform: %w", err)
|
|
}
|
|
|
|
r, err := name.ParseReference(ref)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot parse reference: %w", err)
|
|
}
|
|
|
|
desc, err := remote.Get(r)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot get remote image: %w", err)
|
|
}
|
|
|
|
if desc.MediaType != gcrTypes.OCIImageIndex && desc.MediaType != gcrTypes.DockerManifestList {
|
|
// it's non-multi-arch image
|
|
var img v1.Image
|
|
var cfg *v1.ConfigFile
|
|
img, err = desc.Image()
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot get image from the descriptor: %w", err)
|
|
}
|
|
cfg, err = img.ConfigFile()
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot get config file for the image: %w", err)
|
|
}
|
|
|
|
if plat.OS == cfg.OS &&
|
|
plat.Architecture == cfg.Architecture {
|
|
return ref, nil
|
|
}
|
|
return "", fmt.Errorf("the %q platform is not supported by the %q image", platform, ref)
|
|
}
|
|
|
|
idx, err := desc.ImageIndex()
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot get image index: %w", err)
|
|
}
|
|
|
|
idxMft, err := idx.IndexManifest()
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot get index manifest: %w", err)
|
|
}
|
|
|
|
if len(idxMft.Manifests) > 1000 {
|
|
return "", fmt.Errorf("platform image has too many manifests")
|
|
}
|
|
|
|
for _, manifest := range idxMft.Manifests {
|
|
if plat.OS == manifest.Platform.OS &&
|
|
plat.Architecture == manifest.Platform.Architecture {
|
|
return r.Context().Name() + "@" + manifest.Digest.String(), nil
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("the %q platform is not supported by the %q image", platform, ref)
|
|
}
|