Provide an API to return the resources that a label is referenced by

The API returns the resources that the label is referenced by. The resources contain only replication policies for now.
This commit is contained in:
Wenkai Yin 79628 2018-06-13 16:49:43 +08:00
parent 9c1d3c259a
commit 3298c05157
5 changed files with 199 additions and 0 deletions

View File

@ -1968,6 +1968,33 @@ paths:
description: The resource does not exist.
'500':
description: Unexpected internal errors.
'/labels/{id}/resources':
get:
summary: Get the resources that the label is referenced by.
description: |
This endpoint let user get the resources that the label is referenced by. Only the replication policies are returned for now.
parameters:
- name: id
in: path
type: integer
format: int64
required: true
description: Label ID
tags:
- Products
responses:
'200':
description: Get successfully.
schema:
$ref: '#/definitions/Resource'
'401':
description: User need to log in first.
'403':
description: Forbidden.
'404':
description: The resource does not exist.
'500':
description: Unexpected internal errors.
/replications:
post:
summary: Trigger the replication according to the specified policy.
@ -3624,5 +3651,13 @@ definitions:
ldap_group_dn:
type: string
description: The DN of the LDAP group if group type is 1 (LDAP group).
Resource:
type: object
properties:
replication_policies:
type: array
description: The replication policy list.
items:
$ref: '#/definitions/RepPolicy'

View File

@ -141,6 +141,7 @@ func init() {
beego.Router("/api/replications", &ReplicationAPI{})
beego.Router("/api/labels", &LabelAPI{}, "post:Post;get:List")
beego.Router("/api/labels/:id([0-9]+", &LabelAPI{}, "get:Get;put:Put;delete:Delete")
beego.Router("/api/labels/:id([0-9]+)/resources", &LabelAPI{}, "get:ListResources")
beego.Router("/api/ping", &SystemInfoAPI{}, "get:Ping")
_ = updateInitPassword(1, "Harbor12345")

View File

@ -22,6 +22,9 @@ import (
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/replication"
"github.com/vmware/harbor/src/replication/core"
rep_models "github.com/vmware/harbor/src/replication/models"
)
// LabelAPI handles requests for label management
@ -266,3 +269,57 @@ func (l *LabelAPI) Delete() {
return
}
}
// ListResources lists the resources that the label is referenced by
func (l *LabelAPI) ListResources() {
if !l.SecurityCtx.IsAuthenticated() {
l.HandleUnauthorized()
return
}
id, err := l.GetInt64FromPath(":id")
if err != nil || id <= 0 {
l.HandleBadRequest("invalid label ID")
return
}
label, err := dao.GetLabel(id)
if err != nil {
l.HandleInternalServerError(fmt.Sprintf("failed to get label %d: %v", id, err))
return
}
if label == nil || label.Deleted {
l.HandleNotFound(fmt.Sprintf("label %d not found", id))
return
}
if label.Scope == common.LabelScopeGlobal && !l.SecurityCtx.IsSysAdmin() ||
label.Scope == common.LabelScopeProject && !l.SecurityCtx.HasAllPerm(label.ProjectID) {
l.HandleForbidden(l.SecurityCtx.GetUsername())
return
}
result, err := core.GlobalController.GetPolicies(rep_models.QueryParameter{})
if err != nil {
l.HandleInternalServerError(fmt.Sprintf("failed to get policies: %v", err))
return
}
policies := []*rep_models.ReplicationPolicy{}
if result != nil {
for _, policy := range result.Policies {
for _, filter := range policy.Filters {
if filter.Kind != replication.FilterItemKindLabel {
continue
}
if filter.Value.(int64) == label.ID {
policies = append(policies, policy)
}
}
}
}
resources := map[string]interface{}{}
resources["replication_policies"] = policies
l.Data["json"] = resources
l.ServeJSON()
}

View File

@ -23,7 +23,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/replication"
rep_models "github.com/vmware/harbor/src/replication/models"
)
var (
@ -433,3 +436,105 @@ func TestLabelAPIDelete(t *testing.T) {
runCodeCheckingCases(t, cases...)
}
func TestListResources(t *testing.T) {
// global level label
globalLabelID, err := dao.AddLabel(&models.Label{
Name: "globel_level_label",
Scope: common.LabelScopeGlobal,
})
require.Nil(t, err)
defer dao.DeleteLabel(globalLabelID)
// project level label
projectLabelID, err := dao.AddLabel(&models.Label{
Name: "project_level_label",
Scope: common.LabelScopeProject,
ProjectID: 1,
})
require.Nil(t, err)
defer dao.DeleteLabel(projectLabelID)
targetID, err := dao.AddRepTarget(models.RepTarget{
Name: "target_for_testing_label_resource",
URL: "https://192.168.0.1",
})
require.Nil(t, err)
defer dao.DeleteRepTarget(targetID)
// create a policy references both global and project labels
policyID, err := dao.AddRepPolicy(models.RepPolicy{
Name: "policy_for_testing_label_resource",
ProjectID: 1,
TargetID: targetID,
Trigger: fmt.Sprintf(`{"kind":"%s"}`, replication.TriggerKindManual),
Filters: fmt.Sprintf(`[{"kind":"%s","value":%d}, {"kind":"%s","value":%d}]`,
replication.FilterItemKindLabel, globalLabelID,
replication.FilterItemKindLabel, projectLabelID),
})
require.Nil(t, err)
defer dao.DeleteRepPolicy(policyID)
cases := []*codeCheckingCase{
// 401
&codeCheckingCase{
request: &testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, globalLabelID),
},
code: http.StatusUnauthorized,
},
// 404
&codeCheckingCase{
request: &testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, 10000),
credential: sysAdmin,
},
code: http.StatusNotFound,
},
// 403: global level label
&codeCheckingCase{
request: &testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, globalLabelID),
credential: projAdmin,
},
code: http.StatusForbidden,
},
// 403: project level label
&codeCheckingCase{
request: &testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, projectLabelID),
credential: projDeveloper,
},
code: http.StatusForbidden,
},
}
runCodeCheckingCases(t, cases...)
// 200: global level label
resources := map[string][]rep_models.ReplicationPolicy{}
err = handleAndParse(&testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, globalLabelID),
credential: sysAdmin,
}, &resources)
require.Nil(t, err)
policies := resources["replication_policies"]
require.Equal(t, 1, len(policies))
assert.Equal(t, policyID, policies[0].ID)
// 200: project level label
resources = map[string][]rep_models.ReplicationPolicy{}
err = handleAndParse(&testingRequest{
method: http.MethodGet,
url: fmt.Sprintf("%s/%d/resources", labelAPIBasePath, projectLabelID),
credential: projAdmin,
}, &resources)
require.Nil(t, err)
policies = resources["replication_policies"]
require.Equal(t, 1, len(policies))
assert.Equal(t, policyID, policies[0].ID)
}

View File

@ -104,6 +104,7 @@ func initRouters() {
beego.Router("/api/replications", &api.ReplicationAPI{})
beego.Router("/api/labels", &api.LabelAPI{}, "post:Post;get:List")
beego.Router("/api/labels/:id([0-9]+)", &api.LabelAPI{}, "get:Get;put:Put;delete:Delete")
beego.Router("/api/labels/:id([0-9]+)/resources", &api.LabelAPI{}, "get:ListResources")
beego.Router("/api/systeminfo", &api.SystemInfoAPI{}, "get:GetGeneralInfo")
beego.Router("/api/systeminfo/volumes", &api.SystemInfoAPI{}, "get:GetVolumeInfo")