mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-27 12:46:03 +01:00
Add helth check method to registry adapter
Signed-off-by: cd1989 <chende@caicloud.io>
This commit is contained in:
parent
f71a110bec
commit
5a2d03593f
@ -157,3 +157,23 @@ func (r *Registry) Ping() error {
|
||||
Message: string(b),
|
||||
}
|
||||
}
|
||||
|
||||
// PingSimple checks whether the registry is available. It checks the connectivity and certificate (if TLS enabled)
|
||||
// only, regardless of credential.
|
||||
func (r *Registry) PingSimple() error {
|
||||
err := r.Ping()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
httpErr, ok := err.(*commonhttp.Error)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
if httpErr.Code < 500 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return httpErr
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ func (t *RegistryAPI) Ping() {
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.URL) == 0 || r.Credential == nil {
|
||||
t.CustomAbort(http.StatusBadRequest, "URL or credential emptry")
|
||||
if len(r.URL) == 0 {
|
||||
t.CustomAbort(http.StatusBadRequest, "URL can't be emptry")
|
||||
return
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ func (t *RegistryAPI) Ping() {
|
||||
return
|
||||
}
|
||||
|
||||
if status != registry.Healthy {
|
||||
if status != model.Healthy {
|
||||
t.CustomAbort(http.StatusBadRequest, fmt.Sprintf("Ping registry %d failed", r.ID))
|
||||
}
|
||||
return
|
||||
|
@ -132,9 +132,7 @@ func (suite *RegistrySuite) TestPing() {
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusNotFound, code)
|
||||
|
||||
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
|
||||
URL: "http://foo.bar",
|
||||
})
|
||||
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{})
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusBadRequest, code)
|
||||
|
||||
|
@ -40,6 +40,8 @@ type Adapter interface {
|
||||
// Get the namespace specified by the name, the returning value should
|
||||
// contain the metadata about the namespace if it has
|
||||
GetNamespace(string) (*model.Namespace, error)
|
||||
// HealthCheck checks health status of registry
|
||||
HealthCheck() (model.HealthStatus, error)
|
||||
}
|
||||
|
||||
// RegisterFactory registers one adapter factory to the registry
|
||||
@ -67,6 +69,12 @@ func GetFactory(t model.RegistryType) (Factory, error) {
|
||||
return factory, nil
|
||||
}
|
||||
|
||||
// HasFactory checks whether there is given type adapter factory
|
||||
func HasFactory(t model.RegistryType) bool {
|
||||
_, ok := registry[t]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ListRegisteredAdapterTypes lists the registered Adapter type
|
||||
func ListRegisteredAdapterTypes() []model.RegistryType {
|
||||
types := []model.RegistryType{}
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
common_http_auth "github.com/goharbor/harbor/src/common/http/modifier/auth"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
registry_pkg "github.com/goharbor/harbor/src/common/utils/registry"
|
||||
util_registry "github.com/goharbor/harbor/src/common/utils/registry"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry/auth"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
"github.com/goharbor/harbor/src/replication/ng/util"
|
||||
@ -54,9 +55,10 @@ type ImageRegistry interface {
|
||||
// DefaultImageRegistry provides a default implementation for interface ImageRegistry
|
||||
type DefaultImageRegistry struct {
|
||||
sync.RWMutex
|
||||
client *http.Client
|
||||
url string
|
||||
clients map[string]*registry_pkg.Repository
|
||||
registry *model.Registry
|
||||
client *http.Client
|
||||
url string
|
||||
clients map[string]*registry_pkg.Repository
|
||||
}
|
||||
|
||||
// NewDefaultImageRegistry returns an instance of DefaultImageRegistry
|
||||
@ -92,9 +94,10 @@ func NewDefaultImageRegistry(registry *model.Registry) *DefaultImageRegistry {
|
||||
Transport: registry_pkg.NewTransport(transport, modifiers...),
|
||||
}
|
||||
return &DefaultImageRegistry{
|
||||
client: client,
|
||||
clients: map[string]*registry_pkg.Repository{},
|
||||
url: registry.URL,
|
||||
client: client,
|
||||
registry: registry,
|
||||
clients: map[string]*registry_pkg.Repository{},
|
||||
url: registry.URL,
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +137,52 @@ func (d *DefaultImageRegistry) create(repository string) (*registry_pkg.Reposito
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// HealthCheck checks health status of a registry
|
||||
func (d *DefaultImageRegistry) HealthCheck() (model.HealthStatus, error) {
|
||||
if d.registry.Credential == nil || (len(d.registry.Credential.AccessKey) == 0 && len(d.registry.Credential.AccessSecret) == 0) {
|
||||
return d.pingAnonymously()
|
||||
}
|
||||
|
||||
// TODO(ChenDe): Support other credential type like OAuth, for the moment, only basic auth is supported.
|
||||
if d.registry.Credential.Type != model.CredentialTypeBasic {
|
||||
return model.Unknown, fmt.Errorf("unknown credential type '%s', only '%s' supported yet", d.registry.Credential.Type, model.CredentialTypeBasic)
|
||||
}
|
||||
|
||||
transport := util.GetHTTPTransport(d.registry.Insecure)
|
||||
credential := auth.NewBasicAuthCredential(d.registry.Credential.AccessKey, d.registry.Credential.AccessSecret)
|
||||
authorizer := auth.NewStandardTokenAuthorizer(&http.Client{
|
||||
Transport: transport,
|
||||
}, credential)
|
||||
registry, err := util_registry.NewRegistry(d.registry.URL, &http.Client{
|
||||
Transport: util_registry.NewTransport(transport, authorizer),
|
||||
})
|
||||
if err != nil {
|
||||
return model.Unknown, err
|
||||
}
|
||||
|
||||
err = registry.Ping()
|
||||
if err != nil {
|
||||
return model.Unhealthy, err
|
||||
}
|
||||
return model.Healthy, nil
|
||||
}
|
||||
|
||||
func (d *DefaultImageRegistry) pingAnonymously() (model.HealthStatus, error) {
|
||||
registry, err := util_registry.NewRegistry(d.registry.URL, &http.Client{
|
||||
Transport: util_registry.NewTransport(util.GetHTTPTransport(d.registry.Insecure)),
|
||||
})
|
||||
if err != nil {
|
||||
return model.Unknown, err
|
||||
}
|
||||
|
||||
err = registry.PingSimple()
|
||||
if err != nil {
|
||||
return model.Unhealthy, err
|
||||
}
|
||||
|
||||
return model.Healthy, nil
|
||||
}
|
||||
|
||||
// FetchImages ...
|
||||
func (d *DefaultImageRegistry) FetchImages(namespaces []string, filters []*model.Filter) ([]*model.Resource, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
|
@ -56,6 +56,18 @@ type Credential struct {
|
||||
AccessSecret string `json:"access_secret"`
|
||||
}
|
||||
|
||||
// HealthStatus describes whether a target is healthy or not
|
||||
type HealthStatus string
|
||||
|
||||
const (
|
||||
// Healthy indicates registry is healthy
|
||||
Healthy = "healthy"
|
||||
// Unhealthy indicates registry is unhealthy
|
||||
Unhealthy = "unhealthy"
|
||||
// Unknown indicates health status of registry is unknown
|
||||
Unknown = "unknown"
|
||||
)
|
||||
|
||||
// TODO add validation for Registry
|
||||
|
||||
// Registry keeps the related info of registry
|
||||
|
@ -135,6 +135,9 @@ func (f *fakedAdapter) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace
|
||||
func (f *fakedAdapter) CreateNamespace(*model.Namespace) error {
|
||||
return nil
|
||||
}
|
||||
func (f *fakedAdapter) HealthCheck() (model.HealthStatus, error) {
|
||||
return model.Healthy, nil
|
||||
}
|
||||
func (f *fakedAdapter) GetNamespace(ns string) (*model.Namespace, error) {
|
||||
var namespace *model.Namespace
|
||||
if ns == "library" {
|
||||
|
@ -52,6 +52,9 @@ func (f *fakedAdapter) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace
|
||||
func (f *fakedAdapter) CreateNamespace(*model.Namespace) error {
|
||||
return nil
|
||||
}
|
||||
func (f *fakedAdapter) HealthCheck() (model.HealthStatus, error) {
|
||||
return model.Healthy, nil
|
||||
}
|
||||
func (f *fakedAdapter) GetNamespace(ns string) (*model.Namespace, error) {
|
||||
var namespace *model.Namespace
|
||||
if ns == "library" {
|
||||
|
@ -16,32 +16,16 @@ package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/goharbor/harbor/src/replication/ng/util"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry/auth"
|
||||
"github.com/goharbor/harbor/src/replication/ng/adapter"
|
||||
"github.com/goharbor/harbor/src/replication/ng/config"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
)
|
||||
|
||||
// HealthStatus describes whether a target is healthy or not
|
||||
type HealthStatus string
|
||||
|
||||
const (
|
||||
// Healthy indicates target is healthy
|
||||
Healthy = "healthy"
|
||||
// Unhealthy indicates target is unhealthy
|
||||
Unhealthy = "unhealthy"
|
||||
// Unknown indicates health status of target is unknown
|
||||
Unknown = "unknown"
|
||||
)
|
||||
|
||||
// Manager defines the methods that a target manager should implement
|
||||
type Manager interface {
|
||||
// Add new registry
|
||||
@ -203,35 +187,22 @@ func (m *DefaultManager) HealthCheck() error {
|
||||
}
|
||||
|
||||
// CheckHealthStatus checks status of a given registry
|
||||
func CheckHealthStatus(r *model.Registry) (HealthStatus, error) {
|
||||
// TODO(ChenDe): Support other credential type like OAuth, for the moment, only basic auth is supported.
|
||||
if r.Credential.Type != model.CredentialTypeBasic {
|
||||
return Unknown, fmt.Errorf("unknown credential type '%s', only '%s' supported yet", r.Credential.Type, model.CredentialTypeBasic)
|
||||
func CheckHealthStatus(r *model.Registry) (model.HealthStatus, error) {
|
||||
if !adapter.HasFactory(r.Type) {
|
||||
return model.Unknown, fmt.Errorf("no adapter factory for type '%s' registered", r.Type)
|
||||
}
|
||||
|
||||
// TODO(ChenDe): Support health check for other kinds of registry
|
||||
if r.Type != model.RegistryTypeHarbor {
|
||||
return Unknown, fmt.Errorf("unknown registry type '%s'", r.Type)
|
||||
}
|
||||
|
||||
transport := util.GetHTTPTransport(r.Insecure)
|
||||
credential := auth.NewBasicAuthCredential(r.Credential.AccessKey, r.Credential.AccessSecret)
|
||||
authorizer := auth.NewStandardTokenAuthorizer(&http.Client{
|
||||
Transport: transport,
|
||||
}, credential)
|
||||
registry, err := registry.NewRegistry(r.URL, &http.Client{
|
||||
Transport: registry.NewTransport(transport, authorizer),
|
||||
})
|
||||
factory, err := adapter.GetFactory(r.Type)
|
||||
if err != nil {
|
||||
return Unknown, err
|
||||
return model.Unknown, fmt.Errorf("get adaper for type '%s' error: %v", r.Type, err)
|
||||
}
|
||||
|
||||
err = registry.Ping()
|
||||
rAdapter, err := factory(r)
|
||||
if err != nil {
|
||||
return Unhealthy, err
|
||||
return model.Unknown, fmt.Errorf("generate '%s' type adapter form factory error: %v", r.Type, err)
|
||||
}
|
||||
|
||||
return Healthy, nil
|
||||
return rAdapter.HealthCheck()
|
||||
}
|
||||
|
||||
// decrypt checks whether access secret is set in the registry, if so, decrypt it.
|
||||
|
Loading…
Reference in New Issue
Block a user