package registry import ( "context" "crypto/tls" "fmt" "net/http" "path" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2" "oras.land/oras-go/v2/content" orasregistry "oras.land/oras-go/v2/registry" "oras.land/oras-go/v2/registry/remote" "oras.land/oras-go/v2/registry/remote/auth" ) //go:generate mockgen -destination=mocks/storage.go -package=mocks -source storage.go StorageClient //go:generate mockgen -destination=mocks/repository.go -package=mocks oras.land/oras-go/v2/registry Repository // OCIRegistryClient storage client for an OCI registry. type OCIRegistryClient struct { StorageContext registry *remote.Registry } var _ StorageClient = (*OCIRegistryClient)(nil) // NewOCIRegistry create an OCI registry client. func NewOCIRegistry(sc StorageContext, registry *remote.Registry) *OCIRegistryClient { transport := http.DefaultTransport.(*http.Transport).Clone() { // #nosec G402 transport.TLSClientConfig = &tls.Config{ RootCAs: sc.certificates, InsecureSkipVerify: sc.insecure, } } authClient := &auth.Client{ Client: &http.Client{ Transport: transport, }, Cache: auth.NewCache(), } authClient.SetUserAgent("eksa") authClient.Credential = func(ctx context.Context, s string) (auth.Credential, error) { return sc.credentialStore.Credential(s) } registry.Client = authClient return &OCIRegistryClient{ StorageContext: sc, registry: registry, } } // GetHost for registry host. func (or *OCIRegistryClient) GetHost() string { return or.host } // SetProject for registry destination. func (or *OCIRegistryClient) SetProject(project string) { or.project = project } // Destination of this storage registry. func (or *OCIRegistryClient) Destination(image Artifact) string { return path.Join(or.host, or.project, image.Repository) + image.Version() } // GetStorage object based on repository. func (or *OCIRegistryClient) GetStorage(ctx context.Context, artifact Artifact) (repo orasregistry.Repository, err error) { dstRepo := path.Join(or.project, artifact.Repository) repo, err = or.registry.Repository(ctx, dstRepo) if err != nil { return nil, fmt.Errorf("error creating repository %s: %v", dstRepo, err) } return repo, nil } // Resolve the location of the source repository given the image. func (or *OCIRegistryClient) Resolve(ctx context.Context, srcStorage orasregistry.Repository, versionedImage string) (desc ocispec.Descriptor, err error) { or.registry.Reference.Reference = versionedImage return srcStorage.Resolve(ctx, or.registry.Reference.Reference) } // FetchBytes a resource from the registry. func (or *OCIRegistryClient) FetchBytes(ctx context.Context, srcStorage orasregistry.Repository, artifact Artifact) (ocispec.Descriptor, []byte, error) { return oras.FetchBytes(ctx, srcStorage, artifact.VersionedImage(), oras.DefaultFetchBytesOptions) } // FetchBlob get named blob. func (or *OCIRegistryClient) FetchBlob(ctx context.Context, srcStorage orasregistry.Repository, descriptor ocispec.Descriptor) ([]byte, error) { return content.FetchAll(ctx, srcStorage, descriptor) } // CopyGraph copy manifest and all blobs to destination. func (or *OCIRegistryClient) CopyGraph(ctx context.Context, srcStorage orasregistry.Repository, dstStorage orasregistry.Repository, desc ocispec.Descriptor) error { extendedCopyOptions := oras.DefaultExtendedCopyOptions return oras.CopyGraph(ctx, srcStorage, dstStorage, desc, extendedCopyOptions.CopyGraphOptions) }