continue refactor API

Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
wang yan 2019-09-27 19:13:31 +08:00
parent 7c4fd79b5c
commit 8317100cda
8 changed files with 343 additions and 157 deletions

View File

@ -1,24 +1,21 @@
package api package api
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/rbac" "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/immutabletag"
"github.com/goharbor/harbor/src/pkg/retention/policy/rule" "github.com/goharbor/harbor/src/pkg/immutabletag/model"
) )
// ImmutableTagRuleAPI ... // ImmutableTagRuleAPI ...
type ImmutableTagRuleAPI struct { type ImmutableTagRuleAPI struct {
BaseController BaseController
manager immutabletag.Manager ctr immutabletag.APIController
projectID int64 projectID int64
ID int64 ID int64
} }
@ -49,7 +46,7 @@ func (itr *ImmutableTagRuleAPI) Prepare() {
itr.ID = ruleID itr.ID = ruleID
} }
itr.manager = immutabletag.NewDefaultRuleManager() itr.ctr = immutabletag.NewAPIController(immutabletag.NewDefaultRuleManager())
if strings.EqualFold(itr.Ctx.Request.Method, "get") { if strings.EqualFold(itr.Ctx.Request.Method, "get") {
if !itr.requireAccess(rbac.ActionList) { 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 // List list all immutable tag rules of current project
func (itr *ImmutableTagRuleAPI) List() { func (itr *ImmutableTagRuleAPI) List() {
rules, err := itr.manager.QueryImmutableRuleByProjectID(itr.projectID) rules, err := itr.ctr.ListImmutableRules(itr.projectID)
if err != nil { if err != nil {
itr.SendInternalServerError(err) itr.SendInternalServerError(err)
return return
@ -87,19 +84,14 @@ func (itr *ImmutableTagRuleAPI) List() {
// Post create immutable tag rule // Post create immutable tag rule
func (itr *ImmutableTagRuleAPI) Post() { func (itr *ImmutableTagRuleAPI) Post() {
ir := &models.ImmutableRule{} ir := &model.Metadata{}
if err := itr.DecodeJSONReq(ir); err != nil { isValid, err := itr.DecodeJSONReqAndValidate(ir)
itr.SendBadRequestError(fmt.Errorf("the filter must be a valid json, failed to parse json, error %+v", err)) if !isValid {
itr.SendBadRequestError(err)
return return
} }
if !isValidSelectorJSON(ir.TagFilter) {
itr.SendBadRequestError(fmt.Errorf("the filter should be a valid json"))
return
}
ir.ProjectID = itr.projectID ir.ProjectID = itr.projectID
id, err := itr.manager.CreateImmutableRule(ir) id, err := itr.ctr.CreateImmutableRule(ir)
if err != nil { if err != nil {
itr.SendInternalServerError(err) itr.SendInternalServerError(err)
return return
@ -114,7 +106,7 @@ func (itr *ImmutableTagRuleAPI) Delete() {
itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID)) itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID))
return return
} }
_, err := itr.manager.DeleteImmutableRule(itr.ID) err := itr.ctr.DeleteImmutableRule(itr.ID)
if err != nil { if err != nil {
itr.SendInternalServerError(err) itr.SendInternalServerError(err)
return return
@ -123,9 +115,9 @@ func (itr *ImmutableTagRuleAPI) Delete() {
// Put update an immutable tag rule // Put update an immutable tag rule
func (itr *ImmutableTagRuleAPI) Put() { func (itr *ImmutableTagRuleAPI) Put() {
ir := &models.ImmutableRule{} ir := &model.Metadata{}
if err := itr.DecodeJSONReq(ir); err != nil { if err := itr.DecodeJSONReq(ir); err != nil {
itr.SendInternalServerError(err) itr.SendBadRequestError(err)
return return
} }
ir.ID = itr.ID ir.ID = itr.ID
@ -135,32 +127,9 @@ func (itr *ImmutableTagRuleAPI) Put() {
itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID)) itr.SendBadRequestError(fmt.Errorf("invalid immutable rule id %d", itr.ID))
return return
} }
if len(ir.TagFilter) == 0 {
if _, err := itr.manager.EnableImmutableRule(itr.ID, ir.Enabled); err != nil { if err := itr.ctr.UpdateImmutableRule(itr.projectID, ir); err != nil {
itr.SendInternalServerError(err) itr.SendInternalServerError(err)
return 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
}
}
}
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
} }

View File

@ -7,24 +7,34 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/pkg/immutabletag" "github.com/goharbor/harbor/src/pkg/immutabletag"
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
) )
func TestImmutableTagRuleAPI_List(t *testing.T) { func TestImmutableTagRuleAPI_List(t *testing.T) {
tagFilter := `{ metadata := &model.Metadata{
"id":0, ProjectID: 1,
"priority":0, Disabled: false,
"disabled":false, TagSelectors: []*model.Selector{
"action":"immutable", {
"template":"immutable_template", Kind: "doublestar",
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}], Decoration: "matches",
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]} Pattern: "release-[\\d\\.]+",
}` },
},
ScopeSelectors: map[string][]*model.Selector{
"repository": {
{
Kind: "doublestar",
Decoration: "matches",
Pattern: ".+",
},
},
},
}
mgr := immutabletag.NewDefaultRuleManager() mgr := immutabletag.NewDefaultRuleManager()
id, err := mgr.CreateImmutableRule(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter}) id, err := mgr.CreateImmutableRule(metadata)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -46,7 +56,7 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
credential: admin, credential: admin,
}, },
postFunc: func(responseRecorder *httptest.ResponseRecorder) error { postFunc: func(responseRecorder *httptest.ResponseRecorder) error {
var rules []models.ImmutableRule var rules []model.Metadata
err := json.Unmarshal([]byte(responseRecorder.Body.String()), &rules) err := json.Unmarshal([]byte(responseRecorder.Body.String()), &rules)
if err != nil { if err != nil {
return err return err
@ -54,7 +64,7 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
if len(rules) <= 0 { if len(rules) <= 0 {
return fmt.Errorf("no rules found") 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 fmt.Errorf("rule is not expected. actual: %v", responseRecorder.Body.String())
} }
return nil return nil
@ -86,43 +96,68 @@ func TestImmutableTagRuleAPI_List(t *testing.T) {
func TestImmutableTagRuleAPI_Post(t *testing.T) { func TestImmutableTagRuleAPI_Post(t *testing.T) {
tagFilter := `{ // body := `{
"id":0, // "id":0,
"priority":0, // "projectID":1,
"disabled":false, // "priority":0,
"action":"immutable", // "disabled":false,
"template":"immutable_template", // "action":"immutable",
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}], // "template":"immutable_template",
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]} // "tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}],
}` // "scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]}
body := &models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter} // }`
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{ cases := []*codeCheckingCase{
// 401 // 401
{ {
request: &testingRequest{ request: &testingRequest{
method: http.MethodPost, method: http.MethodPost,
url: "/api/projects/1/immutabletagrules", url: "/api/projects/1/immutabletagrules",
bodyJSON: body, bodyJSON: metadata,
}, },
code: http.StatusUnauthorized, code: http.StatusUnauthorized,
}, },
// 200 // 201
{ {
request: &testingRequest{ request: &testingRequest{
method: http.MethodPost, method: http.MethodPost,
url: "/api/projects/1/immutabletagrules", url: "/api/projects/1/immutabletagrules",
credential: admin, credential: admin,
bodyJSON: body, bodyJSON: metadata,
}, },
code: http.StatusCreated, code: http.StatusCreated,
}, },
// 200 // 201
{ {
request: &testingRequest{ request: &testingRequest{
method: http.MethodPost, method: http.MethodPost,
url: "/api/projects/1/immutabletagrules", url: "/api/projects/1/immutabletagrules",
credential: projAdmin, credential: projAdmin,
bodyJSON: body, bodyJSON: metadata,
}, },
code: http.StatusCreated, code: http.StatusCreated,
}, },
@ -132,7 +167,7 @@ func TestImmutableTagRuleAPI_Post(t *testing.T) {
method: http.MethodPost, method: http.MethodPost,
url: "/api/projects/1/immutabletagrules", url: "/api/projects/1/immutabletagrules",
credential: projGuest, credential: projGuest,
bodyJSON: body, bodyJSON: metadata,
}, },
code: http.StatusForbidden, code: http.StatusForbidden,
}, },
@ -142,40 +177,63 @@ func TestImmutableTagRuleAPI_Post(t *testing.T) {
} }
func TestImmutableTagRuleAPI_Put(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() mgr := immutabletag.NewDefaultRuleManager()
id, err := mgr.CreateImmutableRule(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter}) id, err := mgr.CreateImmutableRule(metadata)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
defer mgr.DeleteImmutableRule(id) defer mgr.DeleteImmutableRule(id)
url := fmt.Sprintf("/api/projects/1/immutabletagrules/%d", id) url := fmt.Sprintf("/api/projects/1/immutabletagrules/%d", id)
body := &models.ImmutableRule{ID: id, ProjectID: 1, TagFilter: tagFilter2}
cases := []*codeCheckingCase{ cases := []*codeCheckingCase{
// 401 // 401
{ {
request: &testingRequest{ request: &testingRequest{
method: http.MethodPut, method: http.MethodPut,
url: url, url: url,
bodyJSON: body, bodyJSON: metadata2,
}, },
code: http.StatusUnauthorized, code: http.StatusUnauthorized,
}, },
@ -185,7 +243,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
method: http.MethodPut, method: http.MethodPut,
url: url, url: url,
credential: admin, credential: admin,
bodyJSON: body, bodyJSON: metadata2,
}, },
code: http.StatusOK, code: http.StatusOK,
}, },
@ -195,7 +253,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
method: http.MethodPut, method: http.MethodPut,
url: url, url: url,
credential: projAdmin, credential: projAdmin,
bodyJSON: body, bodyJSON: metadata2,
}, },
code: http.StatusOK, code: http.StatusOK,
}, },
@ -205,7 +263,7 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
method: http.MethodPut, method: http.MethodPut,
url: url, url: url,
credential: projGuest, credential: projGuest,
bodyJSON: body, bodyJSON: metadata2,
}, },
code: http.StatusForbidden, code: http.StatusForbidden,
}, },
@ -214,17 +272,29 @@ func TestImmutableTagRuleAPI_Put(t *testing.T) {
} }
func TestImmutableTagRuleAPI_Delete(t *testing.T) { func TestImmutableTagRuleAPI_Delete(t *testing.T) {
tagFilter := `{ metadata := &model.Metadata{
"id":0, ProjectID: 1,
"priority":0, Disabled: false,
"disabled":false, TagSelectors: []*model.Selector{
"action":"immutable", {
"template":"immutable_template", Kind: "doublestar",
"tag_selectors":[{"kind":"doublestar","decoration":"matches","pattern":"**"}], Decoration: "matches",
"scope_selectors":{"repository":[{"kind":"doublestar","decoration":"repoMatches","pattern":"**"}]} Pattern: "latest",
}` },
},
ScopeSelectors: map[string][]*model.Selector{
"repository": {
{
Kind: "doublestar",
Decoration: "matches",
Pattern: ".+",
},
},
},
}
mgr := immutabletag.NewDefaultRuleManager() mgr := immutabletag.NewDefaultRuleManager()
id, err := mgr.CreateImmutableRule(&models.ImmutableRule{ProjectID: 1, TagFilter: tagFilter}) id, err := mgr.CreateImmutableRule(metadata)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View 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,
}
}

