mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-11 21:48:03 +02:00
Merge pull request #7304 from cd1989/registry-delete-constraint
Use policy controller in registry deletion
This commit is contained in:
commit
f4bf948847
@ -12,13 +12,15 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegistryAPI handles requests to /api/registries/{}. It manages registries integrated to Harbor.
|
// RegistryAPI handles requests to /api/registries/{}. It manages registries integrated to Harbor.
|
||||||
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
|
||||||
|
@ -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)
|
||||||
|
@ -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 -1, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return qs
|
_, err = qs.All(&policies)
|
||||||
}
|
if err != nil {
|
||||||
|
return total, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetTotalOfRepPolicies returns the total count of replication policies
|
return total, policies, nil
|
||||||
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)
|
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.
|
// GetRepPolicy return special policy by id.
|
||||||
|
@ -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
|
||||||
|
@ -152,6 +152,8 @@ type PolicyQuery struct {
|
|||||||
Name string
|
Name string
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user