1. Implement native docker registry adapter.

2. register the native adapter.

Signed-off-by: 慕薇疯魔 <kfanjian@gmail.com>
This commit is contained in:
慕薇疯魔 2019-03-31 23:40:19 +08:00
parent f0f92791c7
commit a555b09df0
5 changed files with 242 additions and 0 deletions

View File

@ -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

View File

@ -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()
}

View 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
}

View 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
}

View File

@ -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 (