Merge pull request #7304 from cd1989/registry-delete-constraint

Use policy controller in registry deletion
This commit is contained in:
Wenkai Yin 2019-04-04 22:46:08 +08:00 committed by GitHub
commit f4bf948847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 93 additions and 79 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/goharbor/harbor/src/replication/ng" "github.com/goharbor/harbor/src/replication/ng"
"github.com/goharbor/harbor/src/replication/ng/adapter" "github.com/goharbor/harbor/src/replication/ng/adapter"
"github.com/goharbor/harbor/src/replication/ng/model" "github.com/goharbor/harbor/src/replication/ng/model"
"github.com/goharbor/harbor/src/replication/ng/policy"
"github.com/goharbor/harbor/src/replication/ng/registry" "github.com/goharbor/harbor/src/replication/ng/registry"
) )
@ -19,6 +20,7 @@ import (
type RegistryAPI struct { type RegistryAPI struct {
BaseController BaseController
manager registry.Manager manager registry.Manager
policyCtl policy.Controller
} }
// Prepare validates the user // Prepare validates the user
@ -35,6 +37,7 @@ func (t *RegistryAPI) Prepare() {
} }
t.manager = ng.RegistryMgr t.manager = ng.RegistryMgr
t.policyCtl = ng.PolicyCtl
} }
// Get gets a registry by id. // Get gets a registry by id.
@ -193,21 +196,39 @@ func (t *RegistryAPI) Delete() {
} }
if registry == nil { if registry == nil {
t.HandleNotFound(fmt.Sprintf("registry %d not found", id)) t.HandleNotFound(fmt.Sprintf("Registry %d not found", id))
return return
} }
// TODO: filter the policies by registry ID // Check whether there are replication policies that use this registry as source registry.
_, policies, err := ng.PolicyCtl.List() total, _, err := t.policyCtl.List([]*model.PolicyQuery{
{
SrcRegistry: id,
},
}...)
if err != nil { if err != nil {
msg := fmt.Sprintf("Get policies related to registry %d error: %v", id, err) t.HandleInternalServerError(fmt.Sprintf("List replication policies with source registry %d error: %v", id, err))
return
}
if total > 0 {
msg := fmt.Sprintf("Can't delete registry %d, %d replication policies use it as source registry", id, total)
log.Error(msg) log.Error(msg)
t.HandleInternalServerError(msg) t.HandleStatusPreconditionFailed(msg)
return return
} }
if len(policies) > 0 { // Check whether there are replication policies that use this registry as destination registry.
msg := fmt.Sprintf("Can't delete registry with replication policies, %d found", len(policies)) total, _, err = t.policyCtl.List([]*model.PolicyQuery{
{
DestRegistry: id,
},
}...)
if err != nil {
t.HandleInternalServerError(fmt.Sprintf("List replication policies with destination registry %d error: %v", id, err))
return
}
if total > 0 {
msg := fmt.Sprintf("Can't delete registry %d, %d replication policies use it as destination registry", id, total)
log.Error(msg) log.Error(msg)
t.HandleStatusPreconditionFailed(msg) t.HandleStatusPreconditionFailed(msg)
return return

View File

@ -38,6 +38,7 @@ import (
"github.com/goharbor/harbor/src/core/filter" "github.com/goharbor/harbor/src/core/filter"
"github.com/goharbor/harbor/src/core/proxy" "github.com/goharbor/harbor/src/core/proxy"
"github.com/goharbor/harbor/src/core/service/token" "github.com/goharbor/harbor/src/core/service/token"
"github.com/goharbor/harbor/src/replication/ng"
) )
const ( const (
@ -129,8 +130,9 @@ func main() {
} }
} }
closing := make(chan struct{}) if err := ng.Init(); err != nil {
go gracefulShutdown(closing) log.Fatalf("failed to initialize replication: %v", err)
}
filter.Init() filter.Init()
beego.InsertFilter("/*", beego.BeforeRouter, filter.SecurityFilter) beego.InsertFilter("/*", beego.BeforeRouter, filter.SecurityFilter)

View File

