zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/extensions/sync/remote.go (about) 1 //go:build sync 2 // +build sync 3 4 package sync 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/containers/image/v5/docker" 11 dockerReference "github.com/containers/image/v5/docker/reference" 12 "github.com/containers/image/v5/manifest" 13 "github.com/containers/image/v5/types" 14 "github.com/opencontainers/go-digest" 15 ispec "github.com/opencontainers/image-spec/specs-go/v1" 16 17 "zotregistry.io/zot/pkg/api/constants" 18 "zotregistry.io/zot/pkg/common" 19 client "zotregistry.io/zot/pkg/extensions/sync/httpclient" 20 "zotregistry.io/zot/pkg/log" 21 ) 22 23 type catalog struct { 24 Repositories []string `json:"repositories"` 25 } 26 27 type RemoteRegistry struct { 28 client *client.Client 29 context *types.SystemContext 30 log log.Logger 31 } 32 33 func NewRemoteRegistry(client *client.Client, logger log.Logger) Remote { 34 registry := &RemoteRegistry{} 35 36 registry.log = logger 37 registry.client = client 38 clientConfig := client.GetConfig() 39 registry.context = getUpstreamContext(clientConfig.CertDir, clientConfig.Username, 40 clientConfig.Password, clientConfig.TLSVerify) 41 42 return registry 43 } 44 45 func (registry *RemoteRegistry) GetContext() *types.SystemContext { 46 return registry.context 47 } 48 49 func (registry *RemoteRegistry) GetRepositories(ctx context.Context) ([]string, error) { 50 var catalog catalog 51 52 _, _, _, err := registry.client.MakeGetRequest(ctx, &catalog, "application/json", //nolint: dogsled 53 constants.RoutePrefix, constants.ExtCatalogPrefix) 54 if err != nil { 55 return []string{}, err 56 } 57 58 return catalog.Repositories, nil 59 } 60 61 func (registry *RemoteRegistry) GetImageReference(repo, reference string) (types.ImageReference, error) { 62 remoteHost := registry.client.GetHostname() 63 64 repoRef, err := parseRepositoryReference(fmt.Sprintf("%s/%s", remoteHost, repo)) 65 if err != nil { 66 registry.log.Error().Str("errorType", common.TypeOf(err)).Str("repo", repo). 67 Str("reference", reference).Str("remote", remoteHost). 68 Err(err).Msg("couldn't parse repository reference") 69 70 return nil, err 71 } 72 73 var namedRepoRef dockerReference.Named 74 75 digest, ok := parseReference(reference) 76 if ok { 77 namedRepoRef, err = dockerReference.WithDigest(repoRef, digest) 78 if err != nil { 79 return nil, err 80 } 81 } else { 82 namedRepoRef, err = dockerReference.WithTag(repoRef, reference) 83 if err != nil { 84 return nil, err 85 } 86 } 87 88 imageRef, err := docker.NewReference(namedRepoRef) 89 if err != nil { 90 registry.log.Err(err).Str("transport", docker.Transport.Name()).Str("reference", namedRepoRef.String()). 91 Msg("cannot obtain a valid image reference for given transport and reference") 92 93 return nil, err 94 } 95 96 return imageRef, nil 97 } 98 99 func (registry *RemoteRegistry) GetManifestContent(imageReference types.ImageReference) ( 100 []byte, string, digest.Digest, error, 101 ) { 102 imageSource, err := imageReference.NewImageSource(context.Background(), registry.GetContext()) 103 if err != nil { 104 return []byte{}, "", "", err 105 } 106 107 defer imageSource.Close() 108 109 manifestBuf, mediaType, err := imageSource.GetManifest(context.Background(), nil) 110 if err != nil { 111 return []byte{}, "", "", err 112 } 113 114 // if mediatype is docker then convert to OCI 115 switch mediaType { 116 case manifest.DockerV2Schema2MediaType: 117 manifestBuf, err = convertDockerManifestToOCI(imageSource, manifestBuf) 118 if err != nil { 119 return []byte{}, "", "", err 120 } 121 case manifest.DockerV2ListMediaType: 122 manifestBuf, err = convertDockerIndexToOCI(imageSource, manifestBuf) 123 if err != nil { 124 return []byte{}, "", "", err 125 } 126 } 127 128 return manifestBuf, ispec.MediaTypeImageManifest, digest.FromBytes(manifestBuf), nil 129 } 130 131 func (registry *RemoteRegistry) GetRepoTags(repo string) ([]string, error) { 132 remoteHost := registry.client.GetHostname() 133 134 tags, err := getRepoTags(context.Background(), registry.GetContext(), remoteHost, repo) 135 if err != nil { 136 registry.log.Error().Str("errorType", common.TypeOf(err)).Str("repo", repo). 137 Str("remote", remoteHost).Err(err).Msg("couldn't fetch tags for repo") 138 139 return []string{}, err 140 } 141 142 return tags, nil 143 }