Implement the resolver for CNAB

This commit introduces a new resolver to resolver metadata for CNAB

Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2020-02-16 20:13:32 +08:00
parent f36152a560
commit ab3aad4d50
12 changed files with 722 additions and 195 deletions

View File

@ -27,15 +27,8 @@ import (
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/repository"
"github.com/opencontainers/image-spec/specs-go/v1"
"regexp"
"strings"
)
// ArtifactTypeUnknown defines the type for the unknown artifacts
const ArtifactTypeUnknown = "UNKNOWN"
var artifactTypeRegExp = regexp.MustCompile(`^application/vnd\.[^.]*\.(.*)\.config\.[^.]*\+json$`)
// Abstractor abstracts the specific information for different types of artifacts
type Abstractor interface {
// AbstractMetadata abstracts the metadata for the specific artifact type into the artifact model,
@ -60,8 +53,6 @@ type abstractor struct {
blobFetcher blob.Fetcher
}
// TODO try CNAB, how to forbid CNAB
// TODO add white list for supported artifact type
func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact) error {
repository, err := a.repoMgr.Get(ctx, artifact.RepositoryID)
@ -101,9 +92,8 @@ func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Ar
artifact.Annotations = manifest.Annotations
// OCI index/docker manifest list
case v1.MediaTypeImageIndex, manifestlist.MediaTypeManifestList:
// the identity of index is still in progress, only handle image index for now
// and use the manifestMediaType as the media type of artifact
// If we want to support CNAB, we should get the media type from annotation
// the identity of index is still in progress, we use the manifest mediaType
// as the media type of artifact
artifact.MediaType = artifact.ManifestMediaType
index := &v1.Index{}
@ -115,7 +105,15 @@ func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Ar
// set annotations
artifact.Annotations = index.Annotations
// TODO handle references in resolvers
// Currently, CNAB put its media type inside the annotations
// try to parse the artifact media type from the annotations
if artifact.Annotations != nil {
mediaType := artifact.Annotations["org.opencontainers.artifactType"]
if len(mediaType) > 0 {
artifact.MediaType = mediaType
}
}
default:
return fmt.Errorf("unsupported manifest media type: %s", artifact.ManifestMediaType)
}
@ -125,8 +123,6 @@ func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Ar
return resolver.ResolveMetadata(ctx, content, artifact)
}
// if got no resolver, try to parse the artifact type based on the media type
artifact.Type = parseArtifactType(artifact.MediaType)
return nil
}
@ -138,12 +134,3 @@ func (a *abstractor) AbstractAddition(ctx context.Context, artifact *artifact.Ar
}
return resolver.ResolveAddition(ctx, artifact, addition)
}
func parseArtifactType(mediaType string) string {
strs := artifactTypeRegExp.FindStringSubmatch(mediaType)
if len(strs) == 2 {
return strings.ToUpper(strs[1])
}
// can not get the artifact type from the media type, return unknown
return ArtifactTypeUnknown
}

View File

@ -284,28 +284,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
a.Require().NotNil(err)
}
func (a *abstractorTestSuite) TestParseArtifactType() {
mediaType := ""
typee := parseArtifactType(mediaType)
a.Equal(ArtifactTypeUnknown, typee)
mediaType = "unknown"
typee = parseArtifactType(mediaType)
a.Equal(ArtifactTypeUnknown, typee)
mediaType = "application/vnd.oci.image.config.v1+json"
typee = parseArtifactType(mediaType)
a.Equal("IMAGE", typee)
mediaType = "application/vnd.cncf.helm.chart.config.v1+json"
typee = parseArtifactType(mediaType)
a.Equal("HELM.CHART", typee)
mediaType = "application/vnd.sylabs.sif.config.v1+json"
typee = parseArtifactType(mediaType)
a.Equal("SIF", typee)
}
func (a *abstractorTestSuite) TestAbstractAddition() {
resolver.Register(a.resolver, v1.MediaTypeImageConfig)
// cannot get the resolver

View File

@ -0,0 +1,130 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cnab
import (
"context"
"encoding/json"
"github.com/goharbor/harbor/src/api/artifact/abstractor/blob"
resolv "github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
"github.com/goharbor/harbor/src/api/artifact/descriptor"
"github.com/goharbor/harbor/src/common/utils/log"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/repository"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
// const definitions
const (
ArtifactTypeCNAB = "CNAB"
mediaType = "application/vnd.cnab.manifest.v1"
)
func init() {
resolver := &resolver{
repoMgr: repository.Mgr,
argMgr: artifact.Mgr,
blobFetcher: blob.Fcher,
}
if err := resolv.Register(resolver, mediaType); err != nil {
log.Errorf("failed to register resolver for media type %s: %v", mediaType, err)
return
}
if err := descriptor.Register(resolver, mediaType); err != nil {
log.Errorf("failed to register descriptor for media type %s: %v", mediaType, err)
return
}
}
type resolver struct {
repoMgr repository.Manager
argMgr artifact.Manager
blobFetcher blob.Fetcher
}
func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *artifact.Artifact) error {
index := &v1.Index{}
if err := json.Unmarshal(manifest, index); err != nil {
return err
}
cfgManiDgt := ""
// populate the referenced artifacts
for _, mani := range index.Manifests {
digest := mani.Digest.String()
// make sure the child artifact exist
ar, err := r.argMgr.GetByDigest(ctx, art.RepositoryID, digest)
if err != nil {
return err
}
art.References = append(art.References, &artifact.Reference{
ChildID: ar.ID,
Platform: mani.Platform,
})
// try to get the digest of the manifest that the config layer is referenced by
if mani.Annotations != nil &&
mani.Annotations["io.cnab.manifest.type"] == "config" {
cfgManiDgt = mani.Digest.String()
}
}
if len(cfgManiDgt) == 0 {
return nil
}
// resolve the config of CNAB
repository, err := r.repoMgr.Get(ctx, art.RepositoryID)
if err != nil {
return err
}
// get the manifest that the config layer is referenced by
_, cfgMani, err := r.blobFetcher.FetchManifest(repository.Name, cfgManiDgt)
if err != nil {
return err
}
m := &v1.Manifest{}
if err := json.Unmarshal(cfgMani, m); err != nil {
return err
}
cfgDgt := m.Config.Digest.String()
// get the config layer
cfg, err := r.blobFetcher.FetchLayer(repository.Name, cfgDgt)
if err != nil {
return err
}
metadata := map[string]interface{}{}
if err := json.Unmarshal(cfg, &metadata); err != nil {
return err
}
if art.ExtraAttrs == nil {
art.ExtraAttrs = map[string]interface{}{}
}
for k, v := range metadata {
art.ExtraAttrs[k] = v
}
return nil
}
func (r *resolver) ResolveAddition(ctx context.Context, artifact *artifact.Artifact, addition string) (*resolv.Addition, error) {
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeCNAB)
}
func (r *resolver) GetArtifactType() string {
return ArtifactTypeCNAB
}
func (r *resolver) ListAdditionTypes() []string {
return nil
}

