Remove robotV1 from code base (#20958) (#20991)

It was deprecated in 2.4.0.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
Co-authored-by: Wang Yan <wangyan@vmware.com>
This commit is contained in:
Samuel Gaist 2025-01-10 06:36:28 +01:00 committed by GitHub
parent 12382fa8ae
commit 15d17a3338
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 0 additions and 447 deletions

View File

@ -2438,160 +2438,6 @@ paths:
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
/projects/{project_name_or_id}/robots:
get:
summary: Get all robot accounts of specified project
description: Get all robot accounts of specified project
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/page'
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/query'
- $ref: '#/parameters/sort'
tags:
- robotv1
operationId: ListRobotV1
responses:
'200':
description: Success
headers:
X-Total-Count:
description: The total count of robot accounts
type: integer
Link:
description: Link refers to the previous page and next page
type: string
schema:
type: array
items:
$ref: '#/definitions/Robot'
'400':
$ref: '#/responses/400'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
post:
summary: Create a robot account
description: Create a robot account
tags:
- robotv1
operationId: CreateRobotV1
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- name: robot
in: body
description: The JSON object of a robot account.
required: true
schema:
$ref: '#/definitions/RobotCreateV1'
responses:
'201':
description: Created
headers:
X-Request-Id:
description: The ID of the corresponding request for the response
type: string
Location:
description: The location of the resource
type: string
schema:
$ref: '#/definitions/RobotCreated'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
/projects/{project_name_or_id}/robots/{robot_id}:
get:
summary: Get a robot account
description: This endpoint returns specific robot account information by robot ID.
tags:
- robotv1
operationId: GetRobotByIDV1
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId'
responses:
'200':
description: Return matched robot information.
schema:
$ref: '#/definitions/Robot'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
put:
summary: Update status of robot account.
description: Used to disable/enable a specified robot account.
tags:
- robotv1
operationId: UpdateRobotV1
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId'
- name: robot
in: body
description: The JSON object of a robot account.
required: true
schema:
$ref: '#/definitions/Robot'
responses:
'200':
$ref: '#/responses/200'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'409':
$ref: '#/responses/409'
'500':
$ref: '#/responses/500'
delete:
summary: Delete a robot account
description: This endpoint deletes specific robot account information by robot ID.
tags:
- robotv1
operationId: DeleteRobotV1
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId'
responses:
'200':
$ref: '#/responses/200'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
'/projects/{project_name_or_id}/immutabletagrules':
get:
summary: List all immutable tag rules of current project

View File

@ -44,7 +44,6 @@ func New() http.Handler {
PreheatAPI: newPreheatAPI(),
IconAPI: newIconAPI(),
RobotAPI: newRobotAPI(),
Robotv1API: newRobotV1API(),
ReplicationAPI: newReplicationAPI(),
RegistryAPI: newRegistryAPI(),
SysteminfoAPI: newSystemInfoAPI(),

View File

@ -1,292 +0,0 @@
// 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"
"regexp"
"strings"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/common/rbac"
rbac_project "github.com/goharbor/harbor/src/common/rbac/project"
"github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/controller/robot"
"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/permission/types"
pkg_robot "github.com/goharbor/harbor/src/pkg/robot"
pkg "github.com/goharbor/harbor/src/pkg/robot/model"
handler_model "github.com/goharbor/harbor/src/server/v2.0/handler/model"
"github.com/goharbor/harbor/src/server/v2.0/models"
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/robotv1"
)
func newRobotV1API() *robotV1API {
return &robotV1API{
robotCtl: robot.Ctl,
robotMgr: pkg_robot.Mgr,
projectCtr: project.Ctl,
}
}
type robotV1API struct {
BaseAPI
robotCtl robot.Controller
robotMgr pkg_robot.Manager
projectCtr project.Controller
}
func (rAPI *robotV1API) CreateRobotV1(ctx context.Context, params operation.CreateRobotV1Params) middleware.Responder {
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionCreate, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err)
}
if err := rAPI.validate(ctx, params); err != nil {
return rAPI.SendError(ctx, err)
}
r := &robot.Robot{
Robot: pkg.Robot{
Name: params.Robot.Name,
Description: params.Robot.Description,
ExpiresAt: params.Robot.ExpiresAt,
Visible: true,
},
Level: robot.LEVELPROJECT,
}
projectName, ok := projectNameOrID.(string)
if !ok {
p, err := rAPI.projectCtr.Get(ctx, projectNameOrID, project.Metadata(false))
if err != nil {
log.Errorf("failed to get project %s: %v", projectNameOrID, err)
return rAPI.SendError(ctx, err)
}
projectName = p.Name
}
permission := &robot.Permission{
Kind: "project",
Namespace: projectName,
}
var policies []*types.Policy
for _, acc := range params.Robot.Access {
policy := &types.Policy{
Action: types.Action(acc.Action),
Effect: types.Effect(acc.Effect),
}
res, err := getRawResource(acc.Resource)
if err != nil {
return rAPI.SendError(ctx, err)
}
policy.Resource = types.Resource(res)
policies = append(policies, policy)
}
permission.Access = policies
r.Permissions = append(r.Permissions, permission)
rid, pwd, err := rAPI.robotCtl.Create(ctx, r)
if err != nil {
return rAPI.SendError(ctx, err)
}
created, err := rAPI.robotCtl.Get(ctx, rid, nil)
if err != nil {
return rAPI.SendError(ctx, err)
}
location := fmt.Sprintf("%s/%d", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), created.ID)
return operation.NewCreateRobotV1Created().WithLocation(location).WithPayload(&models.RobotCreated{
ID: created.ID,
Name: created.Name,
Secret: pwd,
CreationTime: strfmt.DateTime(created.CreationTime),
})
}
func (rAPI *robotV1API) DeleteRobotV1(ctx context.Context, params operation.DeleteRobotV1Params) middleware.Responder {
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err)
}
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil {
return rAPI.SendError(ctx, err)
}
r, err := rAPI.robotCtl.List(ctx, q.New(q.KeyWords{"ProjectID": pro.ProjectID, "ID": params.RobotID}), &robot.Option{
WithPermission: true,
})
if err != nil {
return rAPI.SendError(ctx, err)
}
if len(r) == 0 {
return rAPI.SendError(ctx, errors.NotFoundError(fmt.Errorf("cannot find robot with project id: %d and id: %d", pro.ProjectID, params.RobotID)))
}
// ignore the not permissions error.
if err := rAPI.robotCtl.Delete(ctx, params.RobotID); err != nil && !errors.IsNotFoundErr(err) {
return rAPI.SendError(ctx, err)
}
return operation.NewDeleteRobotV1OK()
}
func (rAPI *robotV1API) ListRobotV1(ctx context.Context, params operation.ListRobotV1Params) middleware.Responder {
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionList, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err)
}
query, err := rAPI.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
if err != nil {
return rAPI.SendError(ctx, err)
}
query.Keywords["Visible"] = true
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil {
return rAPI.SendError(ctx, err)
}
query.Keywords["ProjectID"] = pro.ProjectID
total, err := rAPI.robotCtl.Count(ctx, query)
if err != nil {
return rAPI.SendError(ctx, err)
}
robots, err := rAPI.robotCtl.List(ctx, query, &robot.Option{
WithPermission: true,
})
if err != nil {
return rAPI.SendError(ctx, err)
}
var results []*models.Robot
for _, r := range robots {
results = append(results, handler_model.NewRobot(r).ToSwagger())
}
return operation.NewListRobotV1OK().
WithXTotalCount(total).
WithLink(rAPI.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
WithPayload(results)
}
func (rAPI *robotV1API) GetRobotByIDV1(ctx context.Context, params operation.GetRobotByIDV1Params) middleware.Responder {
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionRead, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err)
}
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil {
return rAPI.SendError(ctx, err)
}
r, err := rAPI.robotCtl.List(ctx, q.New(q.KeyWords{"ProjectID": pro.ProjectID, "ID": params.RobotID}), &robot.Option{
WithPermission: true,
})
if err != nil {
return rAPI.SendError(ctx, err)
}
if len(r) == 0 {
return rAPI.SendError(ctx, errors.NotFoundError(fmt.Errorf("cannot find robot with project id: %d and id: %d", pro.ProjectID, params.RobotID)))
}
return operation.NewGetRobotByIDV1OK().WithPayload(handler_model.NewRobot(r[0]).ToSwagger())
}
func (rAPI *robotV1API) UpdateRobotV1(ctx context.Context, params operation.UpdateRobotV1Params) middleware.Responder {
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionUpdate, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err)
}
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil {
return rAPI.SendError(ctx, err)
}
r, err := rAPI.robotCtl.List(ctx, q.New(q.KeyWords{"ProjectID": pro.ProjectID, "ID": params.RobotID}), &robot.Option{
WithPermission: true,
})
if err != nil {
return rAPI.SendError(ctx, err)
}
if len(r) == 0 {
return rAPI.SendError(ctx, errors.NotFoundError(fmt.Errorf("cannot find robot with project id: %d and id: %d", pro.ProjectID, params.RobotID)))
}
robot := r[0]
// for v1 API, only update the disable.
robot.Disabled = params.Robot.Disable
if err := rAPI.robotCtl.Update(ctx, robot, nil); err != nil {
return rAPI.SendError(ctx, err)
}
return operation.NewUpdateRobotV1OK()
}
func (rAPI *robotV1API) validate(ctx context.Context, params operation.CreateRobotV1Params) error {
if params.Robot == nil {
return errors.New(nil).WithMessage("bad request no robot").WithCode(errors.BadRequestCode)
}
if len(params.Robot.Access) == 0 {
return errors.New(nil).WithMessage("bad request no access").WithCode(errors.BadRequestCode)
}
projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil {
return err
}
policies := rbac_project.GetPoliciesOfProject(pro.ProjectID)
mp := map[string]bool{}
for _, policy := range policies {
mp[policy.String()] = true
}
for _, policy := range params.Robot.Access {
p := &types.Policy{}
if err := lib.JSONCopy(p, policy); err != nil {
log.Warningf("failed to call JSONCopy on robot access policy when validate, error: %v", err)
}
if !mp[p.String()] {
return errors.New(nil).WithMessagef("%s action of %s resource not exist in project %s", policy.Action, policy.Resource, projectNameOrID).WithCode(errors.BadRequestCode)
}
}
return nil
}
// /project/1/repository => repository
func getRawResource(resource string) (string, error) {
resourceReg := regexp.MustCompile("^/project/[0-9]+/(?P<repository>[a-z-]+)$")
matches := resourceReg.FindStringSubmatch(resource)
if len(matches) <= 1 {
return "", errors.New(nil).WithMessagef("bad resource %s", resource).WithCode(errors.BadRequestCode)
}
return matches[1], nil
}