diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go index 886c3793..3cef69c0 100644 --- a/vendor/github.com/containers/image/docker/docker_client.go +++ b/vendor/github.com/containers/image/docker/docker_client.go @@ -372,6 +372,10 @@ func (c *dockerClient) ping() (*pingResponse, error) { pr, err = ping("http") } if err != nil { + err = fmt.Errorf("pinging docker registry returned %+v", err) + if c.ctx.DockerDisableV1Ping { + return nil, err + } // best effort to understand if we're talking to a V1 registry pingV1 := func(scheme string) bool { url := fmt.Sprintf(baseURLV1, scheme, c.registry) @@ -393,8 +397,6 @@ func (c *dockerClient) ping() (*pingResponse, error) { } if isV1 { err = ErrV1NotSupported - } else { - err = fmt.Errorf("pinging docker registry returned %+v", err) } } return pr, err diff --git a/vendor/github.com/containers/image/image/docker_schema1.go b/vendor/github.com/containers/image/image/docker_schema1.go index 587ea50f..c2ad9a7d 100644 --- a/vendor/github.com/containers/image/image/docker_schema1.go +++ b/vendor/github.com/containers/image/image/docker_schema1.go @@ -292,7 +292,7 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl Digest: digest.FromBytes(configJSON), } - m2 := manifestSchema2FromComponents(configDescriptor, configJSON, layers) + m2 := manifestSchema2FromComponents(configDescriptor, nil, configJSON, layers) return memoryImageFromManifest(m2), nil } diff --git a/vendor/github.com/containers/image/image/docker_schema2.go b/vendor/github.com/containers/image/image/docker_schema2.go index 9e5626d3..812d3369 100644 --- a/vendor/github.com/containers/image/image/docker_schema2.go +++ b/vendor/github.com/containers/image/image/docker_schema2.go @@ -52,9 +52,9 @@ func manifestSchema2FromManifest(src types.ImageSource, manifest []byte) (generi } // manifestSchema2FromComponents builds a new manifestSchema2 from the supplied data: -func manifestSchema2FromComponents(config descriptor, configBlob []byte, layers []descriptor) genericManifest { +func manifestSchema2FromComponents(config descriptor, src types.ImageSource, configBlob []byte, layers []descriptor) genericManifest { return &manifestSchema2{ - src: nil, + src: src, configBlob: configBlob, SchemaVersion: 2, MediaType: manifest.DockerV2Schema2MediaType, diff --git a/vendor/github.com/containers/image/image/manifest.go b/vendor/github.com/containers/image/image/manifest.go index 0f3b9411..df3e23f4 100644 --- a/vendor/github.com/containers/image/image/manifest.go +++ b/vendor/github.com/containers/image/image/manifest.go @@ -86,9 +86,9 @@ func manifestInstanceFromBlob(src types.ImageSource, manblob []byte, mt string) // need to happen within the ImageSource. case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType, "application/json": return manifestSchema1FromManifest(manblob) - case manifest.DockerV2Schema2MediaType, imgspecv1.MediaTypeImageManifest: - // FIXME: OCI v1 is compatible with Docker Schema2, "docker_schema2.go" is good enough for reading images, but this will - // need to be modified for write support due to differing MIME types. + case imgspecv1.MediaTypeImageManifest: + return manifestOCI1FromManifest(src, manblob) + case manifest.DockerV2Schema2MediaType: return manifestSchema2FromManifest(src, manblob) case manifest.DockerV2ListMediaType: return manifestSchema2FromManifestList(src, manblob) diff --git a/vendor/github.com/containers/image/image/oci.go b/vendor/github.com/containers/image/image/oci.go new file mode 100644 index 00000000..6ca627a9 --- /dev/null +++ b/vendor/github.com/containers/image/image/oci.go @@ -0,0 +1,167 @@ +package image + +import ( + "encoding/json" + "fmt" + "io/ioutil" + + "github.com/containers/image/manifest" + "github.com/containers/image/types" + "github.com/docker/distribution/digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +type manifestOCI1 struct { + src types.ImageSource // May be nil if configBlob is not nil + configBlob []byte // If set, corresponds to contents of ConfigDescriptor. + SchemaVersion int `json:"schemaVersion"` + MediaType string `json:"mediaType"` + ConfigDescriptor descriptor `json:"config"` + LayersDescriptors []descriptor `json:"layers"` +} + +func manifestOCI1FromManifest(src types.ImageSource, manifest []byte) (genericManifest, error) { + oci := manifestOCI1{src: src} + if err := json.Unmarshal(manifest, &oci); err != nil { + return nil, err + } + return &oci, nil +} + +// manifestOCI1FromComponents builds a new manifestOCI1 from the supplied data: +func manifestOCI1FromComponents(config descriptor, configBlob []byte, layers []descriptor) genericManifest { + return &manifestOCI1{ + src: nil, + configBlob: configBlob, + SchemaVersion: 2, + MediaType: imgspecv1.MediaTypeImageManifest, + ConfigDescriptor: config, + LayersDescriptors: layers, + } +} + +func (m *manifestOCI1) serialize() ([]byte, error) { + return json.Marshal(*m) +} + +func (m *manifestOCI1) manifestMIMEType() string { + return m.MediaType +} + +// ConfigInfo returns a complete BlobInfo for the separate config object, or a BlobInfo{Digest:""} if there isn't a separate object. +// Note that the config object may not exist in the underlying storage in the return value of UpdatedImage! Use ConfigBlob() below. +func (m *manifestOCI1) ConfigInfo() types.BlobInfo { + return types.BlobInfo{Digest: m.ConfigDescriptor.Digest, Size: m.ConfigDescriptor.Size} +} + +// 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 *manifestOCI1) ConfigBlob() ([]byte, error) { + if m.configBlob == nil { + if m.src == nil { + return nil, fmt.Errorf("Internal error: neither src nor configBlob set in manifestOCI1") + } + stream, _, err := m.src.GetBlob(types.BlobInfo{ + Digest: m.ConfigDescriptor.Digest, + Size: m.ConfigDescriptor.Size, + URLs: m.ConfigDescriptor.URLs, + }) + if err != nil { + return nil, err + } + defer stream.Close() + blob, err := ioutil.ReadAll(stream) + if err != nil { + return nil, err + } + computedDigest := digest.FromBytes(blob) + if computedDigest != m.ConfigDescriptor.Digest { + return nil, fmt.Errorf("Download config.json digest %s does not match expected %s", computedDigest, m.ConfigDescriptor.Digest) + } + m.configBlob = blob + } + return m.configBlob, 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. +func (m *manifestOCI1) LayerInfos() []types.BlobInfo { + blobs := []types.BlobInfo{} + for _, layer := range m.LayersDescriptors { + blobs = append(blobs, types.BlobInfo{Digest: layer.Digest, Size: layer.Size}) + } + return blobs +} + +func (m *manifestOCI1) imageInspectInfo() (*types.ImageInspectInfo, error) { + config, err := m.ConfigBlob() + if err != nil { + return nil, err + } + v1 := &v1Image{} + if err := json.Unmarshal(config, v1); err != nil { + return nil, err + } + return &types.ImageInspectInfo{ + DockerVersion: v1.DockerVersion, + Created: v1.Created, + Labels: v1.Config.Labels, + Architecture: v1.Architecture, + Os: v1.OS, + }, nil +} + +// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs. +// This is a horribly specific interface, but computing InformationOnly.LayerDiffIDs can be very expensive to compute +// (most importantly it forces us to download the full layers even if they are already present at the destination). +func (m *manifestOCI1) UpdatedImageNeedsLayerDiffIDs(options types.ManifestUpdateOptions) bool { + return false +} + +// UpdatedImage returns a types.Image modified according to options. +// This does not change the state of the original Image object. +func (m *manifestOCI1) UpdatedImage(options types.ManifestUpdateOptions) (types.Image, error) { + copy := *m // NOTE: This is not a deep copy, it still shares slices etc. + if options.LayerInfos != nil { + if len(copy.LayersDescriptors) != len(options.LayerInfos) { + return nil, fmt.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(copy.LayersDescriptors), len(options.LayerInfos)) + } + copy.LayersDescriptors = make([]descriptor, len(options.LayerInfos)) + for i, info := range options.LayerInfos { + copy.LayersDescriptors[i].Digest = info.Digest + copy.LayersDescriptors[i].Size = info.Size + } + } + + switch options.ManifestMIMEType { + case "": // No conversion, OK + case manifest.DockerV2Schema2MediaType: + return copy.convertToManifestSchema2() + default: + return nil, fmt.Errorf("Conversion of image manifest from %s to %s is not implemented", imgspecv1.MediaTypeImageManifest, options.ManifestMIMEType) + } + + return memoryImageFromManifest(©), nil +} + +func (m *manifestOCI1) convertToManifestSchema2() (types.Image, error) { + // Create a copy of the descriptor. + config := m.ConfigDescriptor + + // The only difference between OCI and DockerSchema2 is the mediatypes. The + // media type of the manifest is handled by manifestSchema2FromComponents. + config.MediaType = manifest.DockerV2Schema2ConfigMediaType + + layers := make([]descriptor, len(m.LayersDescriptors)) + for idx := range layers { + layers[idx] = m.LayersDescriptors[idx] + layers[idx].MediaType = manifest.DockerV2Schema2LayerMediaType + } + + // Rather than copying the ConfigBlob now, we just pass m.src to the + // translated manifest, since the only difference is the mediatype of + // descriptors there is no change to any blob stored in m.src. + m1 := manifestSchema2FromComponents(config, m.src, nil, layers) + return memoryImageFromManifest(m1), nil +} 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 e4bc5846..55581c7e 100644 --- a/vendor/github.com/containers/image/oci/layout/oci_dest.go +++ b/vendor/github.com/containers/image/oci/layout/oci_dest.go @@ -49,7 +49,7 @@ func (d *ociImageDestination) SupportsSignatures() error { // ShouldCompressLayers returns true iff it is desirable to compress layer blobs written to this destination. func (d *ociImageDestination) ShouldCompressLayers() bool { - return false + return true } // AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index 8c436be7..18e0e236 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -276,4 +276,8 @@ type SystemContext struct { DockerAuthConfig *DockerAuthConfig // if not "", an User-Agent header is added to each request when contacting a registry. DockerRegistryUserAgent string + // if true, a V1 ping attempt isn't done to give users a better error. Default is false. + // Note that this field is used mainly to integrate containers/image into projectatomic/docker + // in order to not break any existing docker's integration tests. + DockerDisableV1Ping bool }