Unify the process of job schedule/task retrieve and update (#17012)

Unify the process of jobservice execution/task retrieve and update

   Change regular expression in robot account

Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
stonezdj(Daojun Zhang) 2022-06-22 18:22:33 +08:00 committed by GitHub
parent 0cf036e73a
commit e6eb7821d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 160 additions and 14 deletions

View File

@ -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 (
@ -40,6 +54,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 {
@ -114,7 +143,14 @@ 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{}
if err := lib.JSONCopy(policy, params.Policy); err != nil {
log.Warningf("failed to call JSONCopy on notification policy when UpdateWebhookPolicyOfProject, error: %v", err)
@ -127,10 +163,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)
@ -144,7 +177,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)
}
@ -153,7 +188,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)
}

View File

@ -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 (
@ -578,6 +592,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 +664,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 {
@ -683,7 +705,6 @@ func (api *preheatAPI) ListTasks(ctx context.Context, params operation.ListTasks
if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionList, rbac.ResourcePreatPolicy); 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 +743,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.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 +755,64 @@ 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, 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
}
plc, err := api.preheatCtl.GetPolicyByName(ctx, projectID, policyName)
if err != nil {
return err
}
execs, err := api.executionCtl.List(ctx, q.New(q.KeyWords{"VendorType": job.P2PPreheat, "VendorID": plc.ID}))
if err != nil {
return err
}
if len(execs) == 0 {
return errors.NotFoundError(notFoundErr)
}
var execIds []interface{}
for _, item := range execs {
execIds = append(execIds, item.ID)
}
tasks, err := api.taskCtl.List(ctx, q.New(q.KeyWords{"ExecutionID": q.NewOrList(execIds)}))
if err != nil {
return err
}
if len(tasks) == 0 {
return errors.NotFoundError(notFoundErr)
}
for _, t := range tasks {
if t.ID == taskID {
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
}
execs, err := api.executionCtl.List(ctx, q.New(q.KeyWords{"VendorType": job.P2PPreheat, "VendorID": plc.ID}))
if err != nil {
return err
}
for _, e := range execs {
if e.ID == executionID {
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 {

View File

@ -185,6 +185,9 @@ func (p *purgeAPI) GetPurgeJob(ctx context.Context, params purge.GetPurgeJobPara
}
exec, err := p.executionCtl.Get(ctx, params.PurgeID)
if exec.VendorType != pg.VendorType {
return p.SendError(ctx, fmt.Errorf("purge job with id %d not found", params.PurgeID))
}
if err != nil {
return p.SendError(ctx, err)
}

View File

@ -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 (
@ -95,7 +109,7 @@ func (rAPI *robotAPI) DeleteRobot(ctx context.Context, params operation.DeleteRo
}
if err := rAPI.robotCtl.Delete(ctx, params.RobotID); err != nil {
// for the version 1 robot account, has to ignore the no permissions error.
// for the version 1 robot account, has to ignore the no permission error.
if !r.Editable && errors.IsNotFoundErr(err) {
return operation.NewDeleteRobotOK()
}
@ -177,7 +191,6 @@ func (rAPI *robotAPI) GetRobotByID(ctx context.Context, params operation.GetRobo
if err != nil {
return rAPI.SendError(ctx, err)
}
if err := rAPI.requireAccess(ctx, r.Level, r.ProjectID, rbac.ActionRead); err != nil {
return rAPI.SendError(ctx, err)
}
@ -285,11 +298,16 @@ func (rAPI *robotAPI) updateV2Robot(ctx context.Context, params operation.Update
if err := rAPI.validate(params.Robot.Duration, params.Robot.Level, params.Robot.Permissions); err != nil {
return err
}
if err := rAPI.requireAccess(ctx, params.Robot.Level, params.Robot.Permissions[0].Namespace, rbac.ActionUpdate); err != nil {
projectID, err := getProjectID(ctx, params.Robot.Permissions[0].Namespace)
if err != nil {
return err
}
if r.Level != robot.LEVELSYSTEM && r.ProjectID != projectID {
return errors.BadRequestError(nil).WithMessage("cannot update the project id of robot")
}
if err := rAPI.requireAccess(ctx, params.Robot.Level, projectID, rbac.ActionUpdate); err != nil {
return err
}
if params.Robot.Level != r.Level || params.Robot.Name != r.Name {
return errors.BadRequestError(nil).WithMessage("cannot update the level or name of robot")
}
@ -333,7 +351,7 @@ func isValidDuration(d int64) bool {
func isValidSec(sec string) bool {
hasLower := regexp.MustCompile(`[a-z]`)
hasUpper := regexp.MustCompile(`[A-Z]`)
hasNumber := regexp.MustCompile(`[0-9]`)
hasNumber := regexp.MustCompile(`\d`)
if len(sec) >= 8 && hasLower.MatchString(sec) && hasUpper.MatchString(sec) && hasNumber.MatchString(sec) {
return true
}