mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 18:55:18 +01:00
Merge pull request #7255 from kofj/native_adapter
Implement native docker registry.
This commit is contained in:
commit
63852d6073
@ -30,6 +30,8 @@ import (
|
|||||||
_ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor"
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor"
|
||||||
// register the DockerHub adapter
|
// register the DockerHub adapter
|
||||||
_ "github.com/goharbor/harbor/src/replication/ng/adapter/dockerhub"
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/dockerhub"
|
||||||
|
// register the Native adapter
|
||||||
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/native"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Replication implements the job interface
|
// Replication implements the job interface
|
||||||
|
@ -279,3 +279,23 @@ func (d *DefaultImageRegistry) PushBlob(repository, digest string, size int64, b
|
|||||||
func isDigest(str string) bool {
|
func isDigest(str string) bool {
|
||||||
return strings.Contains(str, ":")
|
return strings.Contains(str, ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListTag ...
|
||||||
|
func (d *DefaultImageRegistry) ListTag(repository string) ([]string, error) {
|
||||||
|
client, err := d.getClient(repository)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.ListTag()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catalog ...
|
||||||
|
func (d *DefaultImageRegistry) Catalog() ([]string, error) {
|
||||||
|
client, err := registry_pkg.NewRegistry(d.registry.URL, d.client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Catalog()
|
||||||
|
}
|
||||||
|
89
src/replication/ng/adapter/native/adapter.go
Normal file
89
src/replication/ng/adapter/native/adapter.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
|
adp "github.com/goharbor/harbor/src/replication/ng/adapter"
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const registryTypeNative model.RegistryType = "native"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := adp.RegisterFactory(registryTypeNative, func(registry *model.Registry) (adp.Adapter, error) {
|
||||||
|
return &native{
|
||||||
|
registry: registry,
|
||||||
|
DefaultImageRegistry: adp.NewDefaultImageRegistry(registry),
|
||||||
|
}, nil
|
||||||
|
}); err != nil {
|
||||||
|
log.Errorf("failed to register factory for %s: %v", registryTypeNative, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("the factory for adapter %s registered", registryTypeNative)
|
||||||
|
}
|
||||||
|
|
||||||
|
type native struct {
|
||||||
|
*adp.DefaultImageRegistry
|
||||||
|
registry *model.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ adp.Adapter = native{}
|
||||||
|
|
||||||
|
func (native) Info() (info *model.RegistryInfo, err error) {
|
||||||
|
return &model.RegistryInfo{
|
||||||
|
Type: registryTypeNative,
|
||||||
|
SupportedResourceTypes: []model.ResourceType{
|
||||||
|
model.ResourceTypeRepository,
|
||||||
|
},
|
||||||
|
SupportedResourceFilters: []*model.FilterStyle{
|
||||||
|
{
|
||||||
|
Type: model.FilterTypeName,
|
||||||
|
Style: model.FilterStyleTypeText,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: model.FilterTypeTag,
|
||||||
|
Style: model.FilterStyleTypeText,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SupportedTriggers: []model.TriggerType{
|
||||||
|
model.TriggerTypeManual,
|
||||||
|
model.TriggerTypeScheduled,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertResourceMetadata convert src to dst resource
|
||||||
|
func (native) ConvertResourceMetadata(metadata *model.ResourceMetadata, namespace *model.Namespace) (*model.ResourceMetadata, error) {
|
||||||
|
if metadata == nil {
|
||||||
|
return nil, errors.New("the metadata cannot be null")
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = &model.ResourceMetadata{
|
||||||
|
Namespace: metadata.Namespace,
|
||||||
|
Repository: metadata.Repository,
|
||||||
|
Vtags: metadata.Vtags,
|
||||||
|
}
|
||||||
|
|
||||||
|
// if dest namespace is set, rename metadata namespace
|
||||||
|
if namespace != nil {
|
||||||
|
result.Namespace = namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Repository = &model.Repository{Name: result.GetResourceName()}
|
||||||
|
result.Namespace = nil
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareForPush nothing need to do.
|
||||||
|
func (native) PrepareForPush(*model.Resource) error { return nil }
|
||||||
|
|
||||||
|
// GetNamespace naitve registry no namespace.
|
||||||
|
func (native) GetNamespace(name string) (*model.Namespace, error) {
|
||||||
|
return &model.Namespace{Name: name}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNamespaces native registry no namespaces, so list empty array.
|
||||||
|
func (native) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) {
|
||||||
|
return []*model.Namespace{}, nil
|
||||||
|
}
|
129
src/replication/ng/adapter/native/image_registry.go
Normal file
129
src/replication/ng/adapter/native/image_registry.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
adp "github.com/goharbor/harbor/src/replication/ng/adapter"
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ adp.ImageRegistry = native{}
|
||||||
|
|
||||||
|
// TODO: support other filters
|
||||||
|
// MUST have filters and name filter
|
||||||
|
// NOT support namespaces
|
||||||
|
func (n native) FetchImages(namespaces []string, filters []*model.Filter) ([]*model.Resource, error) {
|
||||||
|
if len(namespaces) > 0 {
|
||||||
|
return nil, errors.New("native registry adapter not support namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filters) < 1 {
|
||||||
|
return nil, errors.New("no any repository filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources = []*model.Resource{}
|
||||||
|
var nameFilter, tagFilter *model.Filter
|
||||||
|
for i, filter := range filters {
|
||||||
|
switch filter.Type {
|
||||||
|
case model.FilterTypeName:
|
||||||
|
nameFilter = filters[i]
|
||||||
|
case model.FilterTypeTag:
|
||||||
|
tagFilter = filters[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories, err := n.filterRepoistory(nameFilter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagFilterTerm string
|
||||||
|
var haveWildcardChars bool
|
||||||
|
|
||||||
|
if tagFilter != nil {
|
||||||
|
tagFilterTerm = tagFilter.Value.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ContainsAny(tagFilterTerm, "?*") {
|
||||||
|
haveWildcardChars = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if haveWildcardChars || tagFilterTerm == "" {
|
||||||
|
// need call list tag api
|
||||||
|
for _, repository := range repositories {
|
||||||
|
var tags []string
|
||||||
|
resp, err := n.DefaultImageRegistry.ListTag(repository)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if haveWildcardChars {
|
||||||
|
for _, tag := range resp {
|
||||||
|
if m, _ := util.Match(tagFilterTerm, tag); m {
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tags = resp
|
||||||
|
}
|
||||||
|
|
||||||
|
resources = append(resources, &model.Resource{
|
||||||
|
Type: model.ResourceTypeRepository,
|
||||||
|
Registry: n.registry,
|
||||||
|
Metadata: &model.ResourceMetadata{
|
||||||
|
Repository: &model.Repository{
|
||||||
|
Name: repository,
|
||||||
|
},
|
||||||
|
Vtags: tags,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if tagFilterTerm != "" {
|
||||||
|
for _, repository := range repositories {
|
||||||
|
resources = append(resources, &model.Resource{
|
||||||
|
Type: model.ResourceTypeRepository,
|
||||||
|
Registry: n.registry,
|
||||||
|
Metadata: &model.ResourceMetadata{
|
||||||
|
Repository: &model.Repository{
|
||||||
|
Name: repository,
|
||||||
|
},
|
||||||
|
Vtags: []string{tagFilterTerm},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n native) filterRepoistory(nameFilter *model.Filter) (repositories []string, err error) {
|
||||||
|
if nameFilter == nil {
|
||||||
|
return nil, errors.New("native registry adapter must have repository filter")
|
||||||
|
}
|
||||||
|
var nameFilterTerm = nameFilter.Value.(string)
|
||||||
|
|
||||||
|
// search repoistories from catalog api
|
||||||
|
if strings.ContainsAny(nameFilterTerm, "*?") {
|
||||||
|
repos, err := n.DefaultImageRegistry.Catalog()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, repo := range repos {
|
||||||
|
m, err := util.Match(nameFilterTerm, repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if m {
|
||||||
|
repositories = append(repositories, repo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if nameFilterTerm != "" {
|
||||||
|
// only single repository
|
||||||
|
repositories = []string{nameFilterTerm}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -33,6 +33,8 @@ import (
|
|||||||
_ "github.com/goharbor/harbor/src/replication/ng/adapter/dockerhub"
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/dockerhub"
|
||||||
// register the DockerHub adapter
|
// register the DockerHub adapter
|
||||||
_ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor"
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor"
|
||||||
|
// register the Native adapter
|
||||||
|
_ "github.com/goharbor/harbor/src/replication/ng/adapter/native"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
Loading…
Reference in New Issue
Block a user