move out the tags methods of artifact ctl

1, move the tag methods out of artifact ctl, let api to call tag ctr
2, update the ensure sequence for existing tag

Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
wang yan 2020-02-28 15:20:47 +08:00
parent 79cf21f82f
commit 2d4fc0c4da
9 changed files with 36 additions and 132 deletions

View File

@ -73,12 +73,6 @@ type Controller interface {
Delete(ctx context.Context, 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 *tag.Option) (tags []*tag.Tag, err error)
// CreateTag creates a tag
CreateTag(ctx context.Context, tag *tag.Tag) (id int64, err error)
// DeleteTag deletes the tag specified by tagID
DeleteTag(ctx context.Context, tagID int64) (err error)
// UpdatePullTime updates the pull time for the artifact. If the tagID is provides, update the pull
// time of the tag as well
UpdatePullTime(ctx context.Context, artifactID int64, tagID int64, time time.Time) (err error)
@ -300,7 +294,11 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot bool) er
// delete all tags that attached to the root artifact
if isRoot {
if err = c.tagCtl.DeleteTags(ctx, art.Tags); err != nil {
var ids []int64
for _, tag := range art.Tags {
ids = append(ids, tag.ID)
}
if err = c.tagCtl.DeleteTags(ctx, ids); err != nil {
return err
}
}
@ -407,23 +405,6 @@ func (c *controller) copyDeeply(ctx context.Context, srcRepo, reference, dstRepo
return id, nil
}
func (c *controller) CreateTag(ctx context.Context, tag *tag.Tag) (int64, error) {
// TODO fire event
return c.tagCtl.Create(ctx, tag)
}
func (c *controller) ListTags(ctx context.Context, query *q.Query, option *tag.Option) ([]*tag.Tag, error) {
tags, err := c.tagCtl.List(ctx, query, option)
if err != nil {
return nil, err
}
return tags, nil
}
func (c *controller) DeleteTag(ctx context.Context, tagID int64) error {
// TODO fire delete tag event
return c.tagCtl.Delete(ctx, tagID)
}
func (c *controller) UpdatePullTime(ctx context.Context, artifactID int64, tagID int64, time time.Time) error {
tag, err := c.tagCtl.Get(ctx, tagID, nil)
if err != nil {

View File

@ -478,40 +478,6 @@ func (c *controllerTestSuite) TestCopy() {
c.Require().Nil(err)
}
func (c *controllerTestSuite) TestListTags() {
c.tagCtl.On("List").Return([]*tag.Tag{
{
Tag: model_tag.Tag{
ID: 1,
RepositoryID: 1,
Name: "latest",
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)
c.tagCtl.AssertExpectations(c.T())
c.Equal(tags[0].Immutable, false)
// TODO check other properties: label, etc
}
func (c *controllerTestSuite) TestCreateTag() {
c.tagCtl.On("Create").Return(1, nil)
id, err := c.ctl.CreateTag(nil, &tag.Tag{})
c.Require().Nil(err)
c.Equal(int64(1), id)
}
func (c *controllerTestSuite) TestDeleteTag() {
c.tagCtl.On("Delete").Return(nil)
err := c.ctl.DeleteTag(nil, 1)
c.Require().Nil(err)
c.tagCtl.AssertExpectations(c.T())
}
func (c *controllerTestSuite) TestUpdatePullTime() {
// artifact ID and tag ID matches
c.tagCtl.On("Get").Return(&tag.Tag{

View File

@ -38,7 +38,7 @@ type Controller interface {
// Delete the tag specified by ID with limitation check
Delete(ctx context.Context, id int64) (err error)
// DeleteTags deletes all tags
DeleteTags(ctx context.Context, tags []*Tag) (err error)
DeleteTags(ctx context.Context, ids []int64) (err error)
}
// NewController creates an instance of the default repository controller
@ -66,7 +66,6 @@ func (c *controller) Ensure(ctx context.Context, repositoryID, artifactID int64,
}
tags, err := c.List(ctx, query, &Option{
WithImmutableStatus: true,
WithSignature: true,
})
if err != nil {
return err
@ -74,19 +73,15 @@ func (c *controller) Ensure(ctx context.Context, repositoryID, artifactID int64,
// the tag already exists under the repository
if len(tags) > 0 {
tag := tags[0]
// the tag already exists under the repository and is attached to the artifact, return directly
if tag.ArtifactID == artifactID {
return nil
}
// existing tag must check the immutable status and signature
if tag.Immutable {
return ierror.New(nil).WithCode(ierror.PreconditionCode).
WithMessage("the tag %s configured as immutable, cannot be updated", tag.Name)
}
if tag.Signed {
return ierror.New(nil).WithCode(ierror.PreconditionCode).
WithMessage("the tag %s with signature cannot be updated", tag.Name)
}
// the tag already exists under the repository and is attached to the artifact, return directly
if tag.ArtifactID == artifactID {
return nil
}
// the tag exists under the repository, but it is attached to other artifact
// update it to point to the provided artifact
tag.ArtifactID = artifactID
@ -138,15 +133,7 @@ func (c *controller) Get(ctx context.Context, id int64, option *Option) (tag *Ta
return tag, nil
}
if option.WithImmutableStatus {
c.populateImmutableStatus(ctx, tag)
}
if option.WithSignature {
c.populateTagSignature(ctx, tag, option)
}
return tag, nil
return c.assembleTag(ctx, &tag.Tag, option), nil
}
// Create ...
@ -181,10 +168,10 @@ func (c *controller) Delete(ctx context.Context, id int64) (err error) {
}
// DeleteTags ...
func (c *controller) DeleteTags(ctx context.Context, tags []*Tag) (err error) {
func (c *controller) DeleteTags(ctx context.Context, ids []int64) (err error) {
// in order to leverage the signature and immutable status check
for _, tag := range tags {
if err := c.Delete(ctx, tag.ID); err != nil {
for _, id := range ids {
if err := c.Delete(ctx, id); err != nil {
return err
}
}

View File

@ -179,16 +179,8 @@ func (c *controllerTestSuite) TestDeleteTags() {
}, nil)
c.immutableMtr.On("Match").Return(false, nil)
c.tagMgr.On("Delete").Return(nil)
tags := []*Tag{
{
Tag: tag.Tag{
RepositoryID: 10,
Name: "test2",
},
Signed: true,
},
}
err := c.ctl.DeleteTags(nil, tags)
ids := []int64{1, 2, 3, 4}
err := c.ctl.DeleteTags(nil, ids)
c.Require().Nil(err)
}

View File

@ -17,8 +17,8 @@ package registry
import (
"encoding/json"
"fmt"
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/api/repository"
"github.com/goharbor/harbor/src/api/tag"
ierror "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/q"
serror "github.com/goharbor/harbor/src/server/error"
@ -32,13 +32,13 @@ import (
func newTagHandler() http.Handler {
return &tagHandler{
repoCtl: repository.Ctl,
artCtl: artifact.Ctl,
tagCtl: tag.Ctl,
}
}
type tagHandler struct {
repoCtl repository.Controller
artCtl artifact.Controller
tagCtl tag.Controller
repositoryName string
}
@ -80,7 +80,7 @@ func (t *tagHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
// get tags ...
tags, err := t.artCtl.ListTags(req.Context(), &q.Query{
tags, err := t.tagCtl.List(req.Context(), &q.Query{
Keywords: map[string]interface{}{
"RepositoryID": repository.RepositoryID,
}}, nil)

View File

@ -16,13 +16,12 @@ package registry
import (
"encoding/json"
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/api/repository"
"github.com/goharbor/harbor/src/api/tag"
"github.com/goharbor/harbor/src/common/models"
model_tag "github.com/goharbor/harbor/src/pkg/tag/model/tag"
arttesting "github.com/goharbor/harbor/src/testing/api/artifact"
repotesting "github.com/goharbor/harbor/src/testing/api/repository"
tagtesting "github.com/goharbor/harbor/src/testing/api/tag"
"github.com/stretchr/testify/suite"
"net/http"
"net/http/httptest"
@ -33,20 +32,20 @@ type tagTestSuite struct {
suite.Suite
originalRepoCtl repository.Controller
repoCtl *repotesting.FakeController
originalArtCtl artifact.Controller
artCtl *arttesting.FakeController
originalTagCtl tag.Controller
tagCtl *tagtesting.FakeController
}
func (c *tagTestSuite) SetupSuite() {
c.originalArtCtl = artifact.Ctl
c.originalRepoCtl = repository.Ctl
c.originalTagCtl = tag.Ctl
}
func (c *tagTestSuite) SetupTest() {
c.artCtl = &arttesting.FakeController{}
artifact.Ctl = c.artCtl
c.repoCtl = &repotesting.FakeController{}
repository.Ctl = c.repoCtl
c.tagCtl = &tagtesting.FakeController{}
tag.Ctl = c.tagCtl
}
func (c *tagTestSuite) TearDownTest() {
@ -54,7 +53,7 @@ func (c *tagTestSuite) TearDownTest() {
func (c *tagTestSuite) TearDownSuite() {
repository.Ctl = c.originalRepoCtl
artifact.Ctl = c.originalArtCtl
tag.Ctl = c.originalTagCtl
}
func (c *tagTestSuite) TestListTag() {
@ -65,7 +64,7 @@ func (c *tagTestSuite) TestListTag() {
RepositoryID: 1,
Name: "library/hello-world",
}, nil)
c.artCtl.On("ListTags").Return([]*tag.Tag{
c.tagCtl.On("List").Return([]*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
@ -100,7 +99,7 @@ func (c *tagTestSuite) TestListTagPagination1() {
RepositoryID: 1,
Name: "hello-world",
}, nil)
c.artCtl.On("ListTags").Return([]*tag.Tag{
c.tagCtl.On("List").Return([]*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
@ -136,7 +135,7 @@ func (c *tagTestSuite) TestListTagPagination2() {
RepositoryID: 1,
Name: "hello-world",
}, nil)
c.artCtl.On("ListTags").Return([]*tag.Tag{
c.tagCtl.On("List").Return([]*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
@ -172,7 +171,7 @@ func (c *tagTestSuite) TestListTagPagination3() {
RepositoryID: 1,
Name: "hello-world",
}, nil)
c.artCtl.On("ListTags").Return([]*tag.Tag{
c.tagCtl.On("List").Return([]*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,

View File

@ -51,6 +51,7 @@ func newArtifactAPI() *artifactAPI {
proMgr: project.Mgr,
repoCtl: repository.Ctl,
scanCtl: scan.DefaultController,
tagCtl: tag.Ctl,
}
}
@ -60,6 +61,7 @@ type artifactAPI struct {
proMgr project.Manager
repoCtl repository.Controller
scanCtl scan.Controller
tagCtl tag.Controller
}
func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListArtifactsParams) middleware.Responder {
@ -238,7 +240,7 @@ func (a *artifactAPI) CreateTag(ctx context.Context, params operation.CreateTagP
tag.ArtifactID = art.ID
tag.Name = params.Tag.Name
tag.PushTime = time.Now()
if _, err = a.artCtl.CreateTag(ctx, tag); err != nil {
if _, err = a.tagCtl.Create(ctx, tag); err != nil {
return a.SendError(ctx, err)
}
// TODO set location header?
@ -269,7 +271,7 @@ func (a *artifactAPI) DeleteTag(ctx context.Context, params operation.DeleteTagP
"tag %s attached to artifact %d not found", params.TagName, artifact.ID)
return a.SendError(ctx, err)
}
if err = a.artCtl.DeleteTag(ctx, id); err != nil {
if err = a.tagCtl.Delete(ctx, id); err != nil {
return a.SendError(ctx, err)
}
return operation.NewDeleteTagOK()

View File

@ -18,7 +18,6 @@ import (
"context"
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
"github.com/goharbor/harbor/src/api/tag"
"github.com/goharbor/harbor/src/pkg/q"
"github.com/stretchr/testify/mock"
"time"
@ -83,28 +82,6 @@ func (f *FakeController) Copy(ctx context.Context, srcRepo, ref, dstRepo string)
return int64(args.Int(0)), args.Error(1)
}
// ListTags ...
func (f *FakeController) ListTags(ctx context.Context, query *q.Query, option *tag.Option) ([]*tag.Tag, error) {
args := f.Called()
var tags []*tag.Tag
if args.Get(0) != nil {
tags = args.Get(0).([]*tag.Tag)
}
return tags, args.Error(1)
}
// CreateTag ...
func (f *FakeController) CreateTag(ctx context.Context, tag *tag.Tag) (int64, error) {
args := f.Called()
return int64(args.Int(0)), args.Error(1)
}
// DeleteTag ...
func (f *FakeController) DeleteTag(ctx context.Context, tagID int64) (err error) {
args := f.Called()
return args.Error(0)
}
// UpdatePullTime ...
func (f *FakeController) UpdatePullTime(ctx context.Context, artifactID int64, tagID int64, time time.Time) error {
args := f.Called()

View File

@ -63,7 +63,7 @@ func (f *FakeController) Delete(ctx context.Context, id int64) (err error) {
}
// DeleteTags ...
func (f *FakeController) DeleteTags(ctx context.Context, tags []*tag.Tag) (err error) {
func (f *FakeController) DeleteTags(ctx context.Context, ids []int64) (err error) {
args := f.Called()
return args.Error(0)
}