From a555b09df02875a31e85529eda5aa12c0e207c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=85=95=E8=96=87=E7=96=AF=E9=AD=94?= Date: Sun, 31 Mar 2019 23:40:19 +0800 Subject: [PATCH] 1. Implement native docker registry adapter. 2. register the native adapter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 慕薇疯魔 --- .../job/impl/replication/ng/replication.go | 2 + src/replication/ng/adapter/image_registry.go | 20 +++ src/replication/ng/adapter/native/adapter.go | 89 ++++++++++++ .../ng/adapter/native/image_registry.go | 129 ++++++++++++++++++ src/replication/ng/replication.go | 2 + 5 files changed, 242 insertions(+) create mode 100644 src/replication/ng/adapter/native/adapter.go create mode 100644 src/replication/ng/adapter/native/image_registry.go diff --git a/src/jobservice/job/impl/replication/ng/replication.go b/src/jobservice/job/impl/replication/ng/replication.go index 140a4af52..354af73eb 100644 --- a/src/jobservice/job/impl/replication/ng/replication.go +++ b/src/jobservice/job/impl/replication/ng/replication.go @@ -30,6 +30,8 @@ import ( _ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor" // register the DockerHub adapter _ "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 diff --git a/src/replication/ng/adapter/image_registry.go b/src/replication/ng/adapter/image_registry.go index 03b606bb1..55f7cb598 100644 --- a/src/replication/ng/adapter/image_registry.go +++ b/src/replication/ng/adapter/image_registry.go @@ -279,3 +279,23 @@ func (d *DefaultImageRegistry) PushBlob(repository, digest string, size int64, b func isDigest(str string) bool { 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() +} diff --git a/src/replication/ng/adapter/native/adapter.go b/src/replication/ng/adapter/native/adapter.go new file mode 100644 index 000000000..c6479da92 --- /dev/null +++ b/src/replication/ng/adapter/native/adapter.go @@ -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 +} diff --git a/src/replication/ng/adapter/native/image_registry.go b/src/replication/ng/adapter/native/image_registry.go new file mode 100644 index 000000000..f733167e5 --- /dev/null +++ b/src/replication/ng/adapter/native/image_registry.go @@ -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 +} diff --git a/src/replication/ng/replication.go b/src/replication/ng/replication.go index 5180b66f3..004b7191b 100644 --- a/src/replication/ng/replication.go +++ b/src/replication/ng/replication.go @@ -33,6 +33,8 @@ import ( _ "github.com/goharbor/harbor/src/replication/ng/adapter/dockerhub" // register the DockerHub adapter _ "github.com/goharbor/harbor/src/replication/ng/adapter/harbor" + // register the Native adapter + _ "github.com/goharbor/harbor/src/replication/ng/adapter/native" ) var (