Skip to content
Permalink
Browse files
fix(harbor): detect usage of harbor without --repo-container-registry…
…=harbor option

Added warning when an error occurs which is known to be an error from the harbor.
This warning instructs user to specify --repo-container-registry=harbor option (possibly forgotten).
  • Loading branch information
distorhead committed Dec 14, 2021
1 parent bf7a874 commit a3843f9ba34088e8c4c6cf521e274421cf1c6059
@@ -29,7 +29,7 @@ type awsEcrOptions struct {
}

func newAwsEcr(options awsEcrOptions) (*awsEcr, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(AwsEcrImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -40,7 +40,7 @@ type azureCrOptions struct {
}

func newAzureCr(options azureCrOptions) (*azureCr, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(AzureCrImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -5,25 +5,64 @@ import (
"fmt"
"strings"

"github.com/werf/logboek"
"github.com/werf/werf/pkg/image"
)

const DefaultImplementationName = "default"

type defaultImplementation struct {
*api
Implementation string
}

type defaultImplementationOptions struct {
apiOptions
}

func newDefaultImplementation(options defaultImplementationOptions) (*defaultImplementation, error) {
return newDefaultAPIForImplementation(DefaultImplementationName, options)
}

func newDefaultAPIForImplementation(implementation string, options defaultImplementationOptions) (*defaultImplementation, error) {
d := &defaultImplementation{}
d.api = newAPI(options.apiOptions)
d.Implementation = implementation
return d, nil
}

func (r *defaultImplementation) Tags(ctx context.Context, reference string) ([]string, error) {
tags, err := r.api.Tags(ctx, reference)

if (IsHarbor404Error(err) || IsHarborNotFoundError(err)) && r.Implementation != HarborImplementationName {
logboek.Context(ctx).Error().LogF("WARNING: Detected error specific for harbor container registry implementation!\n")
logboek.Context(ctx).Error().LogF("WARNING: Use --repo-container-registry=harbor option (or WERF_CONTAINER_REGISTRY env var)\n")
logboek.Context(ctx).Error().LogF("WARNING: to instruct werf to use harbor driver.\n")
}

return tags, err
}

func (r *defaultImplementation) IsRepoImageExists(ctx context.Context, reference string) (bool, error) {
if imgInfo, err := r.TryGetRepoImage(ctx, reference); err != nil {
return false, err
} else {
return imgInfo != nil, nil
}
}

func (r *defaultImplementation) TryGetRepoImage(ctx context.Context, reference string) (*image.Info, error) {
info, err := r.api.TryGetRepoImage(ctx, reference)

if (IsHarbor404Error(err) || IsHarborNotFoundError(err)) && r.Implementation != HarborImplementationName {
logboek.Context(ctx).Error().LogF("WARNING: Detected error specific for harbor container registry implementation!\n")
logboek.Context(ctx).Error().LogF("WARNING: Use --repo-container-registry=harbor option (or WERF_CONTAINER_REGISTRY env var)\n")
logboek.Context(ctx).Error().LogF("WARNING: to instruct werf to use harbor driver.\n")
}

return info, err
}

func (r *defaultImplementation) CreateRepo(_ context.Context, _ string) error {
return fmt.Errorf("method is not implemented")
}
@@ -55,15 +94,3 @@ func IsBlobUnknownError(err error) bool {
func IsNameUnknownError(err error) bool {
return (err != nil) && strings.Contains(err.Error(), "NAME_UNKNOWN")
}

func IsHarbor404Error(err error) bool {
if err == nil {
return false
}

// Example error:
// GET https://domain/harbor/s3/object/name/prefix/docker/registry/v2/blobs/sha256/2d/3d8c68cd9df32f1beb4392298a123eac58aba1433a15b3258b2f3728bad4b7d1/data?X-Amz-Algorithm=REDACTED&X-Amz-Credential=REDACTED&X-Amz-Date=REDACTED&X-Amz-Expires=REDACTED&X-Amz-Signature=REDACTED&X-Amz-SignedHeaders=REDACTED: unsupported status code 404; body: <?xml version="1.0" encoding="UTF-8"?>
// <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Resource>/harbor/s3/object/name/prefix/docker/registry/v2/blobs/sha256/3d/3d8c68cd9df32f1beb4392298a123eac58aba1433a15b3258b2f3728bad4b7d1/data</Resource><RequestId>c5bb943c-1e85-5930-b455-c3e8edbbaccd</RequestId></Error>

return strings.Contains(err.Error(), "unsupported status code 404")
}
@@ -64,7 +64,7 @@ type dockerHubCredentials struct {
}

func newDockerHub(options dockerHubOptions) (*dockerHub, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(DockerHubImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -20,7 +20,7 @@ type GcrOptions struct {
}

func newGcr(options GcrOptions) (*gcr, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(GcrImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -68,7 +68,7 @@ type gitHubPackagesOptions struct {
}

func newGitHubPackages(options gitHubPackagesOptions) (*gitHubPackages, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(GitHubPackagesImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ type gitLabRegistryOptions struct {
}

func newGitLabRegistry(options gitLabRegistryOptions) (*gitLabRegistry, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(GitLabRegistryImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -47,7 +47,7 @@ type harborCredentials struct {
}

func newHarbor(options harborOptions) (*harbor, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(HarborImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}
@@ -64,7 +64,7 @@ func newHarbor(options harborOptions) (*harbor, error) {
func (r *harbor) Tags(ctx context.Context, reference string) ([]string, error) {
tags, err := r.defaultImplementation.Tags(ctx, reference)
if err != nil {
if IsNotFoundError(err) {
if IsHarborNotFoundError(err) {
return []string{}, nil
}
return nil, err
@@ -84,7 +84,7 @@ func (r *harbor) IsRepoImageExists(ctx context.Context, reference string) (bool,
func (r *harbor) TryGetRepoImage(ctx context.Context, reference string) (*image.Info, error) {
res, err := r.api.TryGetRepoImage(ctx, reference)
if err != nil {
if IsNotFoundError(err) {
if IsHarborNotFoundError(err) {
return nil, nil
}

@@ -130,6 +130,18 @@ func (r *harbor) parseReference(reference string) (string, string, error) {
return parsedReference.RegistryStr(), parsedReference.RepositoryStr(), nil
}

func IsNotFoundError(err error) bool {
return strings.Contains(err.Error(), "NOT_FOUND")
func IsHarborNotFoundError(err error) bool {
return err != nil && strings.Contains(err.Error(), "NOT_FOUND")
}

func IsHarbor404Error(err error) bool {
if err == nil {
return false
}

// Example error:
// GET https://domain/harbor/s3/object/name/prefix/docker/registry/v2/blobs/sha256/2d/3d8c68cd9df32f1beb4392298a123eac58aba1433a15b3258b2f3728bad4b7d1/data?X-Amz-Algorithm=REDACTED&X-Amz-Credential=REDACTED&X-Amz-Date=REDACTED&X-Amz-Expires=REDACTED&X-Amz-Signature=REDACTED&X-Amz-SignedHeaders=REDACTED: unsupported status code 404; body: <?xml version="1.0" encoding="UTF-8"?>
// <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Resource>/harbor/s3/object/name/prefix/docker/registry/v2/blobs/sha256/3d/3d8c68cd9df32f1beb4392298a123eac58aba1433a15b3258b2f3728bad4b7d1/data</Resource><RequestId>c5bb943c-1e85-5930-b455-c3e8edbbaccd</RequestId></Error>

return strings.Contains(err.Error(), "unsupported status code 404")
}
@@ -46,7 +46,7 @@ type quayCredentials struct {
}

func newQuay(options quayOptions) (*quay, error) {
d, err := newDefaultImplementation(options.defaultImplementationOptions)
d, err := newDefaultAPIForImplementation(QuayImplementationName, options.defaultImplementationOptions)
if err != nil {
return nil, err
}

0 comments on commit a3843f9

Please sign in to comment.