mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
Merge pull request #3583 from deitch/lib-manifest-tool
Replace copied code with manifest-tool library
This commit is contained in:
commit
c1b02ee4f0
@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/config"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/estesp/manifest-tool/pkg/registry"
|
||||
"github.com/estesp/manifest-tool/pkg/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -247,7 +248,7 @@ func manifestPush(img string, auth dockertypes.AuthConfig) (hash string, length
|
||||
}
|
||||
|
||||
// push the manifest list with the auth as given, ignore missing, do not allow insecure
|
||||
return pushManifestList(auth, yamlInput, true, false, false, "")
|
||||
return registry.PushManifestList(auth.Username, auth.Password, yamlInput, true, false, false, "")
|
||||
}
|
||||
|
||||
func signManifest(img, digest string, length int, auth dockertypes.AuthConfig) error {
|
||||
|
@ -1,297 +0,0 @@
|
||||
package pkglib
|
||||
|
||||
// manifest utilities
|
||||
|
||||
//go:generate ./gen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
auth "github.com/deislabs/oras/pkg/auth/docker"
|
||||
"github.com/docker/distribution/reference"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/estesp/manifest-tool/pkg/registry"
|
||||
"github.com/estesp/manifest-tool/pkg/store"
|
||||
"github.com/estesp/manifest-tool/pkg/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/*
|
||||
EVERYTHING below here is because github.com/estesp/manifest-tool moved pushManifestList into
|
||||
a non-exported func and passed it cli. If/when it moves back, we can get rid of all of it.
|
||||
This code is copied almost verbatim from github.com/estesp/manifest-tool, mostly in
|
||||
push.go and util.go. It then was modified to remove any command-line dependencies.
|
||||
*/
|
||||
|
||||
func pushManifestList(auth dockertypes.AuthConfig, input types.YAMLInput, ignoreMissing, insecure, plainHTTP bool, configDir string) (hash string, length int, err error) {
|
||||
// resolve the target image reference for the combined manifest list/index
|
||||
targetRef, err := reference.ParseNormalizedNamed(input.Image)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Error parsing name for manifest list (%s): %v", input.Image, err)
|
||||
}
|
||||
|
||||
var configDirs []string
|
||||
if configDir != "" {
|
||||
configDirs = append(configDirs, filepath.Join(configDir, "config.json"))
|
||||
}
|
||||
resolver := newResolver(auth.Username, auth.Password, insecure,
|
||||
plainHTTP, configDirs...)
|
||||
|
||||
imageType := types.Docker
|
||||
manifestList := types.ManifestList{
|
||||
Name: input.Image,
|
||||
Reference: targetRef,
|
||||
Resolver: resolver,
|
||||
Type: imageType,
|
||||
}
|
||||
// create an in-memory store for OCI descriptors and content used during the push operation
|
||||
memoryStore := store.NewMemoryStore()
|
||||
|
||||
log.Info("Retrieving digests of member images")
|
||||
for _, img := range input.Manifests {
|
||||
ref, err := parseName(img.Image)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Unable to parse image reference: %s: %v", img.Image, err)
|
||||
}
|
||||
if reference.Domain(targetRef) != reference.Domain(ref) {
|
||||
return hash, length, fmt.Errorf("Cannot use source images from a different registry than the target image: %s != %s", reference.Domain(ref), reference.Domain(targetRef))
|
||||
}
|
||||
descriptor, err := fetchDescriptor(resolver, memoryStore, ref)
|
||||
if err != nil {
|
||||
if ignoreMissing {
|
||||
log.Warnf("Couldn't access image '%q'. Skipping due to 'ignore missing' configuration.", img.Image)
|
||||
continue
|
||||
}
|
||||
return hash, length, fmt.Errorf("Inspect of image %q failed with error: %v", img.Image, err)
|
||||
}
|
||||
|
||||
// Check that only member images of type OCI manifest or Docker v2.2 manifest are included
|
||||
switch descriptor.MediaType {
|
||||
case ocispec.MediaTypeImageIndex, types.MediaTypeDockerSchema2ManifestList:
|
||||
return hash, length, fmt.Errorf("Cannot include an image in a manifest list/index which is already a multi-platform image: %s", img.Image)
|
||||
case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
|
||||
// valid image type to include
|
||||
default:
|
||||
return hash, length, fmt.Errorf("Cannot include unknown media type '%s' in a manifest list/index push", descriptor.MediaType)
|
||||
}
|
||||
_, db, _ := memoryStore.Get(descriptor)
|
||||
var man ocispec.Manifest
|
||||
if err := json.Unmarshal(db, &man); err != nil {
|
||||
return hash, length, fmt.Errorf("Could not unmarshal manifest object from descriptor for image '%s': %v", img.Image, err)
|
||||
}
|
||||
_, cb, _ := memoryStore.Get(man.Config)
|
||||
var imgConfig types.Image
|
||||
if err := json.Unmarshal(cb, &imgConfig); err != nil {
|
||||
return hash, length, fmt.Errorf("Could not unmarshal config object from descriptor for image '%s': %v", img.Image, err)
|
||||
}
|
||||
// set labels for handling distribution source to get automatic cross-repo blob mounting for the layers
|
||||
info, _ := memoryStore.Info(context.TODO(), descriptor.Digest)
|
||||
for _, layer := range man.Layers {
|
||||
info.Digest = layer.Digest
|
||||
if _, err := memoryStore.Update(context.TODO(), info, ""); err != nil {
|
||||
log.Warnf("couldn't update in-memory store labels for %v: %v", info.Digest, err)
|
||||
}
|
||||
}
|
||||
|
||||
// finalize the platform object that will be used to push with this manifest
|
||||
descriptor.Platform, err = resolvePlatform(descriptor, img, imgConfig)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Unable to create platform object for manifest %s: %v", descriptor.Digest.String(), err)
|
||||
}
|
||||
manifest := types.Manifest{
|
||||
Descriptor: descriptor,
|
||||
PushRef: false,
|
||||
}
|
||||
|
||||
if reference.Path(ref) != reference.Path(targetRef) {
|
||||
// the target manifest list/index is located in a different repo; need to push
|
||||
// the manifest as a digest to the target repo before the list/index is pushed
|
||||
manifest.PushRef = true
|
||||
}
|
||||
manifestList.Manifests = append(manifestList.Manifests, manifest)
|
||||
}
|
||||
|
||||
if ignoreMissing && len(manifestList.Manifests) == 0 {
|
||||
// we need to verify we at least have one valid entry in the list
|
||||
// otherwise our manifest list will be totally empty
|
||||
return hash, length, fmt.Errorf("all entries were skipped due to missing source image references; no manifest list to push")
|
||||
}
|
||||
|
||||
return registry.Push(manifestList, input.Tags, memoryStore)
|
||||
}
|
||||
|
||||
func resolvePlatform(descriptor ocispec.Descriptor, img types.ManifestEntry, imgConfig types.Image) (*ocispec.Platform, error) {
|
||||
platform := &img.Platform
|
||||
if platform == nil {
|
||||
platform = &ocispec.Platform{}
|
||||
}
|
||||
// fill os/arch from inspected image if not specified in input YAML
|
||||
if img.Platform.OS == "" && img.Platform.Architecture == "" {
|
||||
// prefer a full platform object, if one is already available (and appears to have meaningful content)
|
||||
if descriptor.Platform.OS != "" || descriptor.Platform.Architecture != "" {
|
||||
platform = descriptor.Platform
|
||||
} else if imgConfig.OS != "" || imgConfig.Architecture != "" {
|
||||
platform.OS = imgConfig.OS
|
||||
platform.Architecture = imgConfig.Architecture
|
||||
}
|
||||
}
|
||||
// Windows: if the origin image has OSFeature and/or OSVersion information, and
|
||||
// these values were not specified in the creation YAML, then
|
||||
// retain the origin values in the Platform definition for the manifest list:
|
||||
if imgConfig.OSVersion != "" && img.Platform.OSVersion == "" {
|
||||
platform.OSVersion = imgConfig.OSVersion
|
||||
}
|
||||
if len(imgConfig.OSFeatures) > 0 && len(img.Platform.OSFeatures) == 0 {
|
||||
platform.OSFeatures = imgConfig.OSFeatures
|
||||
}
|
||||
|
||||
// validate os/arch input
|
||||
if !isValidOSArch(platform.OS, platform.Architecture, platform.Variant) {
|
||||
return nil, fmt.Errorf("Manifest entry for image %s has unsupported os/arch or os/arch/variant combination: %s/%s/%s", img.Image, platform.OS, platform.Architecture, platform.Variant)
|
||||
}
|
||||
return platform, nil
|
||||
}
|
||||
|
||||
func isValidOSArch(os string, arch string, variant string) bool {
|
||||
osarch := fmt.Sprintf("%s/%s", os, arch)
|
||||
|
||||
if variant != "" {
|
||||
osarch = fmt.Sprintf("%s/%s/%s", os, arch, variant)
|
||||
}
|
||||
|
||||
_, ok := validOSArch[osarch]
|
||||
return ok
|
||||
}
|
||||
|
||||
// list of valid os/arch values (see "Optional Environment Variables" section
|
||||
// of https://golang.org/doc/install/source
|
||||
var validOSArch = map[string]bool{
|
||||
"darwin/386": true,
|
||||
"darwin/amd64": true,
|
||||
"darwin/arm": true,
|
||||
"darwin/arm64": true,
|
||||
"dragonfly/amd64": true,
|
||||
"freebsd/386": true,
|
||||
"freebsd/amd64": true,
|
||||
"freebsd/arm": true,
|
||||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"linux/arm": true,
|
||||
"linux/arm/v5": true,
|
||||
"linux/arm/v6": true,
|
||||
"linux/arm/v7": true,
|
||||
"linux/arm64": true,
|
||||
"linux/arm64/v8": true,
|
||||
"linux/ppc64": true,
|
||||
"linux/ppc64le": true,
|
||||
"linux/mips64": true,
|
||||
"linux/mips64le": true,
|
||||
"linux/s390x": true,
|
||||
"netbsd/386": true,
|
||||
"netbsd/amd64": true,
|
||||
"netbsd/arm": true,
|
||||
"openbsd/386": true,
|
||||
"openbsd/amd64": true,
|
||||
"openbsd/arm": true,
|
||||
"plan9/386": true,
|
||||
"plan9/amd64": true,
|
||||
"solaris/amd64": true,
|
||||
"windows/386": true,
|
||||
"windows/amd64": true,
|
||||
"windows/arm": true,
|
||||
}
|
||||
|
||||
func parseName(name string) (reference.Named, error) {
|
||||
distref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostname, remoteName := splitHostname(distref.String())
|
||||
if hostname == "" {
|
||||
return nil, fmt.Errorf("Please use a fully qualified repository name")
|
||||
}
|
||||
return reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", hostname, remoteName))
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultHostname is the default built-in registry (DockerHub)
|
||||
DefaultHostname = "docker.io"
|
||||
// LegacyDefaultHostname is the old hostname used for DockerHub
|
||||
LegacyDefaultHostname = "index.docker.io"
|
||||
// DefaultRepoPrefix is the prefix used for official images in DockerHub
|
||||
DefaultRepoPrefix = "library/"
|
||||
)
|
||||
|
||||
// splitHostname splits a repository name to hostname and remotename string.
|
||||
// If no valid hostname is found, the default hostname is used. Repository name
|
||||
// needs to be already validated before.
|
||||
func splitHostname(name string) (hostname, remoteName string) {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||
hostname, remoteName = DefaultHostname, name
|
||||
} else {
|
||||
hostname, remoteName = name[:i], name[i+1:]
|
||||
}
|
||||
if hostname == LegacyDefaultHostname {
|
||||
hostname = DefaultHostname
|
||||
}
|
||||
if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') {
|
||||
remoteName = DefaultRepoPrefix + remoteName
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func newResolver(username, password string, insecure, plainHTTP bool, configs ...string) remotes.Resolver {
|
||||
|
||||
opts := docker.ResolverOptions{
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
client := http.DefaultClient
|
||||
if insecure {
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
opts.Client = client
|
||||
|
||||
if username != "" || password != "" {
|
||||
opts.Credentials = func(hostName string) (string, string, error) {
|
||||
return username, password, nil
|
||||
}
|
||||
return docker.NewResolver(opts)
|
||||
}
|
||||
cli, err := auth.NewClient(configs...)
|
||||
if err != nil {
|
||||
log.Warnf("Error loading auth file: %v", err)
|
||||
}
|
||||
resolver, err := cli.Resolver(context.Background(), client, plainHTTP)
|
||||
if err != nil {
|
||||
log.Warnf("Error loading resolver: %v", err)
|
||||
resolver = docker.NewResolver(opts)
|
||||
}
|
||||
return resolver
|
||||
}
|
||||
|
||||
func fetchDescriptor(resolver remotes.Resolver, memoryStore *store.MemoryStore, imageRef reference.Named) (ocispec.Descriptor, error) {
|
||||
return registry.Fetch(context.Background(), memoryStore, types.NewRequest(imageRef, "", allMediaTypes(), resolver))
|
||||
}
|
||||
|
||||
func allMediaTypes() []string {
|
||||
return []string{
|
||||
types.MediaTypeDockerSchema2Manifest,
|
||||
types.MediaTypeDockerSchema2ManifestList,
|
||||
ocispec.MediaTypeImageManifest,
|
||||
ocispec.MediaTypeImageIndex,
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ github.com/docker/go-events e31b211e4f1cd09aa76fe4ac244571fab96ae47f
|
||||
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
|
||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||
github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20
|
||||
github.com/estesp/manifest-tool bae5531170d45955c2d72d1b29d77ce1b0c9dedb
|
||||
github.com/estesp/manifest-tool 2d360eeba276afaf63ab22270b7c6b4f8447e261
|
||||
github.com/fvbommel/sortorder 6b6b45a52fcc54f788363c1880630248b63402a1
|
||||
github.com/go-ini/ini afbc45e87f3ba324c532d12c71918ef52e0fb194
|
||||
github.com/gogo/protobuf v1.3.1
|
||||
|
2
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/go.mod
generated
vendored
2
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/go.mod
generated
vendored
@ -3,7 +3,7 @@ module github.com/estesp/manifest-tool
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/containerd/containerd v1.3.7
|
||||
github.com/containerd/containerd v1.4.3
|
||||
github.com/deislabs/oras v0.8.1
|
||||
github.com/docker/cli v20.10.0-beta1+incompatible // indirect
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
|
||||
|
24
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/registry/fetch.go
generated
vendored
Normal file
24
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/registry/fetch.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/estesp/manifest-tool/pkg/store"
|
||||
"github.com/estesp/manifest-tool/pkg/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
func FetchDescriptor(resolver remotes.Resolver, memoryStore *store.MemoryStore, imageRef reference.Named) (ocispec.Descriptor, error) {
|
||||
return Fetch(context.Background(), memoryStore, types.NewRequest(imageRef, "", allMediaTypes(), resolver))
|
||||
}
|
||||
|
||||
func allMediaTypes() []string {
|
||||
return []string{
|
||||
types.MediaTypeDockerSchema2Manifest,
|
||||
types.MediaTypeDockerSchema2ManifestList,
|
||||
ocispec.MediaTypeImageManifest,
|
||||
ocispec.MediaTypeImageIndex,
|
||||
}
|
||||
}
|
144
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/registry/push.go
generated
vendored
Normal file
144
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/registry/push.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/estesp/manifest-tool/pkg/store"
|
||||
"github.com/estesp/manifest-tool/pkg/types"
|
||||
"github.com/estesp/manifest-tool/pkg/util"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func PushManifestList(username, password string, input types.YAMLInput, ignoreMissing, insecure, plainHttp bool, configDir string) (hash string, length int, err error) {
|
||||
// resolve the target image reference for the combined manifest list/index
|
||||
targetRef, err := reference.ParseNormalizedNamed(input.Image)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Error parsing name for manifest list (%s): %v", input.Image, err)
|
||||
}
|
||||
|
||||
var configDirs []string
|
||||
if configDir != "" {
|
||||
configDirs = append(configDirs, filepath.Join(configDir, "config.json"))
|
||||
}
|
||||
resolver := util.NewResolver(username, password, insecure,
|
||||
plainHttp, configDirs...)
|
||||
|
||||
imageType := types.Docker
|
||||
manifestList := types.ManifestList{
|
||||
Name: input.Image,
|
||||
Reference: targetRef,
|
||||
Resolver: resolver,
|
||||
Type: imageType,
|
||||
}
|
||||
// create an in-memory store for OCI descriptors and content used during the push operation
|
||||
memoryStore := store.NewMemoryStore()
|
||||
|
||||
logrus.Info("Retrieving digests of member images")
|
||||
for _, img := range input.Manifests {
|
||||
ref, err := util.ParseName(img.Image)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Unable to parse image reference: %s: %v", img.Image, err)
|
||||
}
|
||||
if reference.Domain(targetRef) != reference.Domain(ref) {
|
||||
return hash, length, fmt.Errorf("Cannot use source images from a different registry than the target image: %s != %s", reference.Domain(ref), reference.Domain(targetRef))
|
||||
}
|
||||
descriptor, err := FetchDescriptor(resolver, memoryStore, ref)
|
||||
if err != nil {
|
||||
if ignoreMissing {
|
||||
logrus.Warnf("Couldn't access image '%q'. Skipping due to 'ignore missing' configuration.", img.Image)
|
||||
continue
|
||||
}
|
||||
return hash, length, fmt.Errorf("Inspect of image %q failed with error: %v", img.Image, err)
|
||||
}
|
||||
|
||||
// Check that only member images of type OCI manifest or Docker v2.2 manifest are included
|
||||
switch descriptor.MediaType {
|
||||
case ocispec.MediaTypeImageIndex, types.MediaTypeDockerSchema2ManifestList:
|
||||
return hash, length, fmt.Errorf("Cannot include an image in a manifest list/index which is already a multi-platform image: %s", img.Image)
|
||||
case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
|
||||
// valid image type to include
|
||||
default:
|
||||
return hash, length, fmt.Errorf("Cannot include unknown media type '%s' in a manifest list/index push", descriptor.MediaType)
|
||||
}
|
||||
_, db, _ := memoryStore.Get(descriptor)
|
||||
var man ocispec.Manifest
|
||||
if err := json.Unmarshal(db, &man); err != nil {
|
||||
return hash, length, fmt.Errorf("Could not unmarshal manifest object from descriptor for image '%s': %v", img.Image, err)
|
||||
}
|
||||
_, cb, _ := memoryStore.Get(man.Config)
|
||||
var imgConfig types.Image
|
||||
if err := json.Unmarshal(cb, &imgConfig); err != nil {
|
||||
return hash, length, fmt.Errorf("Could not unmarshal config object from descriptor for image '%s': %v", img.Image, err)
|
||||
}
|
||||
// set labels for handling distribution source to get automatic cross-repo blob mounting for the layers
|
||||
info, _ := memoryStore.Info(context.TODO(), descriptor.Digest)
|
||||
for _, layer := range man.Layers {
|
||||
info.Digest = layer.Digest
|
||||
if _, err := memoryStore.Update(context.TODO(), info, ""); err != nil {
|
||||
logrus.Warnf("couldn't update in-memory store labels for %v: %v", info.Digest, err)
|
||||
}
|
||||
}
|
||||
|
||||
// finalize the platform object that will be used to push with this manifest
|
||||
descriptor.Platform, err = resolvePlatform(descriptor, img, imgConfig)
|
||||
if err != nil {
|
||||
return hash, length, fmt.Errorf("Unable to create platform object for manifest %s: %v", descriptor.Digest.String(), err)
|
||||
}
|
||||
manifest := types.Manifest{
|
||||
Descriptor: descriptor,
|
||||
PushRef: false,
|
||||
}
|
||||
|
||||
if reference.Path(ref) != reference.Path(targetRef) {
|
||||
// the target manifest list/index is located in a different repo; need to push
|
||||
// the manifest as a digest to the target repo before the list/index is pushed
|
||||
manifest.PushRef = true
|
||||
}
|
||||
manifestList.Manifests = append(manifestList.Manifests, manifest)
|
||||
}
|
||||
|
||||
if ignoreMissing && len(manifestList.Manifests) == 0 {
|
||||
// we need to verify we at least have one valid entry in the list
|
||||
// otherwise our manifest list will be totally empty
|
||||
return hash, length, fmt.Errorf("all entries were skipped due to missing source image references; no manifest list to push")
|
||||
}
|
||||
|
||||
return Push(manifestList, input.Tags, memoryStore)
|
||||
}
|
||||
|
||||
func resolvePlatform(descriptor ocispec.Descriptor, img types.ManifestEntry, imgConfig types.Image) (*ocispec.Platform, error) {
|
||||
platform := &img.Platform
|
||||
if platform == nil {
|
||||
platform = &ocispec.Platform{}
|
||||
}
|
||||
// fill os/arch from inspected image if not specified in input YAML
|
||||
if img.Platform.OS == "" && img.Platform.Architecture == "" {
|
||||
// prefer a full platform object, if one is already available (and appears to have meaningful content)
|
||||
if descriptor.Platform.OS != "" || descriptor.Platform.Architecture != "" {
|
||||
platform = descriptor.Platform
|
||||
} else if imgConfig.OS != "" || imgConfig.Architecture != "" {
|
||||
platform.OS = imgConfig.OS
|
||||
platform.Architecture = imgConfig.Architecture
|
||||
}
|
||||
}
|
||||
// Windows: if the origin image has OSFeature and/or OSVersion information, and
|
||||
// these values were not specified in the creation YAML, then
|
||||
// retain the origin values in the Platform definition for the manifest list:
|
||||
if imgConfig.OSVersion != "" && img.Platform.OSVersion == "" {
|
||||
platform.OSVersion = imgConfig.OSVersion
|
||||
}
|
||||
if len(imgConfig.OSFeatures) > 0 && len(img.Platform.OSFeatures) == 0 {
|
||||
platform.OSFeatures = imgConfig.OSFeatures
|
||||
}
|
||||
|
||||
// validate os/arch input
|
||||
if !util.IsValidOSArch(platform.OS, platform.Architecture, platform.Variant) {
|
||||
return nil, fmt.Errorf("Manifest entry for image %s has unsupported os/arch or os/arch/variant combination: %s/%s/%s", img.Image, platform.OS, platform.Architecture, platform.Variant)
|
||||
}
|
||||
return platform, nil
|
||||
}
|
48
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/name.go
generated
vendored
Normal file
48
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/name.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultHostname is the default built-in registry (DockerHub)
|
||||
DefaultHostname = "docker.io"
|
||||
// LegacyDefaultHostname is the old hostname used for DockerHub
|
||||
LegacyDefaultHostname = "index.docker.io"
|
||||
// DefaultRepoPrefix is the prefix used for official images in DockerHub
|
||||
DefaultRepoPrefix = "library/"
|
||||
)
|
||||
|
||||
func ParseName(name string) (reference.Named, error) {
|
||||
distref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostname, remoteName := splitHostname(distref.String())
|
||||
if hostname == "" {
|
||||
return nil, fmt.Errorf("Please use a fully qualified repository name")
|
||||
}
|
||||
return reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", hostname, remoteName))
|
||||
}
|
||||
|
||||
// splitHostname splits a repository name to hostname and remotename string.
|
||||
// If no valid hostname is found, the default hostname is used. Repository name
|
||||
// needs to be already validated before.
|
||||
func splitHostname(name string) (hostname, remoteName string) {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||
hostname, remoteName = DefaultHostname, name
|
||||
} else {
|
||||
hostname, remoteName = name[:i], name[i+1:]
|
||||
}
|
||||
if hostname == LegacyDefaultHostname {
|
||||
hostname = DefaultHostname
|
||||
}
|
||||
if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') {
|
||||
remoteName = DefaultRepoPrefix + remoteName
|
||||
}
|
||||
return
|
||||
}
|
52
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/os.go
generated
vendored
Normal file
52
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/os.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package util
|
||||
|
||||
import "fmt"
|
||||
|
||||
// list of valid os/arch values (see "Optional Environment Variables" section
|
||||
// of https://golang.org/doc/install/source
|
||||
var validOSArch = map[string]bool{
|
||||
"darwin/386": true,
|
||||
"darwin/amd64": true,
|
||||
"darwin/arm": true,
|
||||
"darwin/arm64": true,
|
||||
"dragonfly/amd64": true,
|
||||
"freebsd/386": true,
|
||||
"freebsd/amd64": true,
|
||||
"freebsd/arm": true,
|
||||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"linux/arm": true,
|
||||
"linux/arm/v5": true,
|
||||
"linux/arm/v6": true,
|
||||
"linux/arm/v7": true,
|
||||
"linux/arm64": true,
|
||||
"linux/arm64/v8": true,
|
||||
"linux/ppc64": true,
|
||||
"linux/ppc64le": true,
|
||||
"linux/mips64": true,
|
||||
"linux/mips64le": true,
|
||||
"linux/s390x": true,
|
||||
"netbsd/386": true,
|
||||
"netbsd/amd64": true,
|
||||
"netbsd/arm": true,
|
||||
"openbsd/386": true,
|
||||
"openbsd/amd64": true,
|
||||
"openbsd/arm": true,
|
||||
"plan9/386": true,
|
||||
"plan9/amd64": true,
|
||||
"solaris/amd64": true,
|
||||
"windows/386": true,
|
||||
"windows/amd64": true,
|
||||
"windows/arm": true,
|
||||
}
|
||||
|
||||
func IsValidOSArch(os string, arch string, variant string) bool {
|
||||
osarch := fmt.Sprintf("%s/%s", os, arch)
|
||||
|
||||
if variant != "" {
|
||||
osarch = fmt.Sprintf("%s/%s/%s", os, arch, variant)
|
||||
}
|
||||
|
||||
_, ok := validOSArch[osarch]
|
||||
return ok
|
||||
}
|
45
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/resolver.go
generated
vendored
Normal file
45
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/pkg/util/resolver.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
auth "github.com/deislabs/oras/pkg/auth/docker"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func NewResolver(username, password string, insecure, plainHTTP bool, configs ...string) remotes.Resolver {
|
||||
|
||||
opts := docker.ResolverOptions{
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
client := http.DefaultClient
|
||||
if insecure {
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
opts.Client = client
|
||||
|
||||
if username != "" || password != "" {
|
||||
opts.Credentials = func(hostName string) (string, string, error) {
|
||||
return username, password, nil
|
||||
}
|
||||
return docker.NewResolver(opts)
|
||||
}
|
||||
cli, err := auth.NewClient(configs...)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error loading auth file: %v", err)
|
||||
}
|
||||
resolver, err := cli.Resolver(context.Background(), client, plainHTTP)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error loading resolver: %v", err)
|
||||
resolver = docker.NewResolver(opts)
|
||||
}
|
||||
return resolver
|
||||
}
|
Loading…
Reference in New Issue
Block a user