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/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)
}
// 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())
}
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{})
}

View File

@ -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]
}

View File

@ -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) {