mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 20:26:13 +01:00
Merge pull request #9274 from wy65701436/immu-refatctor
refactor immutable dao code to align the new structure under pkg
This commit is contained in:
commit
a2938c5d78
@ -1,74 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
)
|
||||
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
func CreateImmutableRule(ir *models.ImmutableRule) (int64, error) {
|
||||
ir.Enabled = true
|
||||
o := GetOrmer()
|
||||
return o.Insert(ir)
|
||||
}
|
||||
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
func UpdateImmutableRule(projectID int64, ir *models.ImmutableRule) (int64, error) {
|
||||
ir.ProjectID = projectID
|
||||
o := GetOrmer()
|
||||
return o.Update(ir, "TagFilter")
|
||||
}
|
||||
|
||||
// ToggleImmutableRule enable/disable immutable rules
|
||||
func ToggleImmutableRule(id int64, enabled bool) (int64, error) {
|
||||
o := GetOrmer()
|
||||
ir := &models.ImmutableRule{ID: id, Enabled: enabled}
|
||||
return o.Update(ir, "Enabled")
|
||||
}
|
||||
|
||||
// GetImmutableRule get immutable rule
|
||||
func GetImmutableRule(id int64) (*models.ImmutableRule, error) {
|
||||
o := GetOrmer()
|
||||
ir := &models.ImmutableRule{ID: id}
|
||||
err := o.Read(ir)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ir, nil
|
||||
}
|
||||
|
||||
// QueryImmutableRuleByProjectID get all immutable rule by project
|
||||
func QueryImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error) {
|
||||
o := GetOrmer()
|
||||
qs := o.QueryTable(&models.ImmutableRule{}).Filter("ProjectID", projectID)
|
||||
var r []models.ImmutableRule
|
||||
_, err := qs.All(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get immutable tag rule by projectID %d, error: %v", projectID, err)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project
|
||||
func QueryEnabledImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error) {
|
||||
o := GetOrmer()
|
||||
qs := o.QueryTable(&models.ImmutableRule{}).Filter("ProjectID", projectID).Filter("Enabled", true)
|
||||
var r []models.ImmutableRule
|
||||
_, err := qs.All(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get enabled immutable tag rule for by projectID %d, error: %v", projectID, err)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
func DeleteImmutableRule(id int64) (int64, error) {
|
||||
o := GetOrmer()
|
||||
ir := &models.ImmutableRule{ID: id}
|
||||
return o.Delete(ir)
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
)
|
||||
|
||||
func TestCreateImmutableRule(t *testing.T) {
|
||||
ir := &models.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := CreateImmutableRule(ir)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
if id <= 0 {
|
||||
t.Error("Can not create immutable tag rule")
|
||||
}
|
||||
_, err = DeleteImmutableRule(id)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateImmutableRule(t *testing.T) {
|
||||
ir := &models.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := CreateImmutableRule(ir)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
if id <= 0 {
|
||||
t.Error("Can not create immutable tag rule")
|
||||
}
|
||||
|
||||
updatedIR := &models.ImmutableRule{ID: id, TagFilter: "1.2.0", ProjectID: 1}
|
||||
updatedCnt, err := UpdateImmutableRule(1, updatedIR)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
if updatedCnt <= 0 {
|
||||
t.Error("Failed to update immutable id")
|
||||
}
|
||||
|
||||
newIr, err := GetImmutableRule(id)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
|
||||
if newIr.TagFilter != "1.2.0" {
|
||||
t.Error("Failed to update immutable tag")
|
||||
}
|
||||
|
||||
defer DeleteImmutableRule(id)
|
||||
|
||||
}
|
||||
|
||||
func TestEnableImmutableRule(t *testing.T) {
|
||||
ir := &models.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := CreateImmutableRule(ir)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
if id <= 0 {
|
||||
t.Error("Can not create immutable tag rule")
|
||||
}
|
||||
|
||||
ToggleImmutableRule(id, false)
|
||||
newIr, err := GetImmutableRule(id)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
|
||||
if newIr.Enabled != false {
|
||||
t.Error("Failed to disable the immutable rule")
|
||||
}
|
||||
|
||||
defer DeleteImmutableRule(id)
|
||||
}
|
||||
|
||||
func TestGetImmutableRuleByProject(t *testing.T) {
|
||||
irs := []*models.ImmutableRule{
|
||||
{TagFilter: "version1", ProjectID: 99},
|
||||
{TagFilter: "version2", ProjectID: 99},
|
||||
{TagFilter: "version3", ProjectID: 99},
|
||||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for _, ir := range irs {
|
||||
CreateImmutableRule(ir)
|
||||
}
|
||||
|
||||
qrs, err := QueryImmutableRuleByProjectID(99)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
|
||||
if len(qrs) != 4 {
|
||||
t.Error("Failed to query 4 rows!")
|
||||
}
|
||||
|
||||
defer ExecuteBatchSQL([]string{"delete from immutable_tag_rule where project_id = 99 "})
|
||||
|
||||
}
|
||||
func TestGetEnabledImmutableRuleByProject(t *testing.T) {
|
||||
irs := []*models.ImmutableRule{
|
||||
{TagFilter: "version1", ProjectID: 99},
|
||||
{TagFilter: "version2", ProjectID: 99},
|
||||
{TagFilter: "version3", ProjectID: 99},
|
||||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for i, ir := range irs {
|
||||
id, _ := CreateImmutableRule(ir)
|
||||
if i == 1 {
|
||||
ToggleImmutableRule(id, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
qrs, err := QueryEnabledImmutableRuleByProjectID(99)
|
||||
if err != nil {
|
||||
t.Errorf("error: %+v", err)
|
||||
}
|
||||
|
||||
if len(qrs) != 3 {
|
||||
t.Errorf("Failed to query 3 rows!, got %v", len(qrs))
|
||||
}
|
||||
|
||||
defer ExecuteBatchSQL([]string{"delete from immutable_tag_rule where project_id = 99 "})
|
||||
|
||||
}
|
@ -46,6 +46,5 @@ func init() {
|
||||
new(CVEWhitelist),
|
||||
new(Quota),
|
||||
new(QuotaUsage),
|
||||
new(ImmutableRule),
|
||||
)
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/retention/policy/rule"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
// ImmutableTagRuleAPI ...
|
||||
type ImmutableTagRuleAPI struct {
|
||||
BaseController
|
||||
manager immutabletag.RuleManager
|
||||
ctr immutabletag.APIController
|
||||
projectID int64
|
||||
ID int64
|
||||
}
|
||||
@ -49,7 +46,7 @@ func (itr *ImmutableTagRuleAPI) Prepare() {
|
||||
itr.ID = ruleID
|
||||
}
|
||||
|
||||
itr.manager = immutabletag.NewDefaultRuleManager()
|
||||
itr.ctr = immutabletag.NewAPIController(immutabletag.NewDefaultRuleManager())
|
||||
|
||||
if strings.EqualFold(itr.Ctx.Request.Method, "get") {
|
||||
if !itr.requireAccess(rbac.ActionList) {
|
||||
@ -77,7 +74,7 @@ func (itr *ImmutableTagRuleAPI) requireAccess(action rbac.Action) bool {
|
||||
|
||||
// List list all immutable tag rules of current project
|
||||
func (itr *ImmutableTagRuleAPI) List() {
|
||||
rules, err := itr.manager.QueryImmutableRuleByProjectID(itr.projectID)
|
||||
rules, err := itr.ctr.ListImmutableRules(itr.projectID)
|
||||
if err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
@ -87,19 +84,14 @@ func (itr *ImmutableTagRuleAPI) List() {
|
||||
|
||||
// Post create immutable tag rule
|
||||
func (itr *ImmutableTagRuleAPI) Post() {
|
||||
ir := &models.ImmutableRule{}
|
||||
if err := itr.DecodeJSONReq(ir); err != nil {
|
||||
itr.SendBadRequestError(fmt.Errorf("the filter must be a valid json, failed to parse json, error %+v", err))
|
||||
ir := &model.Metadata{}
|
||||
isValid, err := itr.DecodeJSONReqAndValidate(ir)
|
||||
if !isValid {
|
||||
itr.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !isValidSelectorJSON(ir.TagFilter) {
|
||||
itr.SendBadRequestError(fmt.Errorf("the filter should be a valid json"))
|
||||
return
|
||||
}
|
||||
|
||||
ir.ProjectID = itr.projectID
|
||||
id, err := itr.manager.CreateImmutableRule(ir)
|
||||
id, err := itr.ctr.CreateImmutableRule(ir)
|
||||
if err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
@ -114,7 +106,7 @@ func (itr *ImmutableTagRuleAPI) Delete() {
|
||||
itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID))
|
||||
return
|
||||
}
|
||||
_, err := itr.manager.DeleteImmutableRule(itr.ID)
|
||||
err := itr.ctr.DeleteImmutableRule(itr.ID)
|
||||
if err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
@ -123,9 +115,9 @@ func (itr *ImmutableTagRuleAPI) Delete() {
|
||||
|
||||
// Put update an immutable tag rule
|
||||
func (itr *ImmutableTagRuleAPI) Put() {
|
||||
ir := &models.ImmutableRule{}
|
||||
ir := &model.Metadata{}
|
||||
if err := itr.DecodeJSONReq(ir); err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
itr.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
ir.ID = itr.ID
|
||||
@ -135,32 +127,9 @@ func (itr *ImmutableTagRuleAPI) Put() {
|
||||
itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID))
|
||||
return
|
||||
}
|
||||
if len(ir.TagFilter) == 0 {
|
||||
if _, err := itr.manager.EnableImmutableRule(itr.ID, ir.Enabled); err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
if !isValidSelectorJSON(ir.TagFilter) {
|
||||
itr.SendBadRequestError(fmt.Errorf("the filter should be a valid json"))
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := itr.manager.UpdateImmutableRule(itr.ID, ir); err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
if err := itr.ctr.UpdateImmutableRule(itr.projectID, ir); err != nil {
|
||||
itr.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func isValidSelectorJSON(filter string) bool {
|
||||
tagSector := &rule.Metadata{}
|
||||
err := json.Unmarshal([]byte(filter), tagSector)
|
||||
if err != nil {
|
||||
log.Errorf("The json is %v", filter)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -7,24 +7,34 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
func TestImmutableTagRuleAPI_List(t *testing.T) {
|
||||
|
||||
tagFilter := `{
|
||||
"id":0,
|
||||
"priority":0,
|
||||
"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,
|
||||
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(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter})
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -46,7 +56,7 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
|
||||
credential: admin,
|
||||
},
|
||||
postFunc: func(responseRecorder *httptest.ResponseRecorder) error {
|
||||
var rules []models.ImmutableRule
|
||||
var rules []model.Metadata
|
||||
err := json.Unmarshal([]byte(responseRecorder.Body.String()), &rules)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -54,7 +64,7 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
|
||||
if len(rules) <= 0 {
|
||||
return fmt.Errorf("no rules found")
|
||||
}
|
||||
if rules[0].TagFilter != tagFilter {
|
||||
if rules[0].TagSelectors[0].Kind != "doublestar" {
|
||||
return fmt.Errorf("rule is not expected. actual: %v", responseRecorder.Body.String())
|
||||
}
|
||||
return nil
|
||||
@ -86,43 +96,68 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
|
||||
|
||||
func TestImmutableTagRuleAPI_Post(t *testing.T) {
|
||||
|
||||
tagFilter := `{
|
||||
"id":0,
|
||||
"priority":0,
|
||||
"disabled":false,
|
||||
"action":"immutable",
|
||||
"template":"immutable_template",
|
||||
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}],
|
||||
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]}
|
||||
}`
|
||||
body := &models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter}
|
||||
// body := `{
|
||||
// "id":0,
|
||||
// "projectID":1,
|
||||
// "priority":0,
|
||||
// "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: body,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
// 200
|
||||
// 201
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: admin,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusCreated,
|
||||
},
|
||||
// 200
|
||||
// 201
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projAdmin,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusCreated,
|
||||
},
|
||||
@ -132,7 +167,7 @@ func TestImmutableTagRuleAPI_Post(t *testing.T) {
|
||||
method: http.MethodPost,
|
||||
url: "/api/projects/1/immutabletagrules",
|
||||
credential: projGuest,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
@ -142,40 +177,63 @@ func TestImmutableTagRuleAPI_Post(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
tagFilter := `{
|
||||
"id":0,
|
||||
"priority":0,
|
||||
"disabled":false,
|
||||
"action":"immutable",
|
||||
"template":"immutable_template",
|
||||
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}],
|
||||
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]}
|
||||
}`
|
||||
tagFilter2 := `{
|
||||
"id":0,
|
||||
"priority":0,
|
||||
"disabled":false,
|
||||
"action":"immutable",
|
||||
"template":"immutable_template",
|
||||
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"release-1.6.0"}],
|
||||
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"regids"}]}
|
||||
}`
|
||||
|
||||
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(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter})
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer mgr.DeleteImmutableRule(id)
|
||||
|
||||
url := fmt.Sprintf("/api/projects/1/immutabletagrules/%d", id)
|
||||
body := &models.ImmutableRule{ID: id, ProjectID: 1, TagFilter: tagFilter2}
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
@ -185,7 +243,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: admin,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
@ -195,7 +253,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: projAdmin,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
@ -205,7 +263,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
method: http.MethodPut,
|
||||
url: url,
|
||||
credential: projGuest,
|
||||
bodyJSON: body,
|
||||
bodyJSON: metadata2,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
@ -214,17 +272,29 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestImmutableTagRuleAPI_Delete(t *testing.T) {
|
||||
tagFilter := `{
|
||||
"id":0,
|
||||
"priority":0,
|
||||
"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,
|
||||
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(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter})
|
||||
id, err := mgr.CreateImmutableRule(metadata)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
70
src/pkg/immutabletag/controller.go
Normal file
70
src/pkg/immutabletag/controller.go
Normal file
@ -0,0 +1,70 @@
|
||||
package immutabletag
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
)
|
||||
|
||||
// APIController to handle the requests related with immutabletag
|
||||
type APIController 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.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) APIController {
|
||||
return &DefaultAPIController{
|
||||
manager: immutableMgr,
|
||||
}
|
||||
}
|
1
src/pkg/immutabletag/controller_test.go
Normal file
1
src/pkg/immutabletag/controller_test.go
Normal file
@ -0,0 +1 @@
|
||||
package immutabletag
|
93
src/pkg/immutabletag/dao/immutable.go
Normal file
93
src/pkg/immutabletag/dao/immutable.go
Normal file
@ -0,0 +1,93 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"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, enabled 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.Enabled = true
|
||||
o := dao.GetOrmer()
|
||||
return o.Insert(ir)
|
||||
}
|
||||
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
func (i *immutableRuleDao) UpdateImmutableRule(projectID int64, ir *model.ImmutableRule) (int64, error) {
|
||||
ir.ProjectID = projectID
|
||||
o := dao.GetOrmer()
|
||||
return o.Update(ir, "TagFilter")
|
||||
}
|
||||
|
||||
// ToggleImmutableRule enable/disable immutable rules
|
||||
func (i *immutableRuleDao) ToggleImmutableRule(id int64, enabled bool) (int64, error) {
|
||||
o := dao.GetOrmer()
|
||||
ir := &model.ImmutableRule{ID: id, Enabled: enabled}
|
||||
return o.Update(ir, "Enabled")
|
||||
}
|
||||
|
||||
// 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 == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
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)
|
||||
var r []model.ImmutableRule
|
||||
_, err := qs.All(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get immutable tag rule by projectID %d, error: %v", 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("Enabled", true)
|
||||
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: %v", 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)
|
||||
}
|
113
src/pkg/immutabletag/dao/immutable_test.go
Normal file
113
src/pkg/immutabletag/dao/immutable_test.go
Normal file
@ -0,0 +1,113 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type immutableRuleDaoTestSuite struct {
|
||||
suite.Suite
|
||||
require *require.Assertions
|
||||
assert *assert.Assertions
|
||||
dao ImmutableRuleDao
|
||||
id int64
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) SetupSuite() {
|
||||
t.require = require.New(t.T())
|
||||
t.assert = assert.New(t.T())
|
||||
dao.PrepareTestForPostgresSQL()
|
||||
t.dao = New()
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestCreateImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(ir)
|
||||
t.require.Nil(err)
|
||||
t.require.True(id > 0, "Can not create immutable tag rule")
|
||||
_, err = t.dao.DeleteImmutableRule(id)
|
||||
t.require.Nil(err)
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestUpdateImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(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)
|
||||
t.require.Nil(err)
|
||||
t.require.True(updatedCnt > 0, "Failed to update immutable id")
|
||||
|
||||
newIr, err := t.dao.GetImmutableRule(id)
|
||||
t.require.Nil(err)
|
||||
t.require.True(newIr.TagFilter == "1.2.0", "Failed to update immutable tag")
|
||||
|
||||
defer t.dao.DeleteImmutableRule(id)
|
||||
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestEnableImmutableRule() {
|
||||
ir := &model.ImmutableRule{TagFilter: "**", ProjectID: 1}
|
||||
id, err := t.dao.CreateImmutableRule(ir)
|
||||
t.require.Nil(err)
|
||||
t.require.True(id > 0, "Can not create immutable tag rule")
|
||||
|
||||
t.dao.ToggleImmutableRule(id, false)
|
||||
newIr, err := t.dao.GetImmutableRule(id)
|
||||
|
||||
t.require.Nil(err)
|
||||
t.require.False(newIr.Enabled, "Failed to disable the immutable rule")
|
||||
|
||||
defer t.dao.DeleteImmutableRule(id)
|
||||
}
|
||||
|
||||
func (t *immutableRuleDaoTestSuite) TestGetImmutableRuleByProject() {
|
||||
irs := []*model.ImmutableRule{
|
||||
{TagFilter: "version1", ProjectID: 99},
|
||||
{TagFilter: "version2", ProjectID: 99},
|
||||
{TagFilter: "version3", ProjectID: 99},
|
||||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for _, ir := range irs {
|
||||
t.dao.CreateImmutableRule(ir)
|
||||
}
|
||||
|
||||
qrs, err := t.dao.QueryImmutableRuleByProjectID(99)
|
||||
t.require.Nil(err)
|
||||
t.require.True(len(qrs) == 4, "Failed to query 4 rows!")
|
||||
|
||||
defer dao.ExecuteBatchSQL([]string{"delete from immutable_tag_rule where project_id = 99 "})
|
||||
|
||||
}
|
||||
func (t *immutableRuleDaoTestSuite) TestGetEnabledImmutableRuleByProject() {
|
||||
irs := []*model.ImmutableRule{
|
||||
{TagFilter: "version1", ProjectID: 99},
|
||||
{TagFilter: "version2", ProjectID: 99},
|
||||
{TagFilter: "version3", ProjectID: 99},
|
||||
{TagFilter: "version4", ProjectID: 99},
|
||||
}
|
||||
for i, ir := range irs {
|
||||
id, _ := t.dao.CreateImmutableRule(ir)
|
||||
if i == 1 {
|
||||
t.dao.ToggleImmutableRule(id, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
qrs, err := t.dao.QueryEnabledImmutableRuleByProjectID(99)
|
||||
t.require.Nil(err)
|
||||
t.require.True(len(qrs) == 3, "Failed to query 3 rows!, got %v", len(qrs))
|
||||
|
||||
defer dao.ExecuteBatchSQL([]string{"delete from immutable_tag_rule where project_id = 99 "})
|
||||
|
||||
}
|
||||
|
||||
func TestImmutableRuleDaoTestSuite(t *testing.T) {
|
||||
suite.Run(t, &immutableRuleDaoTestSuite{})
|
||||
}
|
@ -1,4 +1,12 @@
|
||||
package models
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
orm.RegisterModel(&ImmutableRule{})
|
||||
}
|
||||
|
||||
// ImmutableRule - rule which filter image tags should be immutable.
|
||||
type ImmutableRule struct {
|
110
src/pkg/immutabletag/manager.go
Normal file
110
src/pkg/immutabletag/manager.go
Normal file
@ -0,0 +1,110 @@
|
||||
package immutabletag
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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.Enabled = !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.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 err = json.Unmarshal([]byte(daoRule.TagFilter), rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) QueryImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error) {
|
||||
daoRules, err := drm.dao.QueryImmutableRuleByProjectID(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
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
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
|
||||
}
|
||||
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(),
|
||||
}
|
||||
}
|
201
src/pkg/immutabletag/manager_test.go
Normal file
201
src/pkg/immutabletag/manager_test.go
Normal file
@ -0,0 +1,201 @@
|
||||
package immutabletag
|
||||
|
||||
import (
|
||||
dao_model "github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
|
||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"os"
|
||||
"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
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) SetupSuite() {
|
||||
m.t = m.T()
|
||||
m.assert = assert.New(m.t)
|
||||
m.require = require.New(m.t)
|
||||
|
||||
err := os.Setenv("RUN_MODE", "TEST")
|
||||
m.require.Nil(err)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TearDownSuite() {
|
||||
err := os.Unsetenv("RUN_MODE")
|
||||
m.require.Nil(err)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) SetupTest() {
|
||||
m.mockImmutableDao = &mockImmutableDao{}
|
||||
Mgr = &defaultRuleManager{
|
||||
dao: m.mockImmutableDao,
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerTestingSuite(t *testing.T) {
|
||||
suite.Run(t, &managerTestingSuite{})
|
||||
}
|
||||
|
||||
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.require.Nil(err)
|
||||
m.assert.Equal(int64(1), id)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestQueryImmutableRuleByProjectID() {
|
||||
m.mockImmutableDao.On("QueryImmutableRuleByProjectID", mock.Anything).Return([]dao_model.ImmutableRule{
|
||||
{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
Enabled: true,
|
||||
TagFilter: "{\"id\":1, \"projectID\":1,\"priority\":0,\"disabled\":false,\"action\":\"immutable\"," +
|
||||
"\"template\":\"immutable_template\"," +
|
||||
"\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}]," +
|
||||
"\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]}}",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
ProjectID: 1,
|
||||
Enabled: false,
|
||||
TagFilter: "{\"id\":2, \"projectID\":1,\"priority\":0,\"disabled\":false,\"action\":\"immutable\"," +
|
||||
"\"template\":\"immutable_template\"," +
|
||||
"\"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)
|
||||
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{
|
||||
{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
Enabled: true,
|
||||
TagFilter: "{\"id\":1, \"projectID\":1,\"priority\":0,\"disabled\":false,\"action\":\"immutable\"," +
|
||||
"\"template\":\"immutable_template\"," +
|
||||
"\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}]," +
|
||||
"\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]}}",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
ProjectID: 1,
|
||||
Enabled: true,
|
||||
TagFilter: "{\"id\":2, \"projectID\":1,\"priority\":0,\"disabled\":false,\"action\":\"immutable\"," +
|
||||
"\"template\":\"immutable_template\"," +
|
||||
"\"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)
|
||||
m.require.Nil(err)
|
||||
m.assert.Equal(len(irs), 2)
|
||||
m.assert.Equal(irs[0].Disabled, false)
|
||||
}
|
||||
|
||||
func (m *managerTestingSuite) TestGetImmutableRule() {
|
||||
m.mockImmutableDao.On("GetImmutableRule", mock.Anything).Return(&dao_model.ImmutableRule{
|
||||
ID: 1,
|
||||
ProjectID: 1,
|
||||
Enabled: true,
|
||||
TagFilter: "{\"id\":1, \"projectID\":1,\"priority\":0,\"disabled\":false,\"action\":\"immutable\"," +
|
||||
"\"template\":\"immutable_template\"," +
|
||||
"\"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)
|
||||
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.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.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.require.Nil(err)
|
||||
m.assert.Equal(int64(1), id)
|
||||
}
|
64
src/pkg/immutabletag/model/rule.go
Normal file
64
src/pkg/immutabletag/model/rule.go
Normal file
@ -0,0 +1,64 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/validation"
|
||||
)
|
||||
|
||||
// Metadata of the immutable rule
|
||||
type Metadata struct {
|
||||
// UUID of rule
|
||||
ID int64 `json:"id"`
|
||||
|
||||
// ProjectID of project
|
||||
ProjectID int64 `json:"project_id"`
|
||||
|
||||
// Disabled rule
|
||||
Disabled bool `json:"disabled"`
|
||||
|
||||
// Priority of rule when doing calculating
|
||||
Priority int `json:"priority"`
|
||||
|
||||
// Action of the rule performs
|
||||
// "immutable"
|
||||
Action string `json:"action" valid:"Required"`
|
||||
|
||||
// Template ID
|
||||
Template string `json:"template" valid:"Required"`
|
||||
|
||||
// TagSelectors attached to the rule for filtering tags
|
||||
TagSelectors []*Selector `json:"tag_selectors" valid:"Required"`
|
||||
|
||||
// Selector attached to the rule for filtering scope (e.g: repositories or namespaces)
|
||||
ScopeSelectors map[string][]*Selector `json:"scope_selectors" valid:"Required"`
|
||||
}
|
||||
|
||||
// Valid Valid
|
||||
func (m *Metadata) Valid(v *validation.Validation) {
|
||||
for _, ts := range m.TagSelectors {
|
||||
if pass, _ := v.Valid(ts); !pass {
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, ss := range m.ScopeSelectors {
|
||||
for _, s := range ss {
|
||||
if pass, _ := v.Valid(s); !pass {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Selector to narrow down the list
|
||||
type Selector struct {
|
||||
// Kind of the selector
|
||||
// "doublestar" or "label"
|
||||
Kind string `json:"kind" valid:"Required;Match(doublestar)"`
|
||||
|
||||
// Decorated the selector
|
||||
// for "doublestar" : "matching" and "excluding"
|
||||
// for "label" : "with" and "without"
|
||||
Decoration string `json:"decoration" valid:"Required"`
|
||||
|
||||
// Param for the selector
|
||||
Pattern string `json:"pattern" valid:"Required"`
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package immutabletag
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
)
|
||||
|
||||
// RuleManager ...
|
||||
type RuleManager interface {
|
||||
// CreateImmutableRule creates the Immutable Rule
|
||||
CreateImmutableRule(ir *models.ImmutableRule) (int64, error)
|
||||
// UpdateImmutableRule update the immutable rules
|
||||
UpdateImmutableRule(projectID int64, ir *models.ImmutableRule) (int64, error)
|
||||
// EnableImmutableRule enable/disable immutable rules
|
||||
EnableImmutableRule(id int64, enabled bool) (int64, error)
|
||||
// GetImmutableRule get immutable rule
|
||||
GetImmutableRule(id int64) (*models.ImmutableRule, error)
|
||||
// QueryImmutableRuleByProjectID get all immutable rule by project
|
||||
QueryImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error)
|
||||
// QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project
|
||||
QueryEnabledImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error)
|
||||
// DeleteImmutableRule delete the immutable rule
|
||||
DeleteImmutableRule(id int64) (int64, error)
|
||||
}
|
||||
|
||||
type defaultRuleManager struct{}
|
||||
|
||||
func (drm *defaultRuleManager) CreateImmutableRule(ir *models.ImmutableRule) (int64, error) {
|
||||
return dao.CreateImmutableRule(ir)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) UpdateImmutableRule(projectID int64, ir *models.ImmutableRule) (int64, error) {
|
||||
return dao.UpdateImmutableRule(projectID, ir)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) EnableImmutableRule(id int64, enabled bool) (int64, error) {
|
||||
return dao.ToggleImmutableRule(id, enabled)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) GetImmutableRule(id int64) (*models.ImmutableRule, error) {
|
||||
return dao.GetImmutableRule(id)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) QueryImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error) {
|
||||
return dao.QueryImmutableRuleByProjectID(projectID)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]models.ImmutableRule, error) {
|
||||
return dao.QueryEnabledImmutableRuleByProjectID(projectID)
|
||||
}
|
||||
|
||||
func (drm *defaultRuleManager) DeleteImmutableRule(id int64) (int64, error) {
|
||||
return dao.DeleteImmutableRule(id)
|
||||
}
|
||||
|
||||
// NewDefaultRuleManager return a new instance of defaultRuleManager
|
||||
func NewDefaultRuleManager() RuleManager {
|
||||
return &defaultRuleManager{}
|
||||
}
|
Loading…
Reference in New Issue
Block a user