add ping for adapter to wait for service ready

Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
wang yan 2019-08-14 12:39:23 +08:00
parent 6e11ecc6fc
commit b9d6108624
5 changed files with 89 additions and 29 deletions

View File

@ -34,8 +34,9 @@ import (
) )
var ( var (
timeout = 60 * time.Second timeout = 60 * time.Second
healthCheckerRegistry = map[string]health.Checker{} // HealthCheckerRegistry ...
HealthCheckerRegistry = map[string]health.Checker{}
) )
type overallHealthStatus struct { type overallHealthStatus struct {
@ -67,11 +68,11 @@ type HealthAPI struct {
func (h *HealthAPI) CheckHealth() { func (h *HealthAPI) CheckHealth() {
var isHealthy healthy = true var isHealthy healthy = true
components := []*componentHealthStatus{} components := []*componentHealthStatus{}
c := make(chan *componentHealthStatus, len(healthCheckerRegistry)) c := make(chan *componentHealthStatus, len(HealthCheckerRegistry))
for name, checker := range healthCheckerRegistry { for name, checker := range HealthCheckerRegistry {
go check(name, checker, timeout, c) go check(name, checker, timeout, c)
} }
for i := 0; i < len(healthCheckerRegistry); i++ { for i := 0; i < len(HealthCheckerRegistry); i++ {
componentStatus := <-c componentStatus := <-c
if len(componentStatus.Error) != 0 { if len(componentStatus.Error) != 0 {
isHealthy = false isHealthy = false
@ -290,21 +291,21 @@ func redisHealthChecker() health.Checker {
} }
func registerHealthCheckers() { func registerHealthCheckers() {
healthCheckerRegistry["core"] = coreHealthChecker() HealthCheckerRegistry["core"] = coreHealthChecker()
healthCheckerRegistry["portal"] = portalHealthChecker() HealthCheckerRegistry["portal"] = portalHealthChecker()
healthCheckerRegistry["jobservice"] = jobserviceHealthChecker() HealthCheckerRegistry["jobservice"] = jobserviceHealthChecker()
healthCheckerRegistry["registry"] = registryHealthChecker() HealthCheckerRegistry["registry"] = registryHealthChecker()
healthCheckerRegistry["registryctl"] = registryCtlHealthChecker() HealthCheckerRegistry["registryctl"] = registryCtlHealthChecker()
healthCheckerRegistry["database"] = databaseHealthChecker() HealthCheckerRegistry["database"] = databaseHealthChecker()
healthCheckerRegistry["redis"] = redisHealthChecker() HealthCheckerRegistry["redis"] = redisHealthChecker()
if config.WithChartMuseum() { if config.WithChartMuseum() {
healthCheckerRegistry["chartmuseum"] = chartmuseumHealthChecker() HealthCheckerRegistry["chartmuseum"] = chartmuseumHealthChecker()
} }
if config.WithClair() { if config.WithClair() {
healthCheckerRegistry["clair"] = clairHealthChecker() HealthCheckerRegistry["clair"] = clairHealthChecker()
} }
if config.WithNotary() { if config.WithNotary() {
healthCheckerRegistry["notary"] = notaryHealthChecker() HealthCheckerRegistry["notary"] = notaryHealthChecker()
} }
} }

View File

@ -92,9 +92,9 @@ func fakeHealthChecker(healthy bool) health.Checker {
} }
func TestCheckHealth(t *testing.T) { func TestCheckHealth(t *testing.T) {
// component01: healthy, component02: healthy => status: healthy // component01: healthy, component02: healthy => status: healthy
healthCheckerRegistry = map[string]health.Checker{} HealthCheckerRegistry = map[string]health.Checker{}
healthCheckerRegistry["component01"] = fakeHealthChecker(true) HealthCheckerRegistry["component01"] = fakeHealthChecker(true)
healthCheckerRegistry["component02"] = fakeHealthChecker(true) HealthCheckerRegistry["component02"] = fakeHealthChecker(true)
status := map[string]interface{}{} status := map[string]interface{}{}
err := handleAndParse(&testingRequest{ err := handleAndParse(&testingRequest{
method: http.MethodGet, method: http.MethodGet,
@ -104,9 +104,9 @@ func TestCheckHealth(t *testing.T) {
assert.Equal(t, "healthy", status["status"].(string)) assert.Equal(t, "healthy", status["status"].(string))
// component01: healthy, component02: unhealthy => status: unhealthy // component01: healthy, component02: unhealthy => status: unhealthy
healthCheckerRegistry = map[string]health.Checker{} HealthCheckerRegistry = map[string]health.Checker{}
healthCheckerRegistry["component01"] = fakeHealthChecker(true) HealthCheckerRegistry["component01"] = fakeHealthChecker(true)
healthCheckerRegistry["component02"] = fakeHealthChecker(false) HealthCheckerRegistry["component02"] = fakeHealthChecker(false)
status = map[string]interface{}{} status = map[string]interface{}{}
err = handleAndParse(&testingRequest{ err = handleAndParse(&testingRequest{
method: http.MethodGet, method: http.MethodGet,
@ -128,7 +128,7 @@ func TestDatabaseHealthChecker(t *testing.T) {
} }
func TestRegisterHealthCheckers(t *testing.T) { func TestRegisterHealthCheckers(t *testing.T) {
healthCheckerRegistry = map[string]health.Checker{} HealthCheckerRegistry = map[string]health.Checker{}
registerHealthCheckers() registerHealthCheckers()
assert.NotNil(t, healthCheckerRegistry["core"]) assert.NotNil(t, HealthCheckerRegistry["core"])
} }

View File

@ -21,6 +21,7 @@ import (
"github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/models"
common_quota "github.com/goharbor/harbor/src/common/quota" common_quota "github.com/goharbor/harbor/src/common/quota"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/api"
quota "github.com/goharbor/harbor/src/core/api/quota" quota "github.com/goharbor/harbor/src/core/api/quota"
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/promgr" "github.com/goharbor/harbor/src/core/promgr"
@ -49,6 +50,11 @@ var (
controllerOnce sync.Once controllerOnce sync.Once
) )
// Ping ...
func (rm *Migrator) Ping() error {
return api.HealthCheckerRegistry["chartmuseum"].Check()
}
// Dump ... // Dump ...
// Depends on DB to dump chart data, as chart cannot get all of namespaces. // Depends on DB to dump chart data, as chart cannot get all of namespaces.
func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) { func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) {
@ -99,8 +105,6 @@ func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) {
defer wg.Done() defer wg.Done()
var repos []quota.RepoData var repos []quota.RepoData
var afs []*models.Artifact
ctr, err := chartController() ctr, err := chartController()
if err != nil { if err != nil {
errChan <- err errChan <- err
@ -115,6 +119,7 @@ func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) {
// repo // repo
for _, chart := range chartInfo { for _, chart := range chartInfo {
var afs []*models.Artifact
chartVersions, err := ctr.GetChart(project.Name, chart.Name) chartVersions, err := ctr.GetChart(project.Name, chart.Name)
if err != nil { if err != nil {
errChan <- err errChan <- err
@ -171,7 +176,8 @@ func (rm *Migrator) Usage(projects []quota.ProjectInfo) ([]quota.ProjectUsage, e
proUsage := quota.ProjectUsage{ proUsage := quota.ProjectUsage{
Project: project.Name, Project: project.Name,
Used: common_quota.ResourceList{ Used: common_quota.ResourceList{
common_quota.ResourceCount: count, common_quota.ResourceCount: count,
common_quota.ResourceStorage: 0,
}, },
} }
pros = append(pros, proUsage) pros = append(pros, proUsage)

View File

@ -21,11 +21,15 @@ import (
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/promgr" "github.com/goharbor/harbor/src/core/promgr"
"github.com/goharbor/harbor/src/pkg/types"
"strconv" "strconv"
) )
// QuotaMigrator ... // QuotaMigrator ...
type QuotaMigrator interface { type QuotaMigrator interface {
// Ping validates and wait for backend service ready.
Ping() error
// Dump exports all data from backend service, registry, chartmuseum // Dump exports all data from backend service, registry, chartmuseum
Dump() ([]ProjectInfo, error) Dump() ([]ProjectInfo, error)
@ -74,6 +78,7 @@ func Register(name string, adapter Instance) {
// Sync ... // Sync ...
func Sync(pm promgr.ProjectManager, populate bool) error { func Sync(pm promgr.ProjectManager, populate bool) error {
totalUsage := make(map[string][]ProjectUsage)
for name, instanceFunc := range adapters { for name, instanceFunc := range adapters {
if !config.WithChartMuseum() { if !config.WithChartMuseum() {
if name == "chart" { if name == "chart" {
@ -81,6 +86,9 @@ func Sync(pm promgr.ProjectManager, populate bool) error {
} }
} }
adapter := instanceFunc(pm) adapter := instanceFunc(pm)
if err := adapter.Ping(); err != nil {
return err
}
data, err := adapter.Dump() data, err := adapter.Dump()
if err != nil { if err != nil {
return err return err
@ -89,18 +97,58 @@ func Sync(pm promgr.ProjectManager, populate bool) error {
if err != nil { if err != nil {
return err return err
} }
if err := ensureQuota(usage); err != nil { totalUsage[name] = usage
return err
}
if populate { if populate {
if err := adapter.Persist(data); err != nil { if err := adapter.Persist(data); err != nil {
return err return err
} }
} }
} }
merged := mergeUsage(totalUsage)
if err := ensureQuota(merged); err != nil {
return err
}
return nil return nil
} }
// mergeUsage merges the usage of adapters
func mergeUsage(total map[string][]ProjectUsage) []ProjectUsage {
if !config.WithChartMuseum() {
return total["registry"]
}
regUsgs := total["registry"]
chartUsgs := total["chart"]
var mergedUsage []ProjectUsage
temp := make(map[string]quota.ResourceList)
for _, regUsg := range regUsgs {
_, exist := temp[regUsg.Project]
if !exist {
temp[regUsg.Project] = regUsg.Used
mergedUsage = append(mergedUsage, ProjectUsage{
Project: regUsg.Project,
Used: regUsg.Used,
})
}
}
for _, chartUsg := range chartUsgs {
var usedTemp quota.ResourceList
_, exist := temp[chartUsg.Project]
if !exist {
usedTemp = chartUsg.Used
} else {
usedTemp = types.Add(temp[chartUsg.Project], chartUsg.Used)
}
temp[chartUsg.Project] = usedTemp
mergedUsage = append(mergedUsage, ProjectUsage{
Project: chartUsg.Project,
Used: usedTemp,
})
}
return mergedUsage
}
// ensureQuota updates the quota and quota usage in the data base. // ensureQuota updates the quota and quota usage in the data base.
func ensureQuota(usages []ProjectUsage) error { func ensureQuota(usages []ProjectUsage) error {
var pid int64 var pid int64

View File

@ -46,6 +46,11 @@ func NewRegistryMigrator(pm promgr.ProjectManager) quota.QuotaMigrator {
return &migrator return &migrator
} }
// Ping ...
func (rm *Migrator) Ping() error {
return api.HealthCheckerRegistry["registry"].Check()
}
// Dump ... // Dump ...
func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) { func (rm *Migrator) Dump() ([]quota.ProjectInfo, error) {
var ( var (