Use the repository name of artifact model

As we store the repository name in the artifact table, we can use it direclty in the code to reduce the database query

Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2020-02-25 21:40:49 +08:00
parent 7857528e45
commit 02c2647e1e
25 changed files with 178 additions and 297 deletions

View File

@ -56,9 +56,6 @@ WHERE ordered_art.seq=1;
ALTER TABLE artifact DROP COLUMN tag;
/*TODO: remove this after insert the repository_name when create artifact*/
ALTER TABLE artifact ALTER COLUMN repository_name DROP NOT NULL;
/*remove the duplicate artifact rows*/
DELETE FROM artifact
WHERE id NOT IN (

View File

@ -25,7 +25,6 @@ import (
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/repository"
"github.com/opencontainers/image-spec/specs-go/v1"
)
@ -43,24 +42,18 @@ type Abstractor interface {
// NewAbstractor returns an instance of the default abstractor
func NewAbstractor() Abstractor {
return &abstractor{
repoMgr: repository.Mgr,
blobFetcher: blob.Fcher,
}
}
type abstractor struct {
repoMgr repository.Manager
blobFetcher blob.Fetcher
}
// 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)
if err != nil {
return err
}
// read manifest content
manifestMediaType, content, err := a.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
manifestMediaType, content, err := a.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
if err != nil {
return err
}

View File

@ -18,12 +18,10 @@ import (
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
"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"
tresolver "github.com/goharbor/harbor/src/testing/api/artifact/abstractor/resolver"
"github.com/goharbor/harbor/src/testing/pkg/repository"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/suite"
"testing"
@ -203,16 +201,13 @@ type abstractorTestSuite struct {
suite.Suite
abstractor Abstractor
fetcher *blob.FakeFetcher
repoMgr *repository.FakeManager
resolver *tresolver.FakeResolver
}
func (a *abstractorTestSuite) SetupTest() {
a.fetcher = &blob.FakeFetcher{}
a.repoMgr = &repository.FakeManager{}
a.resolver = &tresolver.FakeResolver{}
a.abstractor = &abstractor{
repoMgr: a.repoMgr,
blobFetcher: a.fetcher,
}
}
@ -220,7 +215,6 @@ func (a *abstractorTestSuite) SetupTest() {
// docker manifest v1
func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
resolver.Register(a.resolver, schema1.MediaTypeSignedManifest)
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
a.fetcher.On("FetchManifest").Return(schema1.MediaTypeSignedManifest, []byte(v1Manifest), nil)
a.resolver.On("ArtifactType").Return(fakeArtifactType)
a.resolver.On("ResolveMetadata").Return(nil)
@ -238,7 +232,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
// docker manifest v2
func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
resolver.Register(a.resolver, schema2.MediaTypeImageConfig)
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
a.fetcher.On("FetchManifest").Return(schema2.MediaTypeManifest, []byte(v2Manifest), nil)
a.resolver.On("ArtifactType").Return(fakeArtifactType)
a.resolver.On("ResolveMetadata").Return(nil)
@ -257,7 +250,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
// OCI index
func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
resolver.Register(a.resolver, v1.MediaTypeImageIndex)
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
a.fetcher.On("FetchManifest").Return(v1.MediaTypeImageIndex, []byte(index), nil)
a.resolver.On("ArtifactType").Return(fakeArtifactType)
a.resolver.On("ResolveMetadata").Return(nil)
@ -275,7 +267,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
// OCI index
func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
a.fetcher.On("FetchManifest").Return("unsupported-manifest", []byte{}, nil)
artifact := &artifact.Artifact{
ID: 1,

View File

@ -24,7 +24,6 @@ import (
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/chart"
"github.com/goharbor/harbor/src/pkg/repository"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -41,7 +40,6 @@ const (
func init() {
resolver := &resolver{
repoMgr: repository.Mgr,
blobFetcher: blob.Fcher,
chartOperator: chart.Optr,
}
@ -56,22 +54,17 @@ func init() {
}
type resolver struct {
repoMgr repository.Manager
blobFetcher blob.Fetcher
chartOperator chart.Operator
}
func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error {
repository, err := r.repoMgr.Get(ctx, artifact.RepositoryID)
if err != nil {
return err
}
m := &v1.Manifest{}
if err := json.Unmarshal(manifest, m); err != nil {
return err
}
digest := m.Config.Digest.String()
layer, err := r.blobFetcher.FetchLayer(repository.Name, digest)
layer, err := r.blobFetcher.FetchLayer(artifact.RepositoryName, digest)
if err != nil {
return err
}
@ -95,11 +88,7 @@ func (r *resolver) ResolveAddition(ctx context.Context, artifact *artifact.Artif
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeChart)
}
repository, err := r.repoMgr.Get(ctx, artifact.RepositoryID)
if err != nil {
return nil, err
}
_, content, err := r.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
_, content, err := r.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
if err != nil {
return nil, err
}
@ -112,7 +101,7 @@ func (r *resolver) ResolveAddition(ctx context.Context, artifact *artifact.Artif
// chart do have two layers, one is config, we should resolve the other one.
layerDgst := layer.Digest.String()
if layerDgst != manifest.Config.Digest.String() {
content, err = r.blobFetcher.FetchLayer(repository.Name, layerDgst)
content, err = r.blobFetcher.FetchLayer(artifact.RepositoryName, layerDgst)
if err != nil {
return nil, err
}

View File

@ -15,13 +15,11 @@
package chart
import (
"github.com/goharbor/harbor/src/common/models"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/artifact"
chartserver "github.com/goharbor/harbor/src/pkg/chart"
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
"github.com/goharbor/harbor/src/testing/pkg/chart"
"github.com/goharbor/harbor/src/testing/pkg/repository"
"github.com/stretchr/testify/suite"
"k8s.io/helm/pkg/chartutil"
"testing"
@ -30,17 +28,14 @@ import (
type resolverTestSuite struct {
suite.Suite
resolver *resolver
repoMgr *repository.FakeManager
blobFetcher *blob.FakeFetcher
chartOptr *chart.FakeOpertaor
}
func (r *resolverTestSuite) SetupTest() {
r.repoMgr = &repository.FakeManager{}
r.blobFetcher = &blob.FakeFetcher{}
r.chartOptr = &chart.FakeOpertaor{}
r.resolver = &resolver{
repoMgr: r.repoMgr,
blobFetcher: r.blobFetcher,
chartOperator: r.chartOptr,
}
@ -92,11 +87,9 @@ func (r *resolverTestSuite) TestResolveMetadata() {
"appVersion": "1.8.2"
}`
artifact := &artifact.Artifact{}
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
err := r.resolver.ResolveMetadata(nil, []byte(content), artifact)
r.Require().Nil(err)
r.repoMgr.AssertExpectations(r.T())
r.blobFetcher.AssertExpectations(r.T())
r.Assert().Equal("1.1.2", artifact.ExtraAttrs["version"].(string))
r.Assert().Equal("1.8.2", artifact.ExtraAttrs["appVersion"].(string))
@ -158,7 +151,6 @@ func (r *resolverTestSuite) TestResolveAddition() {
}
artifact := &artifact.Artifact{}
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
r.blobFetcher.On("FetchManifest").Return("", []byte(chartManifest), nil)
r.blobFetcher.On("FetchLayer").Return([]byte(chartYaml), nil)
r.chartOptr.On("GetDetails").Return(chartDetails, nil)

View File

@ -23,7 +23,6 @@ import (
"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"
)
@ -35,7 +34,6 @@ const (
func init() {
resolver := &resolver{
repoMgr: repository.Mgr,
argMgr: artifact.Mgr,
blobFetcher: blob.Fcher,
}
@ -50,7 +48,6 @@ func init() {
}
type resolver struct {
repoMgr repository.Manager
argMgr artifact.Manager
blobFetcher blob.Fetcher
}
@ -65,7 +62,7 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
for _, mani := range index.Manifests {
digest := mani.Digest.String()
// make sure the child artifact exist
ar, err := r.argMgr.GetByDigest(ctx, art.RepositoryID, digest)
ar, err := r.argMgr.GetByDigest(ctx, art.RepositoryName, digest)
if err != nil {
return err
}
@ -84,12 +81,8 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
}
// 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)
_, cfgMani, err := r.blobFetcher.FetchManifest(art.RepositoryName, cfgManiDgt)
if err != nil {
return err
}
@ -99,7 +92,7 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
}
cfgDgt := m.Config.Digest.String()
// get the config layer
cfg, err := r.blobFetcher.FetchLayer(repository.Name, cfgDgt)
cfg, err := r.blobFetcher.FetchLayer(art.RepositoryName, cfgDgt)
if err != nil {
return err
}

View File

@ -15,12 +15,10 @@
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"
)
@ -28,17 +26,14 @@ import (
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,
}
@ -115,7 +110,6 @@ func (r *resolverTestSuite) TestResolveMetadata() {
}`
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)

View File

@ -58,7 +58,7 @@ func (i *indexResolver) ResolveMetadata(ctx context.Context, manifest []byte, ar
for _, mani := range index.Manifests {
digest := mani.Digest.String()
// make sure the child artifact exist
ar, err := i.artMgr.GetByDigest(ctx, art.RepositoryID, digest)
ar, err := i.artMgr.GetByDigest(ctx, art.RepositoryName, digest)
if err != nil {
return err
}

View File

@ -24,7 +24,6 @@ import (
"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"
"github.com/opencontainers/image-spec/specs-go/v1"
)
@ -37,7 +36,6 @@ const (
func init() {
rslver := &manifestV2Resolver{
repoMgr: repository.Mgr,
blobFetcher: blob.Fcher,
}
mediaTypes := []string{
@ -56,21 +54,16 @@ func init() {
// manifestV2Resolver resolve artifact with OCI manifest and docker v2 manifest
type manifestV2Resolver struct {
repoMgr repository.Manager
blobFetcher blob.Fetcher
}
func (m *manifestV2Resolver) ResolveMetadata(ctx context.Context, content []byte, artifact *artifact.Artifact) error {
repository, err := m.repoMgr.Get(ctx, artifact.RepositoryID)
if err != nil {
return err
}
manifest := &v1.Manifest{}
if err := json.Unmarshal(content, manifest); err != nil {
return err
}
digest := manifest.Config.Digest.String()
layer, err := m.blobFetcher.FetchLayer(repository.Name, digest)
layer, err := m.blobFetcher.FetchLayer(artifact.RepositoryName, digest)
if err != nil {
return err
}
@ -93,11 +86,7 @@ func (m *manifestV2Resolver) ResolveAddition(ctx context.Context, artifact *arti
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
WithMessage("addition %s isn't supported for %s(manifest version 2)", addition, ArtifactTypeImage)
}
repository, err := m.repoMgr.Get(ctx, artifact.RepositoryID)
if err != nil {
return nil, err
}
_, content, err := m.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
_, content, err := m.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
if err != nil {
return nil, err
}
@ -105,7 +94,7 @@ func (m *manifestV2Resolver) ResolveAddition(ctx context.Context, artifact *arti
if err := json.Unmarshal(content, manifest); err != nil {
return nil, err
}
content, err = m.blobFetcher.FetchLayer(repository.Name, manifest.Config.Digest.String())
content, err = m.blobFetcher.FetchLayer(artifact.RepositoryName, manifest.Config.Digest.String())
if err != nil {
return nil, err
}

View File

@ -15,11 +15,9 @@
package image
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"
"github.com/goharbor/harbor/src/testing/pkg/repository"
"github.com/stretchr/testify/suite"
"testing"
)
@ -123,15 +121,12 @@ var (
type manifestV2ResolverTestSuite struct {
suite.Suite
resolver *manifestV2Resolver
repoMgr *repository.FakeManager
blobFetcher *blob.FakeFetcher
}
func (m *manifestV2ResolverTestSuite) SetupTest() {
m.repoMgr = &repository.FakeManager{}
m.blobFetcher = &blob.FakeFetcher{}
m.resolver = &manifestV2Resolver{
repoMgr: m.repoMgr,
blobFetcher: m.blobFetcher,
}
@ -139,11 +134,9 @@ func (m *manifestV2ResolverTestSuite) SetupTest() {
func (m *manifestV2ResolverTestSuite) TestResolveMetadata() {
artifact := &artifact.Artifact{}
m.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
err := m.resolver.ResolveMetadata(nil, []byte(manifest), artifact)
m.Require().Nil(err)
m.repoMgr.AssertExpectations(m.T())
m.blobFetcher.AssertExpectations(m.T())
m.Assert().Equal("amd64", artifact.ExtraAttrs["architecture"].(string))
m.Assert().Equal("linux", artifact.ExtraAttrs["os"].(string))
@ -156,7 +149,6 @@ func (m *manifestV2ResolverTestSuite) TestResolveAddition() {
// build history
artifact := &artifact.Artifact{}
m.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
m.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
addition, err := m.resolver.ResolveAddition(nil, artifact, AdditionTypeBuildHistory)

View File

@ -20,7 +20,6 @@ import (
"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"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/internal"
"github.com/goharbor/harbor/src/pkg/art"
@ -61,7 +60,7 @@ type Controller interface {
// creates it if it doesn't exist. If tags are provided, ensure they exist
// and are attached to the artifact. If the tags don't exist, create them first.
// The "created" will be set as true when the artifact is created
Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (created bool, id int64, err error)
Ensure(ctx context.Context, repository, digest string, tags ...string) (created bool, id int64, err error)
// Count returns the total count of artifacts according to the query.
// The artifacts that referenced by others and without tags are not counted
Count(ctx context.Context, query *q.Query) (total int64, err error)
@ -75,8 +74,8 @@ type Controller interface {
GetByReference(ctx context.Context, repository, reference string, option *Option) (artifact *Artifact, err error)
// Delete the artifact specified by ID. All tags attached to the artifact are deleted as well
Delete(ctx context.Context, id int64) (err error)
// Copy the artifact whose ID is specified by "srcArtID" into the repository specified by "dstRepoID"
Copy(ctx context.Context, srcArtID, dstRepoID int64) (id int64, err error)
// Copy the artifact specified by "srcRepo" and "reference" into the repository specified by "dstRepo"
Copy(ctx context.Context, srcRepo, reference, dstRepo string) (id int64, err error)
// ListTags lists the tags according to the query, specify the properties returned with option
ListTags(ctx context.Context, query *q.Query, option *TagOption) (tags []*Tag, err error)
// CreateTag creates a tag
@ -127,46 +126,47 @@ type controller struct {
regCli registry.Client
}
func (c *controller) Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (bool, int64, error) {
created, id, err := c.ensureArtifact(ctx, repositoryID, digest)
func (c *controller) Ensure(ctx context.Context, repository, digest string, tags ...string) (bool, int64, error) {
created, artifact, err := c.ensureArtifact(ctx, repository, digest)
if err != nil {
return false, 0, err
}
for _, tag := range tags {
if err = c.ensureTag(ctx, repositoryID, id, tag); err != nil {
if err = c.ensureTag(ctx, artifact.RepositoryID, artifact.ID, tag); err != nil {
return false, 0, err
}
}
return created, id, nil
return created, artifact.ID, nil
}
// ensure the artifact exists under the repository, create it if doesn't exist.
func (c *controller) ensureArtifact(ctx context.Context, repositoryID int64, digest string) (bool, int64, error) {
art, err := c.artMgr.GetByDigest(ctx, repositoryID, digest)
func (c *controller) ensureArtifact(ctx context.Context, repository, digest string) (bool, *artifact.Artifact, error) {
art, err := c.artMgr.GetByDigest(ctx, repository, digest)
// the artifact already exists under the repository, return directly
if err == nil {
return false, art.ID, nil
return false, art, nil
}
// got other error when get the artifact, return the error
if !ierror.IsErr(err, ierror.NotFoundCode) {
return false, 0, err
return false, nil, err
}
// the artifact doesn't exist under the repository, create it first
repository, err := c.repoMgr.Get(ctx, repositoryID)
repo, err := c.repoMgr.GetByName(ctx, repository)
if err != nil {
return false, 0, err
return false, nil, err
}
artifact := &artifact.Artifact{
ProjectID: repository.ProjectID,
RepositoryID: repositoryID,
Digest: digest,
PushTime: time.Now(),
ProjectID: repo.ProjectID,
RepositoryID: repo.RepositoryID,
RepositoryName: repository,
Digest: digest,
PushTime: time.Now(),
}
// abstract the metadata for the artifact
if err = c.abstractor.AbstractMetadata(ctx, artifact); err != nil {
return false, 0, err
return false, nil, err
}
// populate the artifact type
@ -177,15 +177,16 @@ func (c *controller) ensureArtifact(ctx context.Context, repositoryID int64, dig
if err != nil {
// if got conflict error, try to get the artifact again
if ierror.IsConflictErr(err) {
art, err = c.artMgr.GetByDigest(ctx, repositoryID, digest)
art, err = c.artMgr.GetByDigest(ctx, repository, digest)
if err == nil {
return false, art.ID, nil
return false, art, nil
}
return false, 0, err
return false, nil, err
}
return false, 0, err
return false, nil, err
}
return true, id, nil
artifact.ID = id
return true, artifact, nil
}
func (c *controller) ensureTag(ctx context.Context, repositoryID, artifactID int64, name string) error {
@ -236,10 +237,6 @@ func (c *controller) List(ctx context.Context, query *q.Query, option *Option) (
return nil, err
}
if err := c.populateRepositoryName(ctx, arts...); err != nil {
return nil, err
}
var artifacts []*Artifact
for _, art := range arts {
artifacts = append(artifacts, c.assembleArtifact(ctx, art, option))
@ -265,11 +262,7 @@ func (c *controller) GetByReference(ctx context.Context, repository, reference s
}
func (c *controller) getByDigest(ctx context.Context, repository, digest string, option *Option) (*Artifact, error) {
repo, err := c.repoMgr.GetByName(ctx, repository)
if err != nil {
return nil, err
}
art, err := c.artMgr.GetByDigest(ctx, repo.RepositoryID, digest)
art, err := c.artMgr.GetByDigest(ctx, repository, digest)
if err != nil {
return nil, err
}
@ -377,14 +370,10 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot bool) er
return err
}
repo, err := c.repoMgr.Get(ctx, art.RepositoryID)
if err != nil && !ierror.IsErr(err, ierror.NotFoundCode) {
return err
}
_, err = c.artrashMgr.Create(ctx, &model.ArtifactTrash{
MediaType: art.MediaType,
ManifestMediaType: art.ManifestMediaType,
RepositoryName: repo.Name,
RepositoryName: art.RepositoryName,
Digest: art.Digest,
})
if err != nil && !ierror.IsErr(err, ierror.ConflictCode) {
@ -395,61 +384,63 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot bool) er
return nil
}
func (c *controller) Copy(ctx context.Context, srcArtID, dstRepoID int64) (int64, error) {
srcArt, err := c.Get(ctx, srcArtID, &Option{WithTag: true})
if err != nil {
return 0, err
func (c *controller) Copy(ctx context.Context, srcRepo, reference, dstRepo string) (int64, error) {
return c.copyDeeply(ctx, srcRepo, reference, dstRepo, true)
}
// as we call the docker registry APIs in the registry client directly,
// this bypass our own logic(ensure, fire event, etc.) inside the registry handlers,
// these logic must be covered explicitly here.
// "copyDeeply" iterates the child artifacts and copy them first
func (c *controller) copyDeeply(ctx context.Context, srcRepo, reference, dstRepo string, isRoot bool) (int64, error) {
var option *Option
// only get the tags of the root parent
if isRoot {
option = &Option{WithTag: true}
}
srcRepo, err := c.repoMgr.Get(ctx, srcArt.RepositoryID)
if err != nil {
return 0, err
}
dstRepo, err := c.repoMgr.Get(ctx, dstRepoID)
srcArt, err := c.GetByReference(ctx, srcRepo, reference, option)
if err != nil {
return 0, err
}
_, err = c.artMgr.GetByDigest(ctx, dstRepoID, srcArt.Digest)
// the artifact already exists in the destination repository
digest := srcArt.Digest
// check the existence of artifact in the destination repository
dstArt, err := c.GetByReference(ctx, dstRepo, digest, option)
if err == nil {
return 0, ierror.New(nil).WithCode(ierror.ConflictCode).
WithMessage("the artifact %s already exists under the repository %s",
srcArt.Digest, dstRepo.Name)
// return conflict error if the root parent artifact already exists under the destination repository
if isRoot {
return 0, ierror.New(nil).WithCode(ierror.ConflictCode).
WithMessage("the artifact %s@%s already exists", dstRepo, digest)
}
// the child artifact already under the destination repository, skip
return dstArt.ID, nil
}
if !ierror.IsErr(err, ierror.NotFoundCode) {
return 0, err
}
// the artifact doesn't exist under the destination repository, continue to copy
// copy child artifacts if contains any
for _, reference := range srcArt.References {
if _, err = c.copyDeeply(ctx, srcRepo, reference.ChildDigest, dstRepo, false); err != nil {
return 0, err
}
}
// copy the parent artifact into the backend docker registry
if err := c.regCli.Copy(srcRepo, digest, dstRepo, digest, false); err != nil {
return 0, err
}
// only copy the tags of outermost artifact
var tags []string
for _, tag := range srcArt.Tags {
tags = append(tags, tag.Name)
}
return c.copyDeeply(ctx, srcRepo, srcArt, dstRepo, tags...)
}
// as we call the docker registry APIs in the registry client directly,
// this bypass our own logic(ensure, fire event, etc.) inside the registry handlers,
// these logic must be covered explicitly here.
// "copyDeeply" iterates the child artifacts and copy them first
func (c *controller) copyDeeply(ctx context.Context, srcRepo *models.RepoRecord, srcArt *Artifact,
dstRepo *models.RepoRecord, tags ...string) (int64, error) {
// copy child artifacts if contains any
for _, reference := range srcArt.References {
childArt, err := c.Get(ctx, reference.ChildID, nil)
if err != nil {
return 0, err
}
if _, err = c.copyDeeply(ctx, srcRepo, childArt, dstRepo); err != nil {
return 0, err
}
}
// copy the parent artifact
if err := c.regCli.Copy(srcRepo.Name, srcArt.Digest,
dstRepo.Name, srcArt.Digest, false); err != nil {
return 0, err
}
_, id, err := c.Ensure(ctx, dstRepo.RepositoryID, srcArt.Digest, tags...)
// ensure the parent artifact exist in the database
_, id, err := c.Ensure(ctx, dstRepo, digest, tags...)
if err != nil {
return 0, err
}
@ -468,7 +459,11 @@ func (c *controller) ListTags(ctx context.Context, query *q.Query, option *TagOp
}
var tags []*Tag
for _, tg := range tgs {
tags = append(tags, c.assembleTag(ctx, tg, option))
art, err := c.artMgr.Get(ctx, tg.ArtifactID)
if err != nil {
return nil, err
}
tags = append(tags, c.assembleTag(ctx, art, tg, option))
}
return tags, nil
}
@ -517,19 +512,9 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
artifact := &Artifact{
Artifact: *art,
}
if artifact.RepositoryName == "" {
repo, err := c.repoMgr.Get(ctx, artifact.RepositoryID)
if err != nil {
log.Errorf("get repository %d failed, error: %v", artifact.RepositoryID, err)
return artifact
}
artifact.RepositoryName = repo.Name
}
// populate addition links
c.populateAdditionLinks(ctx, artifact)
if option == nil {
return artifact
}
@ -539,39 +524,9 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
if option.WithLabel {
c.populateLabels(ctx, artifact)
}
// populate addition links
c.populateAdditionLinks(ctx, artifact)
return artifact
}
func (c *controller) populateRepositoryName(ctx context.Context, artifacts ...*artifact.Artifact) error {
var ids []int64
for _, artifact := range artifacts {
ids = append(ids, artifact.RepositoryID)
}
repositories, err := c.repoMgr.List(ctx, &q.Query{Keywords: map[string]interface{}{"repository_id__in": ids}})
if err != nil {
return err
}
mp := make(map[int64]string, len(repositories))
for _, repository := range repositories {
mp[repository.RepositoryID] = repository.Name
}
for _, artifact := range artifacts {
repositoryName, ok := mp[artifact.RepositoryID]
if !ok {
return ierror.NotFoundError(nil).WithMessage("repository %d not found", artifact.RepositoryID)
}
artifact.RepositoryName = repositoryName
}
return nil
}
func (c *controller) populateTags(ctx context.Context, art *Artifact, option *TagOption) {
tags, err := c.tagMgr.List(ctx, &q.Query{
Keywords: map[string]interface{}{
@ -583,46 +538,51 @@ func (c *controller) populateTags(ctx context.Context, art *Artifact, option *Ta
return
}
for _, tag := range tags {
art.Tags = append(art.Tags, c.assembleTag(ctx, tag, option))
art.Tags = append(art.Tags, c.assembleTag(ctx, &art.Artifact, tag, option))
}
}
// assemble several part into a single tag
func (c *controller) assembleTag(ctx context.Context, tag *tm.Tag, option *TagOption) *Tag {
func (c *controller) assembleTag(ctx context.Context, art *artifact.Artifact, tag *tm.Tag, option *TagOption) *Tag {
t := &Tag{
Tag: *tag,
}
if option == nil {
return t
}
repo, err := c.repoMgr.Get(ctx, tag.RepositoryID)
if err != nil {
log.Errorf("Failed to get repo for tag: %s, error: %v", tag.Name, err)
return t
}
if option.WithImmutableStatus {
c.populateImmutableStatus(ctx, t)
c.populateImmutableStatus(ctx, art, t)
}
if option.WithSignature {
if a, err := c.artMgr.Get(ctx, t.ArtifactID); err != nil {
log.Errorf("Failed to get artifact for tag: %s, error: %v, skip populating signature", t.Name, err)
} else {
c.populateTagSignature(ctx, repo.Name, t, a.Digest, option)
}
c.populateTagSignature(ctx, art, t, option)
}
return t
}
func (c *controller) populateTagSignature(ctx context.Context, repo string, tag *Tag, digest string, option *TagOption) {
func (c *controller) populateImmutableStatus(ctx context.Context, artifact *artifact.Artifact, tag *Tag) {
_, repoName := utils.ParseRepository(artifact.RepositoryName)
matched, err := c.immutableMtr.Match(artifact.ProjectID, art.Candidate{
Repository: repoName,
Tags: []string{tag.Name},
NamespaceID: artifact.ProjectID,
})
if err != nil {
log.Error(err)
return
}
tag.Immutable = matched
}
func (c *controller) populateTagSignature(ctx context.Context, artifact *artifact.Artifact, tag *Tag, option *TagOption) {
if option.SignatureChecker == nil {
chk, err := signature.GetManager().GetCheckerByRepo(ctx, repo)
chk, err := signature.GetManager().GetCheckerByRepo(ctx, artifact.RepositoryName)
if err != nil {
log.Error(err)
return
}
option.SignatureChecker = chk
}
tag.Signed = option.SignatureChecker.IsTagSigned(tag.Name, digest)
tag.Signed = option.SignatureChecker.IsTagSigned(tag.Name, artifact.Digest)
}
func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
@ -634,25 +594,6 @@ func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
art.Labels = labels
}
func (c *controller) populateImmutableStatus(ctx context.Context, tag *Tag) {
repo, err := c.repoMgr.Get(ctx, tag.RepositoryID)
if err != nil {
log.Error(err)
return
}
_, repoName := utils.ParseRepository(repo.Name)
matched, err := c.immutableMtr.Match(repo.ProjectID, art.Candidate{
Repository: repoName,
Tags: []string{tag.Name},
NamespaceID: repo.ProjectID,
})
if err != nil {
log.Error(err)
return
}
tag.Immutable = matched
}
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
types := descriptor.ListAdditionTypes(artifact.MediaType)
if len(types) > 0 {

View File

@ -39,6 +39,8 @@ import (
"github.com/stretchr/testify/suite"
)
// TODO find another way to test artifact controller, it's hard to maintain currently
type fakeAbstractor struct {
mock.Mock
}
@ -107,6 +109,13 @@ func (c *controllerTestSuite) SetupTest() {
}
func (c *controllerTestSuite) TestAssembleTag() {
art := &artifact.Artifact{
ID: 1,
ProjectID: 1,
RepositoryID: 1,
RepositoryName: "library/hello-world",
Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180",
}
tg := &tag.Tag{
ID: 1,
RepositoryID: 1,
@ -119,13 +128,8 @@ func (c *controllerTestSuite) TestAssembleTag() {
WithImmutableStatus: true,
}
c.repoMgr.On("Get").Return(&models.RepoRecord{
ProjectID: 1,
Name: "hello-world",
}, nil)
c.immutableMtr.On("Match").Return(true, nil)
tag := c.ctl.assembleTag(nil, tg, option)
tag := c.ctl.assembleTag(nil, art, tg, option)
c.Require().NotNil(tag)
c.Equal(tag.ID, tg.ID)
c.Equal(true, tag.Immutable)
@ -154,9 +158,6 @@ func (c *controllerTestSuite) TestAssembleArtifact() {
PullTime: time.Now(),
}
c.tagMgr.On("List").Return([]*tag.Tag{tg}, nil)
c.repoMgr.On("Get").Return(&models.RepoRecord{
Name: "library/hello-world",
}, nil)
ctx := internal.SetAPIVersion(nil, "2.0")
lb := &models.Label{
ID: 1,
@ -185,25 +186,25 @@ func (c *controllerTestSuite) TestEnsureArtifact() {
c.artMgr.On("GetByDigest").Return(&artifact.Artifact{
ID: 1,
}, nil)
created, id, err := c.ctl.ensureArtifact(nil, 1, digest)
created, art, err := c.ctl.ensureArtifact(nil, "library/hello-world", digest)
c.Require().Nil(err)
c.False(created)
c.Equal(int64(1), id)
c.Equal(int64(1), art.ID)
// reset the mock
c.SetupTest()
// the artifact doesn't exist
c.repoMgr.On("Get").Return(&models.RepoRecord{
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
ProjectID: 1,
}, nil)
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
c.artMgr.On("Create").Return(1, nil)
c.abstractor.On("AbstractMetadata").Return(nil)
created, id, err = c.ctl.ensureArtifact(nil, 1, digest)
created, art, err = c.ctl.ensureArtifact(nil, "library/hello-world", digest)
c.Require().Nil(err)
c.True(created)
c.Equal(int64(1), id)
c.Equal(int64(1), art.ID)
}
func (c *controllerTestSuite) TestEnsureTag() {
@ -252,7 +253,7 @@ func (c *controllerTestSuite) TestEnsure() {
digest := "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180"
// both the artifact and the tag don't exist
c.repoMgr.On("Get").Return(&models.RepoRecord{
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
ProjectID: 1,
}, nil)
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
@ -260,7 +261,7 @@ func (c *controllerTestSuite) TestEnsure() {
c.tagMgr.On("List").Return([]*tag.Tag{}, nil)
c.tagMgr.On("Create").Return(1, nil)
c.abstractor.On("AbstractMetadata").Return(nil)
_, id, err := c.ctl.Ensure(nil, 1, digest, "latest")
_, id, err := c.ctl.Ensure(nil, "library/hello-world", digest, "latest")
c.Require().Nil(err)
c.repoMgr.AssertExpectations(c.T())
c.artMgr.AssertExpectations(c.T())
@ -508,7 +509,12 @@ func (c *controllerTestSuite) TestDeleteDeeply() {
func (c *controllerTestSuite) TestCopy() {
c.artMgr.On("Get").Return(&artifact.Artifact{
ID: 1,
ID: 1,
Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180",
}, nil)
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
RepositoryID: 1,
Name: "library/hello-world",
}, nil)
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
c.tagMgr.On("List").Return([]*tag.Tag{
@ -525,7 +531,7 @@ func (c *controllerTestSuite) TestCopy() {
c.abstractor.On("AbstractMetadata").Return(nil)
c.artMgr.On("Create").Return(1, nil)
c.regCli.On("Copy").Return(nil)
_, err := c.ctl.Copy(nil, 1, 1)
_, err := c.ctl.Copy(nil, "library/hello-world", "latest", "library/hello-world2")
c.Require().Nil(err)
}
@ -538,6 +544,7 @@ func (c *controllerTestSuite) TestListTags() {
ArtifactID: 1,
},
}, nil)
c.artMgr.On("Get").Return(&artifact.Artifact{}, nil)
tags, err := c.ctl.ListTags(nil, nil, nil)
c.Require().Nil(err)
c.Len(tags, 1)

View File

@ -32,8 +32,8 @@ type DAO interface {
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
// Get the artifact specified by ID
Get(ctx context.Context, id int64) (*Artifact, error)
// GetByDigest returns the artifact specified by repository ID and digest
GetByDigest(ctx context.Context, repositoryID int64, digest string) (artifact *Artifact, err error)
// GetByDigest returns the artifact specified by repository and digest
GetByDigest(ctx context.Context, repository, digest string) (artifact *Artifact, err error)
// Create the artifact
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
// Delete the artifact specified by ID
@ -118,11 +118,11 @@ func (d *dao) Get(ctx context.Context, id int64) (*Artifact, error) {
return artifact, nil
}
func (d *dao) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*Artifact, error) {
func (d *dao) GetByDigest(ctx context.Context, repository, digest string) (*Artifact, error) {
qs, err := orm.QuerySetter(ctx, &Artifact{}, &q.Query{
Keywords: map[string]interface{}{
"RepositoryID": repositoryID,
"Digest": digest,
"RepositoryName": repository,
"Digest": digest,
},
})
if err != nil {
@ -134,7 +134,7 @@ func (d *dao) GetByDigest(ctx context.Context, repositoryID int64, digest string
}
if len(artifacts) == 0 {
return nil, ierror.New(nil).WithCode(ierror.NotFoundCode).
WithMessage("artifact %s under the repository %d not found", digest, repositoryID)
WithMessage("artifact %s@%s not found", repository, digest)
}
return artifacts[0], nil
}

View File

@ -57,6 +57,7 @@ func (d *daoTestSuite) SetupTest() {
ManifestMediaType: v1.MediaTypeImageIndex,
ProjectID: 1,
RepositoryID: 1,
RepositoryName: "library/hello-world",
Digest: "parent_digest",
PushTime: now,
PullTime: now,
@ -72,6 +73,7 @@ func (d *daoTestSuite) SetupTest() {
ManifestMediaType: v1.MediaTypeImageManifest,
ProjectID: 1,
RepositoryID: 1,
RepositoryName: "library/hello-world",
Digest: "child_digest_01",
Size: 1024,
PushTime: now,
@ -88,6 +90,7 @@ func (d *daoTestSuite) SetupTest() {
ManifestMediaType: v1.MediaTypeImageManifest,
ProjectID: 1,
RepositoryID: 1,
RepositoryName: "library/hello-world",
Digest: "child_digest_02",
Size: 1024,
PushTime: now,
@ -324,12 +327,12 @@ func (d *daoTestSuite) TestGet() {
func (d *daoTestSuite) TestGetByDigest() {
// get the non-exist artifact
_, err := d.dao.GetByDigest(d.ctx, 1, "non_existing_digest")
_, err := d.dao.GetByDigest(d.ctx, "library/hello-world", "non_existing_digest")
d.Require().NotNil(err)
d.True(ierror.IsErr(err, ierror.NotFoundCode))
// get the exist artifact
artifact, err := d.dao.GetByDigest(d.ctx, 1, "child_digest_02")
artifact, err := d.dao.GetByDigest(d.ctx, "library/hello-world", "child_digest_02")
d.Require().Nil(err)
d.Require().NotNil(artifact)
d.Equal(d.childArt02ID, artifact.ID)

View File

@ -33,6 +33,7 @@ type Artifact struct {
ManifestMediaType string `orm:"column(manifest_media_type)"` // the media type of manifest/index
ProjectID int64 `orm:"column(project_id)"` // needed for quota
RepositoryID int64 `orm:"column(repository_id)"`
RepositoryName string `orm:"column(repository_name)"`
Digest string `orm:"column(digest)"`
Size int64 `orm:"column(size)"`
PushTime time.Time `orm:"column(push_time)"`

View File

@ -37,8 +37,8 @@ type Manager interface {
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
// Get the artifact specified by the ID
Get(ctx context.Context, id int64) (artifact *Artifact, err error)
// GetByDigest returns the artifact specified by repository ID and digest
GetByDigest(ctx context.Context, repositoryID int64, digest string) (artifact *Artifact, err error)
// GetByDigest returns the artifact specified by repository and digest
GetByDigest(ctx context.Context, repository, digest string) (artifact *Artifact, err error)
// Create the artifact. If the artifact is an index, make sure all the artifacts it references
// already exist
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
@ -94,8 +94,8 @@ func (m *manager) Get(ctx context.Context, id int64) (*Artifact, error) {
return m.assemble(ctx, art)
}
func (m *manager) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*Artifact, error) {
art, err := m.dao.GetByDigest(ctx, repositoryID, digest)
func (m *manager) GetByDigest(ctx context.Context, repository, digest string) (*Artifact, error) {
art, err := m.dao.GetByDigest(ctx, repository, digest)
if err != nil {
return nil, err
}

View File

@ -40,7 +40,7 @@ func (f *fakeDao) Get(ctx context.Context, id int64) (*dao.Artifact, error) {
args := f.Called()
return args.Get(0).(*dao.Artifact), args.Error(1)
}
func (f *fakeDao) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*dao.Artifact, error) {
func (f *fakeDao) GetByDigest(ctx context.Context, repository, digest string) (*dao.Artifact, error) {
args := f.Called()
return args.Get(0).(*dao.Artifact), args.Error(1)
}
@ -195,7 +195,7 @@ func (m *managerTestSuite) TestGetByDigest() {
}
m.dao.On("GetByDigest", mock.Anything).Return(art, nil)
m.dao.On("ListReferences").Return([]*dao.ArtifactReference{}, nil)
artifact, err := m.mgr.GetByDigest(nil, 1, "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180")
artifact, err := m.mgr.GetByDigest(nil, "library/hello-world", "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180")
m.Require().Nil(err)
m.Require().NotNil(artifact)
m.Equal(art.ID, artifact.ID)

View File

@ -33,6 +33,7 @@ type Artifact struct {
ManifestMediaType string `json:"manifest_media_type"` // the media type of manifest/index
ProjectID int64 `json:"project_id"`
RepositoryID int64 `json:"repository_id"`
RepositoryName string `json:"repository_name"`
Digest string `json:"digest"`
Size int64 `json:"size"`
PushTime time.Time `json:"push_time"`
@ -40,8 +41,6 @@ type Artifact struct {
ExtraAttrs map[string]interface{} `json:"extra_attrs"` // only contains the simple attributes specific for the different artifact type, most of them should come from the config layer
Annotations map[string]string `json:"annotations"`
References []*Reference `json:"references"` // child artifacts referenced by the parent artifact if the artifact is an index
RepositoryName string `json:"-"` // repository name, eg: library/photon
}
// From converts the database level artifact to the business level object
@ -52,6 +51,7 @@ func (a *Artifact) From(art *dao.Artifact) {
a.ManifestMediaType = art.ManifestMediaType
a.ProjectID = art.ProjectID
a.RepositoryID = art.RepositoryID
a.RepositoryName = art.RepositoryName
a.Digest = art.Digest
a.Size = art.Size
a.PushTime = art.PushTime
@ -79,6 +79,7 @@ func (a *Artifact) To() *dao.Artifact {
ManifestMediaType: a.ManifestMediaType,
ProjectID: a.ProjectID,
RepositoryID: a.RepositoryID,
RepositoryName: a.RepositoryName,
Digest: a.Digest,
Size: a.Size,
PushTime: a.PushTime,

View File

@ -173,7 +173,7 @@ func (suite *DaoTestSuite) TestFindBlobsShouldUnassociatedWithProject() {
artifact1 := suite.DigestString()
artifact2 := suite.DigestString()
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?)`
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id, repository_name) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?, 'library/hello-world')`
suite.ExecSQL(sql, artifact1, projectID, 10)
suite.ExecSQL(sql, artifact2, projectID, 10)

View File

@ -92,7 +92,7 @@ func (suite *ManagerTestSuite) TestCleanupAssociationsForProject() {
artifact1 := suite.DigestString()
artifact2 := suite.DigestString()
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?)`
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id, repository_name) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?, 'library/hello-world')`
suite.ExecSQL(sql, artifact1, projectID, 10)
suite.ExecSQL(sql, artifact2, projectID, 10)

View File

@ -110,15 +110,16 @@ func (suite *HandlerSuite) addProject(projectName string) int64 {
return projectID
}
func (suite *HandlerSuite) addArt(ctx context.Context, pid, repositoryID int64, dgt string) int64 {
func (suite *HandlerSuite) addArt(ctx context.Context, pid, repositoryID int64, repositoryName, dgt string) int64 {
af := &artifact.Artifact{
Type: "Docker-Image",
ProjectID: pid,
RepositoryID: repositoryID,
Digest: dgt,
Size: 1024,
PushTime: time.Now(),
PullTime: time.Now(),
Type: "Docker-Image",
ProjectID: pid,
RepositoryID: repositoryID,
RepositoryName: repositoryName,
Digest: dgt,
Size: 1024,
PushTime: time.Now(),
PullTime: time.Now(),
}
afid, err := artifact.Mgr.Create(ctx, af)
suite.Nil(err, fmt.Sprintf("Add artifact failed for %d", repositoryID))
@ -185,7 +186,7 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() {
projectID := suite.addProject(projectName)
immuRuleID := suite.addImmutableRule(projectID)
repoID := suite.addRepo(ctx, projectID, repoName)
afID := suite.addArt(ctx, projectID, repoID, dgt)
afID := suite.addArt(ctx, projectID, repoID, repoName, dgt)
tagID := suite.addTags(ctx, repoID, afID, "release-1.10")
defer func() {

View File

@ -70,7 +70,7 @@ func putManifest(w http.ResponseWriter, req *http.Request) {
reference := router.Param(req.Context(), ":reference")
// make sure the repository exist before pushing the manifest
_, repositoryID, err := repository.Ctl.Ensure(req.Context(), repo)
_, _, err := repository.Ctl.Ensure(req.Context(), repo)
if err != nil {
serror.SendError(w, err)
return
@ -98,7 +98,7 @@ func putManifest(w http.ResponseWriter, req *http.Request) {
tags = append(tags, reference)
}
_, _, err = artifact.Ctl.Ensure(req.Context(), repositoryID, dgt, tags...)
_, _, err = artifact.Ctl.Ensure(req.Context(), repo, dgt, tags...)
if err != nil {
serror.SendError(w, err)
return

View File

@ -81,11 +81,7 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr
if params.PageSize != nil {
query.PageSize = *(params.PageSize)
}
repository, err := a.repoCtl.GetByName(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName))
if err != nil {
return a.SendError(ctx, err)
}
query.Keywords["RepositoryID"] = repository.RepositoryID
query.Keywords["RepositoryName"] = fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName)
// set option
option := option(params.WithTag, params.WithImmutableStatus,
@ -155,23 +151,24 @@ func (a *artifactAPI) CopyArtifact(ctx context.Context, params operation.CopyArt
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionCreate, rbac.ResourceArtifact); err != nil {
return a.SendError(ctx, err)
}
srcRepo, srcRef, err := parse(params.From)
srcRepo, ref, err := parse(params.From)
if err != nil {
return a.SendError(ctx, err)
}
srcPro, _ := utils.ParseRepository(srcRepo)
if err = a.RequireProjectAccess(ctx, srcPro, rbac.ActionRead, rbac.ResourceArtifact); err != nil {
return a.SendError(ctx, err)
}
srcArt, err := a.artCtl.GetByReference(ctx, srcRepo, srcRef, &artifact.Option{WithTag: true})
dstRepo := fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName)
_, id, err := a.repoCtl.Ensure(ctx, dstRepo)
if err != nil {
return a.SendError(ctx, err)
}
_, id, err := a.repoCtl.Ensure(ctx, params.ProjectName+"/"+params.RepositoryName)
if err != nil {
return a.SendError(ctx, err)
}
id, err = a.artCtl.Copy(ctx, srcArt.ID, id)
id, err = a.artCtl.Copy(ctx, srcRepo, ref, dstRepo)
if err != nil {
return a.SendError(ctx, err)
}

View File

@ -29,7 +29,7 @@ type FakeController struct {
}
// Ensure ...
func (f *FakeController) Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (bool, int64, error) {
func (f *FakeController) Ensure(ctx context.Context, repository, digest string, tags ...string) (bool, int64, error) {
args := f.Called()
return args.Bool(0), int64(args.Int(1)), args.Error(2)
}
@ -77,7 +77,7 @@ func (f *FakeController) Delete(ctx context.Context, id int64) (err error) {
}
// Copy ...
func (f *FakeController) Copy(ctx context.Context, srcArtID, dstRepoID int64) (int64, error) {
func (f *FakeController) Copy(ctx context.Context, srcRepo, ref, dstRepo string) (int64, error) {
args := f.Called()
return int64(args.Int(0)), args.Error(1)
}

View File

@ -54,7 +54,7 @@ func (f *FakeManager) Get(ctx context.Context, id int64) (*artifact.Artifact, er
}
// GetByDigest ...
func (f *FakeManager) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*artifact.Artifact, error) {
func (f *FakeManager) GetByDigest(ctx context.Context, repository, digest string) (*artifact.Artifact, error) {
args := f.Called()
var art *artifact.Artifact
if args.Get(0) != nil {