Merge pull request #195 from runcom/vendor-cont/images

vendor containers/image, OCI/image-spec
This commit is contained in:
Miloslav Trmač 2016-09-08 14:03:43 +02:00 committed by GitHub
commit 362bfc5fe3
17 changed files with 95 additions and 60 deletions

View File

@ -19,8 +19,8 @@ var layersCmd = cli.Command{
rawSource, err := parseImageSource(c, c.Args()[0], []string{
// TODO: skopeo layers only support these now
// eventually we'll remove this command altogether...
manifest.DockerV2Schema1SignedMIMEType,
manifest.DockerV2Schema1MIMEType,
manifest.DockerV2Schema1SignedMediaType,
manifest.DockerV2Schema1MediaType,
})
if err != nil {
return err

View File

@ -114,7 +114,11 @@ func Image(ctx *types.SystemContext, policyContext *signature.PolicyContext, des
return fmt.Errorf("Error reading signatures: %v", err)
}
sigs = s
// FIXME: Fail early if we can detect that RemoveSignatures should be used.
}
if len(sigs) != 0 {
if err := dest.SupportsSignatures(); err != nil {
return fmt.Errorf("Can not copy signatures: %v", err)
}
}
blobDigests, err := src.BlobDigests()

View File

@ -34,6 +34,12 @@ func (d *dirImageDestination) SupportedManifestMIMETypes() []string {
return nil
}
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
func (d *dirImageDestination) SupportsSignatures() error {
return nil
}
// PutBlob writes contents of stream and returns its computed digest and size.
// A digest can be optionally provided if known, the specific image destination can decide to play with it or not.
// The length of stream is expected to be expectedSize; if expectedSize == -1, it is not known.

View File

@ -45,12 +45,18 @@ func (d *dockerImageDestination) Close() {
func (d *dockerImageDestination) SupportedManifestMIMETypes() []string {
return []string{
// TODO(runcom): we'll add OCI as part of another PR here
manifest.DockerV2Schema2MIMEType,
manifest.DockerV2Schema1SignedMIMEType,
manifest.DockerV2Schema1MIMEType,
manifest.DockerV2Schema2MediaType,
manifest.DockerV2Schema1SignedMediaType,
manifest.DockerV2Schema1MediaType,
}
}
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
func (d *dockerImageDestination) SupportsSignatures() error {
return fmt.Errorf("Pushing signatures to a Docker Registry is not supported")
}
// PutBlob writes contents of stream and returns its computed digest and size.
// A digest can be optionally provided if known, the specific image destination can decide to play with it or not.
// The length of stream is expected to be expectedSize; if expectedSize == -1, it is not known.
@ -67,7 +73,7 @@ func (d *dockerImageDestination) PutBlob(stream io.Reader, digest string, expect
return "", -1, err
}
defer res.Body.Close()
if res.StatusCode == http.StatusOK && res.Header.Get("Docker-Content-Digest") == digest {
if res.StatusCode == http.StatusOK {
logrus.Debugf("... already exists, not uploading")
blobLength, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 64)
if err != nil {

View File

@ -129,7 +129,7 @@ func deleteImage(ctx *types.SystemContext, ref dockerReference) error {
// When retrieving the digest from a registry >= 2.3 use the following header:
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
headers := make(map[string][]string)
headers["Accept"] = []string{manifest.DockerV2Schema2MIMEType}
headers["Accept"] = []string{manifest.DockerV2Schema2MediaType}
reference, err := ref.tagOrDigest()
if err != nil {

View File

@ -246,7 +246,7 @@ func (i *genericImage) getParsedManifest() (genericManifest, error) {
// "application/json" is a valid v2s1 value per https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md .
// This works for now, when nothing else seems to return "application/json"; if that were not true, the mapping/detection might
// need to happen within the ImageSource.
case manifest.DockerV2Schema1MIMEType, manifest.DockerV2Schema1SignedMIMEType, "application/json":
case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType, "application/json":
mschema1 := &manifestSchema1{}
if err := json.Unmarshal(manblob, mschema1); err != nil {
return nil, err
@ -262,7 +262,7 @@ func (i *genericImage) getParsedManifest() (genericManifest, error) {
//return nil, fmt.Errorf("no FSLayers in manifest for %q", ref.String())
//}
return mschema1, nil
case manifest.DockerV2Schema2MIMEType:
case manifest.DockerV2Schema2MediaType:
v2s2 := manifestSchema2{src: i.src}
if err := json.Unmarshal(manblob, &v2s2); err != nil {
return nil, err

View File

@ -13,23 +13,23 @@ import (
// FIXME(runcom, mitr): should we havea mediatype pkg??
const (
// DockerV2Schema1MIMEType MIME type represents Docker manifest schema 1
DockerV2Schema1MIMEType = "application/vnd.docker.distribution.manifest.v1+json"
// DockerV2Schema1MIMEType MIME type represents Docker manifest schema 1 with a JWS signature
DockerV2Schema1SignedMIMEType = "application/vnd.docker.distribution.manifest.v1+prettyjws"
// DockerV2Schema2MIMEType MIME type represents Docker manifest schema 2
DockerV2Schema2MIMEType = "application/vnd.docker.distribution.manifest.v2+json"
// DockerV2ListMIMEType MIME type represents Docker manifest schema 2 list
DockerV2ListMIMEType = "application/vnd.docker.distribution.manifest.list.v2+json"
// DockerV2Schema1MediaType MIME type represents Docker manifest schema 1
DockerV2Schema1MediaType = "application/vnd.docker.distribution.manifest.v1+json"
// DockerV2Schema1MediaType MIME type represents Docker manifest schema 1 with a JWS signature
DockerV2Schema1SignedMediaType = "application/vnd.docker.distribution.manifest.v1+prettyjws"
// DockerV2Schema2MediaType MIME type represents Docker manifest schema 2
DockerV2Schema2MediaType = "application/vnd.docker.distribution.manifest.v2+json"
// DockerV2ListMediaType MIME type represents Docker manifest schema 2 list
DockerV2ListMediaType = "application/vnd.docker.distribution.manifest.list.v2+json"
)
// DefaultRequestedManifestMIMETypes is a list of MIME types a types.ImageSource
// should request from the backend unless directed otherwise.
var DefaultRequestedManifestMIMETypes = []string{
imgspecv1.MediaTypeImageManifest,
DockerV2Schema2MIMEType,
DockerV2Schema1SignedMIMEType,
DockerV2Schema1MIMEType,
DockerV2Schema2MediaType,
DockerV2Schema1SignedMediaType,
DockerV2Schema1MediaType,
}
// GuessMIMEType guesses MIME type of a manifest and returns it _if it is recognized_, or "" if unknown or unrecognized.
@ -48,25 +48,25 @@ func GuessMIMEType(manifest []byte) string {
}
switch meta.MediaType {
case DockerV2Schema2MIMEType, DockerV2ListMIMEType, imgspecv1.MediaTypeImageManifest, imgspecv1.MediaTypeImageManifestList: // A recognized type.
case DockerV2Schema2MediaType, DockerV2ListMediaType, imgspecv1.MediaTypeImageManifest, imgspecv1.MediaTypeImageManifestList: // A recognized type.
return meta.MediaType
}
// this is the only way the function can return DockerV2Schema1MIMEType, and recognizing that is essential for stripping the JWS signatures = computing the correct manifest digest.
// this is the only way the function can return DockerV2Schema1MediaType, and recognizing that is essential for stripping the JWS signatures = computing the correct manifest digest.
switch meta.SchemaVersion {
case 1:
if meta.Signatures != nil {
return DockerV2Schema1SignedMIMEType
return DockerV2Schema1SignedMediaType
}
return DockerV2Schema1MIMEType
return DockerV2Schema1MediaType
case 2: // Really should not happen, meta.MediaType should have been set. But given the data, this is our best guess.
return DockerV2Schema2MIMEType
return DockerV2Schema2MediaType
}
return ""
}
// Digest returns the a digest of a docker manifest, with any necessary implied transformations like stripping v1s1 signatures.
func Digest(manifest []byte) (string, error) {
if GuessMIMEType(manifest) == DockerV2Schema1SignedMIMEType {
if GuessMIMEType(manifest) == DockerV2Schema1SignedMediaType {
sig, err := libtrust.ParsePrettySignature(manifest, "signatures")
if err != nil {
return "", err

View File

@ -1,4 +1,4 @@
package oci
package layout
import (
"crypto/sha256"
@ -35,6 +35,19 @@ func (d *ociImageDestination) Reference() types.ImageReference {
func (d *ociImageDestination) Close() {
}
func (d *ociImageDestination) SupportedManifestMIMETypes() []string {
return []string{
imgspecv1.MediaTypeImageManifest,
manifest.DockerV2Schema2MediaType,
}
}
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
func (d *ociImageDestination) SupportsSignatures() error {
return fmt.Errorf("Pushing signatures for OCI images is not supported")
}
// PutBlob writes contents of stream and returns its computed digest and size.
// A digest can be optionally provided if known, the specific image destination can decide to play with it or not.
// The length of stream is expected to be expectedSize; if expectedSize == -1, it is not known.
@ -93,27 +106,27 @@ func createManifest(m []byte) ([]byte, string, error) {
om := imgspecv1.Manifest{}
mt := manifest.GuessMIMEType(m)
switch mt {
case manifest.DockerV2Schema1MIMEType:
case manifest.DockerV2Schema1MediaType:
// There a simple reason about not yet implementing this.
// OCI image-spec assure about backward compatibility with docker v2s2 but not v2s1
// generating a v2s2 is a migration docker does when upgrading to 1.10.3
// and I don't think we should bother about this now (I don't want to have migration code here in skopeo)
return nil, "", fmt.Errorf("can't create OCI manifest from Docker V2 schema 1 manifest")
case manifest.DockerV2Schema2MIMEType:
case manifest.DockerV2Schema2MediaType:
if err := json.Unmarshal(m, &om); err != nil {
return nil, "", err
}
om.MediaType = imgspecv1.MediaTypeImageManifest
for i := range om.Layers {
om.Layers[i].MediaType = imgspecv1.MediaTypeImageSerialization
om.Layers[i].MediaType = imgspecv1.MediaTypeImageLayer
}
om.Config.MediaType = imgspecv1.MediaTypeImageSerializationConfig
om.Config.MediaType = imgspecv1.MediaTypeImageConfig
b, err := json.Marshal(om)
if err != nil {
return nil, "", err
}
return b, om.MediaType, nil
case manifest.DockerV2ListMIMEType:
case manifest.DockerV2ListMediaType:
return nil, "", fmt.Errorf("can't create OCI manifest from Docker V2 schema 2 manifest list")
case imgspecv1.MediaTypeImageManifestList:
return nil, "", fmt.Errorf("can't create OCI manifest from OCI manifest list")
@ -176,13 +189,6 @@ func ensureParentDirectoryExists(path string) error {
return ensureDirectoryExists(filepath.Dir(path))
}
func (d *ociImageDestination) SupportedManifestMIMETypes() []string {
return []string{
imgspecv1.MediaTypeImageManifest,
manifest.DockerV2Schema2MIMEType,
}
}
func (d *ociImageDestination) PutSignatures(signatures [][]byte) error {
if len(signatures) != 0 {
return fmt.Errorf("Pushing signatures for OCI images is not supported")

View File

@ -1,4 +1,4 @@
package oci
package layout
import (
"errors"

View File

@ -337,11 +337,17 @@ func (d *openshiftImageDestination) Close() {
func (d *openshiftImageDestination) SupportedManifestMIMETypes() []string {
return []string{
manifest.DockerV2Schema1SignedMIMEType,
manifest.DockerV2Schema1MIMEType,
manifest.DockerV2Schema1SignedMediaType,
manifest.DockerV2Schema1MediaType,
}
}
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
func (d *openshiftImageDestination) SupportsSignatures() error {
return nil
}
// PutBlob writes contents of stream and returns its computed digest and size.
// A digest can be optionally provided if known, the specific image destination can decide to play with it or not.
// The length of stream is expected to be expectedSize; if expectedSize == -1, it is not known.

View File

@ -6,7 +6,7 @@ import (
"github.com/containers/image/directory"
"github.com/containers/image/docker"
"github.com/containers/image/oci"
ociLayout "github.com/containers/image/oci/layout"
"github.com/containers/image/openshift"
"github.com/containers/image/types"
)
@ -19,7 +19,7 @@ func init() {
for _, t := range []types.ImageTransport{
directory.Transport,
docker.Transport,
oci.Transport,
ociLayout.Transport,
openshift.Transport,
} {
name := t.Name()

View File

@ -119,6 +119,14 @@ type ImageDestination interface {
Reference() ImageReference
// Close removes resources associated with an initialized ImageDestination, if any.
Close()
// 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
SupportedManifestMIMETypes() []string
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
SupportsSignatures() error
// PutBlob writes contents of stream and returns its computed digest and size.
// A digest can be optionally provided if known, the specific image destination can decide to play with it or not.
// The length of stream is expected to be expectedSize; if expectedSize == -1, it is not known.
@ -134,9 +142,6 @@ type ImageDestination interface {
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
Commit() error
// 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
SupportedManifestMIMETypes() []string
}
// Image is the primary API for inspecting properties of images.

View File

@ -13,9 +13,10 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine and "-tags disableunsafe"
// is not added to the go build command line.
// +build !appengine,!disableunsafe
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
package spew

View File

@ -13,9 +13,10 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when either the code is running on Google App Engine or "-tags disableunsafe"
// is added to the go build command line.
// +build appengine disableunsafe
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe
package spew

View File

@ -64,7 +64,7 @@ type ConfigState struct {
// inside these interface methods. As a result, this option relies on
// access to the unsafe package, so it will not have any effect when
// running in environments without access to the unsafe package such as
// Google App Engine or with the "disableunsafe" build tag specified.
// Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool
// ContinueOnMethod specifies whether or not recursion should continue once

View File

@ -35,7 +35,7 @@ type ImageConfig struct {
Env []string `json:"Env"`
// Entrypoint defines a list of arguments to use as the command to execute when the container starts.
EntryPoint []string `json:"EntryPoint"`
Entrypoint []string `json:"Entrypoint"`
// Cmd defines the default arguments to the entrypoint of the container.
Cmd []string `json:"Cmd"`

View File

@ -24,9 +24,9 @@ const (
// MediaTypeImageManifestList specifies the mediaType for an image manifest list.
MediaTypeImageManifestList = "application/vnd.oci.image.manifest.list.v1+json"
// MediaTypeImageSerialization is the mediaType used for layers referenced by the manifest.
MediaTypeImageSerialization = "application/vnd.oci.image.layer.tar+gzip"
// MediaTypeImageLayer is the mediaType used for layers referenced by the manifest.
MediaTypeImageLayer = "application/vnd.oci.image.layer.tar+gzip"
// MediaTypeImageSerializationConfig specifies the mediaType for the image configuration.
MediaTypeImageSerializationConfig = "application/vnd.oci.image.config.v1+json"
// MediaTypeImageConfig specifies the mediaType for the image configuration.
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
)