add mimetypes

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2016-05-23 10:08:04 +02:00
parent 814a2a6f94
commit 7d12b66fb8
9 changed files with 87 additions and 15 deletions

View File

@ -54,7 +54,7 @@ func copyHandler(context *cli.Context) {
} }
signBy := context.String("sign-by") signBy := context.String("sign-by")
manifest, err := src.GetManifest() manifest, _, err := src.GetManifest()
if err != nil { if err != nil {
logrus.Fatalf("Error reading manifest: %s", err.Error()) logrus.Fatalf("Error reading manifest: %s", err.Error())
} }

View File

@ -84,8 +84,13 @@ func (s *dirImageSource) IntendedDockerReference() string {
return "" return ""
} }
func (s *dirImageSource) GetManifest() ([]byte, error) { // it's up to the caller to determine the MIME type of the returned manifest's bytes
return ioutil.ReadFile(manifestPath(s.dir)) func (s *dirImageSource) GetManifest() ([]byte, string, error) {
m, err := ioutil.ReadFile(manifestPath(s.dir))
if err != nil {
return nil, "", err
}
return m, "", err
} }
func (s *dirImageSource) GetLayer(digest string) (io.ReadCloser, error) { func (s *dirImageSource) GetLayer(digest string) (io.ReadCloser, error) {

View File

@ -44,7 +44,7 @@ func (i *dockerImage) IntendedDockerReference() string {
// Manifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need. // Manifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need.
func (i *dockerImage) Manifest() ([]byte, error) { func (i *dockerImage) Manifest() ([]byte, error) {
if i.cachedManifest == nil { if i.cachedManifest == nil {
m, err := i.src.GetManifest() m, _, err := i.src.GetManifest()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -55,24 +55,24 @@ func (s *dockerImageSource) IntendedDockerReference() string {
return fmt.Sprintf("%s:%s", s.ref.Name(), s.tag) return fmt.Sprintf("%s:%s", s.ref.Name(), s.tag)
} }
func (s *dockerImageSource) GetManifest() ([]byte, error) { func (s *dockerImageSource) GetManifest() ([]byte, string, error) {
url := fmt.Sprintf(manifestURL, s.ref.RemoteName(), s.tag) url := fmt.Sprintf(manifestURL, s.ref.RemoteName(), s.tag)
// TODO(runcom) set manifest version header! schema1 for now - then schema2 etc etc and v1 // TODO(runcom) set manifest version header! schema1 for now - then schema2 etc etc and v1
// TODO(runcom) NO, switch on the resulter manifest like Docker is doing // TODO(runcom) NO, switch on the resulter manifest like Docker is doing
res, err := s.c.makeRequest("GET", url, nil, nil) res, err := s.c.makeRequest("GET", url, nil, nil)
if err != nil { if err != nil {
return nil, err return nil, "", err
} }
defer res.Body.Close() defer res.Body.Close()
manblob, err := ioutil.ReadAll(res.Body) manblob, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return nil, err return nil, "", err
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
return nil, errFetchManifest{res.StatusCode, manblob} return nil, "", errFetchManifest{res.StatusCode, manblob}
} }
// We might validate manblob against the Docker-Content-Digest header here to protect against transport errors. // We might validate manblob against the Docker-Content-Digest header here to protect against transport errors.
return manblob, nil return manblob, res.Header.Get("Content-Type"), nil
} }
func (s *dockerImageSource) GetLayer(digest string) (io.ReadCloser, error) { func (s *dockerImageSource) GetLayer(digest string) (io.ReadCloser, error) {

View File

@ -0,0 +1,56 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
"size": 2094,
"digest": "sha256:7820f9a86d4ad15a2c4f0c0e5479298df2aa7c2f6871288e2ef8546f3e7b6783",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
"size": 1922,
"digest": "sha256:ae1b0e06e8ade3a11267564a26e750585ba2259c0ecab59ab165ad1af41d1bdd",
"platform": {
"architecture": "amd64",
"os": "linux",
"features": [
"sse"
]
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
"size": 2084,
"digest": "sha256:e4c0df75810b953d6717b8f8f28298d73870e8aa2a0d5e77b8391f16fdfbbbe2",
"platform": {
"architecture": "s390x",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
"size": 2084,
"digest": "sha256:07ebe243465ef4a667b78154ae6c3ea46fdb1582936aac3ac899ea311a701b40",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "armv7"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
"size": 2090,
"digest": "sha256:fb2fc0707b86dafa9959fe3d29e66af8787aee4d9a23581714be65db4265ad8a",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "armv8"
}
}
]
}

View File

@ -10,11 +10,22 @@ import (
// FIXME: Should we just use docker/distribution and docker/docker implementations directly? // FIXME: Should we just use docker/distribution and docker/docker implementations directly?
// ManifestMIMETypes returns a slice of supported MIME types
func ManifestMIMETypes() []string {
return []string{
DockerV2Schema1MIMEType,
DockerV2Schema2MIMEType,
DockerV2ListMIMEType,
}
}
const ( const (
// DockerV2Schema1MIMEType MIME type represents Docker manifest schema 1 // DockerV2Schema1MIMEType MIME type represents Docker manifest schema 1
DockerV2Schema1MIMEType = "application/vnd.docker.distribution.manifest.v1+json" DockerV2Schema1MIMEType = "application/vnd.docker.distribution.manifest.v1+json"
// DockerV2Schema2MIMEType MIME type represents Docker manifest schema 2 // DockerV2Schema2MIMEType MIME type represents Docker manifest schema 2
DockerV2Schema2MIMEType = "application/vnd.docker.distribution.manifest.v2+json" 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"
) )
// GuessManifestMIMEType guesses MIME type of a manifest and returns it _if it is recognized_, or "" if unknown or unrecognized. // GuessManifestMIMEType guesses MIME type of a manifest and returns it _if it is recognized_, or "" if unknown or unrecognized.
@ -32,7 +43,7 @@ func GuessManifestMIMEType(manifest []byte) string {
} }
switch meta.MediaType { switch meta.MediaType {
case DockerV2Schema2MIMEType: // A recognized type. case DockerV2Schema2MIMEType, DockerV2ListMIMEType: // A recognized type.
return meta.MediaType return meta.MediaType
} }
switch meta.SchemaVersion { switch meta.SchemaVersion {

View File

@ -15,6 +15,7 @@ func TestGuessManifestMIMEType(t *testing.T) {
mimeType string mimeType string
}{ }{
{"v2s2.manifest.json", DockerV2Schema2MIMEType}, {"v2s2.manifest.json", DockerV2Schema2MIMEType},
{"v2list.manifest.json", DockerV2ListMIMEType},
{"v2s1.manifest.json", DockerV2Schema1MIMEType}, {"v2s1.manifest.json", DockerV2Schema1MIMEType},
{"v2s1-invalid-signatures.manifest.json", DockerV2Schema1MIMEType}, {"v2s1-invalid-signatures.manifest.json", DockerV2Schema1MIMEType},
{"v2s2nomime.manifest.json", DockerV2Schema2MIMEType}, // It is unclear whether this one is legal, but we should guess v2s2 if anything at all. {"v2s2nomime.manifest.json", DockerV2Schema2MIMEType}, // It is unclear whether this one is legal, but we should guess v2s2 if anything at all.

View File

@ -193,9 +193,9 @@ func (s *openshiftImageSource) IntendedDockerReference() string {
return s.client.canonicalDockerReference() return s.client.canonicalDockerReference()
} }
func (s *openshiftImageSource) GetManifest() ([]byte, error) { func (s *openshiftImageSource) GetManifest() ([]byte, string, error) {
if err := s.ensureImageIsResolved(); err != nil { if err := s.ensureImageIsResolved(); err != nil {
return nil, err return nil, "", err
} }
return s.docker.GetManifest() return s.docker.GetManifest()
} }

View File

@ -27,9 +27,8 @@ type ImageSource interface {
// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. // (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image.
// May be "" if unknown. // May be "" if unknown.
IntendedDockerReference() string IntendedDockerReference() string
// GetManifest returns the image's manifest. It may use a remote (= slow) service. // GetManifest returns the image's manifest along with its MIME type. The empty string is returned if the MIME type is unknown. It may use a remote (= slow) service.
// FIXME? This should also return a MIME type if known, to differentiate between schema versions. GetManifest() ([]byte, string, error)
GetManifest() ([]byte, error)
// Note: Calling GetLayer() may have ordering dependencies WRT other methods of this type. FIXME: How does this work with (docker save) on stdin? // Note: Calling GetLayer() may have ordering dependencies WRT other methods of this type. FIXME: How does this work with (docker save) on stdin?
GetLayer(digest string) (io.ReadCloser, error) GetLayer(digest string) (io.ReadCloser, error)
// GetSignatures returns the image's signatures. It may use a remote (= slow) service. // GetSignatures returns the image's signatures. It may use a remote (= slow) service.