View File

@ -0,0 +1,144 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cnab
import (
"github.com/goharbor/harbor/src/common/models"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
testingartifact "github.com/goharbor/harbor/src/testing/pkg/artifact"
"github.com/goharbor/harbor/src/testing/pkg/repository"
"github.com/stretchr/testify/suite"
"testing"
)
type resolverTestSuite struct {
suite.Suite
resolver *resolver
repoMgr *repository.FakeManager
artMgr *testingartifact.FakeManager
blobFetcher *blob.FakeFetcher
}
func (r *resolverTestSuite) SetupTest() {
r.repoMgr = &repository.FakeManager{}
r.artMgr = &testingartifact.FakeManager{}
r.blobFetcher = &blob.FakeFetcher{}
r.resolver = &resolver{
repoMgr: r.repoMgr,
argMgr: r.artMgr,
blobFetcher: r.blobFetcher,
}
}
func (r *resolverTestSuite) TestResolveMetadata() {
index := `{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549",
"size": 193,
"annotations": {
"io.cnab.manifest.type": "config"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6",
"size": 942,
"annotations": {
"io.cnab.manifest.type": "invocation"
}
}
],
"annotations": {
"io.cnab.keywords": "[\"helloworld\",\"cnab\",\"tutorial\"]",
"io.cnab.runtime_version": "v1.0.0",
"org.opencontainers.artifactType": "application/vnd.cnab.manifest.v1",
"org.opencontainers.image.authors": "[{\"name\":\"Jane Doe\",\"email\":\"jane.doe@example.com\",\"url\":\"https://example.com\"}]",
"org.opencontainers.image.description": "A short description of your bundle",
"org.opencontainers.image.title": "helloworld",
"org.opencontainers.image.version": "0.1.1"
}
}`
manifest := `{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:e91b9dfcbbb3b88bac94726f276b89de46e4460b55f6e6d6f876e666b150ec5b",
"size": 498
},
"layers": null
}`
config := `{
"description": "A short description of your bundle",
"invocationImages": [
{
"contentDigest": "sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6",
"image": "cnab/helloworld:0.1.1",
"imageType": "docker",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 942
}
],
"keywords": [
"helloworld",
"cnab",
"tutorial"
],
"maintainers": [
{
"email": "jane.doe@example.com",
"name": "Jane Doe",
"url": "https://example.com"
}
],
"name": "helloworld",
"schemaVersion": "v1.0.0",
"version": "0.1.1"
}`
art := &artifact.Artifact{}
r.artMgr.On("GetByDigest").Return(&artifact.Artifact{ID: 1}, nil)
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
r.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
err := r.resolver.ResolveMetadata(nil, []byte(index), art)
r.Require().Nil(err)
r.Len(art.References, 2)
r.Equal("0.1.1", art.ExtraAttrs["version"].(string))
r.Equal("helloworld", art.ExtraAttrs["name"].(string))
}
func (r *resolverTestSuite) TestResolveAddition() {
_, err := r.resolver.ResolveAddition(nil, nil, "")
r.Require().NotNil(err)
r.True(ierror.IsErr(err, ierror.BadRequestCode))
}
func (r *resolverTestSuite) TestGetArtifactType() {
r.Assert().Equal(ArtifactTypeCNAB, r.resolver.GetArtifactType())
}
func (r *resolverTestSuite) TestListAdditionTypes() {
r.Nil(r.resolver.ListAdditionTypes())
}
func TestResolverTestSuite(t *testing.T) {
suite.Run(t, &resolverTestSuite{})
}

View File

