Try to parse the type of the artifact based on the media type when no resolver found

Try to parse the type of the artifact based on the media type when no resolver found, if parse failed, set it's type to unknown. This won't block the pushing for artifacts that has no resolver registered in Harbor

Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2020-01-20 00:44:56 +08:00
parent 63ef743ba7
commit 1f3fcbde36
4 changed files with 65 additions and 16 deletions

View File

@ -26,8 +26,15 @@ import (
"github.com/goharbor/harbor/src/pkg/artifact" "github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/repository" "github.com/goharbor/harbor/src/pkg/repository"
"github.com/opencontainers/image-spec/specs-go/v1" "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 // Abstractor abstracts the specific information for different types of artifacts
type Abstractor interface { type Abstractor interface {
// Abstract the specific information for the specific artifact type into the artifact model, // Abstract the specific information for the specific artifact type into the artifact model,
@ -109,10 +116,22 @@ func (a *abstractor) Abstract(ctx context.Context, artifact *artifact.Artifact)
return fmt.Errorf("unsupported manifest media type: %s", artifact.ManifestMediaType) return fmt.Errorf("unsupported manifest media type: %s", artifact.ManifestMediaType)
} }
resolver, err := resolver.Get(artifact.MediaType) resolver := resolver.Get(artifact.MediaType)
if err != nil { if resolver != nil {
return err artifact.Type = resolver.ArtifactType()
return resolver.Resolve(ctx, content, artifact)
} }
artifact.Type = resolver.ArtifactType()
return resolver.Resolve(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
}
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

@ -294,6 +294,28 @@ func (a *abstractorTestSuite) TestAbstractUnsupported() {
a.fetcher.AssertExpectations(a.T()) a.fetcher.AssertExpectations(a.T())
} }
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 TestAbstractorTestSuite(t *testing.T) { func TestAbstractorTestSuite(t *testing.T) {
suite.Run(t, &abstractorTestSuite{}) suite.Run(t, &abstractorTestSuite{})
} }

View File

@ -49,10 +49,6 @@ func Register(resolver Resolver, mediaTypes ...string) error {
} }
// Get the resolver according to the media type // Get the resolver according to the media type
func Get(mediaType string) (Resolver, error) { func Get(mediaType string) Resolver {
resolver, exist := registry[mediaType] return registry[mediaType]
if !exist {
return nil, fmt.Errorf("resolver resolves %s not found", mediaType)
}
return resolver, nil
} }

View File

@ -11,10 +11,22 @@
package resolver package resolver
import ( import (
"context"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"testing" "testing"
) )
type fakeResolver struct{}
func (f *fakeResolver) ArtifactType() string {
return ""
}
func (f *fakeResolver) Resolve(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error {
return nil
}
type resolverTestSuite struct { type resolverTestSuite struct {
suite.Suite suite.Suite
} }
@ -37,16 +49,16 @@ func (r *resolverTestSuite) TestRegister() {
func (r *resolverTestSuite) TestGet() { func (r *resolverTestSuite) TestGet() {
// registry a resolver // registry a resolver
mediaType := "fake_media_type" mediaType := "fake_media_type"
err := Register(nil, mediaType) err := Register(&fakeResolver{}, mediaType)
r.Assert().Nil(err) r.Assert().Nil(err)
// get the resolver // get the resolver
_, err = Get(mediaType) resolver := Get(mediaType)
r.Assert().Nil(err) r.Assert().NotNil(resolver)
// get the not exist resolver // get the not exist resolver
_, err = Get("not_existing_media_type") resolver = Get("not_existing_media_type")
r.Assert().NotNil(err) r.Assert().Nil(resolver)
} }
func TestResolverTestSuite(t *testing.T) { func TestResolverTestSuite(t *testing.T) {