Wait for manifest in notification handler

There's an issue in registry 2.6.x, that when the webhook is sent the
manifest of the image may not be written.
For details: https://github.com/docker/distribution/issues/2625

This will cause issue in "scan on push" or replication.
This commit mitigates the issue by adding retries in notification
handler.

Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2018-11-06 14:02:44 +08:00
parent 35f3346948
commit abe728325b
3 changed files with 36 additions and 1 deletions

View File

@ -106,6 +106,10 @@ func (n *NotificationHandler) Post() {
log.Errorf("Error happens when adding repository: %v", err)
}
}()
if !coreutils.WaitForManifestReady(repository, tag, 5) {
log.Errorf("Manifest for image %s:%s is not ready, skip the follow up actions.", repository, tag)
return
}
go func() {
image := repository + ":" + tag

View File

@ -94,7 +94,10 @@ func TriggerImageScan(repository string, tag string) error {
if err != nil {
return err
}
digest, _, err := repoClient.ManifestExist(tag)
digest, exist, err := repoClient.ManifestExist(tag)
if !exist {
return fmt.Errorf("unable to perform scan: the manifest of image %s:%s does not exist", repository, tag)
}
if err != nil {
log.Errorf("Failed to get Manifest for %s:%s", repository, tag)
return err

View File

@ -17,7 +17,9 @@ package utils
import (
"net/http"
"time"
"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/core/config"
@ -42,3 +44,29 @@ func NewRepositoryClientForUI(username, repository string) (*registry.Repository
}
return registry.NewRepository(repository, endpoint, client)
}
// WaitForManifestReady implements exponential sleeep to wait until manifest is ready in registry.
// This is a workaround for https://github.com/docker/distribution/issues/2625
func WaitForManifestReady(repository string, tag string, maxRetry int) bool {
// The initial wait interval, hard-coded to 50ms
interval := 50 * time.Millisecond
repoClient, err := NewRepositoryClientForUI("harbor-core", repository)
if err != nil {
log.Errorf("Failed to create repo client.")
return false
}
for i := 0; i < maxRetry; i++ {
_, exist, err := repoClient.ManifestExist(tag)
if err != nil {
log.Errorf("Unexpected error when checking manifest existence, image: %s:%s, error: %v", repository, tag, err)
continue
}
if exist {
return true
}
log.Warningf("manifest for image %s:%s is not ready, retry after %v", repository, tag, interval)
time.Sleep(interval)
interval = interval * 2
}
return false
}