@ -5,8 +5,10 @@ import (
"time" "time"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
common_dao "github.com/goharbor/harbor/src/common/dao" common_dao "github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/replication/ng/dao/models" "github.com/goharbor/harbor/src/replication/ng/dao/models"
"github.com/goharbor/harbor/src/replication/ng/model"
) )
// AddRepPolicy insert new policy to DB. // AddRepPolicy insert new policy to DB.
@ -19,33 +21,53 @@ func AddRepPolicy(policy *models.RepPolicy) (int64, error) {
return o.Insert(policy) return o.Insert(policy)
} }
func filteredRepPolicyQuerySeter(name, namespace string) orm.QuerySeter { // GetPolicies list polices with given query parameters.
func GetPolicies(queries ...*model.PolicyQuery) (int64, []*models.RepPolicy, error) {
var qs = common_dao.GetOrmer().QueryTable(new(models.RepPolicy)) var qs = common_dao.GetOrmer().QueryTable(new(models.RepPolicy))
var policies []*models.RepPolicy
// TODO: just filter polices by name now, and need consider how to filter namespace. if len(queries) == 0 {
qs = qs.Filter("name__icontains", name) total, err := qs.Count()
if err != nil {
return qs return -1, nil, err
}
// GetTotalOfRepPolicies returns the total count of replication policies
func GetTotalOfRepPolicies(name, namespace string) (int64, error) {
var qs = filteredRepPolicyQuerySeter(name, namespace)
return qs.Count()
}
// GetPolicies filter policies and pagination.
func GetPolicies(name, namespace string, page, pageSize int64) (policies []*models.RepPolicy, err error) {
var qs = filteredRepPolicyQuerySeter(name, namespace)
// Paginate
if page > 0 && pageSize > 0 {
qs = qs.Limit(pageSize, (page-1)*pageSize)
} }
_, err = qs.All(&policies) _, err = qs.All(&policies)
if err != nil {
return total, nil, err
}
return return total, policies, nil
}
query := queries[0]
if len(query.Name) != 0 {
qs = qs.Filter("Name__icontains", query.Name)
}
if len(query.Namespace) != 0 {
// TODO: Namespace filter not implemented yet
}
if query.SrcRegistry > 0 {
qs = qs.Filter("SrcRegistryID__exact", query.SrcRegistry)
}
if query.DestRegistry > 0 {
qs = qs.Filter("DestRegistryID__exact", query.DestRegistry)
}
total, err := qs.Count()
if err != nil {
return -1, nil, err
}
if query.Page > 0 && query.Size > 0 {
qs = qs.Limit(query.Size, (query.Page-1)*query.Size)
}
_, err = qs.All(&policies)
if err != nil {
return total, nil, err
}
return total, policies, nil
} }
// GetRepPolicy return special policy by id. // GetRepPolicy return special policy by id.

View File

@ -3,9 +3,12 @@ package dao
import ( import (
"testing" "testing"
"github.com/goharbor/harbor/src/replication/ng/dao/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
common_models "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/replication/ng/dao/models"
"github.com/goharbor/harbor/src/replication/ng/model"
) )
var ( var (
@ -84,34 +87,6 @@ func TestAddRepPolicy(t *testing.T) {
} }
} }
func TestGetTotalOfRepPolicies(t *testing.T) {
type args struct {
name string
namespace string
}
tests := []struct {
name string
args args
want int64
wantErr bool
}{
{name: "GetTotalOfRepPolicies 1", args: args{name: "Test 1"}, want: 1},
{name: "GetTotalOfRepPolicies 2", args: args{name: "Test"}, want: 3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetTotalOfRepPolicies(tt.args.name, tt.args.namespace)
if tt.wantErr {
require.NotNil(t, err, "wantErr: %s", err)
return
}
require.Nil(t, err)
assert.Equal(t, tt.want, got)
})
}
}
func TestGetPolicies(t *testing.T) { func TestGetPolicies(t *testing.T) {
type args struct { type args struct {
name string name string
@ -131,7 +106,16 @@ func TestGetPolicies(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotPolicies, err := GetPolicies(tt.args.name, tt.args.namespace, tt.args.page, tt.args.pageSize) _, gotPolicies, err := GetPolicies([]*model.PolicyQuery{
{
Name: tt.args.name,
Namespace: tt.args.namespace,
Pagination: common_models.Pagination{
Page: tt.args.page,
Size: tt.args.pageSize,
},
},
}...)
if tt.wantErr { if tt.wantErr {
require.NotNil(t, err, "wantErr: %s", err) require.NotNil(t, err, "wantErr: %s", err)
return return

View File

@ -153,5 +153,7 @@ type PolicyQuery struct {
// TODO: need to consider how to support listing the policies // TODO: need to consider how to support listing the policies
// of one namespace in both pull and push modes // of one namespace in both pull and push modes
Namespace string Namespace string
SrcRegistry int64
DestRegistry int64
models.Pagination models.Pagination
} }

View File

@ -156,25 +156,8 @@ func (m *DefaultManager) Create(policy *model.Policy) (int64, error) {
// List returns all the policies // List returns all the policies
func (m *DefaultManager) List(queries ...*model.PolicyQuery) (total int64, policies []*model.Policy, err error) { func (m *DefaultManager) List(queries ...*model.PolicyQuery) (total int64, policies []*model.Policy, err error) {
// default query parameters
var name = ""
var namespace = ""
var page int64 = 1
var pageSize int64 = 15
if len(queries) > 0 {
name = queries[0].Name
namespace = queries[0].Namespace
page = queries[0].Pagination.Page
pageSize = queries[0].Pagination.Size
}
var persistPolicies []*persist_models.RepPolicy var persistPolicies []*persist_models.RepPolicy
persistPolicies, err = dao.GetPolicies(name, namespace, page, pageSize) total, persistPolicies, err = dao.GetPolicies(queries...)
if err != nil {
return
}
total, err = dao.GetTotalOfRepPolicies(name, namespace)
if err != nil { if err != nil {
return return
} }