Skip to content

Instantly share code, notes, and snippets.

@cognifloyd
Created May 1, 2022 02:20
Show Gist options
  • Save cognifloyd/effee107fc62ee4f722814ce94ee6d63 to your computer and use it in GitHub Desktop.
Save cognifloyd/effee107fc62ee4f722814ce94ee6d63 to your computer and use it in GitHub Desktop.
Docker Registry client in go (rough outline)
package image // import "github.com/go-vela/worker/internal/image"
import (
"context"
dist "github.com/docker/distribution"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/distribution"
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/registry"
)
// ImageExists queries the registry to see if the image exists.
func ImageExists(ctx context.Context, image string) (bool, error) {
// this should be a vela user agent instead
userAgent := dockerversion.DockerUserAgent(ctx)
authConfig := &types.AuthConfig{
// stored in user docker file
Username: "",
Password: "",
Auth: "", // replaces plaintext Username+Password
ServerAddress: "",
IdentityToken: "", // used to authenticate user and get registry access token
RegistryToken: "", // bearer token to send to registry
}
registryService, err := registry.NewService(registry.ServiceOptions{
AllowNondistributableArtifacts: []string{"...", "..."},
Mirrors: []string{"...", "..."},
InsecureRegistries: []string{"...", "..."},
})
_, _, err = registryService.Auth(ctx, authConfig, userAgent)
if err != nil {
return false, err
}
// on success:
// status = "Login Succeded"
// token = authConfig.IdentityToken
// err = nil
ref, err := reference.ParseAnyReference(image)
if err != nil {
return false, err
}
namedRef, ok := ref.(reference.Named)
if !ok {
if _, ok := ref.(reference.Digested); ok {
// image is a full image ID with a digest instead of a tag
return false, nil
}
return false, nil
}
repoInfo, err := registryService.ResolveRepository(namedRef)
if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
// name is empty or `scratch`
return false, nil
}
var (
confirmedV2 bool
distrepo dist.Repository // this is a registry client with the repo path
lastError error
)
endpoints, err := registryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
for _, endpoint := range endpoints {
if endpoint.Version == registry.APIVersion1 {
continue
}
distrepo, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
if lastError == nil && confirmedV2 {
break
}
}
taggedRef, ok := namedRef.(reference.NamedTagged)
_, err = distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
if err != nil {
return false, err
}
return true, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment