diff --git a/vendor/github.com/containers/image/copy/copy.go b/vendor/github.com/containers/image/copy/copy.go index 3f054cd3..fb1c61fd 100644 --- a/vendor/github.com/containers/image/copy/copy.go +++ b/vendor/github.com/containers/image/copy/copy.go @@ -354,7 +354,7 @@ type diffIDResult struct { func (ic *imageCopier) copyLayer(srcInfo types.BlobInfo) (types.BlobInfo, digest.Digest, error) { // Check if we already have a blob with this digest haveBlob, extantBlobSize, err := ic.dest.HasBlob(srcInfo) - if err != nil && err != types.ErrBlobNotFound { + if err != nil { return types.BlobInfo{}, "", errors.Wrapf(err, "Error checking for blob %s at destination", srcInfo.Digest) } // If we already have a cached diffID for this blob, we don't need to compute it diff --git a/vendor/github.com/containers/image/directory/directory_dest.go b/vendor/github.com/containers/image/directory/directory_dest.go index c310d662..9fe7de1e 100644 --- a/vendor/github.com/containers/image/directory/directory_dest.go +++ b/vendor/github.com/containers/image/directory/directory_dest.go @@ -95,6 +95,10 @@ func (d *dirImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo return types.BlobInfo{Digest: computedDigest, Size: size}, nil } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (d *dirImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { if info.Digest == "" { return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`) @@ -102,7 +106,7 @@ func (d *dirImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) blobPath := d.ref.layerPath(info.Digest) finfo, err := os.Stat(blobPath) if err != nil && os.IsNotExist(err) { - return false, -1, types.ErrBlobNotFound + return false, -1, nil } if err != nil { return false, -1, err diff --git a/vendor/github.com/containers/image/docker/daemon/daemon_dest.go b/vendor/github.com/containers/image/docker/daemon/daemon_dest.go index f8ba97af..f94de3b1 100644 --- a/vendor/github.com/containers/image/docker/daemon/daemon_dest.go +++ b/vendor/github.com/containers/image/docker/daemon/daemon_dest.go @@ -151,7 +151,11 @@ func (d *daemonImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI return types.BlobInfo{}, errors.Errorf(`Can not stream a blob with unknown digest to "docker-daemon:"`) } - if ok, size, err := d.HasBlob(inputInfo); err == nil && ok { + ok, size, err := d.HasBlob(inputInfo) + if err != nil { + return types.BlobInfo{}, err + } + if ok { return types.BlobInfo{Digest: inputInfo.Digest, Size: size}, nil } @@ -186,6 +190,10 @@ func (d *daemonImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI return types.BlobInfo{Digest: digester.Digest(), Size: inputInfo.Size}, nil } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (d *daemonImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { if info.Digest == "" { return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`) @@ -193,7 +201,7 @@ func (d *daemonImageDestination) HasBlob(info types.BlobInfo) (bool, int64, erro if blob, ok := d.blobs[info.Digest]; ok { return true, blob.Size, nil } - return false, -1, types.ErrBlobNotFound + return false, -1, nil } func (d *daemonImageDestination) ReapplyBlob(info types.BlobInfo) (types.BlobInfo, error) { 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 88979b48..1971aa91 100644 --- a/vendor/github.com/containers/image/docker/docker_image_dest.go +++ b/vendor/github.com/containers/image/docker/docker_image_dest.go @@ -113,11 +113,10 @@ func (c *sizeCounter) Write(p []byte) (n int, err error) { func (d *dockerImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo) (types.BlobInfo, error) { if inputInfo.Digest.String() != "" { haveBlob, size, err := d.HasBlob(inputInfo) - if err != nil && err != types.ErrBlobNotFound { + if err != nil { return types.BlobInfo{}, err } - // Now err == nil || err == types.ErrBlobNotFound - if err == nil && haveBlob { + if haveBlob { return types.BlobInfo{Digest: inputInfo.Digest, Size: size}, nil } } @@ -175,6 +174,10 @@ func (d *dockerImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI return types.BlobInfo{Digest: computedDigest, Size: sizeCounter.size}, nil } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (d *dockerImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { if info.Digest == "" { return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`) @@ -196,7 +199,7 @@ func (d *dockerImageDestination) HasBlob(info types.BlobInfo) (bool, int64, erro return false, -1, errors.Errorf("not authorized to read from destination repository %s", reference.Path(d.ref.ref)) case http.StatusNotFound: logrus.Debugf("... not present") - return false, -1, types.ErrBlobNotFound + return false, -1, nil default: return false, -1, errors.Errorf("failed to read from destination repository %s: %v", reference.Path(d.ref.ref), http.StatusText(res.StatusCode)) } @@ -274,6 +277,7 @@ func (d *dockerImageDestination) putSignaturesToLookaside(signatures [][]byte) e return errors.Errorf("Unknown manifest digest, can't add signatures") } + // NOTE: Keep this in sync with docs/signature-protocols.md! for i, signature := range signatures { url := signatureStorageURL(d.c.signatureBase, d.manifestDigest, i) if url == nil { @@ -307,6 +311,7 @@ func (d *dockerImageDestination) putSignaturesToLookaside(signatures [][]byte) e } // putOneSignature stores one signature to url. +// NOTE: Keep this in sync with docs/signature-protocols.md! func (d *dockerImageDestination) putOneSignature(url *url.URL, signature []byte) error { switch url.Scheme { case "file": @@ -330,6 +335,7 @@ func (d *dockerImageDestination) putOneSignature(url *url.URL, signature []byte) // deleteOneSignature deletes a signature from url, if it exists. // If it successfully determines that the signature does not exist, returns (true, nil) +// NOTE: Keep this in sync with docs/signature-protocols.md! func (c *dockerClient) deleteOneSignature(url *url.URL) (missing bool, err error) { switch url.Scheme { case "file": diff --git a/vendor/github.com/containers/image/docker/docker_image_src.go b/vendor/github.com/containers/image/docker/docker_image_src.go index 01a287bb..ebc5cfab 100644 --- a/vendor/github.com/containers/image/docker/docker_image_src.go +++ b/vendor/github.com/containers/image/docker/docker_image_src.go @@ -217,6 +217,7 @@ func (s *dockerImageSource) getSignaturesFromLookaside() ([][]byte, error) { return nil, err } + // NOTE: Keep this in sync with docs/signature-protocols.md! signatures := [][]byte{} for i := 0; ; i++ { url := signatureStorageURL(s.c.signatureBase, manifestDigest, i) @@ -237,6 +238,7 @@ func (s *dockerImageSource) getSignaturesFromLookaside() ([][]byte, error) { // getOneSignature downloads one signature from url. // If it successfully determines that the signature does not exist, returns with missing set to true and error set to nil. +// NOTE: Keep this in sync with docs/signature-protocols.md! func (s *dockerImageSource) getOneSignature(url *url.URL) (signature []byte, missing bool, err error) { switch url.Scheme { case "file": diff --git a/vendor/github.com/containers/image/docker/lookaside.go b/vendor/github.com/containers/image/docker/lookaside.go index ba2bd9b4..c6dca5e4 100644 --- a/vendor/github.com/containers/image/docker/lookaside.go +++ b/vendor/github.com/containers/image/docker/lookaside.go @@ -63,6 +63,7 @@ func configuredSignatureStorageBase(ctx *types.SystemContext, ref dockerReferenc if err != nil { return nil, errors.Wrapf(err, "Invalid signature storage URL %s", topLevel) } + // NOTE: Keep this in sync with docs/signature-protocols.md! // FIXME? Restrict to explicitly supported schemes? repo := reference.Path(ref.ref) // Note that this is without a tag or digest. if path.Clean(repo) != repo { // Coverage: This should not be reachable because /./ and /../ components are not valid in docker references @@ -190,6 +191,7 @@ func (ns registryNamespace) signatureTopLevel(write bool) string { // signatureStorageURL returns an URL usable for acessing signature index in base with known manifestDigest, or nil if not applicable. // Returns nil iff base == nil. +// NOTE: Keep this in sync with docs/signature-protocols.md! func signatureStorageURL(base signatureStorageBase, manifestDigest digest.Digest, index int) *url.URL { if base == nil { return nil diff --git a/vendor/github.com/containers/image/image/docker_schema1.go b/vendor/github.com/containers/image/image/docker_schema1.go index 7d6de1a6..6d09a868 100644 --- a/vendor/github.com/containers/image/image/docker_schema1.go +++ b/vendor/github.com/containers/image/image/docker_schema1.go @@ -10,6 +10,7 @@ import ( "github.com/containers/image/manifest" "github.com/containers/image/types" "github.com/opencontainers/go-digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -112,6 +113,17 @@ func (m *manifestSchema1) ConfigBlob() ([]byte, error) { return nil, nil } +// OCIConfig returns the image configuration as per OCI v1 image-spec. Information about +// layers in the resulting configuration isn't guaranteed to be returned to due how +// old image manifests work (docker v2s1 especially). +func (m *manifestSchema1) OCIConfig() (*imgspecv1.Image, error) { + v2s2, err := m.convertToManifestSchema2(nil, nil) + if err != nil { + return nil, err + } + return v2s2.OCIConfig() +} + // LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers). // The Digest field is guaranteed to be provided; Size may be -1. // WARNING: The list may contain duplicates, and they are semantically relevant. @@ -243,10 +255,10 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl if len(m.History) != len(m.FSLayers) { return nil, errors.Errorf("Inconsistent schema 1 manifest: %d history entries, %d fsLayers entries", len(m.History), len(m.FSLayers)) } - if len(uploadedLayerInfos) != len(m.FSLayers) { + if uploadedLayerInfos != nil && len(uploadedLayerInfos) != len(m.FSLayers) { return nil, errors.Errorf("Internal error: uploaded %d blobs, but schema1 manifest has %d fsLayers", len(uploadedLayerInfos), len(m.FSLayers)) } - if len(layerDiffIDs) != len(m.FSLayers) { + if layerDiffIDs != nil && len(layerDiffIDs) != len(m.FSLayers) { return nil, errors.Errorf("Internal error: collected %d DiffID values, but schema1 manifest has %d fsLayers", len(layerDiffIDs), len(m.FSLayers)) } @@ -273,12 +285,20 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl } if !v1compat.ThrowAway { + var size int64 + if uploadedLayerInfos != nil { + size = uploadedLayerInfos[v2Index].Size + } + var d digest.Digest + if layerDiffIDs != nil { + d = layerDiffIDs[v2Index] + } layers = append(layers, descriptor{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Size: uploadedLayerInfos[v2Index].Size, + Size: size, Digest: m.FSLayers[v1Index].BlobSum, }) - rootFS.DiffIDs = append(rootFS.DiffIDs, layerDiffIDs[v2Index]) + rootFS.DiffIDs = append(rootFS.DiffIDs, d) } } configJSON, err := configJSONFromV1Config([]byte(m.History[0].V1Compatibility), rootFS, history) diff --git a/vendor/github.com/containers/image/image/docker_schema2.go b/vendor/github.com/containers/image/image/docker_schema2.go index 76ceea78..ea529e24 100644 --- a/vendor/github.com/containers/image/image/docker_schema2.go +++ b/vendor/github.com/containers/image/image/docker_schema2.go @@ -78,6 +78,24 @@ func (m *manifestSchema2) ConfigInfo() types.BlobInfo { return types.BlobInfo{Digest: m.ConfigDescriptor.Digest, Size: m.ConfigDescriptor.Size} } +// OCIConfig returns the image configuration as per OCI v1 image-spec. Information about +// layers in the resulting configuration isn't guaranteed to be returned to due how +// old image manifests work (docker v2s1 especially). +func (m *manifestSchema2) OCIConfig() (*imgspecv1.Image, error) { + configBlob, err := m.ConfigBlob() + if err != nil { + return nil, err + } + // docker v2s2 and OCI v1 are mostly compatible but v2s2 contains more fields + // than OCI v1. This unmarshal makes sure we drop docker v2s2 + // fields that aren't needed in OCI v1. + configOCI := &imgspecv1.Image{} + if err := json.Unmarshal(configBlob, configOCI); err != nil { + return nil, err + } + return configOCI, nil +} + // ConfigBlob returns the blob described by ConfigInfo, iff ConfigInfo().Digest != ""; nil otherwise. // The result is cached; it is OK to call this however often you need. func (m *manifestSchema2) ConfigBlob() ([]byte, error) { @@ -177,17 +195,10 @@ func (m *manifestSchema2) UpdatedImage(options types.ManifestUpdateOptions) (typ } func (m *manifestSchema2) convertToManifestOCI1() (types.Image, error) { - configBlob, err := m.ConfigBlob() + configOCI, err := m.OCIConfig() if err != nil { return nil, err } - // docker v2s2 and OCI v1 are mostly compatible but v2s2 contains more fields - // than OCI v1. This unmarshal, then re-marshal makes sure we drop docker v2s2 - // fields that aren't needed in OCI v1. - configOCI := &imgspecv1.Image{} - if err := json.Unmarshal(configBlob, configOCI); err != nil { - return nil, err - } configOCIBytes, err := json.Marshal(configOCI) if err != nil { return nil, err diff --git a/vendor/github.com/containers/image/image/manifest.go b/vendor/github.com/containers/image/image/manifest.go index 782f4e8a..1893c7b6 100644 --- a/vendor/github.com/containers/image/image/manifest.go +++ b/vendor/github.com/containers/image/image/manifest.go @@ -64,6 +64,10 @@ type genericManifest interface { // ConfigBlob returns the blob described by ConfigInfo, iff ConfigInfo().Digest != ""; nil otherwise. // The result is cached; it is OK to call this however often you need. ConfigBlob() ([]byte, error) + // OCIConfig returns the image configuration as per OCI v1 image-spec. Information about + // layers in the resulting configuration isn't guaranteed to be returned to due how + // old image manifests work (docker v2s1 especially). + OCIConfig() (*imgspecv1.Image, error) // LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers). // The Digest field is guaranteed to be provided; Size may be -1. // WARNING: The list may contain duplicates, and they are semantically relevant. diff --git a/vendor/github.com/containers/image/image/oci.go b/vendor/github.com/containers/image/image/oci.go index 9c10c5f0..74084204 100644 --- a/vendor/github.com/containers/image/image/oci.go +++ b/vendor/github.com/containers/image/image/oci.go @@ -81,6 +81,21 @@ func (m *manifestOCI1) ConfigBlob() ([]byte, error) { return m.configBlob, nil } +// OCIConfig returns the image configuration as per OCI v1 image-spec. Information about +// layers in the resulting configuration isn't guaranteed to be returned to due how +// old image manifests work (docker v2s1 especially). +func (m *manifestOCI1) OCIConfig() (*imgspecv1.Image, error) { + cb, err := m.ConfigBlob() + if err != nil { + return nil, err + } + configOCI := &imgspecv1.Image{} + if err := json.Unmarshal(cb, configOCI); err != nil { + return nil, err + } + return configOCI, nil +} + // LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers). // The Digest field is guaranteed to be provided; Size may be -1. // WARNING: The list may contain duplicates, and they are semantically relevant. 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 b665f87d..f2a73d31 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_dest.go +++ b/vendor/github.com/containers/image/oci/layout/oci_dest.go @@ -112,6 +112,10 @@ func (d *ociImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo return types.BlobInfo{Digest: computedDigest, Size: size}, nil } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (d *ociImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { if info.Digest == "" { return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`) @@ -122,7 +126,7 @@ func (d *ociImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) } finfo, err := os.Stat(blobPath) if err != nil && os.IsNotExist(err) { - return false, -1, types.ErrBlobNotFound + return false, -1, nil } if err != nil { return false, -1, err diff --git a/vendor/github.com/containers/image/openshift/openshift.go b/vendor/github.com/containers/image/openshift/openshift.go index 9ab905e2..7f03d1f8 100644 --- a/vendor/github.com/containers/image/openshift/openshift.go +++ b/vendor/github.com/containers/image/openshift/openshift.go @@ -371,6 +371,10 @@ func (d *openshiftImageDestination) PutBlob(stream io.Reader, inputInfo types.Bl return d.docker.PutBlob(stream, inputInfo) } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (d *openshiftImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { return d.docker.HasBlob(info) } diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go index 7930cb32..f18c75bf 100644 --- a/vendor/github.com/containers/image/storage/storage_image.go +++ b/vendor/github.com/containers/image/storage/storage_image.go @@ -290,6 +290,10 @@ func (s *storageImageDestination) PutBlob(stream io.Reader, blobinfo types.BlobI return s.putBlob(stream, blobinfo, true) } +// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. +// Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. +// If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); +// it returns a non-nil error only on an unexpected failure. func (s *storageImageDestination) HasBlob(blobinfo types.BlobInfo) (bool, int64, error) { if blobinfo.Digest == "" { return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`) @@ -299,7 +303,7 @@ func (s *storageImageDestination) HasBlob(blobinfo types.BlobInfo) (bool, int64, return true, blob.Size, nil } } - return false, -1, types.ErrBlobNotFound + return false, -1, nil } func (s *storageImageDestination) ReapplyBlob(blobinfo types.BlobInfo) (types.BlobInfo, error) { diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index e114a95e..a32bf5a9 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -6,7 +6,7 @@ import ( "github.com/containers/image/docker/reference" "github.com/opencontainers/go-digest" - "github.com/pkg/errors" + "github.com/opencontainers/image-spec/specs-go/v1" ) // ImageTransport is a top-level namespace for ways to to store/load an image. @@ -160,7 +160,10 @@ type ImageDestination interface { // to any other readers for download using the supplied digest. // If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. PutBlob(stream io.Reader, inputInfo BlobInfo) (BlobInfo, error) - // HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. A false result will often be accompanied by an ErrBlobNotFound error. + // HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob. + // Unlike PutBlob, the digest can not be empty. If HasBlob returns true, the size of the blob must also be returned. + // If the destination does not contain the blob, or it is unknown, HasBlob ordinarily returns (false, -1, nil); + // it returns a non-nil error only on an unexpected failure. HasBlob(info BlobInfo) (bool, int64, error) // ReapplyBlob informs the image destination that a blob for which HasBlob previously returned true would have been passed to PutBlob if it had returned false. Like HasBlob and unlike PutBlob, the digest can not be empty. If the blob is a filesystem layer, this signifies that the changes it describes need to be applied again when composing a filesystem tree. ReapplyBlob(info BlobInfo) (BlobInfo, error) @@ -202,6 +205,10 @@ type Image interface { // ConfigBlob returns the blob described by ConfigInfo, iff ConfigInfo().Digest != ""; nil otherwise. // The result is cached; it is OK to call this however often you need. ConfigBlob() ([]byte, error) + // OCIConfig returns the image configuration as per OCI v1 image-spec. Information about + // layers in the resulting configuration isn't guaranteed to be returned to due how + // old image manifests work (docker v2s1 especially). + OCIConfig() (*v1.Image, error) // LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers). // The Digest field is guaranteed to be provided; Size may be -1. // WARNING: The list may contain duplicates, and they are semantically relevant. @@ -300,8 +307,3 @@ type ProgressProperties struct { Artifact BlobInfo Offset uint64 } - -var ( - // ErrBlobNotFound can be returned by an ImageDestination's HasBlob() method - ErrBlobNotFound = errors.New("no such blob present") -)