@ -17,9 +17,6 @@ package artifact
import (
"context"
"fmt"
"strings"
"time"
"github.com/goharbor/harbor/src/api/artifact/abstractor"
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
"github.com/goharbor/harbor/src/api/artifact/descriptor"
@ -36,11 +33,14 @@ import (
"github.com/goharbor/harbor/src/pkg/registry"
"github.com/goharbor/harbor/src/pkg/signature"
"github.com/opencontainers/go-digest"
"strings"
"time"
// registry image resolvers
_ "github.com/goharbor/harbor/src/api/artifact/abstractor/resolver/image"
// register chart resolver
_ "github.com/goharbor/harbor/src/api/artifact/abstractor/resolver/chart"
// register CNAB resolver
_ "github.com/goharbor/harbor/src/api/artifact/abstractor/resolver/cnab"
"github.com/goharbor/harbor/src/common/utils/log"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
@ -170,11 +170,7 @@ func (c *controller) ensureArtifact(ctx context.Context, repositoryID int64, dig
}
// populate the artifact type
typee, err := descriptor.GetArtifactType(artifact.MediaType)
if err != nil {
return false, 0, err
}
artifact.Type = typee
artifact.Type = descriptor.GetArtifactType(artifact.MediaType)
// create it
id, err := c.artMgr.Create(ctx, artifact)
@ -658,12 +654,7 @@ func (c *controller) populateImmutableStatus(ctx context.Context, tag *Tag) {
}
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
types, err := descriptor.ListAdditionTypes(artifact.MediaType)
if err != nil {
log.Error(err.Error())
return
}
types := descriptor.ListAdditionTypes(artifact.MediaType)
if len(types) > 0 {
version := internal.GetAPIVersion(ctx)
for _, t := range types {

View File

@ -17,10 +17,16 @@ package descriptor
import (
"fmt"
"github.com/goharbor/harbor/src/common/utils/log"
"regexp"
"strings"
)
// ArtifactTypeUnknown defines the type for the unknown artifacts
const ArtifactTypeUnknown = "UNKNOWN"
var (
registry = map[string]Descriptor{}
registry = map[string]Descriptor{}
artifactTypeRegExp = regexp.MustCompile(`^application/vnd\.[^.]*\.(.*)\.config\.[^.]*\+json$`)
)
// Descriptor describes the static information for one kind of media type
@ -45,28 +51,34 @@ func Register(descriptor Descriptor, mediaTypes ...string) error {
}
// Get the descriptor according to the media type
func Get(mediaType string) (Descriptor, error) {
descriptor := registry[mediaType]
if descriptor == nil {
return nil, fmt.Errorf("descriptor for media type %s not found", mediaType)
}
return descriptor, nil
func Get(mediaType string) Descriptor {
return registry[mediaType]
}
// GetArtifactType gets the artifact type according to the media type
func GetArtifactType(mediaType string) (string, error) {
descriptor, err := Get(mediaType)
if err != nil {
return "", err
func GetArtifactType(mediaType string) string {
descriptor := Get(mediaType)
if descriptor != nil {
return descriptor.GetArtifactType()
}
return descriptor.GetArtifactType(), nil
// if got no descriptor, try to parse the artifact type based on the media type
return parseArtifactType(mediaType)
}
// ListAdditionTypes lists the supported addition types according to the media type
func ListAdditionTypes(mediaType string) ([]string, error) {
descriptor, err := Get(mediaType)
if err != nil {
return nil, err
func ListAdditionTypes(mediaType string) []string {
descriptor := Get(mediaType)
if descriptor != nil {
return descriptor.ListAdditionTypes()
}
return descriptor.ListAdditionTypes(), nil
return nil
}
func parseArtifactType(mediaType string) string {
strs := artifactTypeRegExp.FindStringSubmatch(mediaType)
if len(strs) == 2 {
return strings.ToUpper(strs[1])
}
// can not get the artifact type from the media type, return unknown
return ArtifactTypeUnknown
}

View File

@ -0,0 +1,50 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package descriptor
import (
"github.com/stretchr/testify/suite"
"testing"
)
type descriptorTestSuite struct {
suite.Suite
}
func (d *descriptorTestSuite) TestParseArtifactType() {
mediaType := ""
typee := parseArtifactType(mediaType)
d.Equal(ArtifactTypeUnknown, typee)
mediaType = "unknown"
typee = parseArtifactType(mediaType)
d.Equal(ArtifactTypeUnknown, typee)
mediaType = "application/vnd.oci.image.config.v1+json"
typee = parseArtifactType(mediaType)
d.Equal("IMAGE", typee)
mediaType = "application/vnd.cncf.helm.chart.config.v1+json"
typee = parseArtifactType(mediaType)
d.Equal("HELM.CHART", typee)
mediaType = "application/vnd.sylabs.sif.config.v1+json"
typee = parseArtifactType(mediaType)
d.Equal("SIF", typee)
}
func TestDescriptorTestSuite(t *testing.T) {
suite.Run(t, &descriptorTestSuite{})
}

View File

@ -25,6 +25,8 @@ import (
_ "github.com/docker/distribution/manifest/schema2"
// manifestlist
_ "github.com/docker/distribution/manifest/manifestlist"
// oci schema
_ "github.com/docker/distribution/manifest/ocischema"
ref "github.com/docker/distribution/reference"
"github.com/goharbor/harbor/src/common/utils"
)

View File

@ -88,8 +88,9 @@ func (r *Route) Handler(handler http.Handler) {
middleware.WithMiddlewares(handler, middlewares...).
ServeHTTP(ctx.ResponseWriter, ctx.Request)
})
if len(methods) == 0 {
beego.Any(r.path, filterFunc)
beego.Any(path, filterFunc)
return
}
for _, method := range methods {

View File

@ -0,0 +1,107 @@
package ocischema
import (
"context"
"errors"
"github.com/docker/distribution"
"github.com/docker/distribution/manifest"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go/v1"
)
// Builder is a type for constructing manifests.
type Builder struct {
// bs is a BlobService used to publish the configuration blob.
bs distribution.BlobService
// configJSON references
configJSON []byte
// layers is a list of layer descriptors that gets built by successive
// calls to AppendReference.
layers []distribution.Descriptor
// Annotations contains arbitrary metadata relating to the targeted content.
annotations map[string]string
// For testing purposes
mediaType string
}
// NewManifestBuilder is used to build new manifests for the current schema
// version. It takes a BlobService so it can publish the configuration blob
// as part of the Build process, and annotations.
func NewManifestBuilder(bs distribution.BlobService, configJSON []byte, annotations map[string]string) distribution.ManifestBuilder {
mb := &Builder{
bs: bs,
configJSON: make([]byte, len(configJSON)),
annotations: annotations,
mediaType: v1.MediaTypeImageManifest,
}
copy(mb.configJSON, configJSON)
return mb
}
// SetMediaType assigns the passed mediatype or error if the mediatype is not a
// valid media type for oci image manifests currently: "" or "application/vnd.oci.image.manifest.v1+json"
func (mb *Builder) SetMediaType(mediaType string) error {
if mediaType != "" && mediaType != v1.MediaTypeImageManifest {
return errors.New("Invalid media type for OCI image manifest")
}
mb.mediaType = mediaType
return nil
}
// Build produces a final manifest from the given references.
func (mb *Builder) Build(ctx context.Context) (distribution.Manifest, error) {
m := Manifest{
Versioned: manifest.Versioned{
SchemaVersion: 2,
MediaType: mb.mediaType,
},
Layers: make([]distribution.Descriptor, len(mb.layers)),
Annotations: mb.annotations,
}
copy(m.Layers, mb.layers)
configDigest := digest.FromBytes(mb.configJSON)
var err error
m.Config, err = mb.bs.Stat(ctx, configDigest)
switch err {
case nil:
// Override MediaType, since Put always replaces the specified media
// type with application/octet-stream in the descriptor it returns.
m.Config.MediaType = v1.MediaTypeImageConfig
return FromStruct(m)
case distribution.ErrBlobUnknown:
// nop
default:
return nil, err
}
// Add config to the blob store
m.Config, err = mb.bs.Put(ctx, v1.MediaTypeImageConfig, mb.configJSON)
// Override MediaType, since Put always replaces the specified media
// type with application/octet-stream in the descriptor it returns.
m.Config.MediaType = v1.MediaTypeImageConfig
if err != nil {
return nil, err
}
return FromStruct(m)
}
// AppendReference adds a reference to the current ManifestBuilder.
func (mb *Builder) AppendReference(d distribution.Describable) error {
mb.layers = append(mb.layers, d.Descriptor())
return nil
}
// References returns the current references added to this builder.
func (mb *Builder) References() []distribution.Descriptor {
return mb.layers
}

View File

@ -0,0 +1,124 @@
package ocischema
import (
"encoding/json"
"errors"
"fmt"
"github.com/docker/distribution"
"github.com/docker/distribution/manifest"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go/v1"
)
var (
// SchemaVersion provides a pre-initialized version structure for this
// packages version of the manifest.
SchemaVersion = manifest.Versioned{
SchemaVersion: 2, // historical value here.. does not pertain to OCI or docker version
MediaType: v1.MediaTypeImageManifest,
}
)
func init() {
ocischemaFunc := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
m := new(DeserializedManifest)
err := m.UnmarshalJSON(b)
if err != nil {
return nil, distribution.Descriptor{}, err
}
dgst := digest.FromBytes(b)
return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: v1.MediaTypeImageManifest}, err
}
err := distribution.RegisterManifestSchema(v1.MediaTypeImageManifest, ocischemaFunc)
if err != nil {
panic(fmt.Sprintf("Unable to register manifest: %s", err))
}
}
// Manifest defines a ocischema manifest.
type Manifest struct {
manifest.Versioned
// Config references the image configuration as a blob.
Config distribution.Descriptor `json:"config"`
// Layers lists descriptors for the layers referenced by the
// configuration.
Layers []distribution.Descriptor `json:"layers"`
// Annotations contains arbitrary metadata for the image manifest.
Annotations map[string]string `json:"annotations,omitempty"`
}
// References returns the descriptors of this manifests references.
func (m Manifest) References() []distribution.Descriptor {
references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
references = append(references, m.Config)
references = append(references, m.Layers...)
return references
}
// Target returns the target of this manifest.
func (m Manifest) Target() distribution.Descriptor {
return m.Config
}
// DeserializedManifest wraps Manifest with a copy of the original JSON.
// It satisfies the distribution.Manifest interface.
type DeserializedManifest struct {
Manifest
// canonical is the canonical byte representation of the Manifest.
canonical []byte
}
// FromStruct takes a Manifest structure, marshals it to JSON, and returns a
// DeserializedManifest which contains the manifest and its JSON representation.
func FromStruct(m Manifest) (*DeserializedManifest, error) {
var deserialized DeserializedManifest
deserialized.Manifest = m
var err error
deserialized.canonical, err = json.MarshalIndent(&m, "", " ")
return &deserialized, err
}
// UnmarshalJSON populates a new Manifest struct from JSON data.
func (m *DeserializedManifest) UnmarshalJSON(b []byte) error {
m.canonical = make([]byte, len(b), len(b))
// store manifest in canonical
copy(m.canonical, b)
// Unmarshal canonical JSON into Manifest object
var manifest Manifest
if err := json.Unmarshal(m.canonical, &manifest); err != nil {
return err
}
if manifest.MediaType != "" && manifest.MediaType != v1.MediaTypeImageManifest {
return fmt.Errorf("if present, mediaType in manifest should be '%s' not '%s'",
v1.MediaTypeImageManifest, manifest.MediaType)
}
m.Manifest = manifest
return nil
}
// MarshalJSON returns the contents of canonical. If canonical is empty,
// marshals the inner contents.
func (m *DeserializedManifest) MarshalJSON() ([]byte, error) {
if len(m.canonical) > 0 {
return m.canonical, nil
}
return nil, errors.New("JSON representation not initialized in DeserializedManifest")
}
// Payload returns the raw content of the manifest. The contents can be used to
// calculate the content identifier.
func (m DeserializedManifest) Payload() (string, []byte, error) {
return v1.MediaTypeImageManifest, m.canonical, nil
}

233
src/vendor/modules.txt vendored
View File

@ -14,82 +14,82 @@ github.com/Unknwon/goconfig
github.com/agl/ed25519
github.com/agl/ed25519/edwards25519
# github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97
github.com/aliyun/alibaba-cloud-sdk-go/services/cr
github.com/aliyun/alibaba-cloud-sdk-go/sdk
github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth
github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests
github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses
github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials
github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider
github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers
github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints
github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors
github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests
github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses
github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils
github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers
github.com/aliyun/alibaba-cloud-sdk-go/services/cr
# github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
github.com/asaskevich/govalidator
# github.com/astaxie/beego v1.12.1
github.com/astaxie/beego
github.com/astaxie/beego/cache
github.com/astaxie/beego/cache/redis
github.com/astaxie/beego
github.com/astaxie/beego/validation
github.com/astaxie/beego/orm
github.com/astaxie/beego/session/redis
github.com/astaxie/beego/context
github.com/astaxie/beego/config
github.com/astaxie/beego/context
github.com/astaxie/beego/context/param
github.com/astaxie/beego/grace
github.com/astaxie/beego/logs
github.com/astaxie/beego/orm
github.com/astaxie/beego/session
github.com/astaxie/beego/session/redis
github.com/astaxie/beego/toolbox
github.com/astaxie/beego/utils
github.com/astaxie/beego/validation
# github.com/aws/aws-sdk-go v1.19.47
github.com/aws/aws-sdk-go/aws
github.com/aws/aws-sdk-go/aws/awserr
github.com/aws/aws-sdk-go/aws/credentials
github.com/aws/aws-sdk-go/aws/session
github.com/aws/aws-sdk-go/service/ecr
github.com/aws/aws-sdk-go/aws/endpoints
github.com/aws/aws-sdk-go/internal/sdkio
github.com/aws/aws-sdk-go/internal/ini
github.com/aws/aws-sdk-go/internal/shareddefaults
github.com/aws/aws-sdk-go/aws/awsutil
github.com/aws/aws-sdk-go/aws/client
github.com/aws/aws-sdk-go/aws/client/metadata
github.com/aws/aws-sdk-go/aws/corehandlers
github.com/aws/aws-sdk-go/aws/credentials
github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds
github.com/aws/aws-sdk-go/aws/credentials/endpointcreds
github.com/aws/aws-sdk-go/aws/credentials/processcreds
github.com/aws/aws-sdk-go/aws/credentials/stscreds
github.com/aws/aws-sdk-go/aws/csm
github.com/aws/aws-sdk-go/aws/defaults
github.com/aws/aws-sdk-go/aws/request
github.com/aws/aws-sdk-go/aws/awsutil
github.com/aws/aws-sdk-go/aws/client/metadata
github.com/aws/aws-sdk-go/aws/signer/v4
github.com/aws/aws-sdk-go/private/protocol
github.com/aws/aws-sdk-go/private/protocol/jsonrpc
github.com/aws/aws-sdk-go/internal/sdkrand
github.com/aws/aws-sdk-go/service/sts
github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds
github.com/aws/aws-sdk-go/aws/credentials/endpointcreds
github.com/aws/aws-sdk-go/aws/ec2metadata
github.com/aws/aws-sdk-go/private/protocol/rest
github.com/aws/aws-sdk-go/private/protocol/json/jsonutil
github.com/aws/aws-sdk-go/private/protocol/query
github.com/aws/aws-sdk-go/aws/endpoints
github.com/aws/aws-sdk-go/aws/request
github.com/aws/aws-sdk-go/aws/session
github.com/aws/aws-sdk-go/aws/signer/v4
github.com/aws/aws-sdk-go/internal/ini
github.com/aws/aws-sdk-go/internal/sdkio
github.com/aws/aws-sdk-go/internal/sdkrand
github.com/aws/aws-sdk-go/internal/sdkuri
github.com/aws/aws-sdk-go/internal/shareddefaults
github.com/aws/aws-sdk-go/private/protocol
github.com/aws/aws-sdk-go/private/protocol/json/jsonutil
github.com/aws/aws-sdk-go/private/protocol/jsonrpc
github.com/aws/aws-sdk-go/private/protocol/query
github.com/aws/aws-sdk-go/private/protocol/query/queryutil
github.com/aws/aws-sdk-go/private/protocol/rest
github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil
github.com/aws/aws-sdk-go/service/ecr
github.com/aws/aws-sdk-go/service/sts
# github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0
github.com/beego/i18n
# github.com/bmatcuk/doublestar v1.1.1
github.com/bmatcuk/doublestar
# github.com/casbin/casbin v1.7.0
github.com/casbin/casbin
github.com/casbin/casbin/model
github.com/casbin/casbin/persist
github.com/casbin/casbin/util
github.com/casbin/casbin/config
github.com/casbin/casbin/effect
github.com/casbin/casbin/log
github.com/casbin/casbin/model
github.com/casbin/casbin/persist
github.com/casbin/casbin/persist/file-adapter
github.com/casbin/casbin/rbac
github.com/casbin/casbin/rbac/default-role-manager
github.com/casbin/casbin/config
github.com/casbin/casbin/util
# github.com/coreos/go-oidc v2.0.0+incompatible
github.com/coreos/go-oidc
# github.com/cyphar/filepath-securejoin v0.2.2
@ -101,27 +101,28 @@ github.com/dghubble/sling
# github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dgrijalva/jwt-go
# github.com/docker/distribution v2.7.1+incompatible
github.com/docker/distribution/manifest/manifestlist
github.com/docker/distribution/manifest/schema1
github.com/docker/distribution/manifest/schema2
github.com/docker/distribution
github.com/docker/distribution/registry/auth/token
github.com/docker/distribution/reference
github.com/docker/distribution/registry/client/auth/challenge
github.com/docker/distribution/health
github.com/docker/distribution/registry/auth
github.com/docker/distribution/manifest
github.com/docker/distribution/context
github.com/docker/distribution/digestset
github.com/docker/distribution/health
github.com/docker/distribution/manifest
github.com/docker/distribution/manifest/manifestlist
github.com/docker/distribution/manifest/ocischema
github.com/docker/distribution/manifest/schema1
github.com/docker/distribution/manifest/schema2
github.com/docker/distribution/reference
github.com/docker/distribution/registry/api/errcode
github.com/docker/distribution/registry/auth
github.com/docker/distribution/registry/auth/token
github.com/docker/distribution/registry/client/auth/challenge
github.com/docker/distribution/uuid
# github.com/docker/go v0.0.0-20160303222718-d30aec9fd63c
github.com/docker/go/canonical/json
# github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7
github.com/docker/libtrust
# github.com/garyburd/redigo v1.6.0
github.com/garyburd/redigo/redis
github.com/garyburd/redigo/internal
github.com/garyburd/redigo/redis
# github.com/ghodss/yaml v1.0.0
github.com/ghodss/yaml
# github.com/go-openapi/analysis v0.19.5
@ -137,8 +138,8 @@ github.com/go-openapi/jsonreference
github.com/go-openapi/loads
# github.com/go-openapi/runtime v0.19.5
github.com/go-openapi/runtime
github.com/go-openapi/runtime/middleware
github.com/go-openapi/runtime/logger
github.com/go-openapi/runtime/middleware
github.com/go-openapi/runtime/middleware/denco
github.com/go-openapi/runtime/middleware/header
github.com/go-openapi/runtime/middleware/untyped
@ -158,11 +159,11 @@ github.com/go-stack/stack
# github.com/gobwas/glob v0.2.3
github.com/gobwas/glob
github.com/gobwas/glob/compiler
github.com/gobwas/glob/syntax
github.com/gobwas/glob/match
github.com/gobwas/glob/syntax
github.com/gobwas/glob/syntax/ast
github.com/gobwas/glob/util/runes
github.com/gobwas/glob/syntax/lexer
github.com/gobwas/glob/util/runes
github.com/gobwas/glob/util/strings
# github.com/gocraft/work v0.5.1
github.com/gocraft/work
@ -171,19 +172,19 @@ github.com/gogo/protobuf/proto
github.com/gogo/protobuf/sortkeys
# github.com/golang-migrate/migrate v3.3.0+incompatible
github.com/golang-migrate/migrate
github.com/golang-migrate/migrate/database/postgres
github.com/golang-migrate/migrate/source/file
github.com/golang-migrate/migrate/database
github.com/golang-migrate/migrate/database/postgres
github.com/golang-migrate/migrate/source
github.com/golang-migrate/migrate/source/file
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/glog
# github.com/golang/protobuf v1.3.1
github.com/golang/protobuf/proto
github.com/golang/protobuf/ptypes/any
github.com/golang/protobuf/ptypes/timestamp
github.com/golang/protobuf/proto
# github.com/gomodule/redigo v2.0.0+incompatible
github.com/gomodule/redigo/redis
github.com/gomodule/redigo/internal
github.com/gomodule/redigo/redis
# github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135
github.com/google/go-querystring/query
# github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf
@ -211,9 +212,9 @@ github.com/lib/pq
github.com/lib/pq/oid
github.com/lib/pq/scram
# github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
github.com/mailru/easyjson/buffer
github.com/mailru/easyjson/jlexer
github.com/mailru/easyjson/jwriter
github.com/mailru/easyjson/buffer
# github.com/mattn/go-runewidth v0.0.4
github.com/mattn/go-runewidth
# github.com/miekg/pkcs11 v0.0.0-20170220202408-7283ca79f35e
@ -229,8 +230,8 @@ github.com/olekukonko/tablewriter
# github.com/opencontainers/go-digest v1.0.0-rc0
github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/image-spec/specs-go/v1
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
# github.com/opentracing/opentracing-go v1.1.0
github.com/opentracing/opentracing-go
github.com/opentracing/opentracing-go/log
@ -252,53 +253,53 @@ github.com/spf13/pflag
# github.com/stretchr/objx v0.2.0
github.com/stretchr/objx
# github.com/stretchr/testify v1.4.0
github.com/stretchr/testify/mock
github.com/stretchr/testify/suite
github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
github.com/stretchr/testify/require
github.com/stretchr/testify/suite
# github.com/theupdateframework/notary v0.6.1
github.com/theupdateframework/notary/tuf/data
github.com/theupdateframework/notary
github.com/theupdateframework/notary/client
github.com/theupdateframework/notary/trustpinning
github.com/theupdateframework/notary/client/changelist
github.com/theupdateframework/notary/cryptoservice
github.com/theupdateframework/notary/storage
github.com/theupdateframework/notary/trustmanager
github.com/theupdateframework/notary/trustmanager/yubikey
github.com/theupdateframework/notary/trustpinning
github.com/theupdateframework/notary/tuf
github.com/theupdateframework/notary/tuf/data
github.com/theupdateframework/notary/tuf/signed
github.com/theupdateframework/notary/tuf/utils
github.com/theupdateframework/notary/tuf/validation
# go.mongodb.org/mongo-driver v1.1.1
go.mongodb.org/mongo-driver/bson
go.mongodb.org/mongo-driver/bson/bsontype
go.mongodb.org/mongo-driver/bson/primitive
go.mongodb.org/mongo-driver/bson/bsoncodec
go.mongodb.org/mongo-driver/bson/bsonrw
go.mongodb.org/mongo-driver/bson/bsontype
go.mongodb.org/mongo-driver/bson/primitive
go.mongodb.org/mongo-driver/x/bsonx/bsoncore
# golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/acme/autocert
golang.org/x/crypto/openpgp
golang.org/x/crypto/openpgp/clearsign
golang.org/x/crypto/openpgp/packet
golang.org/x/crypto/acme
golang.org/x/crypto/ed25519
golang.org/x/crypto/ssh/terminal
golang.org/x/crypto/openpgp/armor
golang.org/x/crypto/openpgp/errors
golang.org/x/crypto/openpgp/s2k
golang.org/x/crypto/acme/autocert
golang.org/x/crypto/cast5
golang.org/x/crypto/openpgp/elgamal
golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/openpgp
golang.org/x/crypto/openpgp/armor
golang.org/x/crypto/openpgp/clearsign
golang.org/x/crypto/openpgp/elgamal
golang.org/x/crypto/openpgp/errors
golang.org/x/crypto/openpgp/packet
golang.org/x/crypto/openpgp/s2k
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/ssh/terminal
# golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/net/http2
golang.org/x/net/idna
golang.org/x/net/context
golang.org/x/net/context/ctxhttp
golang.org/x/net/http/httpguts
golang.org/x/net/http2
golang.org/x/net/http2/hpack
golang.org/x/net/context
golang.org/x/net/idna
# golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
golang.org/x/oauth2
golang.org/x/oauth2/clientcredentials
@ -308,21 +309,21 @@ golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/text v0.3.2
golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
golang.org/x/text/transform
golang.org/x/text/width
# golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
golang.org/x/time/rate
# google.golang.org/appengine v1.4.0
google.golang.org/appengine/cloudsql
google.golang.org/appengine/urlfetch
google.golang.org/appengine/internal
google.golang.org/appengine/internal/urlfetch
google.golang.org/appengine/internal/base
google.golang.org/appengine/internal/datastore
google.golang.org/appengine/internal/log
google.golang.org/appengine/internal/remote_api
google.golang.org/appengine/internal/urlfetch
google.golang.org/appengine/urlfetch
# gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175
gopkg.in/asn1-ber.v1
# gopkg.in/inf.v0 v0.9.1
@ -338,13 +339,13 @@ gopkg.in/square/go-jose.v2/json
# gopkg.in/yaml.v2 v2.2.2
gopkg.in/yaml.v2
# k8s.io/api v0.0.0-20190222213804-5cb15d344471
k8s.io/api/authentication/v1beta1
k8s.io/api/admissionregistration/v1alpha1
k8s.io/api/admissionregistration/v1beta1
k8s.io/api/apps/v1
k8s.io/api/apps/v1beta1
k8s.io/api/apps/v1beta2
k8s.io/api/authentication/v1
k8s.io/api/authentication/v1beta1
k8s.io/api/authorization/v1
k8s.io/api/authorization/v1beta1
k8s.io/api/autoscaling/v1
@ -368,69 +369,69 @@ k8s.io/api/storage/v1
k8s.io/api/storage/v1alpha1
k8s.io/api/storage/v1beta1
# k8s.io/apimachinery v0.0.0-20180704011316-f534d624797b
k8s.io/apimachinery/pkg/apis/meta/v1
k8s.io/apimachinery/pkg/runtime/schema
k8s.io/apimachinery/pkg/runtime/serializer
k8s.io/apimachinery/pkg/version
k8s.io/apimachinery/pkg/runtime
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
k8s.io/apimachinery/pkg/conversion
k8s.io/apimachinery/pkg/conversion/queryparams
k8s.io/apimachinery/pkg/fields
k8s.io/apimachinery/pkg/labels
k8s.io/apimachinery/pkg/selection
k8s.io/apimachinery/pkg/types
k8s.io/apimachinery/pkg/util/intstr
k8s.io/apimachinery/pkg/util/runtime
k8s.io/apimachinery/pkg/watch
k8s.io/apimachinery/pkg/runtime
k8s.io/apimachinery/pkg/runtime/schema
k8s.io/apimachinery/pkg/runtime/serializer
k8s.io/apimachinery/pkg/runtime/serializer/json
k8s.io/apimachinery/pkg/runtime/serializer/protobuf
k8s.io/apimachinery/pkg/runtime/serializer/recognizer
k8s.io/apimachinery/pkg/runtime/serializer/versioning
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/runtime/serializer/streaming
k8s.io/apimachinery/pkg/util/net
k8s.io/apimachinery/pkg/util/sets
k8s.io/apimachinery/pkg/conversion/queryparams
k8s.io/apimachinery/pkg/util/errors
k8s.io/apimachinery/pkg/util/json
k8s.io/apimachinery/third_party/forked/golang/reflect
k8s.io/apimachinery/pkg/util/validation
k8s.io/apimachinery/pkg/util/wait
k8s.io/apimachinery/pkg/util/framer
k8s.io/apimachinery/pkg/util/yaml
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
k8s.io/apimachinery/pkg/util/validation/field
k8s.io/apimachinery/pkg/runtime/serializer/versioning
k8s.io/apimachinery/pkg/selection
k8s.io/apimachinery/pkg/types
k8s.io/apimachinery/pkg/util/clock
k8s.io/apimachinery/pkg/util/errors
k8s.io/apimachinery/pkg/util/framer
k8s.io/apimachinery/pkg/util/intstr
k8s.io/apimachinery/pkg/util/json
k8s.io/apimachinery/pkg/util/net
k8s.io/apimachinery/pkg/util/runtime
k8s.io/apimachinery/pkg/util/sets
k8s.io/apimachinery/pkg/util/validation
k8s.io/apimachinery/pkg/util/validation/field
k8s.io/apimachinery/pkg/util/wait
k8s.io/apimachinery/pkg/util/yaml
k8s.io/apimachinery/pkg/version
k8s.io/apimachinery/pkg/watch
k8s.io/apimachinery/third_party/forked/golang/reflect
# k8s.io/client-go v8.0.0+incompatible
k8s.io/client-go/kubernetes/scheme
k8s.io/client-go/rest
k8s.io/client-go/pkg/apis/clientauthentication
k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1
k8s.io/client-go/pkg/apis/clientauthentication/v1beta1
k8s.io/client-go/pkg/version
k8s.io/client-go/plugin/pkg/client/auth/exec
k8s.io/client-go/rest
k8s.io/client-go/rest/watch
k8s.io/client-go/tools/clientcmd/api
k8s.io/client-go/tools/metrics
k8s.io/client-go/transport
k8s.io/client-go/util/cert
k8s.io/client-go/util/flowcontrol
k8s.io/client-go/pkg/apis/clientauthentication
k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1
k8s.io/client-go/pkg/apis/clientauthentication/v1beta1
k8s.io/client-go/util/connrotation
k8s.io/client-go/util/integer
k8s.io/client-go/util/flowcontrol
k8s.io/client-go/util/homedir
k8s.io/client-go/util/integer
# k8s.io/helm v2.16.1+incompatible
k8s.io/helm/cmd/helm/search
k8s.io/helm/pkg/chartutil
k8s.io/helm/pkg/proto/hapi/chart
k8s.io/helm/pkg/repo
k8s.io/helm/pkg/ignore
k8s.io/helm/pkg/proto/hapi/version
k8s.io/helm/pkg/sympath
k8s.io/helm/pkg/version
k8s.io/helm/pkg/getter
k8s.io/helm/pkg/provenance
k8s.io/helm/pkg/urlutil
k8s.io/helm/pkg/helm/environment
k8s.io/helm/pkg/plugin
k8s.io/helm/pkg/tlsutil
k8s.io/helm/pkg/helm/helmpath
k8s.io/helm/pkg/ignore
k8s.io/helm/pkg/plugin
k8s.io/helm/pkg/proto/hapi/chart
k8s.io/helm/pkg/proto/hapi/version
k8s.io/helm/pkg/provenance
k8s.io/helm/pkg/repo
k8s.io/helm/pkg/sympath
k8s.io/helm/pkg/tlsutil
k8s.io/helm/pkg/urlutil
k8s.io/helm/pkg/version