diff --git a/src/core/api/registry.go b/src/core/api/registry.go index ed8b7b8f9..9f8c0ecc5 100644 --- a/src/core/api/registry.go +++ b/src/core/api/registry.go @@ -12,13 +12,15 @@ import ( "github.com/goharbor/harbor/src/replication/ng" "github.com/goharbor/harbor/src/replication/ng/adapter" "github.com/goharbor/harbor/src/replication/ng/model" + "github.com/goharbor/harbor/src/replication/ng/policy" "github.com/goharbor/harbor/src/replication/ng/registry" ) // RegistryAPI handles requests to /api/registries/{}. It manages registries integrated to Harbor. type RegistryAPI struct { BaseController - manager registry.Manager + manager registry.Manager + policyCtl policy.Controller } // Prepare validates the user @@ -35,6 +37,7 @@ func (t *RegistryAPI) Prepare() { } t.manager = ng.RegistryMgr + t.policyCtl = ng.PolicyCtl } // Get gets a registry by id. @@ -193,21 +196,39 @@ func (t *RegistryAPI) Delete() { } if registry == nil { - t.HandleNotFound(fmt.Sprintf("registry %d not found", id)) + t.HandleNotFound(fmt.Sprintf("Registry %d not found", id)) return } - // TODO: filter the policies by registry ID - _, policies, err := ng.PolicyCtl.List() + // Check whether there are replication policies that use this registry as source registry. + total, _, err := t.policyCtl.List([]*model.PolicyQuery{ + { + SrcRegistry: id, + }, + }...) 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) - t.HandleInternalServerError(msg) + t.HandleStatusPreconditionFailed(msg) return } - if len(policies) > 0 { - msg := fmt.Sprintf("Can't delete registry with replication policies, %d found", len(policies)) + // Check whether there are replication policies that use this registry as destination registry. + 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) t.HandleStatusPreconditionFailed(msg) return diff --git a/src/core/main.go b/src/core/main.go index 1ea4a19a7..7b393cf15 100644 --- a/src/core/main.go +++ b/src/core/main.go @@ -38,6 +38,7 @@ import ( "github.com/goharbor/harbor/src/core/filter" "github.com/goharbor/harbor/src/core/proxy" "github.com/goharbor/harbor/src/core/service/token" + "github.com/goharbor/harbor/src/replication/ng" ) const ( @@ -129,8 +130,9 @@ func main() { } } - closing := make(chan struct{}) - go gracefulShutdown(closing) + if err := ng.Init(); err != nil { + log.Fatalf("failed to initialize replication: %v", err) + } filter.Init() beego.InsertFilter("/*", beego.BeforeRouter, filter.SecurityFilter) diff --git a/src/replication/ng/dao/policy.go b/src/replication/ng/dao/policy.go index 24cdb7386..bc1ef7e00 100644 --- a/src/replication/ng/dao/policy.go +++ b/src/replication/ng/dao/policy.go @@ -5,8 +5,10 @@ import ( "time" "github.com/astaxie/beego/orm" + 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/model" ) // AddRepPolicy insert new policy to DB. @@ -19,33 +21,53 @@ func AddRepPolicy(policy *models.RepPolicy) (int64, error) { 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 policies []*models.RepPolicy - // TODO: just filter polices by name now, and need consider how to filter namespace. - qs = qs.Filter("name__icontains", name) + if len(queries) == 0 { + total, err := qs.Count() + if err != nil { + return -1, nil, err + } - return qs -} + _, err = qs.All(&policies) + if err != nil { + return total, 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) + return total, policies, nil } - _, err = qs.All(&policies) + 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) + } - return + 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. diff --git a/src/replication/ng/dao/policy_test.go b/src/replication/ng/dao/policy_test.go index 8fa9895fc..1d8639d41 100644 --- a/src/replication/ng/dao/policy_test.go +++ b/src/replication/ng/dao/policy_test.go @@ -3,9 +3,12 @@ package dao import ( "testing" - "github.com/goharbor/harbor/src/replication/ng/dao/models" "github.com/stretchr/testify/assert" "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 ( @@ -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) { type args struct { name string @@ -131,7 +106,16 @@ func TestGetPolicies(t *testing.T) { } for _, tt := range tests { 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 { require.NotNil(t, err, "wantErr: %s", err) return diff --git a/src/replication/ng/model/policy.go b/src/replication/ng/model/policy.go index e04c66f80..8ba0b10b6 100644 --- a/src/replication/ng/model/policy.go +++ b/src/replication/ng/model/policy.go @@ -152,6 +152,8 @@ type PolicyQuery struct { Name string // TODO: need to consider how to support listing the policies // of one namespace in both pull and push modes - Namespace string + Namespace string + SrcRegistry int64 + DestRegistry int64 models.Pagination } diff --git a/src/replication/ng/policy/manager/manager.go b/src/replication/ng/policy/manager/manager.go index db6d4d9b3..7a65423df 100644 --- a/src/replication/ng/policy/manager/manager.go +++ b/src/replication/ng/policy/manager/manager.go @@ -156,25 +156,8 @@ func (m *DefaultManager) Create(policy *model.Policy) (int64, error) { // List returns all the policies 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 - persistPolicies, err = dao.GetPolicies(name, namespace, page, pageSize) - if err != nil { - return - } - total, err = dao.GetTotalOfRepPolicies(name, namespace) + total, persistPolicies, err = dao.GetPolicies(queries...) if err != nil { return }