View File

@ -0,0 +1 @@
package immutabletag

View File

@ -1,5 +1,13 @@
package model package model
import (
"github.com/astaxie/beego/orm"
)
func init() {
orm.RegisterModel(&ImmutableRule{})
}
// ImmutableRule - rule which filter image tags should be immutable. // ImmutableRule - rule which filter image tags should be immutable.
type ImmutableRule struct { type ImmutableRule struct {
ID int64 `orm:"pk;auto;column(id)" json:"id,omitempty"` ID int64 `orm:"pk;auto;column(id)" json:"id,omitempty"`

View File

@ -1,8 +1,10 @@
package immutabletag package immutabletag
import ( import (
"encoding/json"
"github.com/goharbor/harbor/src/pkg/immutabletag/dao" "github.com/goharbor/harbor/src/pkg/immutabletag/dao"
"github.com/goharbor/harbor/src/pkg/immutabletag/dao/model" dao_model "github.com/goharbor/harbor/src/pkg/immutabletag/dao/model"
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
) )
var ( var (
@ -13,17 +15,17 @@ var (
// Manager ... // Manager ...
type Manager interface { type Manager interface {
// CreateImmutableRule creates the Immutable Rule // CreateImmutableRule creates the Immutable Rule
CreateImmutableRule(ir *model.ImmutableRule) (int64, error) CreateImmutableRule(m *model.Metadata) (int64, error)
// UpdateImmutableRule update the immutable rules // UpdateImmutableRule update the immutable rules
UpdateImmutableRule(projectID int64, ir *model.ImmutableRule) (int64, error) UpdateImmutableRule(projectID int64, ir *model.Metadata) (int64, error)
// EnableImmutableRule enable/disable immutable rules // EnableImmutableRule enable/disable immutable rules
EnableImmutableRule(id int64, enabled bool) (int64, error) EnableImmutableRule(id int64, enabled bool) (int64, error)
// GetImmutableRule get immutable rule // GetImmutableRule get immutable rule
GetImmutableRule(id int64) (*model.ImmutableRule, error) GetImmutableRule(id int64) (*model.Metadata, error)
// QueryImmutableRuleByProjectID get all immutable rule by project // QueryImmutableRuleByProjectID get all immutable rule by project
QueryImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) QueryImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error)
// QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project // QueryEnabledImmutableRuleByProjectID get all enabled immutable rule by project
QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error)
// DeleteImmutableRule delete the immutable rule // DeleteImmutableRule delete the immutable rule
DeleteImmutableRule(id int64) (int64, error) DeleteImmutableRule(id int64) (int64, error)
} }
@ -32,28 +34,68 @@ type defaultRuleManager struct {
dao dao.ImmutableRuleDao dao dao.ImmutableRuleDao
} }
func (drm *defaultRuleManager) CreateImmutableRule(ir *model.ImmutableRule) (int64, error) { func (drm *defaultRuleManager) CreateImmutableRule(ir *model.Metadata) (int64, error) {
return drm.dao.CreateImmutableRule(ir) 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.ImmutableRule) (int64, error) { func (drm *defaultRuleManager) UpdateImmutableRule(projectID int64, ir *model.Metadata) (int64, error) {
return drm.dao.UpdateImmutableRule(projectID, ir) 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) { func (drm *defaultRuleManager) EnableImmutableRule(id int64, enabled bool) (int64, error) {
return drm.dao.ToggleImmutableRule(id, enabled) return drm.dao.ToggleImmutableRule(id, enabled)
} }
func (drm *defaultRuleManager) GetImmutableRule(id int64) (*model.ImmutableRule, error) { func (drm *defaultRuleManager) GetImmutableRule(id int64) (*model.Metadata, error) {
return drm.dao.GetImmutableRule(id) 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.ImmutableRule, error) { func (drm *defaultRuleManager) QueryImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error) {
return drm.dao.QueryImmutableRuleByProjectID(projectID) 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.ImmutableRule, error) { func (drm *defaultRuleManager) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.Metadata, error) {
return drm.dao.QueryEnabledImmutableRuleByProjectID(projectID) 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) { func (drm *defaultRuleManager) DeleteImmutableRule(id int64) (int64, error) {

View File

@ -1,7 +1,8 @@
package immutabletag package immutabletag
import ( import (
"github.com/goharbor/harbor/src/pkg/immutabletag/dao/model" 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/assert"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -15,30 +16,30 @@ type mockImmutableDao struct {
mock.Mock mock.Mock
} }
func (m *mockImmutableDao) CreateImmutableRule(ir *model.ImmutableRule) (int64, error) { func (m *mockImmutableDao) CreateImmutableRule(ir *dao_model.ImmutableRule) (int64, error) {
args := m.Called(ir) args := m.Called(ir)
return int64(args.Int(0)), args.Error(1) return int64(args.Int(0)), args.Error(1)
} }
func (m *mockImmutableDao) UpdateImmutableRule(projectID int64, ir *model.ImmutableRule) (int64, error) { func (m *mockImmutableDao) UpdateImmutableRule(projectID int64, ir *dao_model.ImmutableRule) (int64, error) {
args := m.Called(ir) args := m.Called(ir)
return int64(0), args.Error(1) return int64(0), args.Error(1)
} }
func (m *mockImmutableDao) QueryImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) { func (m *mockImmutableDao) QueryImmutableRuleByProjectID(projectID int64) ([]dao_model.ImmutableRule, error) {
args := m.Called() args := m.Called()
var irs []model.ImmutableRule var irs []dao_model.ImmutableRule
if args.Get(0) != nil { if args.Get(0) != nil {
irs = args.Get(0).([]model.ImmutableRule) irs = args.Get(0).([]dao_model.ImmutableRule)
} }
return irs, args.Error(1) return irs, args.Error(1)
} }
func (m *mockImmutableDao) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]model.ImmutableRule, error) { func (m *mockImmutableDao) QueryEnabledImmutableRuleByProjectID(projectID int64) ([]dao_model.ImmutableRule, error) {
args := m.Called() args := m.Called()
var irs []model.ImmutableRule var irs []dao_model.ImmutableRule
if args.Get(0) != nil { if args.Get(0) != nil {
irs = args.Get(0).([]model.ImmutableRule) irs = args.Get(0).([]dao_model.ImmutableRule)
} }
return irs, args.Error(1) return irs, args.Error(1)
} }
@ -53,11 +54,11 @@ func (m *mockImmutableDao) ToggleImmutableRule(id int64, enabled bool) (int64, e
return int64(args.Int(0)), args.Error(1) return int64(args.Int(0)), args.Error(1)
} }
func (m *mockImmutableDao) GetImmutableRule(id int64) (*model.ImmutableRule, error) { func (m *mockImmutableDao) GetImmutableRule(id int64) (*dao_model.ImmutableRule, error) {
args := m.Called(id) args := m.Called(id)
var ir *model.ImmutableRule var ir *dao_model.ImmutableRule
if args.Get(0) != nil { if args.Get(0) != nil {
ir = args.Get(0).(*model.ImmutableRule) ir = args.Get(0).(*dao_model.ImmutableRule)
} }
return ir, args.Error(1) return ir, args.Error(1)
@ -98,53 +99,75 @@ func TestManagerTestingSuite(t *testing.T) {
func (m *managerTestingSuite) TestCreateImmutableRule() { func (m *managerTestingSuite) TestCreateImmutableRule() {
m.mockImmutableDao.On("CreateImmutableRule", mock.Anything).Return(1, nil) m.mockImmutableDao.On("CreateImmutableRule", mock.Anything).Return(1, nil)
id, err := Mgr.CreateImmutableRule(&model.ImmutableRule{}) id, err := Mgr.CreateImmutableRule(&model.Metadata{})
m.mockImmutableDao.AssertCalled(m.t, "CreateImmutableRule", mock.Anything) m.mockImmutableDao.AssertCalled(m.t, "CreateImmutableRule", mock.Anything)
m.require.Nil(err) m.require.Nil(err)
m.assert.Equal(int64(1), id) m.assert.Equal(int64(1), id)
} }
func (m *managerTestingSuite) TestQueryImmutableRuleByProjectID() { func (m *managerTestingSuite) TestQueryImmutableRuleByProjectID() {
m.mockImmutableDao.On("QueryImmutableRuleByProjectID", mock.Anything).Return([]model.ImmutableRule{ m.mockImmutableDao.On("QueryImmutableRuleByProjectID", mock.Anything).Return([]dao_model.ImmutableRule{
{ {
ProjectID: int64(1), ID: 1,
TagFilter: "project_1_tag_filter", ProjectID: 1,
Enabled: false, 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\":\"**\"}]}}",
}, },
{ {
ProjectID: int64(2), ID: 2,
TagFilter: "project_2_tag_filter", ProjectID: 1,
Enabled: true, 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) }}, nil)
irs, err := Mgr.QueryImmutableRuleByProjectID(int64(1)) irs, err := Mgr.QueryImmutableRuleByProjectID(int64(1))
m.mockImmutableDao.AssertCalled(m.t, "QueryImmutableRuleByProjectID", mock.Anything) m.mockImmutableDao.AssertCalled(m.t, "QueryImmutableRuleByProjectID", mock.Anything)
m.require.Nil(err) m.require.Nil(err)
m.assert.Equal(len(irs), 2) m.assert.Equal(len(irs), 2)
m.assert.Equal(irs[0].TagFilter, "project_1_tag_filter") m.assert.Equal(irs[1].Disabled, false)
} }
func (m *managerTestingSuite) TestQueryEnabledImmutableRuleByProjectID() { func (m *managerTestingSuite) TestQueryEnabledImmutableRuleByProjectID() {
m.mockImmutableDao.On("QueryEnabledImmutableRuleByProjectID", mock.Anything).Return([]model.ImmutableRule{ m.mockImmutableDao.On("QueryEnabledImmutableRuleByProjectID", mock.Anything).Return([]dao_model.ImmutableRule{
{ {
ProjectID: int64(1), ID: 1,
TagFilter: "project_1_tag_filter", ProjectID: 1,
Enabled: true, 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\":\"**\"}]}}",
}, },
{ {
ProjectID: int64(2), ID: 2,
TagFilter: "project_2_tag_filter", ProjectID: 1,
Enabled: true, 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) }}, nil)
irs, err := Mgr.QueryEnabledImmutableRuleByProjectID(int64(1)) irs, err := Mgr.QueryEnabledImmutableRuleByProjectID(int64(1))
m.mockImmutableDao.AssertCalled(m.t, "QueryEnabledImmutableRuleByProjectID", mock.Anything) m.mockImmutableDao.AssertCalled(m.t, "QueryEnabledImmutableRuleByProjectID", mock.Anything)
m.require.Nil(err) m.require.Nil(err)
m.assert.Equal(len(irs), 2) m.assert.Equal(len(irs), 2)
m.assert.Equal(irs[0].Enabled, true) m.assert.Equal(irs[0].Disabled, false)
} }
func (m *managerTestingSuite) TestGetImmutableRule() { func (m *managerTestingSuite) TestGetImmutableRule() {
m.mockImmutableDao.On("GetImmutableRule", mock.Anything).Return(&model.ImmutableRule{ m.mockImmutableDao.On("GetImmutableRule", mock.Anything).Return(&dao_model.ImmutableRule{
ID: 1, 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) }, nil)
ir, err := Mgr.GetImmutableRule(1) ir, err := Mgr.GetImmutableRule(1)
m.mockImmutableDao.AssertCalled(m.t, "GetImmutableRule", mock.Anything) m.mockImmutableDao.AssertCalled(m.t, "GetImmutableRule", mock.Anything)
@ -155,7 +178,7 @@ func (m *managerTestingSuite) TestGetImmutableRule() {
func (m *managerTestingSuite) TestUpdateImmutableRule() { func (m *managerTestingSuite) TestUpdateImmutableRule() {
m.mockImmutableDao.On("UpdateImmutableRule", mock.Anything).Return(1, nil) m.mockImmutableDao.On("UpdateImmutableRule", mock.Anything).Return(1, nil)
id, err := Mgr.UpdateImmutableRule(int64(1), &model.ImmutableRule{}) id, err := Mgr.UpdateImmutableRule(int64(1), &model.Metadata{})
m.mockImmutableDao.AssertCalled(m.t, "UpdateImmutableRule", mock.Anything) m.mockImmutableDao.AssertCalled(m.t, "UpdateImmutableRule", mock.Anything)
m.require.Nil(err) m.require.Nil(err)
m.assert.Equal(int64(0), id) m.assert.Equal(int64(0), id)

View File

@ -7,7 +7,10 @@ import (
// Metadata of the immutable rule // Metadata of the immutable rule
type Metadata struct { type Metadata struct {
// UUID of rule // UUID of rule
ID int `json:"id"` ID int64 `json:"id"`
// ProjectID of project
ProjectID int64 `json:"project_id"`
// Disabled rule // Disabled rule
Disabled bool `json:"disabled"` Disabled bool `json:"disabled"`