diff options
16 files changed, 214 insertions, 226 deletions
diff --git a/vendor.conf b/vendor.conf index 1121f3b50..e3acae833 100644 --- a/vendor.conf +++ b/vendor.conf @@ -10,7 +10,7 @@ github.com/containerd/cgroups 77e628511d924b13a77cebdc73b757a47f6d751b github.com/containerd/continuity master github.com/containernetworking/cni v0.6.0 github.com/containernetworking/plugins 1fb94a4222eafc6f948eacdca9c9f2158b427e53 -github.com/containers/image ad33f7b73fbac0acf05b9e2cea021b61b4b0c3e0 +github.com/containers/image 5144ced37a1b21b63c6ef605e56811e29a687528 github.com/containers/storage 51f1f85c2b7863b2fd361471f05b937fd8059124 github.com/coreos/go-systemd v14 github.com/cri-o/ocicni master diff --git a/vendor/github.com/containers/image/copy/copy.go b/vendor/github.com/containers/image/copy/copy.go index 65c3853be..6714a91f2 100644 --- a/vendor/github.com/containers/image/copy/copy.go +++ b/vendor/github.com/containers/image/copy/copy.go @@ -347,6 +347,9 @@ func checkImageDestinationForCurrentRuntimeOS(ctx context.Context, sys *types.Sy // updateEmbeddedDockerReference handles the Docker reference embedded in Docker schema1 manifests. func (ic *imageCopier) updateEmbeddedDockerReference() error { + if ic.c.dest.IgnoresEmbeddedDockerReference() { + return nil // Destination would prefer us not to update the embedded reference. + } destRef := ic.c.dest.Reference().DockerReference() if destRef == nil { return nil // Destination does not care about Docker references diff --git a/vendor/github.com/containers/image/directory/directory_dest.go b/vendor/github.com/containers/image/directory/directory_dest.go index a38d7d5cf..d888931fe 100644 --- a/vendor/github.com/containers/image/directory/directory_dest.go +++ b/vendor/github.com/containers/image/directory/directory_dest.go @@ -117,6 +117,13 @@ func (d *dirImageDestination) MustMatchRuntimeOS() bool { return false } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *dirImageDestination) IgnoresEmbeddedDockerReference() bool { + return false // N/A, DockerReference() returns nil. +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go index 4a1d42149..0a6dd9b80 100644 --- a/vendor/github.com/containers/image/docker/docker_client.go +++ b/vendor/github.com/containers/image/docker/docker_client.go @@ -280,13 +280,19 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima v2Res := &V2Results{} v1Res := &V1Results{} + // Get credentials from authfile for the underlying hostname + username, password, err := config.GetAuthentication(sys, registry) + if err != nil { + return nil, errors.Wrapf(err, "error getting username and password") + } + // The /v2/_catalog endpoint has been disabled for docker.io therefore the call made to that endpoint will fail // So using the v1 hostname for docker.io for simplicity of implementation and the fact that it returns search results if registry == dockerHostname { registry = dockerV1Hostname } - client, err := newDockerClientWithDetails(sys, registry, "", "", "", nil, "") + client, err := newDockerClientWithDetails(sys, registry, username, password, "", nil, "") if err != nil { return nil, errors.Wrapf(err, "error creating new docker client") } diff --git a/vendor/github.com/containers/image/docker/docker_image_dest.go b/vendor/github.com/containers/image/docker/docker_image_dest.go index 782a048ce..85d568995 100644 --- a/vendor/github.com/containers/image/docker/docker_image_dest.go +++ b/vendor/github.com/containers/image/docker/docker_image_dest.go @@ -95,6 +95,13 @@ func (d *dockerImageDestination) MustMatchRuntimeOS() bool { return false } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *dockerImageDestination) IgnoresEmbeddedDockerReference() bool { + return false // We do want the manifest updated; older registry versions refuse manifests if the embedded reference does not match. +} + // sizeCounter is an io.Writer which only counts the total size of its input. type sizeCounter struct{ size int64 } diff --git a/vendor/github.com/containers/image/docker/tarfile/dest.go b/vendor/github.com/containers/image/docker/tarfile/dest.go index b6791af95..d6510ccf1 100644 --- a/vendor/github.com/containers/image/docker/tarfile/dest.go +++ b/vendor/github.com/containers/image/docker/tarfile/dest.go @@ -75,6 +75,13 @@ func (d *Destination) MustMatchRuntimeOS() bool { return false } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *Destination) IgnoresEmbeddedDockerReference() bool { + return false // N/A, we only accept schema2 images where EmbeddedDockerReferenceConflicts() is always false. +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/vendor/github.com/containers/image/oci/archive/oci_dest.go b/vendor/github.com/containers/image/oci/archive/oci_dest.go index 432b310b4..93f3f80f9 100644 --- a/vendor/github.com/containers/image/oci/archive/oci_dest.go +++ b/vendor/github.com/containers/image/oci/archive/oci_dest.go @@ -70,6 +70,13 @@ func (d *ociArchiveImageDestination) MustMatchRuntimeOS() bool { return d.unpackedDest.MustMatchRuntimeOS() } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *ociArchiveImageDestination) IgnoresEmbeddedDockerReference() bool { + return d.unpackedDest.IgnoresEmbeddedDockerReference() +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. 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 a1e27b5d5..0a0cad15e 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_dest.go +++ b/vendor/github.com/containers/image/oci/layout/oci_dest.go @@ -95,6 +95,13 @@ func (d *ociImageDestination) MustMatchRuntimeOS() bool { return false } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *ociImageDestination) IgnoresEmbeddedDockerReference() bool { + return false // N/A, DockerReference() returns nil. +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. 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 857c80818..4e5cecff2 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_transport.go +++ b/vendor/github.com/containers/image/oci/layout/oci_transport.go @@ -23,8 +23,14 @@ func init() { transports.Register(Transport) } -// Transport is an ImageTransport for OCI directories. -var Transport = ociTransport{} +var ( + // Transport is an ImageTransport for OCI directories. + Transport = ociTransport{} + + // ErrMoreThanOneImage is an error returned when the manifest includes + // more than one image and the user should choose which one to use. + ErrMoreThanOneImage = errors.New("more than one image in oci, choose an image") +) type ociTransport struct{} @@ -184,7 +190,7 @@ func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, error) { d = &index.Manifests[0] } else { // ask user to choose image when more than one image in the oci directory - return imgspecv1.Descriptor{}, errors.Wrapf(err, "more than one image in oci, choose an image") + return imgspecv1.Descriptor{}, ErrMoreThanOneImage } } else { // if image specified, look through all manifests for a match diff --git a/vendor/github.com/containers/image/openshift/openshift.go b/vendor/github.com/containers/image/openshift/openshift.go index 3504d8ce1..2cadb0ce2 100644 --- a/vendor/github.com/containers/image/openshift/openshift.go +++ b/vendor/github.com/containers/image/openshift/openshift.go @@ -369,6 +369,13 @@ func (d *openshiftImageDestination) MustMatchRuntimeOS() bool { return false } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *openshiftImageDestination) IgnoresEmbeddedDockerReference() bool { + return d.docker.IgnoresEmbeddedDockerReference() +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/vendor/github.com/containers/image/ostree/ostree_dest.go b/vendor/github.com/containers/image/ostree/ostree_dest.go index 2e0d7fcff..0ae30f1f4 100644 --- a/vendor/github.com/containers/image/ostree/ostree_dest.go +++ b/vendor/github.com/containers/image/ostree/ostree_dest.go @@ -14,6 +14,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strconv" "strings" "syscall" @@ -124,6 +125,13 @@ func (d *ostreeImageDestination) MustMatchRuntimeOS() bool { return true } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (d *ostreeImageDestination) IgnoresEmbeddedDockerReference() bool { + return false // N/A, DockerReference() returns nil. +} + func (d *ostreeImageDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, isConfig bool) (types.BlobInfo, error) { tmpDir, err := ioutil.TempDir(d.tmpDirPath, "blob") if err != nil { @@ -394,6 +402,9 @@ func (d *ostreeImageDestination) PutSignatures(ctx context.Context, signatures [ } func (d *ostreeImageDestination) Commit(ctx context.Context) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + repo, err := otbuiltin.OpenRepo(d.ref.repo) if err != nil { return err diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go index b43caf1a0..a6da88e71 100644 --- a/vendor/github.com/containers/image/storage/storage_image.go +++ b/vendor/github.com/containers/image/storage/storage_image.go @@ -50,8 +50,7 @@ type storageImageSource struct { } type storageImageDestination struct { - imageRef storageReference // The reference we'll use to name the image - publicRef storageReference // The reference we return when asked about the name we'll give to the image + imageRef storageReference directory string // Temporary directory where we store blobs until Commit() time nextTempFileID int32 // A counter that we use for computing filenames to assign to blobs manifest []byte // Manifest contents, temporary @@ -243,15 +242,8 @@ func newImageDestination(imageRef storageReference) (*storageImageDestination, e if err != nil { return nil, errors.Wrapf(err, "error creating a temporary directory") } - // Break reading of the reference we're writing, so that copy.Image() won't try to rewrite - // schema1 image manifests to remove embedded references, since that changes the manifest's - // digest, and that makes the image unusable if we subsequently try to access it using a - // reference that mentions the no-longer-correct digest. - publicRef := imageRef - publicRef.name = nil image := &storageImageDestination{ imageRef: imageRef, - publicRef: publicRef, directory: directory, blobDiffIDs: make(map[digest.Digest]digest.Digest), fileSizes: make(map[digest.Digest]int64), @@ -261,11 +253,10 @@ func newImageDestination(imageRef storageReference) (*storageImageDestination, e return image, nil } -// Reference returns a mostly-usable image reference that can't return a DockerReference, to -// avoid triggering logic in copy.Image() that rewrites schema 1 image manifests in order to -// remove image names that they contain which don't match the value we're using. +// Reference returns the reference used to set up this destination. Note that this should directly correspond to user's intent, +// e.g. it should use the public hostname instead of the result of resolving CNAMEs or following redirects. func (s storageImageDestination) Reference() types.ImageReference { - return s.publicRef + return s.imageRef } // Close cleans up the temporary directory. @@ -613,7 +604,7 @@ func (s *storageImageDestination) Commit(ctx context.Context) error { if name := s.imageRef.DockerReference(); len(oldNames) > 0 || name != nil { names := []string{} if name != nil { - names = append(names, verboseName(name)) + names = append(names, name.String()) } if len(oldNames) > 0 { names = append(names, oldNames...) @@ -703,6 +694,13 @@ func (s *storageImageDestination) MustMatchRuntimeOS() bool { return true } +// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), +// and would prefer to receive an unmodified manifest instead of one modified for the destination. +// Does not make a difference if Reference().DockerReference() is nil. +func (s *storageImageDestination) IgnoresEmbeddedDockerReference() bool { + return true // Yes, we want the unmodified manifest +} + // PutSignatures records the image's signatures for committing as a single data blob. func (s *storageImageDestination) PutSignatures(ctx context.Context, signatures [][]byte) error { sizes := []int{} diff --git a/vendor/github.com/containers/image/storage/storage_reference.go b/vendor/github.com/containers/image/storage/storage_reference.go index 532716941..73306b972 100644 --- a/vendor/github.com/containers/image/storage/storage_reference.go +++ b/vendor/github.com/containers/image/storage/storage_reference.go @@ -9,7 +9,6 @@ import ( "github.com/containers/image/docker/reference" "github.com/containers/image/types" "github.com/containers/storage" - digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -17,55 +16,65 @@ import ( // A storageReference holds an arbitrary name and/or an ID, which is a 32-byte // value hex-encoded into a 64-character string, and a reference to a Store // where an image is, or would be, kept. +// Either "named" or "id" must be set. type storageReference struct { transport storageTransport - reference string + named reference.Named // may include a tag and/or a digest id string - name reference.Named - tag string - digest digest.Digest } -func newReference(transport storageTransport, reference, id string, name reference.Named, tag string, digest digest.Digest) *storageReference { +func newReference(transport storageTransport, named reference.Named, id string) (*storageReference, error) { + if named == nil && id == "" { + return nil, ErrInvalidReference + } // We take a copy of the transport, which contains a pointer to the // store that it used for resolving this reference, so that the // transport that we'll return from Transport() won't be affected by // further calls to the original transport's SetStore() method. return &storageReference{ transport: transport, - reference: reference, + named: named, id: id, - name: name, - tag: tag, - digest: digest, + }, nil +} + +// imageMatchesRepo returns true iff image.Names contains an element with the same repo as ref +func imageMatchesRepo(image *storage.Image, ref reference.Named) bool { + repo := ref.Name() + for _, name := range image.Names { + if named, err := reference.ParseNormalizedNamed(name); err == nil { + if named.Name() == repo { + return true + } + } } + return false } // Resolve the reference's name to an image ID in the store, if there's already // one present with the same name or ID, and return the image. func (s *storageReference) resolveImage() (*storage.Image, error) { + var loadedImage *storage.Image if s.id == "" { // Look for an image that has the expanded reference name as an explicit Name value. - image, err := s.transport.store.Image(s.reference) + image, err := s.transport.store.Image(s.named.String()) if image != nil && err == nil { + loadedImage = image s.id = image.ID } } - if s.id == "" && s.name != nil && s.digest != "" { - // Look for an image with the specified digest that has the same name, - // though possibly with a different tag or digest, as a Name value, so - // that the canonical reference can be implicitly resolved to the image. - images, err := s.transport.store.ImagesByDigest(s.digest) - if images != nil && err == nil { - repo := reference.FamiliarName(reference.TrimNamed(s.name)) - search: - for _, image := range images { - for _, name := range image.Names { - if named, err := reference.ParseNormalizedNamed(name); err == nil { - if reference.FamiliarName(reference.TrimNamed(named)) == repo { - s.id = image.ID - break search - } + if s.id == "" && s.named != nil { + if digested, ok := s.named.(reference.Digested); ok { + // Look for an image with the specified digest that has the same name, + // though possibly with a different tag or digest, as a Name value, so + // that the canonical reference can be implicitly resolved to the image. + images, err := s.transport.store.ImagesByDigest(digested.Digest()) + if images != nil && err == nil { + for _, image := range images { + if imageMatchesRepo(image, s.named) { + loadedImage = image + s.id = image.ID + break } } } @@ -75,27 +84,20 @@ func (s *storageReference) resolveImage() (*storage.Image, error) { logrus.Debugf("reference %q does not resolve to an image ID", s.StringWithinTransport()) return nil, errors.Wrapf(ErrNoSuchImage, "reference %q does not resolve to an image ID", s.StringWithinTransport()) } - img, err := s.transport.store.Image(s.id) - if err != nil { - return nil, errors.Wrapf(err, "error reading image %q", s.id) - } - if s.name != nil { - repo := reference.FamiliarName(reference.TrimNamed(s.name)) - nameMatch := false - for _, name := range img.Names { - if named, err := reference.ParseNormalizedNamed(name); err == nil { - if reference.FamiliarName(reference.TrimNamed(named)) == repo { - nameMatch = true - break - } - } + if loadedImage == nil { + img, err := s.transport.store.Image(s.id) + if err != nil { + return nil, errors.Wrapf(err, "error reading image %q", s.id) } - if !nameMatch { + loadedImage = img + } + if s.named != nil { + if !imageMatchesRepo(loadedImage, s.named) { logrus.Errorf("no image matching reference %q found", s.StringWithinTransport()) return nil, ErrNoSuchImage } } - return img, nil + return loadedImage, nil } // Return a Transport object that defaults to using the same store that we used @@ -110,20 +112,7 @@ func (s storageReference) Transport() types.ImageTransport { // Return a name with a tag or digest, if we have either, else return it bare. func (s storageReference) DockerReference() reference.Named { - if s.name == nil { - return nil - } - if s.tag != "" { - if namedTagged, err := reference.WithTag(s.name, s.tag); err == nil { - return namedTagged - } - } - if s.digest != "" { - if canonical, err := reference.WithDigest(s.name, s.digest); err == nil { - return canonical - } - } - return s.name + return s.named } // Return a name with a tag, prefixed with the graph root and driver name, to @@ -135,25 +124,25 @@ func (s storageReference) StringWithinTransport() string { if len(options) > 0 { optionsList = ":" + strings.Join(options, ",") } - storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "+" + s.transport.store.RunRoot() + optionsList + "]" - if s.reference == "" { - return storeSpec + "@" + s.id + res := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "+" + s.transport.store.RunRoot() + optionsList + "]" + if s.named != nil { + res = res + s.named.String() } - if s.id == "" { - return storeSpec + s.reference + if s.id != "" { + res = res + "@" + s.id } - return storeSpec + s.reference + "@" + s.id + return res } func (s storageReference) PolicyConfigurationIdentity() string { - storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "]" - if s.name == nil { - return storeSpec + "@" + s.id + res := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "]" + if s.named != nil { + res = res + s.named.String() } - if s.id == "" { - return storeSpec + s.reference + if s.id != "" { + res = res + "@" + s.id } - return storeSpec + s.reference + "@" + s.id + return res } // Also accept policy that's tied to the combination of the graph root and @@ -164,9 +153,17 @@ func (s storageReference) PolicyConfigurationNamespaces() []string { storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "]" driverlessStoreSpec := "[" + s.transport.store.GraphRoot() + "]" namespaces := []string{} - if s.name != nil { - name := reference.TrimNamed(s.name) - components := strings.Split(name.String(), "/") + if s.named != nil { + if s.id != "" { + // The reference without the ID is also a valid namespace. + namespaces = append(namespaces, storeSpec+s.named.String()) + } + tagged, isTagged := s.named.(reference.Tagged) + _, isDigested := s.named.(reference.Digested) + if isTagged && isDigested { // s.named is "name:tag@digest"; add a "name:tag" parent namespace. + namespaces = append(namespaces, storeSpec+s.named.Name()+":"+tagged.Tag()) + } + components := strings.Split(s.named.Name(), "/") for len(components) > 0 { namespaces = append(namespaces, storeSpec+strings.Join(components, "/")) components = components[:len(components)-1] diff --git a/vendor/github.com/containers/image/storage/storage_transport.go b/vendor/github.com/containers/image/storage/storage_transport.go index f6ebcdc4a..8886f9250 100644 --- a/vendor/github.com/containers/image/storage/storage_transport.go +++ b/vendor/github.com/containers/image/storage/storage_transport.go @@ -3,6 +3,7 @@ package storage import ( + "fmt" "path/filepath" "strings" @@ -105,7 +106,6 @@ func (s *storageTransport) DefaultGIDMap() []idtools.IDMap { // ParseStoreReference takes a name or an ID, tries to figure out which it is // relative to the given store, and returns it in a reference object. func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (*storageReference, error) { - var name reference.Named if ref == "" { return nil, errors.Wrapf(ErrInvalidReference, "%q is an empty reference") } @@ -118,66 +118,36 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) ( ref = ref[closeIndex+1:] } - // The last segment, if there's more than one, is either a digest from a reference, or an image ID. + // The reference may end with an image ID. Image IDs and digests use the same "@" separator; + // here we only peel away an image ID, and leave digests alone. split := strings.LastIndex(ref, "@") - idOrDigest := "" - if split != -1 { - // Peel off that last bit so that we can work on the rest. - idOrDigest = ref[split+1:] - if idOrDigest == "" { - return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like a digest or image ID", idOrDigest) - } - ref = ref[:split] - } - - // The middle segment (now the last segment), if there is one, is a digest. - split = strings.LastIndex(ref, "@") - sum := digest.Digest("") - if split != -1 { - sum = digest.Digest(ref[split+1:]) - if sum == "" { - return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like an image digest", sum) - } - ref = ref[:split] - } - - // If we have something that unambiguously should be a digest, validate it, and then the third part, - // if we have one, as an ID. id := "" - if sum != "" { - if idSum, err := digest.Parse("sha256:" + idOrDigest); err != nil || idSum.Validate() != nil { - return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like an image ID", idOrDigest) - } - if err := sum.Validate(); err != nil { - return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like an image digest", sum) - } - id = idOrDigest - if img, err := store.Image(idOrDigest); err == nil && img != nil && len(idOrDigest) >= minimumTruncatedIDLength && strings.HasPrefix(img.ID, idOrDigest) { - // The ID is a truncated version of the ID of an image that's present in local storage, - // so we might as well use the expanded value. - id = img.ID + if split != -1 { + possibleID := ref[split+1:] + if possibleID == "" { + return nil, errors.Wrapf(ErrInvalidReference, "empty trailing digest or ID in %q", ref) } - } else if idOrDigest != "" { - // There was no middle portion, so the final portion could be either a digest or an ID. - if idSum, err := digest.Parse("sha256:" + idOrDigest); err == nil && idSum.Validate() == nil { - // It's an ID. - id = idOrDigest - } else if idSum, err := digest.Parse(idOrDigest); err == nil && idSum.Validate() == nil { - // It's a digest. - sum = idSum - } else if img, err := store.Image(idOrDigest); err == nil && img != nil && len(idOrDigest) >= minimumTruncatedIDLength && strings.HasPrefix(img.ID, idOrDigest) { - // It's a truncated version of the ID of an image that's present in local storage, - // and we may need the expanded value. - id = img.ID - } else { - return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like a digest or image ID", idOrDigest) + // If it looks like a digest, leave it alone for now. + if _, err := digest.Parse(possibleID); err != nil { + // Otherwise… + if idSum, err := digest.Parse("sha256:" + possibleID); err == nil && idSum.Validate() == nil { + id = possibleID // … it is a full ID + } else if img, err := store.Image(possibleID); err == nil && img != nil && len(possibleID) >= minimumTruncatedIDLength && strings.HasPrefix(img.ID, possibleID) { + // … it is a truncated version of the ID of an image that's present in local storage, + // so we might as well use the expanded value. + id = img.ID + } else { + return nil, errors.Wrapf(ErrInvalidReference, "%q does not look like an image ID or digest", possibleID) + } + // We have recognized an image ID; peel it off. + ref = ref[:split] } } - // If we only had one portion, then _maybe_ it's a truncated image ID. Only check on that if it's + // If we only have one @-delimited portion, then _maybe_ it's a truncated image ID. Only check on that if it's // at least of what we guess is a reasonable minimum length, because we don't want a really short value // like "a" matching an image by ID prefix when the input was actually meant to specify an image name. - if len(ref) >= minimumTruncatedIDLength && sum == "" && id == "" { + if id == "" && len(ref) >= minimumTruncatedIDLength && !strings.ContainsAny(ref, "@:") { if img, err := store.Image(ref); err == nil && img != nil && strings.HasPrefix(img.ID, ref) { // It's a truncated version of the ID of an image that's present in local storage; // we need to expand it. @@ -186,53 +156,24 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) ( } } - // The initial portion is probably a name, possibly with a tag. + var named reference.Named + // Unless we have an un-named "ID" or "@ID" reference (where ID might only have been a prefix), which has been + // completely parsed above, the initial portion should be a name, possibly with a tag and/or a digest.. if ref != "" { var err error - if name, err = reference.ParseNormalizedNamed(ref); err != nil { + named, err = reference.ParseNormalizedNamed(ref) + if err != nil { return nil, errors.Wrapf(err, "error parsing named reference %q", ref) } - } - if name == nil && sum == "" && id == "" { - return nil, errors.Errorf("error parsing reference") + named = reference.TagNameOnly(named) } - // Construct a copy of the store spec. - optionsList := "" - options := store.GraphOptions() - if len(options) > 0 { - optionsList = ":" + strings.Join(options, ",") - } - storeSpec := "[" + store.GraphDriverName() + "@" + store.GraphRoot() + "+" + store.RunRoot() + optionsList + "]" - - // Convert the name back into a reference string, if we got a name. - refname := "" - tag := "" - if name != nil { - if sum.Validate() == nil { - canonical, err := reference.WithDigest(name, sum) - if err != nil { - return nil, errors.Wrapf(err, "error mixing name %q with digest %q", name, sum) - } - refname = verboseName(canonical) - } else { - name = reference.TagNameOnly(name) - tagged, ok := name.(reference.Tagged) - if !ok { - return nil, errors.Errorf("error parsing possibly-tagless name %q", ref) - } - refname = verboseName(name) - tag = tagged.Tag() - } - } - if refname == "" { - logrus.Debugf("parsed reference to id into %q", storeSpec+"@"+id) - } else if id == "" { - logrus.Debugf("parsed reference to refname into %q", storeSpec+refname) - } else { - logrus.Debugf("parsed reference to refname@id into %q", storeSpec+refname+"@"+id) + result, err := newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, named, id) + if err != nil { + return nil, err } - return newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, refname, id, name, tag, sum), nil + logrus.Debugf("parsed reference into %q", result.StringWithinTransport()) + return result, nil } func (s *storageTransport) GetStore() (storage.Store, error) { @@ -252,7 +193,7 @@ func (s *storageTransport) GetStore() (storage.Store, error) { } // ParseReference takes a name and a tag or digest and/or ID -// ("_name_"/"@_id_"/"_name_:_tag_"/"_name_:_tag_@_id_"/"_name_@_digest_"/"_name_@_digest_@_id_"), +// ("_name_"/"@_id_"/"_name_:_tag_"/"_name_:_tag_@_id_"/"_name_@_digest_"/"_name_@_digest_@_id_"/"_name_:_tag_@_digest_"/"_name_:_tag_@_digest_@_id_"), // possibly prefixed with a store specifier in the form "[_graphroot_]" or // "[_driver_@_graphroot_]" or "[_driver_@_graphroot_+_runroot_]" or // "[_driver_@_graphroot_:_options_]" or "[_driver_@_graphroot_+_runroot_:_options_]", @@ -338,7 +279,7 @@ func (s *storageTransport) ParseReference(reference string) (types.ImageReferenc func (s storageTransport) GetStoreImage(store storage.Store, ref types.ImageReference) (*storage.Image, error) { dref := ref.DockerReference() if dref != nil { - if img, err := store.Image(verboseName(dref)); err == nil { + if img, err := store.Image(dref.String()); err == nil { return img, nil } } @@ -399,52 +340,29 @@ func (s storageTransport) ValidatePolicyConfigurationScope(scope string) error { if scope == "" { return nil } - // But if there is anything left, it has to be a name, with or without - // a tag, with or without an ID, since we don't return namespace values - // that are just bare IDs. - scopeInfo := strings.SplitN(scope, "@", 2) - if len(scopeInfo) == 1 && scopeInfo[0] != "" { - _, err := reference.ParseNormalizedNamed(scopeInfo[0]) - if err != nil { - return err + + fields := strings.SplitN(scope, "@", 3) + switch len(fields) { + case 1: // name only + case 2: // name:tag@ID or name[:tag]@digest + if _, idErr := digest.Parse("sha256:" + fields[1]); idErr != nil { + if _, digestErr := digest.Parse(fields[1]); digestErr != nil { + return fmt.Errorf("%v is neither a valid digest(%s) nor a valid ID(%s)", fields[1], digestErr.Error(), idErr.Error()) + } } - } else if len(scopeInfo) == 2 && scopeInfo[0] != "" && scopeInfo[1] != "" { - _, err := reference.ParseNormalizedNamed(scopeInfo[0]) - if err != nil { + case 3: // name[:tag]@digest@ID + if _, err := digest.Parse(fields[1]); err != nil { return err } - _, err = digest.Parse("sha256:" + scopeInfo[1]) - if err != nil { + if _, err := digest.Parse("sha256:" + fields[2]); err != nil { return err } - } else { - return ErrInvalidReference + default: // Coverage: This should never happen + return errors.New("Internal error: unexpected number of fields form strings.SplitN") } + // As for field[0], if it is non-empty at all: + // 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 } - -func verboseName(r reference.Reference) string { - if r == nil { - return "" - } - named, isNamed := r.(reference.Named) - digested, isDigested := r.(reference.Digested) - tagged, isTagged := r.(reference.Tagged) - name := "" - tag := "" - sum := "" - if isNamed { - name = (reference.TrimNamed(named)).String() - } - if isTagged { - if tagged.Tag() != "" { - tag = ":" + tagged.Tag() - } - } - if isDigested { - if digested.Digest().Validate() == nil { - sum = "@" + digested.Digest().String() - } - } - return name + tag + sum -} diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index 2823a05c0..3ec77e0d1 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -174,6 +174,11 @@ type ImageDestination interface { AcceptsForeignLayerURLs() bool // MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime OS. False otherwise. MustMatchRuntimeOS() bool + // IgnoresEmbeddedDockerReference() returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(), + // and would prefer to receive an unmodified manifest instead of one modified for the destination. + // Does not make a difference if Reference().DockerReference() is nil. + IgnoresEmbeddedDockerReference() bool + // PutBlob writes contents of stream and returns data representing the result. // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/vendor/github.com/containers/image/vendor.conf b/vendor/github.com/containers/image/vendor.conf index 123bde98a..a84ab18b3 100644 --- a/vendor/github.com/containers/image/vendor.conf +++ b/vendor/github.com/containers/image/vendor.conf @@ -40,3 +40,5 @@ github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460 github.com/gogo/protobuf fcdc5011193ff531a548e9b0301828d5a5b97fd8 github.com/pquerna/ffjson master github.com/syndtr/gocapability master +github.com/Microsoft/go-winio ab35fc04b6365e8fcb18e6e9e41ea4a02b10b175 +github.com/Microsoft/hcsshim eca7177590cdcbd25bbc5df27e3b693a54b53a6a |