mirror of
https://github.com/goharbor/harbor
synced 2025-04-16 19:32:44 +00:00
refactor immutable rule (#14371)
Migrate immutable realted APIs to v2 swagger Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
parent
f0dd9e5aeb
commit
85254ccc22
|
@ -2069,126 +2069,6 @@ paths:
|
|||
description: User have no permission to list webhook jobs of the project.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
'/projects/{project_id}/immutabletagrules':
|
||||
get:
|
||||
summary: List all immutable tag rules of current project
|
||||
description: |
|
||||
This endpoint returns the immutable tag rules of a project
|
||||
parameters:
|
||||
- name: project_id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Relevant project ID.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: List project immutable tag rules successfully.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
'400':
|
||||
description: Illegal format of provided ID value.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User have no permission to list immutable tag rules of the project.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
post:
|
||||
summary: Add an immutable tag rule to current project
|
||||
description: |
|
||||
This endpoint add an immutable tag rule to the project
|
||||
parameters:
|
||||
- name: project_id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Relevant project ID.
|
||||
- name: ImmutableRule
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Add the immutable tag rule successfully.
|
||||
'400':
|
||||
description: Illegal format of provided ID value.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User have no permission to get immutable tag rule of the project.
|
||||
'500':
|
||||
description: Internal server errors.
|
||||
'/projects/{project_id}/immutabletagrules/{id}':
|
||||
put:
|
||||
summary: Update the immutable tag rule or enable or disable the rule
|
||||
parameters:
|
||||
- name: project_id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Relevant project ID.
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Immutable tag rule ID.
|
||||
- name: ImmutableRule
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Update the immutable tag rule successfully.
|
||||
'400':
|
||||
description: Illegal format of provided ID value.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User have no permission to update the immutable tag rule of the project.
|
||||
'500':
|
||||
description: Internal server errors.
|
||||
delete:
|
||||
summary: Delete the immutable tag rule.
|
||||
parameters:
|
||||
- name: project_id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Relevant project ID.
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: Immutable tag rule ID.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Delete the immutable tag rule successfully.
|
||||
'400':
|
||||
description: Illegal format of provided ID value.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User have no permission to delete immutable tags of the project.
|
||||
'500':
|
||||
description: Internal server errors.
|
||||
responses:
|
||||
OK:
|
||||
description: 'Success'
|
||||
|
@ -3422,45 +3302,6 @@ definitions:
|
|||
type: string
|
||||
description: Webhook supportted notify type.
|
||||
example: 'http'
|
||||
ImmutableRule:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
priority:
|
||||
type: integer
|
||||
disabled:
|
||||
type: boolean
|
||||
action:
|
||||
type: string
|
||||
template:
|
||||
type: string
|
||||
params:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
tag_selectors:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableSelector'
|
||||
scope_selectors:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableSelector'
|
||||
|
||||
ImmutableSelector:
|
||||
type: object
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
decoration:
|
||||
type: string
|
||||
pattern:
|
||||
type: string
|
||||
extras:
|
||||
type: string
|
||||
|
||||
parameters:
|
||||
query:
|
||||
|
|
|
@ -1702,6 +1702,120 @@ paths:
|
|||
$ref: '#/responses/404'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
'/projects/{project_name_or_id}/immutabletagrules':
|
||||
get:
|
||||
summary: List all immutable tag rules of current project
|
||||
description: |
|
||||
This endpoint returns the immutable tag rules of a project
|
||||
tags:
|
||||
- immutable
|
||||
operationId: ListImmuRules
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/isResourceName'
|
||||
- $ref: '#/parameters/projectNameOrId'
|
||||
- $ref: '#/parameters/page'
|
||||
- $ref: '#/parameters/pageSize'
|
||||
- $ref: '#/parameters/query'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
headers:
|
||||
X-Total-Count:
|
||||
description: The total count of immutable tag
|
||||
type: integer
|
||||
Link:
|
||||
description: Link refers to the previous page and next page
|
||||
type: string
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
'400':
|
||||
$ref: '#/responses/400'
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
post:
|
||||
summary: Add an immutable tag rule to current project
|
||||
description: |
|
||||
This endpoint add an immutable tag rule to the project
|
||||
tags:
|
||||
- immutable
|
||||
operationId: CreateImmuRule
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/isResourceName'
|
||||
- $ref: '#/parameters/projectNameOrId'
|
||||
- name: ImmutableRule
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
responses:
|
||||
'201':
|
||||
$ref: '#/responses/201'
|
||||
'400':
|
||||
$ref: '#/responses/400'
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
'/projects/{project_name_or_id}/immutabletagrules/{immutable_rule_id}':
|
||||
put:
|
||||
summary: Update the immutable tag rule or enable or disable the rule
|
||||
tags:
|
||||
- immutable
|
||||
operationId: UpdateImmuRule
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/isResourceName'
|
||||
- $ref: '#/parameters/projectNameOrId'
|
||||
- $ref: '#/parameters/immutableRuleId'
|
||||
- name: ImmutableRule
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/ImmutableRule'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/200'
|
||||
'400':
|
||||
$ref: '#/responses/400'
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
delete:
|
||||
summary: Delete the immutable tag rule.
|
||||
tags:
|
||||
- immutable
|
||||
operationId: DeleteImmuRule
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/isResourceName'
|
||||
- $ref: '#/parameters/projectNameOrId'
|
||||
- $ref: '#/parameters/immutableRuleId'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/200'
|
||||
'400':
|
||||
$ref: '#/responses/400'
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/icons/{digest}:
|
||||
get:
|
||||
summary: Get artifact icon
|
||||
|
@ -3251,6 +3365,14 @@ parameters:
|
|||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
immutableRuleId:
|
||||
name: immutable_rule_id
|
||||
in: path
|
||||
description: The ID of the immutable rule
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
|
@ -5046,3 +5168,42 @@ definitions:
|
|||
import:
|
||||
package: "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
alias: v1
|
||||
|
||||
ImmutableRule:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
priority:
|
||||
type: integer
|
||||
disabled:
|
||||
type: boolean
|
||||
action:
|
||||
type: string
|
||||
template:
|
||||
type: string
|
||||
params:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
tag_selectors:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableSelector'
|
||||
scope_selectors:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ImmutableSelector'
|
||||
ImmutableSelector:
|
||||
type: object
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
decoration:
|
||||
type: string
|
||||
pattern:
|
||||
type: string
|
||||
extras:
|
||||
type: string
|
||||
|
|
|
@ -39,8 +39,8 @@ import (
|
|||
"github.com/goharbor/harbor/src/pkg/artifactrash"
|
||||
"github.com/goharbor/harbor/src/pkg/artifactrash/model"
|
||||
"github.com/goharbor/harbor/src/pkg/blob"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/label"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notifier/event"
|
||||
|
|
|
@ -16,6 +16,7 @@ package artifact
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/immutable"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -36,7 +37,6 @@ import (
|
|||
arttesting "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
||||
artrashtesting "github.com/goharbor/harbor/src/testing/pkg/artifactrash"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/blob"
|
||||
immutesting "github.com/goharbor/harbor/src/testing/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/label"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||
repotesting "github.com/goharbor/harbor/src/testing/pkg/repository"
|
||||
|
@ -66,7 +66,7 @@ type controllerTestSuite struct {
|
|||
tagCtl *tagtesting.FakeController
|
||||
labelMgr *label.FakeManager
|
||||
abstractor *fakeAbstractor
|
||||
immutableMtr *immutesting.FakeMatcher
|
||||
immutableMtr *immutable.FakeMatcher
|
||||
regCli *registry.FakeClient
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ func (c *controllerTestSuite) SetupTest() {
|
|||
c.tagCtl = &tagtesting.FakeController{}
|
||||
c.labelMgr = &label.FakeManager{}
|
||||
c.abstractor = &fakeAbstractor{}
|
||||
c.immutableMtr = &immutesting.FakeMatcher{}
|
||||
c.immutableMtr = &immutable.FakeMatcher{}
|
||||
c.regCli = ®istry.FakeClient{}
|
||||
c.ctl = &controller{
|
||||
repoMgr: c.repoMgr,
|
||||
|
|
88
src/controller/immutable/controller.go
Normal file
88
src/controller/immutable/controller.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package immutable
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
)
|
||||
|
||||
var (
|
||||
// Ctr is a global variable for the default immutable controller implementation
|
||||
Ctr = NewAPIController(immutable.NewDefaultRuleManager())
|
||||
)
|
||||
|
||||
// Controller to handle the requests related with immutable
|
||||
type Controller interface {
|
||||
// GetImmutableRule ...
|
||||
GetImmutableRule(ctx context.Context, id int64) (*model.Metadata, error)
|
||||
|
||||
// CreateImmutableRule ...
|
||||
CreateImmutableRule(ctx context.Context, m *model.Metadata) (int64, error)
|
||||
|
||||
// DeleteImmutableRule ...
|
||||
DeleteImmutableRule(ctx context.Context, id int64) error
|
||||
|
||||
// UpdateImmutableRule ...
|
||||
UpdateImmutableRule(ctx context.Context, projectID int64, m *model.Metadata) error
|
||||
|
||||
// ListImmutableRules ...
|
||||
ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.Metadata, error)
|
||||
|
||||
// Count count the immutable rules
|
||||
Count(ctx context.Context, query *q.Query) (int64, error)
|
||||
}
|
||||
|
||||
// DefaultAPIController ...
|
||||
type DefaultAPIController struct {
|
||||
manager immutable.Manager
|
||||
}
|
||||
|
||||
// GetImmutableRule ...
|
||||
func (r *DefaultAPIController) GetImmutableRule(ctx context.Context, id int64) (*model.Metadata, error) {
|
||||
return r.manager.GetImmutableRule(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteImmutableRule ...
|
||||
func (r *DefaultAPIController) DeleteImmutableRule(ctx context.Context, id int64) error {
|
||||
return r.manager.DeleteImmutableRule(ctx, id)
|
||||
}
|
||||
|
||||
// CreateImmutableRule ...
|
||||
func (r *DefaultAPIController) CreateImmutableRule(ctx context.Context, m *model.Metadata) (int64, error) {
|
||||
return r.manager.CreateImmutableRule(ctx, m)
|
||||
}
|
||||
|
||||
// UpdateImmutableRule ...
|
||||
func (r *DefaultAPIController) UpdateImmutableRule(ctx context.Context, projectID int64, m *model.Metadata) error {
|
||||
m0, err := r.manager.GetImmutableRule(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m0 == nil {
|
||||
return fmt.Errorf("the immutable tag rule is not found id:%v", m.ID)
|
||||
}
|
||||
if m0.Disabled != m.Disabled {
|
||||
return r.manager.EnableImmutableRule(ctx, m.ID, m.Disabled)
|
||||
}
|
||||
return r.manager.UpdateImmutableRule(ctx, projectID, m)
|
||||
}
|
||||
|
||||
// ListImmutableRules ...
|
||||
func (r *DefaultAPIController) ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.Metadata, error) {
|
||||
return r.manager.ListImmutableRules(ctx, query)
|
||||
}
|
||||
|
||||
// Count count the immutable rules
|
||||
func (r *DefaultAPIController) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
return r.manager.Count(ctx, query)
|
||||
}
|
||||
|
||||
// NewAPIController ...
|
||||
func NewAPIController(immutableMgr immutable.Manager) Controller {
|
||||
return &DefaultAPIController{
|
||||
manager: immutableMgr,
|
||||
}
|
||||
}
|
|
@ -1,19 +1,22 @@
|
|||
package immutabletag
|
||||
package immutable
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type ControllerTestSuite struct {
|
||||
suite.Suite
|
||||
htesting.Suite
|
||||
ctr Controller
|
||||
t *testing.T
|
||||
assert *assert.Assertions
|
||||
|
@ -28,7 +31,7 @@ func (s *ControllerTestSuite) SetupSuite() {
|
|||
s.t = s.T()
|
||||
s.assert = assert.New(s.t)
|
||||
s.require = require.New(s.t)
|
||||
s.ctr = ImmuCtr
|
||||
s.ctr = Ctr
|
||||
}
|
||||
|
||||
func (s *ControllerTestSuite) TestImmutableRule() {
|
||||
|
@ -65,7 +68,7 @@ func (s *ControllerTestSuite) TestImmutableRule() {
|
|||
},
|
||||
},
|
||||
}
|
||||
s.ruleID, err = s.ctr.CreateImmutableRule(rule)
|
||||
s.ruleID, err = s.ctr.CreateImmutableRule(orm.Context(), rule)
|
||||
s.require.Nil(err)
|
||||
|
||||
update := &model.Metadata{
|
||||
|
@ -92,10 +95,10 @@ func (s *ControllerTestSuite) TestImmutableRule() {
|
|||
},
|
||||
Disabled: false,
|
||||
}
|
||||
err = s.ctr.UpdateImmutableRule(projectID, update)
|
||||
err = s.ctr.UpdateImmutableRule(orm.Context(), projectID, update)
|
||||
s.require.Nil(err)
|
||||
|
||||
getRule, err := s.ctr.GetImmutableRule(s.ruleID)
|
||||
getRule, err := s.ctr.GetImmutableRule(orm.Context(), s.ruleID)
|
||||
s.require.Nil(err)
|
||||
s.require.Equal("postgres", getRule.ScopeSelectors["repository"][0].Pattern)
|
||||
|
||||
|
@ -123,9 +126,9 @@ func (s *ControllerTestSuite) TestImmutableRule() {
|
|||
},
|
||||
Disabled: true,
|
||||
}
|
||||
err = s.ctr.UpdateImmutableRule(projectID, update2)
|
||||
err = s.ctr.UpdateImmutableRule(orm.Context(), projectID, update2)
|
||||
s.require.Nil(err)
|
||||
getRule, err = s.ctr.GetImmutableRule(s.ruleID)
|
||||
getRule, err = s.ctr.GetImmutableRule(orm.Context(), s.ruleID)
|
||||
s.require.Nil(err)
|
||||
s.require.True(getRule.Disabled)
|
||||
|
||||
|
@ -151,10 +154,10 @@ func (s *ControllerTestSuite) TestImmutableRule() {
|
|||
},
|
||||
},
|
||||
}
|
||||
s.ruleID, err = s.ctr.CreateImmutableRule(rule2)
|
||||
s.ruleID, err = s.ctr.CreateImmutableRule(orm.Context(), rule2)
|
||||
s.require.Nil(err)
|
||||
|
||||
rules, err := s.ctr.ListImmutableRules(projectID)
|
||||
rules, err := s.ctr.ListImmutableRules(orm.Context(), q.New(q.KeyWords{"ProjectID": projectID}))
|
||||
s.require.Nil(err)
|
||||
s.require.Equal(2, len(rules))
|
||||
|
||||
|
@ -162,7 +165,7 @@ func (s *ControllerTestSuite) TestImmutableRule() {
|
|||
|
||||
// TearDownSuite clears env for test suite
|
||||
func (s *ControllerTestSuite) TearDownSuite() {
|
||||
err := s.ctr.DeleteImmutableRule(s.ruleID)
|
||||
err := s.ctr.DeleteImmutableRule(orm.Context(), s.ruleID)
|
||||
require.NoError(s.T(), err, "delete immutable rule")
|
||||
}
|
||||
|
|
@ -23,8 +23,8 @@ import (
|
|||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/signature"
|
||||
"github.com/goharbor/harbor/src/pkg/tag"
|
||||
model_tag "github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
|
@ -221,7 +221,7 @@ func (c *controller) populateImmutableStatus(ctx context.Context, tag *Tag) {
|
|||
return
|
||||
}
|
||||
_, repoName := utils.ParseRepository(artifact.RepositoryName)
|
||||
matched, err := c.immutableMtr.Match(artifact.ProjectID, selector.Candidate{
|
||||
matched, err := c.immutableMtr.Match(ctx, artifact.ProjectID, selector.Candidate{
|
||||
Repository: repoName,
|
||||
Tags: []string{tag.Name},
|
||||
NamespaceID: artifact.ProjectID,
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
ormtesting "github.com/goharbor/harbor/src/testing/lib/orm"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/artifact"
|
||||
immutesting "github.com/goharbor/harbor/src/testing/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/immutable"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
||||
tagtesting "github.com/goharbor/harbor/src/testing/pkg/tag"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -37,14 +37,14 @@ type controllerTestSuite struct {
|
|||
repoMgr *repository.FakeManager
|
||||
artMgr *artifact.FakeManager
|
||||
tagMgr *tagtesting.FakeManager
|
||||
immutableMtr *immutesting.FakeMatcher
|
||||
immutableMtr *immutable.FakeMatcher
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) SetupTest() {
|
||||
c.repoMgr = &repository.FakeManager{}
|
||||
c.artMgr = &artifact.FakeManager{}
|
||||
c.tagMgr = &tagtesting.FakeManager{}
|
||||
c.immutableMtr = &immutesting.FakeMatcher{}
|
||||
c.immutableMtr = &immutable.FakeMatcher{}
|
||||
c.ctl = &controller{
|
||||
tagMgr: c.tagMgr,
|
||||
artMgr: c.artMgr,
|
||||
|
|
|
@ -133,8 +133,6 @@ func init() {
|
|||
beego.Router("/api/projects/:pid([0-9]+)/webhook/policies/test", &NotificationPolicyAPI{}, "post:Test")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/webhook/lasttrigger", &NotificationPolicyAPI{}, "get:ListGroupByEventType")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/webhook/jobs/", &NotificationJobAPI{}, "get:List")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/immutabletagrules", &ImmutableTagRuleAPI{}, "get:List;post:Post")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/immutabletagrules/:id([0-9]+)", &ImmutableTagRuleAPI{})
|
||||
// Charts are controlled under projects
|
||||
chartRepositoryAPIType := &ChartRepositoryAPI{}
|
||||
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
// ImmutableTagRuleAPI ...
|
||||
type ImmutableTagRuleAPI struct {
|
||||
BaseController
|
||||
ctr immutabletag.Controller
|
||||
projectID int64
|
||||
ID int64
|
||||
}
|
||||
|
||||
// Prepare validates the user and projectID
|
||||
func (itr *ImmutableTagRuleAPI) Prepare() {
|
||||
itr.BaseController.Prepare()
|
||||
// Check access permissions
|
||||
if !itr.RequireAuthenticated() {
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := itr.GetInt64FromPath(":pid")
|
||||
if err != nil || pid <= 0 {
|
||||
text := "invalid project ID: "
|
||||
if err != nil {
|
||||
text += err.Error()
|
||||
} else {
|
||||
text += fmt.Sprintf("%d", pid)
|
||||
}
|
||||
itr.SendError(errors.New(err).WithCode(errors.BadRequestCode))
|
||||
return
|
||||
}
|
||||
itr.projectID = pid
|
||||
itr.ctr = immutabletag.ImmuCtr
|
||||
ruleID, err := itr.GetInt64FromPath(":id")
|
||||
if err == nil || ruleID > 0 {
|
||||
itr.ID = ruleID
|
||||
itRule, err := itr.ctr.GetImmutableRule(itr.ID)
|
||||
if err != nil {
|
||||
itr.SendError(err)
|
||||
return
|
||||
}
|
||||
if itRule.ProjectID != itr.projectID {
|
||||
err := fmt.Errorf("immutable tag rule %v not found", itr.ID)
|
||||
itr.SendError(errors.New(err).WithCode(errors.NotFoundCode))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if strings.EqualFold(itr.Ctx.Request.Method, "get") {
|
||||
if !itr.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
} else if strings.EqualFold(itr.Ctx.Request.Method, "put") {
|
||||
if !itr.requireAccess(rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
} else if strings.EqualFold(itr.Ctx.Request.Method, "post") {
|
||||
if !itr.requireAccess(rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
} else if strings.EqualFold(itr.Ctx.Request.Method, "delete") {
|
||||
if !itr.requireAccess(rbac.ActionDelete) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (itr *ImmutableTagRuleAPI) requireAccess(action rbac.Action) bool {
|
||||
return itr.RequireProjectAccess(itr.projectID, action, rbac.ResourceImmutableTag)
|
||||
}
|
||||
|
||||
// List list all immutable tag rules of current project
|
||||
func (itr *ImmutableTagRuleAPI) List() {
|
||||
rules, err := itr.ctr.ListImmutableRules(itr.projectID)
|
||||
if err != nil {
|
||||
itr.SendError(err)
|
||||
return
|
||||
}
|
||||
itr.WriteJSONData(rules)
|
||||
}
|
||||
|
||||
// Post create immutable tag rule
|
||||
func (itr *ImmutableTagRuleAPI) Post() {
|
||||
ir := &model.Metadata{}
|
||||
isValid, err := itr.DecodeJSONReqAndValidate(ir)
|
||||
if !isValid {
|
||||
itr.SendError(errors.New(err).WithCode(errors.BadRequestCode))
|
||||
return
|
||||
}
|
||||
ir.ProjectID = itr.projectID
|
||||
id, err := itr.ctr.CreateImmutableRule(ir)
|
||||
if err != nil {
|
||||
itr.SendError(err)
|
||||
return
|
||||
}
|
||||
itr.Redirect(http.StatusCreated, strconv.FormatInt(id, 10))
|
||||
}
|
||||
|
||||
// Delete delete immutable tag rule
|
||||
func (itr *ImmutableTagRuleAPI) Delete() {
|
||||
if itr.ID <= 0 {
|
||||
err := fmt.Errorf("invalid immutable rule id %d", itr.ID)
|
||||
itr.SendError(errors.New(err).WithCode(errors.BadRequestCode))
|
||||
return
|
||||
}
|
||||
err := itr.ctr.DeleteImmutableRule(itr.ID)
|
||||
if err != nil {
|
||||
itr.SendError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Put update an immutable tag rule
|
||||
func (itr *ImmutableTagRuleAPI) Put() {
|
||||
ir := &model.Metadata{}
|
||||
if err := itr.DecodeJSONReq(ir); err != nil {
|
||||
itr.SendError(errors.New(err).WithCode(errors.BadRequestCode))
|
||||
return
|
||||
}
|
||||
ir.ID = itr.ID
|
||||
ir.ProjectID = itr.projectID
|
||||
|
||||
if itr.ID <= 0 {
|
||||
err := fmt.Errorf("invalid immutable rule id %d", itr.ID)
|
||||
itr.SendError(errors.New(err).WithCode(errors.BadRequestCode))
|
||||
return
|
||||
}
|
||||
|
||||
if err := itr.ctr.UpdateImmutableRule(itr.projectID, ir); err != nil {
|
||||
itr.SendError(err)
|
||||
return
|
||||
}
|
||||
}
|
|
@ -1,365 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
func TestImmutableTagRuleAPI_List(t *testing.T) {
|
||||
|
||||
metadata := &model.Metadata{
|
||||
ProjectID: 1,
|
||||
Disabled: false,
|
||||
TagSelectors: []*model.Selector{
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*model.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mgr := immutabletag.NewDefaultRuleManager()
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer mgr.DeleteImmutableRule(id)
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: admin,
|
||||
},
|
||||
postFunc: func(responseRecorder *httptest.ResponseRecorder) error {
|
||||
var rules []model.Metadata
|
||||
err := json.Unmarshal([]byte(responseRecorder.Body.String()), &rules)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(rules) <= 0 {
|
||||
return fmt.Errorf("no rules found")
|
||||
}
|
||||
if rules[0].TagSelectors[0].Kind != "doublestar" {
|
||||
return fmt.Errorf("rule is not expected. actual: %v", responseRecorder.Body.String())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projAdmin,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
// 403
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projGuest,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
|
||||
}
|
||||
|
||||
func TestImmutableTagRuleAPI_Post(t *testing.T) {
|
||||
|
||||
// body := `{
|
||||
// "projectID":1,
|
||||
// "priority":0,
|
||||
// "template": "immutable_template",
|
||||
// "action": "immutable",
|
||||
// "disabled":false,
|
||||
// "action":"immutable",
|
||||
// "template":"immutable_template",
|
||||
// "tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}],
|
||||
// "scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]}
|
||||
// }`
|
||||
|
||||
metadata := &model.Metadata{
|
||||
ProjectID: 1,
|
||||
Disabled: false,
|
||||
Priority: 0,
|
||||
Template: "immutable_template",
|
||||
Action: "immutable",
|
||||
TagSelectors: []*model.Selector{
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*model.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
// 201
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: admin,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusCreated,
|
||||
},
|
||||
// 409
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projAdmin,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusConflict,
|
||||
},
|
||||
// 403
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projGuest,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
|
||||
}
|
||||
|
||||
func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
|
||||
metadata := &model.Metadata{
|
||||
ProjectID: 1,
|
||||
Disabled: false,
|
||||
TagSelectors: []*model.Selector{
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*model.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
metadata2 := &model.Metadata{
|
||||
ProjectID: 1,
|
||||
Disabled: false,
|
||||
TagSelectors: []*model.Selector{
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: "latest",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*model.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mgr := immutabletag.NewDefaultRuleManager()
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer mgr.DeleteImmutableRule(id)
|
||||
|
||||
url := fmt.Sprintf("/api/projects/1/immutabletagrules/%d", id)
|
||||
url2 := fmt.Sprintf("/api/projects/3/immutabletagrules/%d", id)
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: admin,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: projAdmin,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
// 403
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: projGuest,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url2,
|
||||
credential: projAdmin,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
||||
|
||||
func TestImmutableTagRuleAPI_Delete(t *testing.T) {
|
||||
metadata := &model.Metadata{
|
||||
ProjectID: 1,
|
||||
Disabled: false,
|
||||
TagSelectors: []*model.Selector{
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: "latest",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*model.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "doublestar",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mgr := immutabletag.NewDefaultRuleManager()
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer mgr.DeleteImmutableRule(id)
|
||||
|
||||
url := fmt.Sprintf("/api/projects/1/immutabletagrules/%d", id)
|
||||
wrongURL := fmt.Sprintf("/api/projects/3/immutabletagrules/%d", id)
|
||||
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: url,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
// 403
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: url,
|
||||
credential: projGuest,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: wrongURL,
|
||||
credential: projAdmin,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: url,
|
||||
credential: projAdmin,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: url,
|
||||
credential: projAdmin,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
142
src/pkg/immutable/dao/dao.go
Normal file
142
src/pkg/immutable/dao/dao.go
Normal file
|
@ -0,0 +1,142 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/dao/model"
|
||||
)
|
||||
|
||||
// DAO defines the interface to access the ImmutableRule data model
|
||||
type DAO interface {
|
||||
CreateImmutableRule(ctx context.Context, ir *model.ImmutableRule) (int64, error)
|
||||
UpdateImmutableRule(ctx context.Context, projectID int64, ir *model.ImmutableRule) error
|
||||
ToggleImmutableRule(ctx context.Context, id int64, status bool) error
|
||||
GetImmutableRule(ctx context.Context, id int64) (*model.ImmutableRule, error)
|
||||
Count(ctx context.Context, query *q.Query) (int64, error)
|
||||
ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.ImmutableRule, error)
|
||||
DeleteImmutableRule(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
// New creates a default implementation for DAO
|
||||
func New() DAO {
|
||||
return &iDao{}
|
||||
}
|
||||
|
||||
type iDao struct{}
|
||||
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
func (i *iDao) CreateImmutableRule(ctx context.Context, ir *model.ImmutableRule) (int64, error) {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ir.Disabled = false
|
||||
id, err := ormer.Insert(ir)
|
||||
if err != nil {
|
||||
if e := orm.AsConflictError(err, "immutable rule already exists"); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
func (i *iDao) UpdateImmutableRule(ctx context.Context, projectID int64, ir *model.ImmutableRule) error {
|
||||
ir.ProjectID = projectID
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := ormer.Update(ir, "TagFilter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return errors.NotFoundError(nil).WithMessage("immutable %d not found", ir.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToggleImmutableRule enable/disable immutable rules
|
||||
func (i *iDao) ToggleImmutableRule(ctx context.Context, id int64, status bool) error {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ir := &model.ImmutableRule{ID: id, Disabled: status}
|
||||
n, err := ormer.Update(ir, "Disabled")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return errors.NotFoundError(nil).WithMessage("immutable %d not found", ir.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetImmutableRule get immutable rule
|
||||
func (i *iDao) GetImmutableRule(ctx context.Context, id int64) (*model.ImmutableRule, error) {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ir := &model.ImmutableRule{ID: id}
|
||||
if err = ormer.Read(ir); err != nil {
|
||||
if e := orm.AsNotFoundError(err, "immutable rule %d not found", id); e != nil {
|
||||
err = e
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return ir, nil
|
||||
}
|
||||
|
||||
// QueryImmutableRuleByProjectID get all immutable rule by project
|
||||
func (i *iDao) ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.ImmutableRule, error) {
|
||||
rules := []*model.ImmutableRule{}
|
||||
qs, err := orm.QuerySetter(ctx, &model.ImmutableRule{}, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if query.Sorting != "" {
|
||||
qs = qs.OrderBy(query.Sorting)
|
||||
}
|
||||
if _, err = qs.All(&rules); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
// Count ...
|
||||
func (i *iDao) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
query = q.MustClone(query)
|
||||
query.Sorting = ""
|
||||
query.PageNumber = 0
|
||||
query.PageSize = 0
|
||||
|
||||
qs, err := orm.QuerySetter(ctx, &model.ImmutableRule{}, query)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return qs.Count()
|
||||
}
|
||||
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
func (i *iDao) DeleteImmutableRule(ctx context.Context, id int64) error {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ir := &model.ImmutableRule{ID: id}
|
||||
|
||||
n, err := ormer.Delete(ir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return errors.NotFoundError(nil).WithMessage("immutable rule %d not found", id)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,21 +1,23 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/dao/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type immutableRuleDaoTestSuite struct {
|
||||
suite.Suite
|
||||
htesting.Suite
|
||||
require *require.Assertions
|
||||
assert *assert.Assertions
|
||||
dao ImmutableRuleDao
|
||||
dao DAO
|
||||
id int64
|
||||
}
|
||||
|
||||
|
@ -28,52 +30,51 @@ func (t *immutableRuleDaoTestSuite) SetupSuite() {
|
|||
|
||||
func (t *immutableRuleDaoTestSuite) TestCreateImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(ir)
|
||||
id, err := t.dao.CreateImmutableRule(t.Context(), ir)
|
||||
t.require.Nil(err)
|
||||
t.require.True(id > 0, "Can not create immutable tag rule")
|
||||
|
||||
// insert duplicate rows
|
||||
ir2 := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id2, err := t.dao.CreateImmutableRule(ir2)
|
||||
t.require.True(strings.Contains(err.Error(), "duplicate key"))
|
||||
id2, err := t.dao.CreateImmutableRule(t.Context(), ir2)
|
||||
t.require.True(strings.Contains(err.Error(), "immutable rule already exist"))
|
||||
t.require.Equal(int64(0), id2)
|
||||
|
||||
_, err = t.dao.DeleteImmutableRule(id)
|
||||
err = t.dao.DeleteImmutableRule(t.Context(), id)
|
||||
t.require.Nil(err)
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestUpdateImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(ir)
|
||||
id, err := t.dao.CreateImmutableRule(t.Context(), ir)
|
||||
t.require.Nil(err)
|
||||
t.require.True(id > 0, "Can not create immutable tag rule")
|
||||
|
||||
updatedIR := &model.ImmutableRule{ID: id, TagFilter: "1.2.0", ProjectID: 1}
|
||||
updatedCnt, err := t.dao.UpdateImmutableRule(1, updatedIR)
|
||||
err = t.dao.UpdateImmutableRule(t.Context(), 1, updatedIR)
|
||||
t.require.Nil(err)
|
||||
t.require.True(updatedCnt > 0, "Failed to update immutable id")
|
||||
|
||||
newIr, err := t.dao.GetImmutableRule(id)
|
||||
newIr, err := t.dao.GetImmutableRule(t.Context(), id)
|
||||
t.require.Nil(err)
|
||||
t.require.True(newIr.TagFilter == "1.2.0", "Failed to update immutable tag")
|
||||
|
||||
defer t.dao.DeleteImmutableRule(id)
|
||||
defer t.dao.DeleteImmutableRule(t.Context(), id)
|
||||
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestEnableImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(ir)
|
||||
id, err := t.dao.CreateImmutableRule(t.Context(), ir)
|
||||
t.require.Nil(err)
|
||||
t.require.True(id > 0, "Can not create immutable tag rule")
|
||||
|
||||
t.dao.ToggleImmutableRule(id, true)
|
||||
newIr, err := t.dao.GetImmutableRule(id)
|
||||
t.dao.ToggleImmutableRule(t.Context(), id, true)
|
||||
newIr, err := t.dao.GetImmutableRule(t.Context(), id)
|
||||
|
||||
t.require.Nil(err)
|
||||
t.require.True(newIr.Disabled, "Failed to disable the immutable rule")
|
||||
|
||||
defer t.dao.DeleteImmutableRule(id)
|
||||
defer t.dao.DeleteImmutableRule(t.Context(), id)
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestGetImmutableRuleByProject() {
|
||||
|
@ -84,10 +85,10 @@ func (t *immutableRuleDaoTestSuite) TestGetImmutableRuleByProject() {
|
|||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for _, ir := range irs {
|
||||
t.dao.CreateImmutableRule(ir)
|
||||
t.dao.CreateImmutableRule(t.Context(), ir)
|
||||
}
|
||||
|
||||
qrs, err := t.dao.QueryImmutableRuleByProjectID(99)
|
||||
qrs, err := t.dao.ListImmutableRules(t.Context(), q.New(q.KeyWords{"ProjectID": 99}))
|
||||
t.require.Nil(err)
|
||||
t.require.True(len(qrs) == 4, "Failed to query 4 rows!")
|
||||
|
||||
|
@ -102,13 +103,13 @@ func (t *immutableRuleDaoTestSuite) TestGetEnabledImmutableRuleByProject() {
|
|||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for i, ir := range irs {
|
||||
id, _ := t.dao.CreateImmutableRule(ir)
|
||||
id, _ := t.dao.CreateImmutableRule(t.Context(), ir)
|
||||
if i == 1 {
|
||||
t.dao.ToggleImmutableRule(id, true)
|
||||
t.dao.ToggleImmutableRule(t.Context(), id, true)
|
||||
}
|
||||
}
|
||||
|
||||
qrs, err := t.dao.QueryEnabledImmutableRuleByProjectID(99)
|
||||
qrs, err := t.dao.ListImmutableRules(t.Context(), q.New(q.KeyWords{"ProjectID": 99, "Disabled": "false"}))
|
||||
t.require.Nil(err)
|
||||
t.require.True(len(qrs) == 3, "Failed to query 3 rows!, got %v", len(qrs))
|
||||
|
113
src/pkg/immutable/manager.go
Normal file
113
src/pkg/immutable/manager.go
Normal file
|
@ -0,0 +1,113 @@
|
|||
package immutable
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"sort"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/dao"
|
||||
dao_model "github.com/goharbor/harbor/src/pkg/immutable/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
)
|
||||
|
||||
var (
|
||||
// Mgr is a global variable for the default immutablerule manager implementation
|
||||
Mgr = NewDefaultRuleManager()
|
||||
)
|
||||
|
||||
// Manager ...
|
||||
type Manager interface {
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
CreateImmutableRule(ctx context.Context, m *model.Metadata) (int64, error)
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
UpdateImmutableRule(ctx context.Context, projectID int64, ir *model.Metadata) error
|
||||
// EnableImmutableRule enable/disable immutable rules
|
||||
EnableImmutableRule(ctx context.Context, id int64, enabled bool) error
|
||||
// GetImmutableRule get immutable rule
|
||||
GetImmutableRule(ctx context.Context, id int64) (*model.Metadata, error)
|
||||
// Count count the immutable rules
|
||||
Count(ctx context.Context, query *q.Query) (int64, error)
|
||||
// ListImmutableRules list the immutable rules
|
||||
ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.Metadata, error)
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
DeleteImmutableRule(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
type defaultRuleManager struct {
|
||||
dao dao.DAO
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) CreateImmutableRule(ctx context.Context, ir *model.Metadata) (int64, error) {
|
||||
daoRule := &dao_model.ImmutableRule{}
|
||||
daoRule.Disabled = ir.Disabled
|
||||
daoRule.ProjectID = ir.ProjectID
|
||||
data, _ := json.Marshal(ir)
|
||||
daoRule.TagFilter = string(data)
|
||||
return drm.dao.CreateImmutableRule(ctx, daoRule)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) UpdateImmutableRule(ctx context.Context, projectID int64, ir *model.Metadata) error {
|
||||
daoRule := &dao_model.ImmutableRule{}
|
||||
data, _ := json.Marshal(ir)
|
||||
daoRule.ID = ir.ID
|
||||
daoRule.TagFilter = string(data)
|
||||
return drm.dao.UpdateImmutableRule(ctx, projectID, daoRule)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) EnableImmutableRule(ctx context.Context, id int64, enabled bool) error {
|
||||
return drm.dao.ToggleImmutableRule(ctx, id, enabled)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) GetImmutableRule(ctx context.Context, id int64) (*model.Metadata, error) {
|
||||
daoRule, err := drm.dao.GetImmutableRule(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule := &model.Metadata{}
|
||||
if daoRule == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if err = json.Unmarshal([]byte(daoRule.TagFilter), rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.ID = daoRule.ID
|
||||
rule.Disabled = daoRule.Disabled
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.Metadata, error) {
|
||||
daoRules, err := drm.dao.ListImmutableRules(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules := make([]*model.Metadata, 0)
|
||||
for _, daoRule := range daoRules {
|
||||
rule := model.Metadata{}
|
||||
if err = json.Unmarshal([]byte(daoRule.TagFilter), &rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.ID = daoRule.ID
|
||||
rule.Disabled = daoRule.Disabled
|
||||
rules = append(rules, &rule)
|
||||
}
|
||||
sort.Slice(rules, func(i, j int) bool {
|
||||
return rules[i].ID < rules[j].ID
|
||||
})
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
return drm.dao.Count(ctx, query)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) DeleteImmutableRule(ctx context.Context, id int64) error {
|
||||
return drm.dao.DeleteImmutableRule(ctx, id)
|
||||
}
|
||||
|
||||
// NewDefaultRuleManager return a new instance of defaultRuleManager
|
||||
func NewDefaultRuleManager() Manager {
|
||||
return &defaultRuleManager{
|
||||
dao: dao.New(),
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
package immutabletag
|
||||
package immutable
|
||||
|
||||
import (
|
||||
dao_model "github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
dao_model "github.com/goharbor/harbor/src/pkg/immutable/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/immutable/dao"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -12,64 +15,12 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
type mockImmutableDao struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) CreateImmutableRule(ir *dao_model.ImmutableRule) (int64, error) {
|
||||
args := m.Called(ir)
|
||||
return int64(args.Int(0)), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) UpdateImmutableRule(projectID int64, ir *dao_model.ImmutableRule) (int64, error) {
|
||||
args := m.Called(ir)
|
||||
return int64(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) QueryImmutableRuleByProjectID(projectID int64) ([]dao_model.ImmutableRule, error) {
|
||||
args := m.Called()
|
||||
var irs []dao_model.ImmutableRule
|
||||
if args.Get(0) != nil {
|
||||
irs = args.Get(0).([]dao_model.ImmutableRule)
|
||||
}
|
||||
return irs, args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]dao_model.ImmutableRule, error) {
|
||||
args := m.Called()
|
||||
var irs []dao_model.ImmutableRule
|
||||
if args.Get(0) != nil {
|
||||
irs = args.Get(0).([]dao_model.ImmutableRule)
|
||||
}
|
||||
return irs, args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) DeleteImmutableRule(id int64) (int64, error) {
|
||||
args := m.Called(id)
|
||||
return int64(args.Int(0)), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) ToggleImmutableRule(id int64, enabled bool) (int64, error) {
|
||||
args := m.Called(id)
|
||||
return int64(args.Int(0)), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockImmutableDao) GetImmutableRule(id int64) (*dao_model.ImmutableRule, error) {
|
||||
args := m.Called(id)
|
||||
var ir *dao_model.ImmutableRule
|
||||
if args.Get(0) != nil {
|
||||
ir = args.Get(0).(*dao_model.ImmutableRule)
|
||||
}
|
||||
return ir, args.Error(1)
|
||||
|
||||
}
|
||||
|
||||
type managerTestingSuite struct {
|
||||
suite.Suite
|
||||
t *testing.T
|
||||
assert *assert.Assertions
|
||||
require *require.Assertions
|
||||
mockImmutableDao *mockImmutableDao
|
||||
mockImmutableDao *dao.DAO
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) SetupSuite() {
|
||||
|
@ -87,7 +38,7 @@ func (m *managerTestingSuite) TearDownSuite() {
|
|||
}
|
||||
|
||||
func (m *managerTestingSuite) SetupTest() {
|
||||
m.mockImmutableDao = &mockImmutableDao{}
|
||||
m.mockImmutableDao = &dao.DAO{}
|
||||
Mgr = &defaultRuleManager{
|
||||
dao: m.mockImmutableDao,
|
||||
}
|
||||
|
@ -98,15 +49,15 @@ func TestManagerTestingSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func (m *managerTestingSuite) TestCreateImmutableRule() {
|
||||
m.mockImmutableDao.On("CreateImmutableRule", mock.Anything).Return(1, nil)
|
||||
id, err := Mgr.CreateImmutableRule(&model.Metadata{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "CreateImmutableRule", mock.Anything)
|
||||
m.mockImmutableDao.On("CreateImmutableRule", mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
id, err := Mgr.CreateImmutableRule(context.Background(), &model.Metadata{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "CreateImmutableRule", mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(int64(1), id)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestQueryImmutableRuleByProjectID() {
|
||||
m.mockImmutableDao.On("QueryImmutableRuleByProjectID", mock.Anything).Return([]dao_model.ImmutableRule{
|
||||
m.mockImmutableDao.On("ListImmutableRules", mock.Anything, mock.Anything).Return([]*dao_model.ImmutableRule{
|
||||
{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
|
@ -125,15 +76,15 @@ func (m *managerTestingSuite) TestQueryImmutableRuleByProjectID() {
|
|||
"\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}]," +
|
||||
"\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]}}",
|
||||
}}, nil)
|
||||
irs, err := Mgr.QueryImmutableRuleByProjectID(int64(1))
|
||||
m.mockImmutableDao.AssertCalled(m.t, "QueryImmutableRuleByProjectID", mock.Anything)
|
||||
irs, err := Mgr.ListImmutableRules(context.Background(), &q.Query{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "ListImmutableRules", mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(len(irs), 2)
|
||||
m.assert.Equal(irs[1].Disabled, false)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestQueryEnabledImmutableRuleByProjectID() {
|
||||
m.mockImmutableDao.On("QueryEnabledImmutableRuleByProjectID", mock.Anything).Return([]dao_model.ImmutableRule{
|
||||
m.mockImmutableDao.On("ListImmutableRules", mock.Anything, mock.Anything).Return([]*dao_model.ImmutableRule{
|
||||
{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
|
@ -152,15 +103,15 @@ func (m *managerTestingSuite) TestQueryEnabledImmutableRuleByProjectID() {
|
|||
"\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}]," +
|
||||
"\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]}}",
|
||||
}}, nil)
|
||||
irs, err := Mgr.QueryEnabledImmutableRuleByProjectID(int64(1))
|
||||
m.mockImmutableDao.AssertCalled(m.t, "QueryEnabledImmutableRuleByProjectID", mock.Anything)
|
||||
irs, err := Mgr.ListImmutableRules(context.Background(), &q.Query{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "ListImmutableRules", mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(len(irs), 2)
|
||||
m.assert.Equal(irs[0].Disabled, false)
|
||||
m.assert.Equal(irs[0].Disabled, true)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestGetImmutableRule() {
|
||||
m.mockImmutableDao.On("GetImmutableRule", mock.Anything).Return(&dao_model.ImmutableRule{
|
||||
m.mockImmutableDao.On("GetImmutableRule", mock.Anything, mock.Anything).Return(&dao_model.ImmutableRule{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
Disabled: true,
|
||||
|
@ -169,33 +120,30 @@ func (m *managerTestingSuite) TestGetImmutableRule() {
|
|||
"\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}]," +
|
||||
"\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]}}",
|
||||
}, nil)
|
||||
ir, err := Mgr.GetImmutableRule(1)
|
||||
m.mockImmutableDao.AssertCalled(m.t, "GetImmutableRule", mock.Anything)
|
||||
ir, err := Mgr.GetImmutableRule(context.Background(), 1)
|
||||
m.mockImmutableDao.AssertCalled(m.t, "GetImmutableRule", mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.require.NotNil(ir)
|
||||
m.assert.Equal(int64(1), ir.ID)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestUpdateImmutableRule() {
|
||||
m.mockImmutableDao.On("UpdateImmutableRule", mock.Anything).Return(1, nil)
|
||||
id, err := Mgr.UpdateImmutableRule(int64(1), &model.Metadata{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "UpdateImmutableRule", mock.Anything)
|
||||
m.mockImmutableDao.On("UpdateImmutableRule", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
err := Mgr.UpdateImmutableRule(context.Background(), int64(1), &model.Metadata{})
|
||||
m.mockImmutableDao.AssertCalled(m.t, "UpdateImmutableRule", mock.Anything, mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(int64(0), id)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestEnableImmutableRule() {
|
||||
m.mockImmutableDao.On("ToggleImmutableRule", mock.Anything).Return(1, nil)
|
||||
id, err := Mgr.EnableImmutableRule(int64(1), true)
|
||||
m.mockImmutableDao.AssertCalled(m.t, "ToggleImmutableRule", mock.Anything)
|
||||
m.mockImmutableDao.On("ToggleImmutableRule", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
err := Mgr.EnableImmutableRule(context.Background(), int64(1), true)
|
||||
m.mockImmutableDao.AssertCalled(m.t, "ToggleImmutableRule", mock.Anything, mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(int64(1), id)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestDeleteImmutableRule() {
|
||||
m.mockImmutableDao.On("DeleteImmutableRule", mock.Anything).Return(1, nil)
|
||||
id, err := Mgr.DeleteImmutableRule(int64(1))
|
||||
m.mockImmutableDao.AssertCalled(m.t, "DeleteImmutableRule", mock.Anything)
|
||||
m.mockImmutableDao.On("DeleteImmutableRule", mock.Anything, mock.Anything).Return(nil)
|
||||
err := Mgr.DeleteImmutableRule(context.Background(), int64(1))
|
||||
m.mockImmutableDao.AssertCalled(m.t, "DeleteImmutableRule", mock.Anything, mock.Anything)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(int64(1), id)
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
package match
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
)
|
||||
|
||||
// ImmutableTagMatcher ...
|
||||
type ImmutableTagMatcher interface {
|
||||
// Match whether the candidate is in the immutable list
|
||||
Match(pid int64, c selector.Candidate) (bool, error)
|
||||
Match(ctx context.Context, pid int64, c selector.Candidate) (bool, error)
|
||||
}
|
|
@ -1,21 +1,23 @@
|
|||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/controller/immutable"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
iselector "github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/lib/selector/selectors/index"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
)
|
||||
|
||||
// Matcher ...
|
||||
type Matcher struct {
|
||||
rules []model.Metadata
|
||||
rules []*model.Metadata
|
||||
}
|
||||
|
||||
// Match ...
|
||||
func (rm *Matcher) Match(pid int64, c iselector.Candidate) (bool, error) {
|
||||
if err := rm.getImmutableRules(pid); err != nil {
|
||||
func (rm *Matcher) Match(ctx context.Context, pid int64, c iselector.Candidate) (bool, error) {
|
||||
if err := rm.getImmutableRules(ctx, pid); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
@ -70,8 +72,8 @@ func (rm *Matcher) Match(pid int64, c iselector.Candidate) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (rm *Matcher) getImmutableRules(pid int64) error {
|
||||
rules, err := immutabletag.ImmuCtr.ListImmutableRules(pid)
|
||||
func (rm *Matcher) getImmutableRules(ctx context.Context, pid int64) error {
|
||||
rules, err := immutable.Ctr.ListImmutableRules(ctx, q.New(q.KeyWords{"ProjectID": pid}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -2,9 +2,10 @@ package rule
|
|||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/controller/immutable"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -18,7 +19,7 @@ type MatchTestSuite struct {
|
|||
t *testing.T
|
||||
assert *assert.Assertions
|
||||
require *require.Assertions
|
||||
ctr immutabletag.Controller
|
||||
ctr immutable.Controller
|
||||
ruleID int64
|
||||
ruleID2 int64
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ func (s *MatchTestSuite) SetupSuite() {
|
|||
s.t = s.T()
|
||||
s.assert = assert.New(s.t)
|
||||
s.require = require.New(s.t)
|
||||
s.ctr = immutabletag.ImmuCtr
|
||||
s.ctr = immutable.Ctr
|
||||
}
|
||||
|
||||
func (s *MatchTestSuite) TestImmuMatch() {
|
||||
|
@ -77,11 +78,11 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||
},
|
||||
}
|
||||
|
||||
id, err := s.ctr.CreateImmutableRule(rule)
|
||||
id, err := s.ctr.CreateImmutableRule(orm.Context(), rule)
|
||||
s.ruleID = id
|
||||
s.require.Nil(err)
|
||||
|
||||
id, err = s.ctr.CreateImmutableRule(rule2)
|
||||
id, err = s.ctr.CreateImmutableRule(orm.Context(), rule2)
|
||||
s.ruleID2 = id
|
||||
s.require.Nil(err)
|
||||
|
||||
|
@ -93,7 +94,7 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||
Repository: "redis",
|
||||
Tags: []string{"release-1.10"},
|
||||
}
|
||||
isMatch, err := match.Match(1, c1)
|
||||
isMatch, err := match.Match(orm.Context(), 1, c1)
|
||||
s.require.Equal(isMatch, true)
|
||||
s.require.Nil(err)
|
||||
|
||||
|
@ -104,7 +105,7 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||
Tags: []string{"1.10"},
|
||||
Kind: selector.Image,
|
||||
}
|
||||
isMatch, err = match.Match(1, c2)
|
||||
isMatch, err = match.Match(orm.Context(), 1, c2)
|
||||
s.require.Equal(isMatch, false)
|
||||
s.require.Nil(err)
|
||||
|
||||
|
@ -115,7 +116,7 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||
Tags: []string{"9.4.8"},
|
||||
Kind: selector.Image,
|
||||
}
|
||||
isMatch, err = match.Match(1, c3)
|
||||
isMatch, err = match.Match(orm.Context(), 1, c3)
|
||||
s.require.Equal(isMatch, true)
|
||||
s.require.Nil(err)
|
||||
|
||||
|
@ -126,17 +127,17 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||
Tags: []string{"world"},
|
||||
Kind: selector.Image,
|
||||
}
|
||||
isMatch, err = match.Match(1, c4)
|
||||
isMatch, err = match.Match(orm.Context(), 1, c4)
|
||||
s.require.Equal(isMatch, false)
|
||||
s.require.Nil(err)
|
||||
}
|
||||
|
||||
// TearDownSuite clears env for test suite
|
||||
func (s *MatchTestSuite) TearDownSuite() {
|
||||
err := s.ctr.DeleteImmutableRule(s.ruleID)
|
||||
err := s.ctr.DeleteImmutableRule(orm.Context(), s.ruleID)
|
||||
require.NoError(s.T(), err, "delete immutable")
|
||||
|
||||
err = s.ctr.DeleteImmutableRule(s.ruleID2)
|
||||
err = s.ctr.DeleteImmutableRule(orm.Context(), s.ruleID2)
|
||||
require.NoError(s.T(), err, "delete immutable")
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
package immutabletag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
var (
|
||||
// ImmuCtr is a global variable for the default immutable controller implementation
|
||||
ImmuCtr = NewAPIController(NewDefaultRuleManager())
|
||||
)
|
||||
|
||||
// Controller to handle the requests related with immutabletag
|
||||
type Controller interface {
|
||||
// GetImmutableRule ...
|
||||
GetImmutableRule(id int64) (*model.Metadata, error)
|
||||
|
||||
// CreateImmutableRule ...
|
||||
CreateImmutableRule(m *model.Metadata) (int64, error)
|
||||
|
||||
// DeleteImmutableRule ...
|
||||
DeleteImmutableRule(id int64) error
|
||||
|
||||
// UpdateImmutableRule ...
|
||||
UpdateImmutableRule(pid int64, m *model.Metadata) error
|
||||
|
||||
// ListImmutableRules ...
|
||||
ListImmutableRules(pid int64) ([]model.Metadata, error)
|
||||
}
|
||||
|
||||
// DefaultAPIController ...
|
||||
type DefaultAPIController struct {
|
||||
manager Manager
|
||||
}
|
||||
|
||||
// GetImmutableRule ...
|
||||
func (r *DefaultAPIController) GetImmutableRule(id int64) (*model.Metadata, error) {
|
||||
return r.manager.GetImmutableRule(id)
|
||||
}
|
||||
|
||||
// DeleteImmutableRule ...
|
||||
func (r *DefaultAPIController) DeleteImmutableRule(id int64) error {
|
||||
_, err := r.manager.DeleteImmutableRule(id)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateImmutableRule ...
|
||||
func (r *DefaultAPIController) CreateImmutableRule(m *model.Metadata) (int64, error) {
|
||||
return r.manager.CreateImmutableRule(m)
|
||||
}
|
||||
|
||||
// UpdateImmutableRule ...
|
||||
func (r *DefaultAPIController) UpdateImmutableRule(pid int64, m *model.Metadata) error {
|
||||
m0, err := r.manager.GetImmutableRule(m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m0 == nil {
|
||||
return fmt.Errorf("the immutable tag rule is not found id:%v", m.ID)
|
||||
}
|
||||
if m0.Disabled != m.Disabled {
|
||||
_, err := r.manager.EnableImmutableRule(m.ID, m.Disabled)
|
||||
return err
|
||||
}
|
||||
_, err = r.manager.UpdateImmutableRule(pid, m)
|
||||
return err
|
||||
}
|
||||
|
||||
// ListImmutableRules ...
|
||||
func (r *DefaultAPIController) ListImmutableRules(pid int64) ([]model.Metadata, error) {
|
||||
return r.manager.QueryImmutableRuleByProjectID(pid)
|
||||
}
|
||||
|
||||
// NewAPIController ...
|
||||
func NewAPIController(immutableMgr Manager) Controller {
|
||||
return &DefaultAPIController{
|
||||
manager: immutableMgr,
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
)
|
||||
|
||||
// ImmutableRuleDao defines the interface to access the ImmutableRule data model
|
||||
type ImmutableRuleDao interface {
|
||||
CreateImmutableRule(ir *model.ImmutableRule) (int64, error)
|
||||
UpdateImmutableRule(projectID int64, ir *model.ImmutableRule) (int64, error)
|
||||
ToggleImmutableRule(id int64, status bool) (int64, error)
|
||||
GetImmutableRule(id int64) (*model.ImmutableRule, error)
|
||||
QueryImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error)
|
||||
QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error)
|
||||
DeleteImmutableRule(id int64) (int64, error)
|
||||
}
|
||||
|
||||
// New creates a default implementation for ImmutableRuleDao
|
||||
func New() ImmutableRuleDao {
|
||||
return &immutableRuleDao{}
|
||||
}
|
||||
|
||||
type immutableRuleDao struct{}
|
||||
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
func (i *immutableRuleDao) CreateImmutableRule(ir *model.ImmutableRule) (int64, error) {
|
||||
ir.Disabled = false
|
||||
o := dao.GetOrmer()
|
||||
id, err := o.Insert(ir)
|
||||
if err != nil {
|
||||
if dao.IsDupRecErr(err) {
|
||||
return id, errors.ConflictError(err)
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
func (i *immutableRuleDao) UpdateImmutableRule(projectID int64, ir *model.ImmutableRule) (int64, error) {
|
||||
ir.ProjectID = projectID
|
||||
o := dao.GetOrmer()
|
||||
id, err := o.Update(ir, "TagFilter")
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrNoRows) {
|
||||
return id, errors.NotFoundError(err)
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// ToggleImmutableRule enable/disable immutable rules
|
||||
func (i *immutableRuleDao) ToggleImmutableRule(id int64, status bool) (int64, error) {
|
||||
o := dao.GetOrmer()
|
||||
ir := &model.ImmutableRule{ID: id, Disabled: status}
|
||||
id, err := o.Update(ir, "Disabled")
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrNoRows) {
|
||||
return id, errors.NotFoundError(err)
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetImmutableRule get immutable rule
|
||||
func (i *immutableRuleDao) GetImmutableRule(id int64) (*model.ImmutableRule, error) {
|
||||
o := dao.GetOrmer()
|
||||
ir := &model.ImmutableRule{ID: id}
|
||||
err := o.Read(ir)
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrNoRows) {
|
||||
return nil, errors.New(err).WithCode(errors.NotFoundCode).
|
||||
WithMessage(fmt.Sprintf("the immutable rule %d is not found.", id))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return ir, nil
|
||||
}
|
||||
|
||||
// QueryImmutableRuleByProjectID get all immutable rule by project
|
||||
func (i *immutableRuleDao) QueryImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) {
|
||||
o := dao.GetOrmer()
|
||||
qs := o.QueryTable(&model.ImmutableRule{}).Filter("ProjectID", projectID)
|
||||
r := make([]model.ImmutableRule, 0)
|
||||
_, err := qs.All(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get immutable tag rule by projectID %d, error: %w", projectID, err)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project
|
||||
func (i *immutableRuleDao) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) {
|
||||
o := dao.GetOrmer()
|
||||
qs := o.QueryTable(&model.ImmutableRule{}).Filter("ProjectID", projectID).Filter("Disabled", false)
|
||||
var r []model.ImmutableRule
|
||||
_, err := qs.All(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get enabled immutable tag rule for by projectID %d, error: %w", projectID, err)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
func (i *immutableRuleDao) DeleteImmutableRule(id int64) (int64, error) {
|
||||
o := dao.GetOrmer()
|
||||
ir := &model.ImmutableRule{ID: id}
|
||||
return o.Delete(ir)
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
package immutabletag
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/dao"
|
||||
dao_model "github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
var (
|
||||
// Mgr is a global variable for the default immutablerule manager implementation
|
||||
Mgr = NewDefaultRuleManager()
|
||||
)
|
||||
|
||||
// Manager ...
|
||||
type Manager interface {
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
CreateImmutableRule(m *model.Metadata) (int64, error)
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
UpdateImmutableRule(projectID int64, ir *model.Metadata) (int64, error)
|
||||
// EnableImmutableRule enable/disable immutable rules
|
||||
EnableImmutableRule(id int64, enabled bool) (int64, error)
|
||||
// GetImmutableRule get immutable rule
|
||||
GetImmutableRule(id int64) (*model.Metadata, error)
|
||||
// QueryImmutableRuleByProjectID get all immutable rule by project
|
||||
QueryImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error)
|
||||
// QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project
|
||||
QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error)
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
DeleteImmutableRule(id int64) (int64, error)
|
||||
}
|
||||
|
||||
type defaultRuleManager struct {
|
||||
dao dao.ImmutableRuleDao
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) CreateImmutableRule(ir *model.Metadata) (int64, error) {
|
||||
daoRule := &dao_model.ImmutableRule{}
|
||||
daoRule.Disabled = ir.Disabled
|
||||
daoRule.ProjectID = ir.ProjectID
|
||||
data, _ := json.Marshal(ir)
|
||||
daoRule.TagFilter = string(data)
|
||||
return drm.dao.CreateImmutableRule(daoRule)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) UpdateImmutableRule(projectID int64, ir *model.Metadata) (int64, error) {
|
||||
daoRule := &dao_model.ImmutableRule{}
|
||||
data, _ := json.Marshal(ir)
|
||||
daoRule.ID = ir.ID
|
||||
daoRule.TagFilter = string(data)
|
||||
return drm.dao.UpdateImmutableRule(projectID, daoRule)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) EnableImmutableRule(id int64, enabled bool) (int64, error) {
|
||||
return drm.dao.ToggleImmutableRule(id, enabled)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) GetImmutableRule(id int64) (*model.Metadata, error) {
|
||||
daoRule, err := drm.dao.GetImmutableRule(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule := &model.Metadata{}
|
||||
if daoRule == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if err = json.Unmarshal([]byte(daoRule.TagFilter), rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.ID = daoRule.ID
|
||||
rule.Disabled = daoRule.Disabled
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) QueryImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error) {
|
||||
daoRules, err := drm.dao.QueryImmutableRuleByProjectID(projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules := make([]model.Metadata, 0)
|
||||
for _, daoRule := range daoRules {
|
||||
rule := model.Metadata{}
|
||||
if err = json.Unmarshal([]byte(daoRule.TagFilter), &rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.ID = daoRule.ID
|
||||
rule.Disabled = daoRule.Disabled
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
sort.Slice(rules, func(i, j int) bool {
|
||||
return rules[i].ID < rules[j].ID
|
||||
})
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error) {
|
||||
daoRules, err := drm.dao.QueryEnabledImmutableRuleByProjectID(projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rules []model.Metadata
|
||||
for _, daoRule := range daoRules {
|
||||
rule := model.Metadata{}
|
||||
if err = json.Unmarshal([]byte(daoRule.TagFilter), &rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.ID = daoRule.ID
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) DeleteImmutableRule(id int64) (int64, error) {
|
||||
return drm.dao.DeleteImmutableRule(id)
|
||||
}
|
||||
|
||||
// NewDefaultRuleManager return a new instance of defaultRuleManager
|
||||
func NewDefaultRuleManager() Manager {
|
||||
return &defaultRuleManager{
|
||||
dao: dao.New(),
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ func (pj *Job) Run(ctx job.Context, params job.Parameters) error {
|
|||
}
|
||||
|
||||
// Run the flow
|
||||
results, err := processor.Process(allCandidates)
|
||||
results, err := processor.Process(ctx.SystemContext(), allCandidates)
|
||||
if err != nil {
|
||||
return logError(myLogger, err)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package index
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -57,7 +58,7 @@ func (suite *IndexTestSuite) TestGet() {
|
|||
require.NoError(suite.T(), err)
|
||||
require.NotNil(suite.T(), p)
|
||||
|
||||
results, err := p.Perform(suite.candidates)
|
||||
results, err := p.Perform(context.TODO(), suite.candidates)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), 1, len(results))
|
||||
assert.Condition(suite.T(), func() (success bool) {
|
||||
|
@ -77,7 +78,7 @@ type fakePerformer struct {
|
|||
}
|
||||
|
||||
// Perform the artifacts
|
||||
func (p *fakePerformer) Perform(candidates []*selector.Candidate) (results []*selector.Result, err error) {
|
||||
func (p *fakePerformer) Perform(ctx context.Context, candidates []*selector.Candidate) (results []*selector.Result, err error) {
|
||||
for _, c := range candidates {
|
||||
results = append(results, &selector.Result{
|
||||
Target: c,
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package action
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/retention/dep"
|
||||
)
|
||||
|
||||
|
@ -37,7 +38,7 @@ type Performer interface {
|
|||
// Returns:
|
||||
// []*art.Result : result infos
|
||||
// error : common error if any errors occurred
|
||||
Perform(candidates []*selector.Candidate) ([]*selector.Result, error)
|
||||
Perform(ctx context.Context, candidates []*selector.Candidate) ([]*selector.Result, error)
|
||||
}
|
||||
|
||||
// PerformerFactory is factory method for creating Performer
|
||||
|
@ -51,7 +52,7 @@ type retainAction struct {
|
|||
}
|
||||
|
||||
// Perform the action
|
||||
func (ra *retainAction) Perform(candidates []*selector.Candidate) (results []*selector.Result, err error) {
|
||||
func (ra *retainAction) Perform(ctx context.Context, candidates []*selector.Candidate) (results []*selector.Result, err error) {
|
||||
retainedShare := make(map[string]bool)
|
||||
immutableShare := make(map[string]bool)
|
||||
for _, c := range candidates {
|
||||
|
@ -62,7 +63,7 @@ func (ra *retainAction) Perform(candidates []*selector.Candidate) (results []*se
|
|||
if _, ok := retainedShare[c.Hash()]; ok {
|
||||
continue
|
||||
}
|
||||
if isImmutable(c) {
|
||||
if isImmutable(ctx, c) {
|
||||
immutableShare[c.Hash()] = true
|
||||
}
|
||||
}
|
||||
|
@ -91,11 +92,11 @@ func (ra *retainAction) Perform(candidates []*selector.Candidate) (results []*se
|
|||
return
|
||||
}
|
||||
|
||||
func isImmutable(c *selector.Candidate) bool {
|
||||
func isImmutable(ctx context.Context, c *selector.Candidate) bool {
|
||||
projectID := c.NamespaceID
|
||||
repo := c.Repository
|
||||
_, repoName := utils.ParseRepository(repo)
|
||||
matched, err := rule.NewRuleMatcher().Match(projectID, selector.Candidate{
|
||||
matched, err := rule.NewRuleMatcher().Match(ctx, projectID, selector.Candidate{
|
||||
Repository: repoName,
|
||||
Tags: c.Tags,
|
||||
NamespaceID: projectID,
|
||||
|
|
|
@ -16,13 +16,14 @@ package action
|
|||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/controller/immutable"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
immumodel "github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
immumodel "github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
"github.com/goharbor/harbor/src/pkg/retention/dep"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -93,7 +94,7 @@ func (suite *TestPerformerSuite) TestPerform() {
|
|||
},
|
||||
}
|
||||
|
||||
results, err := p.Perform(candidates)
|
||||
results, err := p.Perform(orm.Context(), candidates)
|
||||
require.NoError(suite.T(), err)
|
||||
require.Equal(suite.T(), 1, len(results))
|
||||
require.NotNil(suite.T(), results[0].Target)
|
||||
|
@ -171,10 +172,10 @@ func (suite *TestPerformerSuite) TestPerformImmutable() {
|
|||
},
|
||||
},
|
||||
}
|
||||
imid, e := immutabletag.ImmuCtr.CreateImmutableRule(rule)
|
||||
imid, e := immutable.Ctr.CreateImmutableRule(orm.Context(), rule)
|
||||
assert.NoError(suite.T(), e)
|
||||
defer func() {
|
||||
assert.NoError(suite.T(), immutabletag.ImmuCtr.DeleteImmutableRule(imid))
|
||||
assert.NoError(suite.T(), immutable.Ctr.DeleteImmutableRule(orm.Context(), imid))
|
||||
}()
|
||||
|
||||
candidates := []*selector.Candidate{
|
||||
|
@ -190,7 +191,7 @@ func (suite *TestPerformerSuite) TestPerformImmutable() {
|
|||
},
|
||||
}
|
||||
|
||||
results, err := p.Perform(candidates)
|
||||
results, err := p.Perform(orm.Context(), candidates)
|
||||
require.NoError(suite.T(), err)
|
||||
require.Equal(suite.T(), 3, len(results))
|
||||
for _, r := range results {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package or
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"sync"
|
||||
|
||||
|
@ -59,7 +60,7 @@ func New(parameters []*alg.Parameter) alg.Processor {
|
|||
}
|
||||
|
||||
// Process the candidates with the rules
|
||||
func (p *processor) Process(artifacts []*selector.Candidate) ([]*selector.Result, error) {
|
||||
func (p *processor) Process(ctx context.Context, artifacts []*selector.Candidate) ([]*selector.Result, error) {
|
||||
if len(artifacts) == 0 {
|
||||
log.Debug("no artifacts to retention")
|
||||
return make([]*selector.Result, 0), nil
|
||||
|
@ -181,7 +182,7 @@ func (p *processor) Process(artifacts []*selector.Candidate) ([]*selector.Result
|
|||
cl := hash.toList()
|
||||
|
||||
if pf, ok := p.performers[act]; ok {
|
||||
if theRes, err := pf.Perform(cl); err != nil {
|
||||
if theRes, err := pf.Perform(ctx, cl); err != nil {
|
||||
attachedErr = err
|
||||
} else {
|
||||
results = append(results, theRes...)
|
||||
|
|
|
@ -17,6 +17,7 @@ package or
|
|||
import (
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -111,7 +112,7 @@ func (suite *ProcessorTestSuite) TestProcess() {
|
|||
|
||||
p := New(params)
|
||||
|
||||
results, err := p.Process(suite.all)
|
||||
results, err := p.Process(orm.Context(), suite.all)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), 1, len(results))
|
||||
assert.Condition(suite.T(), func() bool {
|
||||
|
@ -142,7 +143,7 @@ func (suite *ProcessorTestSuite) TestProcess2() {
|
|||
|
||||
p := New(params)
|
||||
|
||||
results, err := p.Process(suite.all)
|
||||
results, err := p.Process(orm.Context(), suite.all)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), 1, len(results))
|
||||
assert.Condition(suite.T(), func() bool {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package alg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/retention/policy/action"
|
||||
"github.com/goharbor/harbor/src/pkg/retention/policy/rule"
|
||||
|
@ -32,7 +33,7 @@ type Processor interface {
|
|||
// Returns:
|
||||
// []*art.Result : the processed results
|
||||
// error : common error object if any errors occurred
|
||||
Process(artifacts []*selector.Candidate) ([]*selector.Result, error)
|
||||
Process(ctx context.Context, artifacts []*selector.Candidate) ([]*selector.Result, error)
|
||||
}
|
||||
|
||||
// Parameter for constructing a processor
|
||||
|
|
|
@ -16,6 +16,7 @@ package policy
|
|||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -148,7 +149,7 @@ func (suite *TestBuilderSuite) TestBuild() {
|
|||
require.NoError(suite.T(), err)
|
||||
require.NotNil(suite.T(), p)
|
||||
|
||||
results, err := p.Process(suite.all)
|
||||
results, err := p.Process(orm.Context(), suite.all)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), 1, len(results))
|
||||
assert.Condition(suite.T(), func() (success bool) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package immutable
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/immutable"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
@ -15,8 +16,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/lib"
|
||||
internal_orm "github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
immu_model "github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
immu_model "github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
"github.com/goharbor/harbor/src/pkg/repository"
|
||||
"github.com/goharbor/harbor/src/pkg/tag"
|
||||
tag_model "github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
|
@ -141,7 +141,7 @@ func (suite *HandlerSuite) addImmutableRule(pid int64) int64 {
|
|||
},
|
||||
},
|
||||
}
|
||||
id, err := immutabletag.ImmuCtr.CreateImmutableRule(metadata)
|
||||
id, err := immutable.Ctr.CreateImmutableRule(internal_orm.Context(), metadata)
|
||||
require.NoError(suite.T(), err, "nil error expected but got %s", err)
|
||||
return id
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() {
|
|||
artifact.Mgr.Delete(ctx, afID)
|
||||
repository.Mgr.Delete(ctx, repoID)
|
||||
tag.Mgr.Delete(ctx, tagID)
|
||||
immutabletag.ImmuCtr.DeleteImmutableRule(immuRuleID)
|
||||
immutable.Ctr.DeleteImmutableRule(internal_orm.Context(), immuRuleID)
|
||||
}()
|
||||
|
||||
code1 := doPutManifestRequest(projectID, projectName, "photon", "release-1.10", dgt)
|
||||
|
|
|
@ -48,6 +48,7 @@ func New() http.Handler {
|
|||
GCAPI: newGCAPI(),
|
||||
QuotaAPI: newQuotaAPI(),
|
||||
RetentionAPI: newRetentionAPI(),
|
||||
ImmutableAPI: newImmutableAPI(),
|
||||
OidcAPI: newOIDCAPI(),
|
||||
})
|
||||
if err != nil {
|
||||
|
|
143
src/server/v2.0/handler/immutable.go
Normal file
143
src/server/v2.0/handler/immutable.go
Normal file
|
@ -0,0 +1,143 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/controller/immutable"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
handler_model "github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/immutable"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newImmutableAPI() *immutableAPI {
|
||||
return &immutableAPI{
|
||||
immuCtl: immutable.Ctr,
|
||||
projectCtr: project.Ctl,
|
||||
}
|
||||
}
|
||||
|
||||
type immutableAPI struct {
|
||||
BaseAPI
|
||||
immuCtl immutable.Controller
|
||||
projectCtr project.Controller
|
||||
}
|
||||
|
||||
func (ia *immutableAPI) CreateImmuRule(ctx context.Context, params operation.CreateImmuRuleParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := ia.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionCreate, rbac.ResourceImmutableTag); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
metadata := model.Metadata{}
|
||||
lib.JSONCopy(&metadata, params.ImmutableRule)
|
||||
|
||||
projectID, err := ia.getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
metadata.ProjectID = projectID
|
||||
|
||||
id, err := ia.immuCtl.CreateImmutableRule(ctx, &metadata)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
location := fmt.Sprintf("%s/%d", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), id)
|
||||
return operation.NewCreateImmuRuleCreated().WithLocation(location)
|
||||
}
|
||||
|
||||
func (ia *immutableAPI) DeleteImmuRule(ctx context.Context, params operation.DeleteImmuRuleParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := ia.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete, rbac.ResourceImmutableTag); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := ia.immuCtl.DeleteImmutableRule(ctx, params.ImmutableRuleID); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
return operation.NewDeleteImmuRuleOK()
|
||||
}
|
||||
|
||||
func (ia *immutableAPI) UpdateImmuRule(ctx context.Context, params operation.UpdateImmuRuleParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := ia.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionUpdate, rbac.ResourceImmutableTag); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
metadata := model.Metadata{}
|
||||
lib.JSONCopy(&metadata, params.ImmutableRule)
|
||||
|
||||
projectID, err := ia.getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
metadata.ProjectID = projectID
|
||||
|
||||
if err := ia.immuCtl.UpdateImmutableRule(ctx, projectID, &metadata); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
return operation.NewUpdateImmuRuleOK()
|
||||
}
|
||||
|
||||
func (ia *immutableAPI) ListImmuRules(ctx context.Context, params operation.ListImmuRulesParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := ia.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionList, rbac.ResourceImmutableTag); err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
query, err := ia.BuildQuery(ctx, params.Q, params.Page, params.PageSize)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
projectID, err := ia.getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
query.Keywords["ProjectID"] = projectID
|
||||
|
||||
total, err := ia.immuCtl.Count(ctx, query)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
rules, err := ia.immuCtl.ListImmutableRules(ctx, query)
|
||||
if err != nil {
|
||||
return ia.SendError(ctx, err)
|
||||
}
|
||||
|
||||
var results []*models.ImmutableRule
|
||||
for _, r := range rules {
|
||||
results = append(results, handler_model.NewImmutableRule(r).ToSwagger())
|
||||
}
|
||||
|
||||
return operation.NewListImmuRulesOK().
|
||||
WithXTotalCount(total).
|
||||
WithLink(ia.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
|
||||
WithPayload(results)
|
||||
}
|
||||
|
||||
func (ia *immutableAPI) getProjectID(ctx context.Context, projectNameOrID interface{}) (int64, error) {
|
||||
projectName, ok := projectNameOrID.(string)
|
||||
if ok {
|
||||
p, err := ia.projectCtr.Get(ctx, projectName, project.Metadata(false))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return p.ProjectID, nil
|
||||
}
|
||||
projectID, ok := projectNameOrID.(int64)
|
||||
if ok {
|
||||
return projectID, nil
|
||||
}
|
||||
return 0, errors.New("unknown project identifier type")
|
||||
}
|
61
src/server/v2.0/handler/model/immutable.go
Normal file
61
src/server/v2.0/handler/model/immutable.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
pkg_model "github.com/goharbor/harbor/src/pkg/immutable/model"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
)
|
||||
|
||||
// ImmutableRule ...
|
||||
type ImmutableRule struct {
|
||||
*pkg_model.Metadata
|
||||
}
|
||||
|
||||
// ToSwagger ...
|
||||
func (ir *ImmutableRule) ToSwagger() *models.ImmutableRule {
|
||||
return &models.ImmutableRule{
|
||||
ID: ir.ID,
|
||||
Disabled: ir.Disabled,
|
||||
Action: ir.Action,
|
||||
Priority: int64(ir.Priority),
|
||||
ScopeSelectors: ir.ToScopeSelectors(),
|
||||
TagSelectors: ir.ToTagSelectors(),
|
||||
Template: ir.Template,
|
||||
}
|
||||
}
|
||||
|
||||
// ToTagSelectors ...
|
||||
func (ir *ImmutableRule) ToTagSelectors() []*models.ImmutableSelector {
|
||||
var results []*models.ImmutableSelector
|
||||
for _, t := range ir.TagSelectors {
|
||||
results = append(results, &models.ImmutableSelector{
|
||||
Decoration: t.Decoration,
|
||||
Kind: t.Kind,
|
||||
Pattern: t.Pattern,
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// ToScopeSelectors ...
|
||||
func (ir *ImmutableRule) ToScopeSelectors() map[string][]models.ImmutableSelector {
|
||||
results := map[string][]models.ImmutableSelector{}
|
||||
for k, v := range ir.ScopeSelectors {
|
||||
var scopeSelectors []models.ImmutableSelector
|
||||
for _, s := range v {
|
||||
scopeSelectors = append(scopeSelectors, models.ImmutableSelector{
|
||||
Decoration: s.Decoration,
|
||||
Kind: s.Kind,
|
||||
Pattern: s.Pattern,
|
||||
})
|
||||
}
|
||||
results[k] = scopeSelectors
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// NewImmutableRule ...
|
||||
func NewImmutableRule(meta *pkg_model.Metadata) *ImmutableRule {
|
||||
return &ImmutableRule{
|
||||
Metadata: meta,
|
||||
}
|
||||
}
|
|
@ -55,9 +55,6 @@ func registerLegacyRoutes() {
|
|||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/webhook/events", &api.NotificationPolicyAPI{}, "get:GetSupportedEventTypes")
|
||||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/webhook/jobs/", &api.NotificationJobAPI{}, "get:List")
|
||||
|
||||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/immutabletagrules", &api.ImmutableTagRuleAPI{}, "get:List;post:Post")
|
||||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/immutabletagrules/:id([0-9]+)", &api.ImmutableTagRuleAPI{})
|
||||
|
||||
beego.Router("/api/"+version+"/configurations", &api.ConfigAPI{}, "get:Get;put:Put")
|
||||
beego.Router("/api/"+version+"/statistics", &api.StatisticAPI{})
|
||||
beego.Router("/api/"+version+"/labels", &api.LabelAPI{}, "post:Post;get:List")
|
||||
|
@ -70,9 +67,6 @@ func registerLegacyRoutes() {
|
|||
beego.Router("/api/"+version+"/registries/:id/info", &api.RegistryAPI{}, "get:GetInfo")
|
||||
beego.Router("/api/"+version+"/registries/:id/namespace", &api.RegistryAPI{}, "get:GetNamespace")
|
||||
|
||||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/immutabletagrules", &api.ImmutableTagRuleAPI{}, "get:List;post:Post")
|
||||
beego.Router("/api/"+version+"/projects/:pid([0-9]+)/immutabletagrules/:id([0-9]+)", &api.ImmutableTagRuleAPI{})
|
||||
|
||||
// APIs for chart repository
|
||||
if config.WithChartMuseum() {
|
||||
// Labels for chart
|
||||
|
|
148
src/testing/pkg/immutable/dao/dao.go
Normal file
148
src/testing/pkg/immutable/dao/dao.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Code generated by mockery v2.1.0. DO NOT EDIT.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
model "github.com/goharbor/harbor/src/pkg/immutable/dao/model"
|
||||
|
||||
q "github.com/goharbor/harbor/src/lib/q"
|
||||
)
|
||||
|
||||
// DAO is an autogenerated mock type for the DAO type
|
||||
type DAO struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Count provides a mock function with given fields: ctx, query
|
||||
func (_m *DAO) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateImmutableRule provides a mock function with given fields: ctx, ir
|
||||
func (_m *DAO) CreateImmutableRule(ctx context.Context, ir *model.ImmutableRule) (int64, error) {
|
||||
ret := _m.Called(ctx, ir)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *model.ImmutableRule) int64); ok {
|
||||
r0 = rf(ctx, ir)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *model.ImmutableRule) error); ok {
|
||||
r1 = rf(ctx, ir)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteImmutableRule provides a mock function with given fields: ctx, id
|
||||
func (_m *DAO) DeleteImmutableRule(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetImmutableRule provides a mock function with given fields: ctx, id
|
||||
func (_m *DAO) GetImmutableRule(ctx context.Context, id int64) (*model.ImmutableRule, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 *model.ImmutableRule
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) *model.ImmutableRule); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.ImmutableRule)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListImmutableRules provides a mock function with given fields: ctx, query
|
||||
func (_m *DAO) ListImmutableRules(ctx context.Context, query *q.Query) ([]*model.ImmutableRule, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
var r0 []*model.ImmutableRule
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*model.ImmutableRule); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.ImmutableRule)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ToggleImmutableRule provides a mock function with given fields: ctx, id, status
|
||||
func (_m *DAO) ToggleImmutableRule(ctx context.Context, id int64, status bool) error {
|
||||
ret := _m.Called(ctx, id, status)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, bool) error); ok {
|
||||
r0 = rf(ctx, id, status)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateImmutableRule provides a mock function with given fields: ctx, projectID, ir
|
||||
func (_m *DAO) UpdateImmutableRule(ctx context.Context, projectID int64, ir *model.ImmutableRule) error {
|
||||
ret := _m.Called(ctx, projectID, ir)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, *model.ImmutableRule) error); ok {
|
||||
r0 = rf(ctx, projectID, ir)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package immutabletag
|
||||
package immutable
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
@ -11,7 +12,7 @@ type FakeMatcher struct {
|
|||
}
|
||||
|
||||
// Match ...
|
||||
func (f *FakeMatcher) Match(pid int64, c selector.Candidate) (bool, error) {
|
||||
func (f *FakeMatcher) Match(ctx context.Context, pid int64, c selector.Candidate) (bool, error) {
|
||||
args := f.Called()
|
||||
return args.Bool(0), args.Error(1)
|
||||
}
|
|
@ -34,3 +34,4 @@ package pkg
|
|||
//go:generate mockery --case snake --dir ../../pkg/robot --name Manager --output ./robot --outpkg robot
|
||||
//go:generate mockery --case snake --dir ../../pkg/robot/dao --name DAO --output ./robot/dao --outpkg dao
|
||||
//go:generate mockery --case snake --dir ../../pkg/repository/dao --name DAO --output ./repository/dao --outpkg dao
|
||||
//go:generate mockery --case snake --dir ../../pkg/immutable/dao --name DAO --output ./immutable/dao --outpkg dao
|
||||
|
|
|
@ -28,7 +28,7 @@ def get_endpoint():
|
|||
|
||||
def _create_client(server, credential, debug, api_type="products"):
|
||||
cfg = None
|
||||
if api_type in ('projectv2', 'artifact', 'repository', 'scanner', 'scan', 'scanall', 'preheat', 'quota', 'replication', 'robot', 'gc', 'retention'):
|
||||
if api_type in ('projectv2', 'artifact', 'repository', 'scanner', 'scan', 'scanall', 'preheat', 'quota', 'replication', 'robot', 'gc', 'retention', "immutable"):
|
||||
cfg = v2_swagger_client.Configuration()
|
||||
else:
|
||||
cfg = swagger_client.Configuration()
|
||||
|
@ -65,6 +65,7 @@ def _create_client(server, credential, debug, api_type="products"):
|
|||
"robot": v2_swagger_client.RobotApi(v2_swagger_client.ApiClient(cfg)),
|
||||
"gc": v2_swagger_client.GcApi(v2_swagger_client.ApiClient(cfg)),
|
||||
"retention": v2_swagger_client.RetentionApi(v2_swagger_client.ApiClient(cfg)),
|
||||
"immutable": v2_swagger_client.ImmutableApi(v2_swagger_client.ApiClient(cfg)),
|
||||
}.get(api_type,'Error: Wrong API type')
|
||||
|
||||
def _assert_status_code(expect_code, return_code, err_msg = r"HTTPS status code s not as we expected. Expected {}, while actual HTTPS status code is {}."):
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import base
|
||||
import swagger_client
|
||||
from swagger_client.rest import ApiException
|
||||
import v2_swagger_client
|
||||
from v2_swagger_client.rest import ApiException
|
||||
|
||||
class Tag_Immutability(base.Base, object):
|
||||
def __init__(self):
|
||||
super(Tag_Immutability,self).__init__(api_type = "immutable")
|
||||
|
||||
class Tag_Immutability(base.Base):
|
||||
def create_tag_immutability_policy_rule(self, project_id, selector_repository_decoration = "repoMatches",
|
||||
selector_repository="**", selector_tag_decoration = "matches",
|
||||
selector_tag="**", expect_status_code = 201, **kwargs):
|
||||
#repoExcludes,excludes
|
||||
client = self._get_client(**kwargs)
|
||||
immutable_rule = swagger_client.ImmutableRule(
|
||||
immutable_rule = v2_swagger_client.ImmutableRule(
|
||||
action="immutable",
|
||||
template="immutable_template",
|
||||
priority = 0,
|
||||
|
@ -32,7 +35,7 @@ class Tag_Immutability(base.Base):
|
|||
]
|
||||
)
|
||||
try:
|
||||
_, status_code, header = client.projects_project_id_immutabletagrules_post_with_http_info(project_id, immutable_rule)
|
||||
_, status_code, header = client.create_immu_rule_with_http_info(project_id, immutable_rule)
|
||||
except ApiException as e:
|
||||
base._assert_status_code(expect_status_code, e.status)
|
||||
else:
|
||||
|
@ -42,11 +45,13 @@ class Tag_Immutability(base.Base):
|
|||
|
||||
def list_tag_immutability_policy_rules(self, project_id, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
return client.projects_project_id_immutabletagrules_get(project_id)
|
||||
return client.list_immu_rules_with_http_info(project_id)
|
||||
|
||||
def get_rule(self, project_id, rule_id, **kwargs):
|
||||
rules = self.list_tag_immutability_policy_rules(project_id, **kwargs)
|
||||
for r in rules:
|
||||
if len(rules) <= 0:
|
||||
return None
|
||||
for r in rules[0]:
|
||||
if r.id == rule_id:
|
||||
return r
|
||||
return None
|
||||
|
@ -67,7 +72,7 @@ class Tag_Immutability(base.Base):
|
|||
rule.disabled = disabled
|
||||
client = self._get_client(**kwargs)
|
||||
try:
|
||||
_, status_code, header = client.projects_project_id_immutabletagrules_id_put_with_http_info(project_id, rule_id, rule)
|
||||
_, status_code, header = client.update_immu_rule_with_http_info(project_id, rule_id, rule)
|
||||
except ApiException as e:
|
||||
base._assert_status_code(expect_status_code, e.status)
|
||||
if expect_response_body is not None:
|
||||
|
|
Loading…
Reference in New Issue
Block a user