From 1f3fcbde36e3001ff7b18c7b6fa4817dc6488cf7 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 20 Jan 2020 00:44:56 +0800 Subject: [PATCH] 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 --- src/api/artifact/abstractor/abstractor.go | 29 +++++++++++++++---- .../artifact/abstractor/abstractor_test.go | 22 ++++++++++++++ .../artifact/abstractor/resolver/resolver.go | 8 ++--- .../abstractor/resolver/resolver_test.go | 22 ++++++++++---- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/api/artifact/abstractor/abstractor.go b/src/api/artifact/abstractor/abstractor.go index e1ea264e3..0c16ee243 100644 --- a/src/api/artifact/abstractor/abstractor.go +++ b/src/api/artifact/abstractor/abstractor.go @@ -26,8 +26,15 @@ 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 { // 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) } - resolver, err := resolver.Get(artifact.MediaType) - if err != nil { - return err + resolver := resolver.Get(artifact.MediaType) + if resolver != nil { + 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 } diff --git a/src/api/artifact/abstractor/abstractor_test.go b/src/api/artifact/abstractor/abstractor_test.go index 0de9c609b..1d93e095e 100644 --- a/src/api/artifact/abstractor/abstractor_test.go +++ b/src/api/artifact/abstractor/abstractor_test.go @@ -294,6 +294,28 @@ func (a *abstractorTestSuite) TestAbstractUnsupported() { 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) { suite.Run(t, &abstractorTestSuite{}) } diff --git a/src/api/artifact/abstractor/resolver/resolver.go b/src/api/artifact/abstractor/resolver/resolver.go index d5a504e17..f8043b3c1 100644 --- a/src/api/artifact/abstractor/resolver/resolver.go +++ b/src/api/artifact/abstractor/resolver/resolver.go @@ -49,10 +49,6 @@ func Register(resolver Resolver, mediaTypes ...string) error { } // Get the resolver according to the media type -func Get(mediaType string) (Resolver, error) { - resolver, exist := registry[mediaType] - if !exist { - return nil, fmt.Errorf("resolver resolves %s not found", mediaType) - } - return resolver, nil +func Get(mediaType string) Resolver { + return registry[mediaType] } diff --git a/src/api/artifact/abstractor/resolver/resolver_test.go b/src/api/artifact/abstractor/resolver/resolver_test.go index 457064551..1b921ba33 100644 --- a/src/api/artifact/abstractor/resolver/resolver_test.go +++ b/src/api/artifact/abstractor/resolver/resolver_test.go @@ -11,10 +11,22 @@ package resolver import ( + "context" + "github.com/goharbor/harbor/src/pkg/artifact" "github.com/stretchr/testify/suite" "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 { suite.Suite } @@ -37,16 +49,16 @@ func (r *resolverTestSuite) TestRegister() { func (r *resolverTestSuite) TestGet() { // registry a resolver mediaType := "fake_media_type" - err := Register(nil, mediaType) + err := Register(&fakeResolver{}, mediaType) r.Assert().Nil(err) // get the resolver - _, err = Get(mediaType) - r.Assert().Nil(err) + resolver := Get(mediaType) + r.Assert().NotNil(resolver) // get the not exist resolver - _, err = Get("not_existing_media_type") - r.Assert().NotNil(err) + resolver = Get("not_existing_media_type") + r.Assert().Nil(resolver) } func TestResolverTestSuite(t *testing.T) {