From 5c54c53534d3e09a99341864f1c0c96a1f0ad0fe Mon Sep 17 00:00:00 2001 From: umohnani8 Date: Wed, 16 May 2018 11:01:36 -0400 Subject: Vendor in latest containers/image Changes include saving image to docker-archive and oci-archive eithout an image reference. Signed-off-by: umohnani8 Closes: #782 Approved by: rhatdan --- .../containers/image/docker/archive/dest.go | 12 ++-- .../containers/image/docker/archive/transport.go | 6 +- .../image/docker/daemon/daemon_transport.go | 51 ++++++++++++-- .../containers/image/docker/docker_image.go | 78 +++++++++++++++++----- .../containers/image/docker/tarfile/dest.go | 75 +++++++++++++-------- .../containers/image/internal/tmpdir/tmpdir.go | 12 +++- .../containers/image/oci/layout/oci_dest.go | 14 ++-- .../containers/image/oci/layout/oci_transport.go | 4 +- .../containers/image/pkg/docker/config/config.go | 8 ++- .../containers/image/storage/storage_image.go | 5 +- vendor/github.com/containers/image/types/types.go | 3 + 11 files changed, 191 insertions(+), 77 deletions(-) (limited to 'vendor') diff --git a/vendor/github.com/containers/image/docker/archive/dest.go b/vendor/github.com/containers/image/docker/archive/dest.go index 12bbfa747..c88aea3b3 100644 --- a/vendor/github.com/containers/image/docker/archive/dest.go +++ b/vendor/github.com/containers/image/docker/archive/dest.go @@ -16,11 +16,7 @@ type archiveImageDestination struct { writer io.Closer } -func newImageDestination(ref archiveReference) (types.ImageDestination, error) { - if ref.destinationRef == nil { - return nil, errors.Errorf("docker-archive: destination reference not supplied (must be of form :)") - } - +func newImageDestination(sys *types.SystemContext, ref archiveReference) (types.ImageDestination, error) { // ref.path can be either a pipe or a regular file // in the case of a pipe, we require that we can open it for write // in the case of a regular file, we don't want to overwrite any pre-existing file @@ -40,8 +36,12 @@ func newImageDestination(ref archiveReference) (types.ImageDestination, error) { return nil, errors.New("docker-archive doesn't support modifying existing images") } + tarDest := tarfile.NewDestination(fh, ref.destinationRef) + if sys != nil && sys.DockerArchiveAdditionalTags != nil { + tarDest.AddRepoTags(sys.DockerArchiveAdditionalTags) + } return &archiveImageDestination{ - Destination: tarfile.NewDestination(fh, ref.destinationRef), + Destination: tarDest, ref: ref, writer: fh, }, nil diff --git a/vendor/github.com/containers/image/docker/archive/transport.go b/vendor/github.com/containers/image/docker/archive/transport.go index 169a2b2e2..f345b343c 100644 --- a/vendor/github.com/containers/image/docker/archive/transport.go +++ b/vendor/github.com/containers/image/docker/archive/transport.go @@ -41,7 +41,9 @@ func (t archiveTransport) ValidatePolicyConfigurationScope(scope string) error { // archiveReference is an ImageReference for Docker images. type archiveReference struct { - destinationRef reference.NamedTagged // only used for destinations + // only used for destinations + // archiveReference.destinationRef is optional and can be nil for destinations as well. + destinationRef reference.NamedTagged path string } @@ -148,7 +150,7 @@ func (ref archiveReference) NewImageSource(ctx context.Context, sys *types.Syste // NewImageDestination returns a types.ImageDestination for this reference. // The caller must call .Close() on the returned ImageDestination. func (ref archiveReference) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) { - return newImageDestination(ref) + return newImageDestination(sys, ref) } // DeleteImage deletes the named image from the registry, if supported. diff --git a/vendor/github.com/containers/image/docker/daemon/daemon_transport.go b/vendor/github.com/containers/image/docker/daemon/daemon_transport.go index b083628ae..1a265bf76 100644 --- a/vendor/github.com/containers/image/docker/daemon/daemon_transport.go +++ b/vendor/github.com/containers/image/docker/daemon/daemon_transport.go @@ -2,13 +2,15 @@ package daemon import ( "context" - "github.com/pkg/errors" + "fmt" + "github.com/containers/image/docker/policyconfiguration" "github.com/containers/image/docker/reference" "github.com/containers/image/image" "github.com/containers/image/transports" "github.com/containers/image/types" "github.com/opencontainers/go-digest" + "github.com/pkg/errors" ) func init() { @@ -35,8 +37,15 @@ func (t daemonTransport) ParseReference(reference string) (types.ImageReference, // It is acceptable to allow an invalid value which will never be matched, it can "only" cause user confusion. // scope passed to this function will not be "", that value is always allowed. func (t daemonTransport) ValidatePolicyConfigurationScope(scope string) error { - // See the explanation in daemonReference.PolicyConfigurationIdentity. - return errors.New(`docker-daemon: does not support any scopes except the default "" one`) + // ID values cannot be effectively namespaced, and are clearly invalid host:port values. + if _, err := digest.Parse(scope); err == nil { + return errors.Errorf(`docker-daemon: can not use algo:digest value %s as a namespace`, scope) + } + + // FIXME? We could be verifying the various character set and length restrictions + // from docker/distribution/reference.regexp.go, but other than that there + // are few semantically invalid strings. + return nil } // daemonReference is an ImageReference for images managed by a local Docker daemon @@ -88,6 +97,8 @@ func NewReference(id digest.Digest, ref reference.Named) (types.ImageReference, // A github.com/distribution/reference value can have a tag and a digest at the same time! // Most versions of docker/reference do not handle that (ignoring the tag), so reject such input. // This MAY be accepted in the future. + // (Even if it were supported, the semantics of policy namespaces are unclear - should we drop + // the tag or the digest first?) _, isTagged := ref.(reference.NamedTagged) _, isDigested := ref.(reference.Canonical) if isTagged && isDigested { @@ -137,9 +148,28 @@ func (ref daemonReference) DockerReference() reference.Named { // Returns "" if configuration identities for these references are not supported. func (ref daemonReference) PolicyConfigurationIdentity() string { // We must allow referring to images in the daemon by image ID, otherwise untagged images would not be accessible. - // But the existence of image IDs means that we can’t truly well namespace the input; the untagged images would have to fall into the default policy, - // which can be unexpected. So, punt. - return "" // This still allows using the default "" scope to define a policy for this transport. + // But the existence of image IDs means that we can’t truly well namespace the input: + // a single image can be namespaced either using the name or the ID depending on how it is named. + // + // That’s fairly unexpected, but we have to cope somehow. + // + // So, use the ordinary docker/policyconfiguration namespacing for named images. + // image IDs all fall into the root namespace. + // Users can set up the root namespace to be either untrusted or rejected, + // and to set up specific trust for named namespaces. This allows verifying image + // identity when a name is known, and unnamed images would be untrusted or rejected. + switch { + case ref.id != "": + return "" // This still allows using the default "" scope to define a global policy for ID-identified images. + case ref.ref != nil: + res, err := policyconfiguration.DockerReferenceIdentity(ref.ref) + if res == "" || err != nil { // Coverage: Should never happen, NewReference above should refuse values which could cause a failure. + panic(fmt.Sprintf("Internal inconsistency: policyconfiguration.DockerReferenceIdentity returned %#v, %v", res, err)) + } + return res + default: // Coverage: Should never happen, NewReference above should refuse such values. + panic("Internal inconsistency: daemonReference has empty id and nil ref") + } } // PolicyConfigurationNamespaces returns a list of other policy configuration namespaces to search @@ -149,7 +179,14 @@ func (ref daemonReference) PolicyConfigurationIdentity() string { // and each following element to be a prefix of the element preceding it. func (ref daemonReference) PolicyConfigurationNamespaces() []string { // See the explanation in daemonReference.PolicyConfigurationIdentity. - return []string{} + switch { + case ref.id != "": + return []string{} + case ref.ref != nil: + return policyconfiguration.DockerReferenceNamespaces(ref.ref) + default: // Coverage: Should never happen, NewReference above should refuse such values. + panic("Internal inconsistency: daemonReference has empty id and nil ref") + } } // NewImage returns a types.ImageCloser for this reference, possibly specialized for this ImageTransport. diff --git a/vendor/github.com/containers/image/docker/docker_image.go b/vendor/github.com/containers/image/docker/docker_image.go index 7f8ad858e..010791241 100644 --- a/vendor/github.com/containers/image/docker/docker_image.go +++ b/vendor/github.com/containers/image/docker/docker_image.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" + "strings" "github.com/containers/image/docker/reference" "github.com/containers/image/image" @@ -39,25 +41,67 @@ func (i *Image) SourceRefFullName() string { return i.src.ref.ref.Name() } -// GetRepositoryTags list all tags available in the repository. Note that this has no connection with the tag(s) used for this specific image, if any. +// GetRepositoryTags list all tags available in the repository. The tag +// provided inside the ImageReference will be ignored. (This is a +// backward-compatible shim method which calls the module-level +// GetRepositoryTags) func (i *Image) GetRepositoryTags(ctx context.Context) ([]string, error) { - path := fmt.Sprintf(tagsPath, reference.Path(i.src.ref.ref)) - // FIXME: Pass the context.Context - res, err := i.src.c.makeRequest(ctx, "GET", path, nil, nil) - if err != nil { - return nil, err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - // print url also - return nil, errors.Errorf("Invalid status code returned when fetching tags list %d", res.StatusCode) + return GetRepositoryTags(ctx, i.src.c.sys, i.src.ref) +} + +// GetRepositoryTags list all tags available in the repository. The tag +// provided inside the ImageReference will be ignored. +func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.ImageReference) ([]string, error) { + dr, ok := ref.(dockerReference) + if !ok { + return nil, errors.Errorf("ref must be a dockerReference") } - type tagsRes struct { - Tags []string + + path := fmt.Sprintf(tagsPath, reference.Path(dr.ref)) + client, err := newDockerClientFromRef(sys, dr, false, "pull") + if err != nil { + return nil, errors.Wrap(err, "failed to create client") } - tags := &tagsRes{} - if err := json.NewDecoder(res.Body).Decode(tags); err != nil { - return nil, err + + tags := make([]string, 0) + + for { + res, err := client.makeRequest(ctx, "GET", path, nil, nil) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + // print url also + return nil, errors.Errorf("Invalid status code returned when fetching tags list %d", res.StatusCode) + } + + var tagsHolder struct { + Tags []string + } + if err = json.NewDecoder(res.Body).Decode(&tagsHolder); err != nil { + return nil, err + } + tags = append(tags, tagsHolder.Tags...) + + link := res.Header.Get("Link") + if link == "" { + break + } + + linkURLStr := strings.Trim(strings.Split(link, ";")[0], "<>") + linkURL, err := url.Parse(linkURLStr) + if err != nil { + return tags, err + } + + // can be relative or absolute, but we only want the path (and I + // guess we're in trouble if it forwards to a new place...) + path = linkURL.Path + if linkURL.RawQuery != "" { + path += "?" + path += linkURL.RawQuery + } } - return tags.Tags, nil + return tags, nil } diff --git a/vendor/github.com/containers/image/docker/tarfile/dest.go b/vendor/github.com/containers/image/docker/tarfile/dest.go index 2bbaf4320..b6791af95 100644 --- a/vendor/github.com/containers/image/docker/tarfile/dest.go +++ b/vendor/github.com/containers/image/docker/tarfile/dest.go @@ -23,9 +23,9 @@ import ( // Destination is a partial implementation of types.ImageDestination for writing to an io.Writer. type Destination struct { - writer io.Writer - tar *tar.Writer - reference reference.NamedTagged + writer io.Writer + tar *tar.Writer + repoTags []reference.NamedTagged // Other state. blobs map[digest.Digest]types.BlobInfo // list of already-sent blobs config []byte @@ -33,14 +33,23 @@ type Destination struct { // NewDestination returns a tarfile.Destination for the specified io.Writer. func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination { + repoTags := []reference.NamedTagged{} + if ref != nil { + repoTags = append(repoTags, ref) + } return &Destination{ - writer: dest, - tar: tar.NewWriter(dest), - reference: ref, - blobs: make(map[digest.Digest]types.BlobInfo), + writer: dest, + tar: tar.NewWriter(dest), + repoTags: repoTags, + blobs: make(map[digest.Digest]types.BlobInfo), } } +// AddRepoTags adds the specified tags to the destination's repoTags. +func (d *Destination) AddRepoTags(tags []reference.NamedTagged) { + d.repoTags = append(d.repoTags, tags...) +} + // SupportedManifestMIMETypes tells which manifest mime types the destination supports // If an empty slice or nil it's returned, then any mime type can be tried to upload func (d *Destination) SupportedManifestMIMETypes() []string { @@ -161,8 +170,15 @@ func (d *Destination) ReapplyBlob(ctx context.Context, info types.BlobInfo) (typ } func (d *Destination) createRepositoriesFile(rootLayerID string) error { - repositories := map[string]map[string]string{ - d.reference.Name(): {d.reference.Tag(): rootLayerID}} + repositories := map[string]map[string]string{} + for _, repoTag := range d.repoTags { + if val, ok := repositories[repoTag.Name()]; ok { + val[repoTag.Tag()] = rootLayerID + } else { + repositories[repoTag.Name()] = map[string]string{repoTag.Tag(): rootLayerID} + } + } + b, err := json.Marshal(repositories) if err != nil { return errors.Wrap(err, "Error marshaling repositories") @@ -199,26 +215,31 @@ func (d *Destination) PutManifest(ctx context.Context, m []byte) error { } } - // For github.com/docker/docker consumers, this works just as well as - // refString := ref.String() - // because when reading the RepoTags strings, github.com/docker/docker/reference - // normalizes both of them to the same value. - // - // Doing it this way to include the normalized-out `docker.io[/library]` does make - // a difference for github.com/projectatomic/docker consumers, with the - // “Add --add-registry and --block-registry options to docker daemon” patch. - // These consumers treat reference strings which include a hostname and reference - // strings without a hostname differently. - // - // Using the host name here is more explicit about the intent, and it has the same - // effect as (docker pull) in projectatomic/docker, which tags the result using - // a hostname-qualified reference. - // See https://github.com/containers/image/issues/72 for a more detailed - // analysis and explanation. - refString := fmt.Sprintf("%s:%s", d.reference.Name(), d.reference.Tag()) + repoTags := []string{} + for _, tag := range d.repoTags { + // For github.com/docker/docker consumers, this works just as well as + // refString := ref.String() + // because when reading the RepoTags strings, github.com/docker/docker/reference + // normalizes both of them to the same value. + // + // Doing it this way to include the normalized-out `docker.io[/library]` does make + // a difference for github.com/projectatomic/docker consumers, with the + // “Add --add-registry and --block-registry options to docker daemon” patch. + // These consumers treat reference strings which include a hostname and reference + // strings without a hostname differently. + // + // Using the host name here is more explicit about the intent, and it has the same + // effect as (docker pull) in projectatomic/docker, which tags the result using + // a hostname-qualified reference. + // See https://github.com/containers/image/issues/72 for a more detailed + // analysis and explanation. + refString := fmt.Sprintf("%s:%s", tag.Name(), tag.Tag()) + repoTags = append(repoTags, refString) + } + items := []ManifestItem{{ Config: man.ConfigDescriptor.Digest.Hex() + ".json", - RepoTags: []string{refString}, + RepoTags: repoTags, Layers: layerPaths, Parent: "", LayerSources: nil, diff --git a/vendor/github.com/containers/image/internal/tmpdir/tmpdir.go b/vendor/github.com/containers/image/internal/tmpdir/tmpdir.go index a28020edc..8c776929c 100644 --- a/vendor/github.com/containers/image/internal/tmpdir/tmpdir.go +++ b/vendor/github.com/containers/image/internal/tmpdir/tmpdir.go @@ -5,6 +5,16 @@ import ( "runtime" ) +// unixTempDirForBigFiles is the directory path to store big files on non Windows systems. +// You can override this at build time with +// -ldflags '-X github.com/containers/image/internal/tmpdir.unixTempDirForBigFiles=$your_path' +var unixTempDirForBigFiles = builtinUnixTempDirForBigFiles + +// builtinUnixTempDirForBigFiles is the directory path to store big files. +// Do not use the system default of os.TempDir(), usually /tmp, because with systemd it could be a tmpfs. +// DO NOT change this, instead see unixTempDirForBigFiles above. +const builtinUnixTempDirForBigFiles = "/var/tmp" + // TemporaryDirectoryForBigFiles returns a directory for temporary (big) files. // On non Windows systems it avoids the use of os.TempDir(), because the default temporary directory usually falls under /tmp // which on systemd based systems could be the unsuitable tmpfs filesystem. @@ -13,7 +23,7 @@ func TemporaryDirectoryForBigFiles() string { if runtime.GOOS == "windows" { temporaryDirectoryForBigFiles = os.TempDir() } else { - temporaryDirectoryForBigFiles = "/var/tmp" + temporaryDirectoryForBigFiles = unixTempDirForBigFiles } return temporaryDirectoryForBigFiles } diff --git a/vendor/github.com/containers/image/oci/layout/oci_dest.go b/vendor/github.com/containers/image/oci/layout/oci_dest.go index e0761c693..a1e27b5d5 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_dest.go +++ b/vendor/github.com/containers/image/oci/layout/oci_dest.go @@ -25,10 +25,6 @@ type ociImageDestination struct { // newImageDestination returns an ImageDestination for writing to an existing directory. func newImageDestination(sys *types.SystemContext, ref ociReference) (types.ImageDestination, error) { - if ref.image == "" { - return nil, errors.Errorf("cannot save image with empty reference name (syntax must be of form ::)") - } - var index *imgspecv1.Index if indexExists(ref) { var err error @@ -217,13 +213,11 @@ func (d *ociImageDestination) PutManifest(ctx context.Context, m []byte) error { return err } - if d.ref.image == "" { - return errors.Errorf("cannot save image with empyt image.ref.name") + if d.ref.image != "" { + annotations := make(map[string]string) + annotations["org.opencontainers.image.ref.name"] = d.ref.image + desc.Annotations = annotations } - - annotations := make(map[string]string) - annotations["org.opencontainers.image.ref.name"] = d.ref.image - desc.Annotations = annotations desc.Platform = &imgspecv1.Platform{ Architecture: runtime.GOARCH, OS: runtime.GOOS, diff --git a/vendor/github.com/containers/image/oci/layout/oci_transport.go b/vendor/github.com/containers/image/oci/layout/oci_transport.go index 95a9def2c..857c80818 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_transport.go +++ b/vendor/github.com/containers/image/oci/layout/oci_transport.go @@ -55,7 +55,9 @@ type ociReference struct { // (But in general, we make no attempt to be completely safe against concurrent hostile filesystem modifications.) dir string // As specified by the user. May be relative, contain symlinks, etc. resolvedDir string // Absolute path with no symlinks, at least at the time of its creation. Primarily used for policy namespaces. - image string // If image=="", it means the only image in the index.json is used + // If image=="", it means the "only image" in the index.json is used in the case it is a source + // for destinations, the image name annotation "image.ref.name" is not added to the index.json + image string } // ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference. diff --git a/vendor/github.com/containers/image/pkg/docker/config/config.go b/vendor/github.com/containers/image/pkg/docker/config/config.go index 3edab0539..724aef4e6 100644 --- a/vendor/github.com/containers/image/pkg/docker/config/config.go +++ b/vendor/github.com/containers/image/pkg/docker/config/config.go @@ -149,13 +149,15 @@ func getPathToAuth(sys *types.SystemContext) (string, error) { runtimeDir := os.Getenv("XDG_RUNTIME_DIR") if runtimeDir != "" { + // This function does not in general need to separately check that the returned path exists; that’s racy, and callers will fail accessing the file anyway. + // We are checking for os.IsNotExist here only to give the user better guidance what to do in this special case. _, err := os.Stat(runtimeDir) if os.IsNotExist(err) { // This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory - // or made a typo while setting the environment variable - // so we log the error and return an empty string as the path + // or made a typo while setting the environment variable, + // so return an error referring to $XDG_RUNTIME_DIR instead of …/authCfgFileName inside. return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir) - } + } // else ignore err and let the caller fail accessing …/authCfgFileName. runtimeDir = filepath.Join(runtimeDir, authCfg) } else { runtimeDir = filepath.Join(defaultPath, authCfg, strconv.Itoa(os.Getuid())) diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go index e6e759456..b43caf1a0 100644 --- a/vendor/github.com/containers/image/storage/storage_image.go +++ b/vendor/github.com/containers/image/storage/storage_image.go @@ -14,6 +14,7 @@ import ( "sync/atomic" "github.com/containers/image/image" + "github.com/containers/image/internal/tmpdir" "github.com/containers/image/manifest" "github.com/containers/image/types" "github.com/containers/storage" @@ -25,8 +26,6 @@ import ( "github.com/sirupsen/logrus" ) -const temporaryDirectoryForBigFiles = "/var/tmp" // Do not use the system default of os.TempDir(), usually /tmp, because with systemd it could be a tmpfs. - var ( // ErrBlobDigestMismatch is returned when PutBlob() is given a blob // with a digest-based name that doesn't match its contents. @@ -240,7 +239,7 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest * // newImageDestination sets us up to write a new image, caching blobs in a temporary directory until // it's time to Commit() the image func newImageDestination(imageRef storageReference) (*storageImageDestination, error) { - directory, err := ioutil.TempDir(temporaryDirectoryForBigFiles, "storage") + directory, err := ioutil.TempDir(tmpdir.TemporaryDirectoryForBigFiles(), "storage") if err != nil { return nil, errors.Wrapf(err, "error creating a temporary directory") } diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index 62aa78ddd..2823a05c0 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -347,6 +347,9 @@ type SystemContext struct { // If not "", overrides the use of platform.GOOS when choosing an image or verifying OS match. OSChoice string + // Additional tags when creating or copying a docker-archive. + DockerArchiveAdditionalTags []reference.NamedTagged + // === OCI.Transport overrides === // If not "", a directory containing a CA certificate (ending with ".crt"), // a client certificate (ending with ".cert") and a client ceritificate key -- cgit v1.2.3-54-g00ecf