mirror of
https://github.com/goharbor/harbor
synced 2025-04-21 17:51:41 +00:00

Support specifying what part of the repository will be replaced by the provided namespace Signed-off-by: Wenkai Yin <yinw@vmware.com>
304 lines
9.6 KiB
Go
304 lines
9.6 KiB
Go
// 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"
|
|
"github.com/goharbor/harbor/src/lib"
|
|
"github.com/goharbor/harbor/src/lib/errors"
|
|
"strings"
|
|
|
|
"github.com/go-openapi/runtime/middleware"
|
|
"github.com/goharbor/harbor/src/common/rbac"
|
|
"github.com/goharbor/harbor/src/controller/registry"
|
|
"github.com/goharbor/harbor/src/lib/q"
|
|
"github.com/goharbor/harbor/src/pkg/reg/model"
|
|
"github.com/goharbor/harbor/src/server/v2.0/models"
|
|
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/registry"
|
|
)
|
|
|
|
func newRegistryAPI() *registryAPI {
|
|
return ®istryAPI{
|
|
ctl: registry.Ctl,
|
|
}
|
|
}
|
|
|
|
type registryAPI struct {
|
|
BaseAPI
|
|
ctl registry.Controller
|
|
}
|
|
|
|
func (r *registryAPI) CreateRegistry(ctx context.Context, params operation.CreateRegistryParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionCreate, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
registry := &model.Registry{
|
|
Name: params.Registry.Name,
|
|
Description: params.Registry.Description,
|
|
Type: params.Registry.Type,
|
|
URL: params.Registry.URL,
|
|
Insecure: params.Registry.Insecure,
|
|
}
|
|
if params.Registry.Credential != nil {
|
|
registry.Credential = &model.Credential{
|
|
Type: params.Registry.Credential.Type,
|
|
AccessKey: params.Registry.Credential.AccessKey,
|
|
AccessSecret: params.Registry.Credential.AccessSecret,
|
|
}
|
|
}
|
|
|
|
id, err := r.ctl.Create(ctx, registry)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
location := fmt.Sprintf("%s/%d", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), id)
|
|
return operation.NewCreateRegistryCreated().WithLocation(location)
|
|
}
|
|
|
|
func (r *registryAPI) GetRegistry(ctx context.Context, params operation.GetRegistryParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
registry, err := r.ctl.Get(ctx, params.ID)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
return operation.NewGetRegistryOK().WithPayload(convertRegistry(registry))
|
|
}
|
|
|
|
func (r *registryAPI) ListRegistries(ctx context.Context, params operation.ListRegistriesParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
query, err := r.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
// keep backward compatibility for the "name" query
|
|
if params.Name != nil {
|
|
query.Keywords["Name"] = q.NewFuzzyMatchValue(*params.Name)
|
|
}
|
|
|
|
total, err := r.ctl.Count(ctx, query)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
registries, err := r.ctl.List(ctx, query)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
var regs []*models.Registry
|
|
for _, registry := range registries {
|
|
regs = append(regs, convertRegistry(registry))
|
|
}
|
|
return operation.NewListRegistriesOK().WithXTotalCount(total).
|
|
WithLink(r.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
|
|
WithPayload(regs)
|
|
}
|
|
|
|
func (r *registryAPI) DeleteRegistry(ctx context.Context, params operation.DeleteRegistryParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionDelete, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
if err := r.ctl.Delete(ctx, params.ID); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
return operation.NewDeleteRegistryOK()
|
|
}
|
|
|
|
func (r *registryAPI) UpdateRegistry(ctx context.Context, params operation.UpdateRegistryParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionUpdate, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
registry, err := r.ctl.Get(ctx, params.ID)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
if params.Registry != nil {
|
|
if params.Registry.Name != nil {
|
|
registry.Name = *params.Registry.Name
|
|
}
|
|
if params.Registry.Description != nil {
|
|
registry.Description = *params.Registry.Description
|
|
}
|
|
if params.Registry.URL != nil {
|
|
registry.URL = *params.Registry.URL
|
|
}
|
|
if params.Registry.Insecure != nil {
|
|
registry.Insecure = *params.Registry.Insecure
|
|
}
|
|
if registry.Credential == nil {
|
|
registry.Credential = &model.Credential{}
|
|
}
|
|
if params.Registry.CredentialType != nil {
|
|
registry.Credential.Type = *params.Registry.CredentialType
|
|
}
|
|
if params.Registry.AccessKey != nil {
|
|
registry.Credential.AccessKey = *params.Registry.AccessKey
|
|
}
|
|
if params.Registry.AccessSecret != nil {
|
|
registry.Credential.AccessSecret = *params.Registry.AccessSecret
|
|
}
|
|
}
|
|
if err := r.ctl.Update(ctx, registry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
return operation.NewUpdateRegistryOK()
|
|
}
|
|
|
|
func (r *registryAPI) GetRegistryInfo(ctx context.Context, params operation.GetRegistryInfoParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
info, err := r.ctl.GetInfo(ctx, params.ID)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
in := &models.RegistryInfo{
|
|
Description: info.Description,
|
|
Type: string(info.Type),
|
|
}
|
|
for _, filter := range info.SupportedResourceFilters {
|
|
in.SupportedResourceFilters = append(in.SupportedResourceFilters, &models.FilterStyle{
|
|
Style: filter.Style,
|
|
Type: string(filter.Type),
|
|
Values: filter.Values,
|
|
})
|
|
}
|
|
for _, trigger := range info.SupportedTriggers {
|
|
in.SupportedTriggers = append(in.SupportedTriggers, string(trigger))
|
|
}
|
|
return operation.NewGetRegistryInfoOK().WithPayload(in)
|
|
}
|
|
|
|
func (r *registryAPI) ListRegistryProviderTypes(ctx context.Context, params operation.ListRegistryProviderTypesParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceReplicationAdapter); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
types, err := r.ctl.ListRegistryProviderTypes(ctx)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
return operation.NewListRegistryProviderTypesOK().WithPayload(types)
|
|
}
|
|
|
|
func (r *registryAPI) PingRegistry(ctx context.Context, params operation.PingRegistryParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceRegistry); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
registry := &model.Registry{}
|
|
var err error
|
|
if params.Registry != nil {
|
|
if params.Registry.ID != nil {
|
|
registry, err = r.ctl.Get(ctx, *params.Registry.ID)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
}
|
|
if params.Registry.Type != nil {
|
|
registry.Type = *params.Registry.Type
|
|
}
|
|
if params.Registry.URL != nil {
|
|
url, err := lib.ValidateHTTPURL(*params.Registry.URL)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
registry.URL = url
|
|
}
|
|
if params.Registry.Insecure != nil {
|
|
registry.Insecure = *params.Registry.Insecure
|
|
}
|
|
if params.Registry.CredentialType != nil {
|
|
if registry.Credential == nil {
|
|
registry.Credential = &model.Credential{}
|
|
}
|
|
registry.Credential.Type = *params.Registry.CredentialType
|
|
}
|
|
if params.Registry.AccessKey != nil {
|
|
if registry.Credential == nil {
|
|
registry.Credential = &model.Credential{}
|
|
}
|
|
registry.Credential.AccessKey = *params.Registry.AccessKey
|
|
}
|
|
if params.Registry.AccessSecret != nil {
|
|
if registry.Credential == nil {
|
|
registry.Credential = &model.Credential{}
|
|
}
|
|
registry.Credential.AccessSecret = *params.Registry.AccessSecret
|
|
}
|
|
}
|
|
|
|
if len(registry.Type) == 0 || len(registry.URL) == 0 {
|
|
return r.SendError(ctx, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("type or url cannot be empty"))
|
|
}
|
|
|
|
healthy, err := r.ctl.IsHealthy(ctx, registry)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
if !healthy {
|
|
return r.SendError(ctx, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("the registry is unhealthy"))
|
|
}
|
|
|
|
return operation.NewPingRegistryOK()
|
|
}
|
|
|
|
func (r *registryAPI) ListRegistryProviderInfos(ctx context.Context, params operation.ListRegistryProviderInfosParams) middleware.Responder {
|
|
if err := r.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceReplicationAdapter); err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
infos, err := r.ctl.ListRegistryProviderInfos(ctx)
|
|
if err != nil {
|
|
return r.SendError(ctx, err)
|
|
}
|
|
|
|
result := map[string]models.RegistryProviderInfo{}
|
|
for key, info := range infos {
|
|
item := models.RegistryProviderInfo{}
|
|
if info.CredentialPattern != nil {
|
|
item.CredentialPattern = &models.RegistryProviderCredentialPattern{
|
|
AccessKeyData: info.CredentialPattern.AccessKeyData,
|
|
AccessKeyType: info.CredentialPattern.AccessKeyType,
|
|
AccessSecretData: info.CredentialPattern.AccessSecretData,
|
|
AccessSecretType: info.CredentialPattern.AccessSecretType,
|
|
}
|
|
}
|
|
if info.EndpointPattern != nil {
|
|
item.EndpointPattern = &models.RegistryProviderEndpointPattern{
|
|
EndpointType: info.EndpointPattern.EndpointType,
|
|
}
|
|
for _, endpoint := range info.EndpointPattern.Endpoints {
|
|
item.EndpointPattern.Endpoints = append(item.EndpointPattern.Endpoints, &models.RegistryEndpoint{
|
|
Key: endpoint.Key,
|
|
Value: endpoint.Value,
|
|
})
|
|
}
|
|
}
|
|
result[key] = item
|
|
}
|
|
|
|
return operation.NewListRegistryProviderInfosOK().WithPayload(result)
|
|
}
|