Merge pull request #6154 from wy65701436/fix-gc-redis

Fix gc jobs issues
This commit is contained in:
Wenkai Yin 2018-10-29 16:29:57 +08:00 committed by GitHub
commit af17c2c3fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 8 deletions

View File

@ -25,6 +25,7 @@ import (
common_http "github.com/goharbor/harbor/src/common/http"
"github.com/goharbor/harbor/src/common/http/modifier/auth"
"github.com/goharbor/harbor/src/common/registryctl"
"github.com/goharbor/harbor/src/common/utils"
reg "github.com/goharbor/harbor/src/common/utils/registry"
"github.com/goharbor/harbor/src/jobservice/env"
"github.com/goharbor/harbor/src/jobservice/logger"
@ -35,13 +36,15 @@ const (
dialConnectionTimeout = 30 * time.Second
dialReadTimeout = time.Minute + 10*time.Second
dialWriteTimeout = 10 * time.Second
blobPrefix = "blobs::*"
repoPrefix = "repository::*"
)
// GarbageCollector is the struct to run registry's garbage collection
type GarbageCollector struct {
registryCtlClient client.Client
logger logger.Interface
uiclient *common_http.Client
coreclient *common_http.Client
CoreURL string
insecure bool
redisURL string
@ -67,10 +70,16 @@ func (gc *GarbageCollector) Run(ctx env.JobContext, params map[string]interface{
if err := gc.init(ctx, params); err != nil {
return err
}
if err := gc.readonly(true); err != nil {
readOnlyCur, err := gc.getReadOnly()
if err != nil {
return err
}
defer gc.readonly(false)
if readOnlyCur != true {
if err := gc.setReadOnly(true); err != nil {
return err
}
defer gc.setReadOnly(readOnlyCur)
}
if err := gc.registryCtlClient.Health(); err != nil {
gc.logger.Errorf("failed to start gc as registry controller is unreachable: %v", err)
return err
@ -95,7 +104,7 @@ func (gc *GarbageCollector) init(ctx env.JobContext, params map[string]interface
gc.logger = ctx.GetLogger()
cred := auth.NewSecretAuthorizer(os.Getenv("JOBSERVICE_SECRET"))
gc.insecure = false
gc.uiclient = common_http.NewClient(&http.Client{
gc.coreclient = common_http.NewClient(&http.Client{
Transport: reg.GetHTTPTransport(gc.insecure),
}, cred)
errTpl := "Failed to get required property: %s"
@ -108,8 +117,16 @@ func (gc *GarbageCollector) init(ctx env.JobContext, params map[string]interface
return nil
}
func (gc *GarbageCollector) readonly(switcher bool) error {
if err := gc.uiclient.Put(fmt.Sprintf("%s/api/configurations", gc.CoreURL), struct {
func (gc *GarbageCollector) getReadOnly() (bool, error) {
cfgs := map[string]interface{}{}
if err := gc.coreclient.Get(fmt.Sprintf("%s/api/configs", gc.CoreURL), &cfgs); err != nil {
return false, err
}
return utils.SafeCastBool(cfgs[common.ReadOnly]), nil
}
func (gc *GarbageCollector) setReadOnly(switcher bool) error {
if err := gc.coreclient.Put(fmt.Sprintf("%s/api/configurations", gc.CoreURL), struct {
ReadOnly bool `json:"read_only"`
}{
ReadOnly: switcher,
@ -139,11 +156,51 @@ func (gc *GarbageCollector) cleanCache() error {
defer con.Close()
// clean all keys in registry redis DB.
_, err = con.Do("FLUSHDB")
// sample of keys in registry redis:
// 1) "blobs::sha256:1a6fd470b9ce10849be79e99529a88371dff60c60aab424c077007f6979b4812"
// 2) "repository::library/hello-world::blobs::sha256:4ab4c602aa5eed5528a6620ff18a1dc4faef0e1ab3a5eddeddb410714478c67f"
err = delKeys(con, blobPrefix)
if err != nil {
gc.logger.Errorf("failed to clean registry cache %v", err)
gc.logger.Errorf("failed to clean registry cache %v, pattern blobs::*", err)
return err
}
err = delKeys(con, repoPrefix)
if err != nil {
gc.logger.Errorf("failed to clean registry cache %v, pattern repository::*", err)
return err
}
return nil
}
func delKeys(con redis.Conn, pattern string) error {
iter := 0
keys := []string{}
for {
arr, err := redis.Values(con.Do("SCAN", iter, "MATCH", pattern))
if err != nil {
return fmt.Errorf("error retrieving '%s' keys", pattern)
}
iter, err = redis.Int(arr[0], nil)
if err != nil {
return fmt.Errorf("unexpected type for Int, got type %T", err)
}
k, err := redis.Strings(arr[1], nil)
if err != nil {
return fmt.Errorf("converts an array command reply to a []string %v", err)
}
keys = append(keys, k...)
if iter == 0 {
break
}
}
for _, key := range keys {
_, err := con.Do("DEL", key)
if err != nil {
return fmt.Errorf("failed to clean registry cache %v", err)
}
}
return nil
}

View File

@ -44,6 +44,7 @@ func StartGC(w http.ResponseWriter, r *http.Request) {
cmd.Stderr = &errBuf
start := time.Now()
log.Debugf("Start to execute garbage collection...")
if err := cmd.Run(); err != nil {
log.Errorf("Fail to execute GC: %v, command err: %s", err, errBuf.String())
handleInternalServerError(w)
@ -55,4 +56,5 @@ func StartGC(w http.ResponseWriter, r *http.Request) {
log.Errorf("failed to write response: %v", err)
return
}
log.Debugf("Successful to execute garbage collection...")
}