drone/registry/app/pkg/maven/controller.go

252 lines
7.0 KiB
Go

// Copyright 2023 Harness, Inc.
//
// 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 maven
import (
"context"
"io"
"github.com/harness/gitness/app/auth/authz"
corestore "github.com/harness/gitness/app/store"
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
"github.com/harness/gitness/registry/app/dist_temp/errcode"
"github.com/harness/gitness/registry/app/pkg"
"github.com/harness/gitness/registry/app/store"
registrytypes "github.com/harness/gitness/registry/types"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
var _ Artifact = (*LocalRegistry)(nil)
var _ Artifact = (*RemoteRegistry)(nil)
type ArtifactType int
const (
LocalRegistryType ArtifactType = 1 << iota
RemoteRegistryType
)
var TypeRegistry = map[ArtifactType]Artifact{}
type Controller struct {
local *LocalRegistry
remote *RemoteRegistry
authorizer authz.Authorizer
DBStore *DBStore
_ dbtx.Transactor
}
type DBStore struct {
RegistryDao store.RegistryRepository
ImageDao store.ImageRepository
ArtifactDao store.ArtifactRepository
SpaceStore corestore.SpaceStore
BandwidthStatDao store.BandwidthStatRepository
DownloadStatDao store.DownloadStatRepository
NodeDao store.NodesRepository
UpstreamProxyDao store.UpstreamProxyConfigRepository
}
func NewController(
local *LocalRegistry,
remote *RemoteRegistry,
authorizer authz.Authorizer,
dBStore *DBStore,
) *Controller {
c := &Controller{
local: local,
remote: remote,
authorizer: authorizer,
DBStore: dBStore,
}
TypeRegistry[LocalRegistryType] = local
TypeRegistry[RemoteRegistryType] = remote
return c
}
func NewDBStore(
registryDao store.RegistryRepository,
imageDao store.ImageRepository,
artifactDao store.ArtifactRepository,
spaceStore corestore.SpaceStore,
bandwidthStatDao store.BandwidthStatRepository,
downloadStatDao store.DownloadStatRepository,
nodeDao store.NodesRepository,
upstreamProxyDao store.UpstreamProxyConfigRepository,
) *DBStore {
return &DBStore{
RegistryDao: registryDao,
SpaceStore: spaceStore,
ImageDao: imageDao,
ArtifactDao: artifactDao,
BandwidthStatDao: bandwidthStatDao,
DownloadStatDao: downloadStatDao,
NodeDao: nodeDao,
UpstreamProxyDao: upstreamProxyDao,
}
}
func (c *Controller) factory(t ArtifactType) Artifact {
switch t {
case LocalRegistryType:
return TypeRegistry[t]
case RemoteRegistryType:
return TypeRegistry[t]
default:
log.Error().Stack().Msgf("Invalid artifact type %v", t)
return nil
}
}
func (c *Controller) GetArtifactRegistry(registry registrytypes.Registry) Artifact {
if string(registry.Type) == string(artifact.RegistryTypeVIRTUAL) {
return c.factory(LocalRegistryType)
}
return c.factory(RemoteRegistryType)
}
func (c *Controller) GetArtifact(ctx context.Context, info pkg.MavenArtifactInfo) Response {
err := pkg.GetRegistryCheckAccess(
ctx, c.DBStore.RegistryDao, c.authorizer, c.DBStore.SpaceStore, info.RegIdentifier, info.ParentID,
enum.PermissionArtifactsDownload,
)
if err != nil {
return &GetArtifactResponse{
Errors: []error{errcode.ErrCodeDenied},
}
}
f := func(registry registrytypes.Registry, a Artifact) Response {
info.SetMavenRepoKey(registry.Name)
info.RegistryID = registry.ID
r, ok := a.(Registry)
if !ok {
log.Error().Stack().Msgf("Proxy wrapper has invalid registry set")
return nil
}
headers, body, fileReader, redirectURL, e := r.GetArtifact(ctx, info) //nolint:errcheck
return &GetArtifactResponse{
e, headers, redirectURL,
body, fileReader,
}
}
return c.ProxyWrapper(ctx, f, info)
}
func (c *Controller) HeadArtifact(ctx context.Context, info pkg.MavenArtifactInfo) Response {
err := pkg.GetRegistryCheckAccess(
ctx, c.DBStore.RegistryDao, c.authorizer, c.DBStore.SpaceStore, info.RegIdentifier, info.ParentID,
enum.PermissionArtifactsDownload,
)
if err != nil {
return &HeadArtifactResponse{
Errors: []error{errcode.ErrCodeDenied},
}
}
f := func(registry registrytypes.Registry, a Artifact) Response {
info.SetMavenRepoKey(registry.Name)
info.RegistryID = registry.ID
r, ok := a.(Registry)
if !ok {
log.Error().Stack().Msgf("Proxy wrapper has invalid registry set")
return nil
}
headers, e := r.HeadArtifact(ctx, info)
return &HeadArtifactResponse{e, headers}
}
return c.ProxyWrapper(ctx, f, info)
}
func (c *Controller) PutArtifact(ctx context.Context, info pkg.MavenArtifactInfo, fileReader io.Reader) Response {
err := pkg.GetRegistryCheckAccess(
ctx, c.DBStore.RegistryDao, c.authorizer, c.DBStore.SpaceStore, info.RegIdentifier, info.ParentID,
enum.PermissionArtifactsUpload,
)
if err != nil {
return &PutArtifactResponse{
Errors: []error{errcode.ErrCodeDenied},
}
}
responseHeaders, errs := c.local.PutArtifact(ctx, info, fileReader)
return &PutArtifactResponse{
ResponseHeaders: responseHeaders,
Errors: errs,
}
}
func (c *Controller) ProxyWrapper(
ctx context.Context,
f func(registry registrytypes.Registry, a Artifact) Response,
info pkg.MavenArtifactInfo,
) Response {
none := pkg.MavenArtifactInfo{}
if info == none {
log.Ctx(ctx).Error().Stack().Msg("artifactinfo is not found")
return nil
}
var response Response
requestRepoKey := info.RegIdentifier
if repos, err := c.GetOrderedRepos(ctx, requestRepoKey, *info.BaseInfo); err == nil {
for _, registry := range repos {
log.Ctx(ctx).Info().Msgf("Using Repository: %s, Type: %s", registry.Name, registry.Type)
artifact, ok := c.GetArtifactRegistry(registry).(Registry)
if !ok {
log.Ctx(ctx).Warn().Msgf("artifact %s is not a registry", registry.Name)
continue
}
if artifact != nil {
response = f(registry, artifact)
if pkg.IsEmpty(response.GetErrors()) {
return response
}
log.Ctx(ctx).Warn().Msgf("Repository: %s, Type: %s, errors: %v", registry.Name, registry.Type,
response.GetErrors())
}
}
}
return response
}
func (c *Controller) GetOrderedRepos(
ctx context.Context,
repoKey string,
artInfo pkg.BaseInfo,
) ([]registrytypes.Registry, error) {
var result []registrytypes.Registry
if registry, err := c.DBStore.RegistryDao.GetByParentIDAndName(ctx, artInfo.ParentID, repoKey); err == nil {
result = append(result, *registry)
proxies := registry.UpstreamProxies
if len(proxies) > 0 {
upstreamRepos, err := c.DBStore.RegistryDao.GetByIDIn(ctx, proxies)
if err != nil {
return result, err
}
result = append(result, *upstreamRepos...)
}
} else {
return result, err
}
return result, nil
}