mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-15 23:05:57 +01:00
fix: update process of webhook and preheat policy (#17243)
1. Update the preheat policy API hander and DAO Get method. 2. Update the webhook policy and webhook job API handler. Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
parent
9cbdb8cca1
commit
3897471486
@ -63,10 +63,13 @@ func (d *dao) Get(ctx context.Context, id int64) (*provider.Instance, error) {
|
||||
}
|
||||
|
||||
di := provider.Instance{ID: id}
|
||||
err = o.Read(&di, "ID")
|
||||
if err == beego_orm.ErrNoRows {
|
||||
return nil, nil
|
||||
if err = o.Read(&di, "ID"); err != nil {
|
||||
if e := orm.AsNotFoundError(err, "instance %d not found", id); e != nil {
|
||||
err = e
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &di, err
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,14 @@ import (
|
||||
"testing"
|
||||
|
||||
beego_orm "github.com/astaxie/beego/orm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
models "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/provider"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -62,6 +63,7 @@ func (is *instanceSuite) TestGet() {
|
||||
// not exist
|
||||
i, err = is.dao.Get(is.ctx, 0)
|
||||
assert.Nil(t, i)
|
||||
assert.True(t, errors.IsNotFoundErr(err))
|
||||
}
|
||||
|
||||
// TestCreate tests create instance.
|
||||
|
@ -2,10 +2,15 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/job"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/policy"
|
||||
policyModel "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
"github.com/goharbor/harbor/src/pkg/project"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/restapi/operations/webhookjob"
|
||||
@ -16,6 +21,7 @@ func newNotificationJobAPI() *notificationJobAPI {
|
||||
return ¬ificationJobAPI{
|
||||
webhookjobMgr: job.Mgr,
|
||||
webhookPolicyMgr: policy.Mgr,
|
||||
projectMgr: project.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +29,7 @@ type notificationJobAPI struct {
|
||||
BaseAPI
|
||||
webhookjobMgr job.Manager
|
||||
webhookPolicyMgr policy.Manager
|
||||
projectMgr project.Manager
|
||||
}
|
||||
|
||||
func (n *notificationJobAPI) ListWebhookJobs(ctx context.Context, params webhookjob.ListWebhookJobsParams) middleware.Responder {
|
||||
@ -36,6 +43,10 @@ func (n *notificationJobAPI) ListWebhookJobs(ctx context.Context, params webhook
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := n.requirePolicyAccess(ctx, projectNameOrID, policy); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
query, err := n.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
|
||||
if err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
@ -65,3 +76,17 @@ func (n *notificationJobAPI) ListWebhookJobs(ctx context.Context, params webhook
|
||||
WithLink(n.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
|
||||
WithPayload(results)
|
||||
}
|
||||
|
||||
// requirePolicyAccess checks whether the project has the permission to the policy.
|
||||
func (n *notificationJobAPI) requirePolicyAccess(ctx context.Context, projectNameIrID interface{}, policy *policyModel.Policy) error {
|
||||
p, err := n.projectMgr.Get(ctx, projectNameIrID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// check the projectID whether match with the projectID in policy
|
||||
if p.ProjectID != policy.ProjectID {
|
||||
return errors.NotFoundError(errors.Errorf("project id %d does not match", p.ProjectID))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,14 +1,33 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/job"
|
||||
@ -18,8 +37,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/restapi/operations/webhook"
|
||||
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/webhook"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func newNotificationPolicyAPI() *notificationPolicyAPI {
|
||||
@ -39,6 +56,21 @@ func (n *notificationPolicyAPI) Prepare(ctx context.Context, operation string, p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *notificationPolicyAPI) requirePolicyInProject(ctx context.Context, projectIDOrName interface{}, policyID int64) error {
|
||||
projectID, err := getProjectID(ctx, projectIDOrName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l, err := n.webhookPolicyMgr.Get(ctx, policyID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if projectID != l.ProjectID {
|
||||
return errors.NotFoundError(fmt.Errorf("project id:%d, webhook policy id: %d not found", projectID, policyID))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *notificationPolicyAPI) ListWebhookPoliciesOfProject(ctx context.Context, params webhook.ListWebhookPoliciesOfProjectParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := n.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionList, rbac.ResourceNotificationPolicy); err != nil {
|
||||
@ -83,7 +115,9 @@ func (n *notificationPolicyAPI) CreateWebhookPolicyOfProject(ctx context.Context
|
||||
}
|
||||
|
||||
policy := &policy_model.Policy{}
|
||||
lib.JSONCopy(policy, params.Policy)
|
||||
if err := lib.JSONCopy(policy, params.Policy); err != nil {
|
||||
log.Warningf("failed to call JSONCopy on notification policy when CreateWebhookPolicyOfProject, error: %v", err)
|
||||
}
|
||||
|
||||
if ok, err := n.validateEventTypes(policy); !ok {
|
||||
return n.SendError(ctx, err)
|
||||
@ -111,9 +145,18 @@ func (n *notificationPolicyAPI) UpdateWebhookPolicyOfProject(ctx context.Context
|
||||
if err := n.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionUpdate, rbac.ResourceNotificationPolicy); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
projectID, err := getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
policyID := params.WebhookPolicyID
|
||||
if err := n.requirePolicyInProject(ctx, projectID, policyID); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
policy := &policy_model.Policy{}
|
||||
lib.JSONCopy(policy, params.Policy)
|
||||
if err := lib.JSONCopy(policy, params.Policy); err != nil {
|
||||
log.Warningf("failed to call JSONCopy on notification policy when UpdateWebhookPolicyOfProject, error: %v", err)
|
||||
}
|
||||
|
||||
if ok, err := n.validateEventTypes(policy); !ok {
|
||||
return n.SendError(ctx, err)
|
||||
@ -122,10 +165,7 @@ func (n *notificationPolicyAPI) UpdateWebhookPolicyOfProject(ctx context.Context
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
projectID, err := getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
policy.ID = policyID
|
||||
policy.ProjectID = projectID
|
||||
if err := n.webhookPolicyMgr.Update(ctx, policy); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
@ -139,7 +179,9 @@ func (n *notificationPolicyAPI) DeleteWebhookPolicyOfProject(ctx context.Context
|
||||
if err := n.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete, rbac.ResourceNotificationPolicy); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := n.requirePolicyInProject(ctx, projectNameOrID, params.WebhookPolicyID); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
if err := n.webhookPolicyMgr.Delete(ctx, params.WebhookPolicyID); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
@ -148,7 +190,14 @@ func (n *notificationPolicyAPI) DeleteWebhookPolicyOfProject(ctx context.Context
|
||||
|
||||
func (n *notificationPolicyAPI) GetWebhookPolicyOfProject(ctx context.Context, params webhook.GetWebhookPolicyOfProjectParams) middleware.Responder {
|
||||
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
|
||||
if err := n.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionRead, rbac.ResourceNotificationPolicy); err != nil {
|
||||
projectID, err := getProjectID(ctx, projectNameOrID)
|
||||
if err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
if err := n.RequireProjectAccess(ctx, projectID, rbac.ActionRead, rbac.ResourceNotificationPolicy); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
if err := n.requirePolicyInProject(ctx, projectID, params.WebhookPolicyID); err != nil {
|
||||
return n.SendError(ctx, err)
|
||||
}
|
||||
|
||||
@ -257,28 +306,26 @@ func (n *notificationPolicyAPI) validateEventTypes(policy *policy_model.Policy)
|
||||
// including event type, enabled, creation time, last trigger time
|
||||
func (n *notificationPolicyAPI) constructPolicyWithTriggerTime(ctx context.Context, policies []*policy_model.Policy) ([]*models.WebhookLastTrigger, error) {
|
||||
res := []*models.WebhookLastTrigger{}
|
||||
if policies != nil {
|
||||
for _, policy := range policies {
|
||||
for _, t := range policy.EventTypes {
|
||||
ply := &models.WebhookLastTrigger{
|
||||
PolicyName: policy.Name,
|
||||
EventType: t,
|
||||
Enabled: policy.Enabled,
|
||||
CreationTime: strfmt.DateTime(policy.CreationTime),
|
||||
}
|
||||
if !policy.CreationTime.IsZero() {
|
||||
ply.CreationTime = strfmt.DateTime(policy.CreationTime)
|
||||
}
|
||||
|
||||
ltTime, err := n.getLastTriggerTimeGroupByEventType(ctx, t, policy.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ltTime.IsZero() {
|
||||
ply.LastTriggerTime = strfmt.DateTime(ltTime)
|
||||
}
|
||||
res = append(res, ply)
|
||||
for _, policy := range policies {
|
||||
for _, t := range policy.EventTypes {
|
||||
ply := &models.WebhookLastTrigger{
|
||||
PolicyName: policy.Name,
|
||||
EventType: t,
|
||||
Enabled: policy.Enabled,
|
||||
CreationTime: strfmt.DateTime(policy.CreationTime),
|
||||
}
|
||||
if !policy.CreationTime.IsZero() {
|
||||
ply.CreationTime = strfmt.DateTime(policy.CreationTime)
|
||||
}
|
||||
|
||||
ltTime, err := n.getLastTriggerTimeGroupByEventType(ctx, t, policy.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ltTime.IsZero() {
|
||||
ply.LastTriggerTime = strfmt.DateTime(ltTime)
|
||||
}
|
||||
res = append(res, ply)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
|
@ -1,3 +1,17 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
@ -10,6 +24,7 @@ import (
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
preheatCtl "github.com/goharbor/harbor/src/controller/p2p/preheat"
|
||||
projectCtl "github.com/goharbor/harbor/src/controller/project"
|
||||
@ -244,6 +259,12 @@ func (api *preheatAPI) CreatePolicy(ctx context.Context, params operation.Create
|
||||
// override project ID
|
||||
policy.ProjectID = project.ProjectID
|
||||
|
||||
// validate provider whether exist
|
||||
_, err = api.preheatCtl.GetInstance(ctx, policy.ProviderID)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
_, err = api.preheatCtl.CreatePolicy(ctx, policy)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
@ -264,6 +285,23 @@ func (api *preheatAPI) UpdatePolicy(ctx context.Context, params operation.Update
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
project, err := api.projectCtl.GetByName(ctx, params.ProjectName)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
// override project ID
|
||||
policy.ProjectID = project.ProjectID
|
||||
|
||||
if err := api.requirePolicyAccess(ctx, policy); err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
// validate provider whether exist
|
||||
_, err = api.preheatCtl.GetInstance(ctx, policy.ProviderID)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
err = api.preheatCtl.UpdatePolicy(ctx, policy)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
@ -578,6 +616,10 @@ func (api *preheatAPI) GetExecution(ctx context.Context, params operation.GetExe
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := api.requireExecutionInProject(ctx, params.ProjectName, params.PreheatPolicyName, params.ExecutionID); err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
execution, err := api.executionCtl.Get(ctx, params.ExecutionID)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
@ -646,6 +688,10 @@ func (api *preheatAPI) StopExecution(ctx context.Context, params operation.StopE
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := api.requireExecutionInProject(ctx, params.ProjectName, params.PreheatPolicyName, params.ExecutionID); err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if params.Execution.Status == "Stopped" {
|
||||
err := api.executionCtl.Stop(ctx, params.ExecutionID)
|
||||
if err != nil {
|
||||
@ -684,6 +730,10 @@ func (api *preheatAPI) ListTasks(ctx context.Context, params operation.ListTasks
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := api.requireExecutionInProject(ctx, params.ProjectName, params.PreheatPolicyName, params.ExecutionID); err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
query, err := api.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
@ -722,6 +772,10 @@ func (api *preheatAPI) GetPreheatLog(ctx context.Context, params operation.GetPr
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := api.requireTaskInProject(ctx, params.ProjectName, params.PreheatPolicyName, params.ExecutionID, params.TaskID); err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
}
|
||||
|
||||
l, err := api.taskCtl.GetLog(ctx, params.TaskID)
|
||||
if err != nil {
|
||||
return api.SendError(ctx, err)
|
||||
@ -730,6 +784,52 @@ func (api *preheatAPI) GetPreheatLog(ctx context.Context, params operation.GetPr
|
||||
return operation.NewGetPreheatLogOK().WithPayload(string(l))
|
||||
}
|
||||
|
||||
func (api *preheatAPI) requireTaskInProject(ctx context.Context, projectNameOrID interface{}, policyName string, executionID, taskID int64) error {
|
||||
projectID, err := getProjectID(ctx, projectNameOrID)
|
||||
notFoundErr := fmt.Errorf("project id %d, task id %d not found", projectID, taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// require execution before require task
|
||||
if err := api.requireExecutionInProject(ctx, projectID, policyName, executionID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
task, err := api.taskCtl.Get(ctx, taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if task != nil && task.ExecutionID == executionID {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.NotFoundError(notFoundErr)
|
||||
}
|
||||
|
||||
func (api *preheatAPI) requireExecutionInProject(ctx context.Context, projectNameOrID interface{}, policyName string, executionID int64) error {
|
||||
projectID, err := getProjectID(ctx, projectNameOrID)
|
||||
notFoundErr := fmt.Errorf("project id %d, execution id %d not found", projectID, executionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plc, err := api.preheatCtl.GetPolicyByName(ctx, projectID, policyName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exec, err := api.executionCtl.Get(ctx, executionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exec != nil && exec.VendorType == job.P2PPreheat && exec.VendorID == plc.ID {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.NotFoundError(notFoundErr)
|
||||
}
|
||||
|
||||
// ListProvidersUnderProject is Get all providers at project level
|
||||
func (api *preheatAPI) ListProvidersUnderProject(ctx context.Context, params operation.ListProvidersUnderProjectParams) middleware.Responder {
|
||||
if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionList, rbac.ResourcePreatPolicy); err != nil {
|
||||
@ -753,3 +853,19 @@ func (api *preheatAPI) ListProvidersUnderProject(ctx context.Context, params ope
|
||||
|
||||
return operation.NewListProvidersUnderProjectOK().WithPayload(providers)
|
||||
}
|
||||
|
||||
// requirePolicyAccess checks the project whether has the permission to the policy.
|
||||
func (api *preheatAPI) requirePolicyAccess(ctx context.Context, policy *policy.Schema) error {
|
||||
if policy != nil && policy.ID != 0 {
|
||||
db, err := api.preheatCtl.GetPolicy(ctx, policy.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// return err if project id does not match
|
||||
if db.ProjectID != policy.ProjectID {
|
||||
return errors.NotFoundError(errors.Errorf("project id %d does not match", policy.ProjectID))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user