func TestInvalidTags(t *testing.T) { tmpDir, err := ioutil.TempDir("", "tag-store-test") defer os.RemoveAll(tmpDir) store, err := NewTagStore(filepath.Join(tmpDir, "repositories.json")) if err != nil { t.Fatalf("error creating tag store: %v", err) } id := image.ID("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6") // sha256 as repo name ref, err := reference.ParseNamed("sha256:abc") if err != nil { t.Fatal(err) } err = store.AddTag(ref, id, true) if err == nil { t.Fatalf("expected setting tag %q to fail", ref) } // setting digest as a tag ref, err = reference.ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6") if err != nil { t.Fatal(err) } err = store.AddTag(ref, id, true) if err == nil { t.Fatalf("expected setting digest %q to fail", ref) } }
// Check if the inspected image matches what we are looking for func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool { // The image string follows the grammar specified here // https://github.com/docker/distribution/blob/master/reference/reference.go#L4 named, err := dockerref.ParseNamed(image) if err != nil { glog.V(4).Infof("couldn't parse image reference %q: %v", image, err) return false } _, isTagged := named.(dockerref.Tagged) digest, isDigested := named.(dockerref.Digested) if !isTagged && !isDigested { // No Tag or SHA specified, so just return what we have return true } if isTagged { // Check the RepoTags for a match. for _, tag := range inspected.RepoTags { // An image name (without the tag/digest) can be [hostname '/'] component ['/' component]* // Because either the RepoTag or the name *may* contain the // hostname or not, we only check for the suffix match. if strings.HasSuffix(image, tag) || strings.HasSuffix(tag, image) { return true } } } if isDigested { for _, repoDigest := range inspected.RepoDigests { named, err := dockerref.ParseNamed(repoDigest) if err != nil { glog.V(4).Infof("couldn't parse image RepoDigest reference %q: %v", repoDigest, err) continue } if d, isDigested := named.(dockerref.Digested); isDigested { if digest.Digest().Algorithm().String() == d.Digest().Algorithm().String() && digest.Digest().Hex() == d.Digest().Hex() { return true } } } // process the ID as a digest id, err := dockerdigest.ParseDigest(inspected.ID) if err != nil { glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err) return false } if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() { return true } } glog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image) return false }
// parseImageName parses a docker image string into two parts: repo and tag. // If tag is empty, return the defaultImageTag. func ParseImageName(image string) (string, string, error) { named, err := reference.ParseNamed(image) if err != nil { return "", "", fmt.Errorf("couldn't parse image name: %v", err) } repoToPull := named.Name() var tag string tagged, ok := named.(reference.Tagged) if ok { tag = tagged.Tag() } digested, ok := named.(reference.Digested) if ok { tag = digested.Digest().String() } // If no tag was specified, use the default "latest". if len(tag) == 0 { tag = defaultImageTag } return repoToPull, tag, nil }
// TestWriteSeek tests that the current file size can be // obtained using Seek func TestWriteSeek(t *testing.T) { ctx := context.Background() imageName, _ := reference.ParseNamed("foo/bar") driver := testdriver.New() registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect) if err != nil { t.Fatalf("error creating registry: %v", err) } repository, err := registry.Repository(ctx, imageName) if err != nil { t.Fatalf("unexpected error getting repo: %v", err) } bs := repository.Blobs(ctx) blobUpload, err := bs.Create(ctx) if err != nil { t.Fatalf("unexpected error starting layer upload: %s", err) } contents := []byte{1, 2, 3} blobUpload.Write(contents) blobUpload.Close() offset := blobUpload.Size() if offset != int64(len(contents)) { t.Fatalf("unexpected value for blobUpload offset: %v != %v", offset, len(contents)) } }
// ParseNamedDockerImageReference parses a Docker pull spec string into a // NamedDockerImageReference. func ParseNamedDockerImageReference(spec string) (NamedDockerImageReference, error) { var ref NamedDockerImageReference namedRef, err := reference.ParseNamed(spec) if err != nil { return ref, err } name := namedRef.Name() i := strings.IndexRune(name, '/') if i == -1 || (!strings.ContainsAny(name[:i], ":.") && name[:i] != "localhost") { ref.Name = name } else { ref.Registry, ref.Name = name[:i], name[i+1:] } if named, ok := namedRef.(reference.NamedTagged); ok { ref.Tag = named.Tag() } if named, ok := namedRef.(reference.Canonical); ok { ref.ID = named.Digest().String() } // It's not enough just to use the reference.ParseNamed(). We have to fill // ref.Namespace from ref.Name if i := strings.IndexRune(ref.Name, '/'); i != -1 { ref.Namespace, ref.Name = ref.Name[:i], ref.Name[i+1:] } return ref, nil }
// sanitizeRepoAndTags parses the raw "t" parameter received from the client // to a slice of repoAndTag. // It also validates each repoName and tag. func sanitizeRepoAndTags(names []string) ([]reference.Named, error) { var ( repoAndTags []reference.Named // This map is used for deduplicating the "-t" paramter. uniqNames = make(map[string]struct{}) ) for _, repo := range names { if repo == "" { continue } ref, err := reference.ParseNamed(repo) if err != nil { return nil, err } if _, isDigested := ref.(reference.Digested); isDigested { return nil, errors.New("build tag cannot be a digest") } if _, isTagged := ref.(reference.Tagged); !isTagged { ref, err = reference.WithTag(ref, tagpkg.DefaultTag) } nameWithTag := ref.String() if _, exists := uniqNames[nameWithTag]; !exists { uniqNames[nameWithTag] = struct{}{} repoAndTags = append(repoAndTags, ref) } } return repoAndTags, nil }
func stripTag(image string) string { ref, err := reference.ParseNamed(image) if err != nil { return image } return ref.Name() }
// ParseDockerURL takes a Docker URL and returns a ParsedDockerURL with its // index URL, image name, and tag. func ParseDockerURL(arg string) (*types.ParsedDockerURL, error) { r, err := reference.ParseNamed(arg) if err != nil { return nil, err } var tag, digest string switch x := r.(type) { case reference.Canonical: digest = x.Digest().String() case reference.NamedTagged: tag = x.Tag() default: tag = defaultTag } indexURL, remoteName := SplitReposName(r.Name()) p := &types.ParsedDockerURL{ IndexURL: indexURL, ImageName: remoteName, Tag: tag, Digest: digest, } return p, nil }
func TestPushImageJSONIndex(t *testing.T) { r := spawnTestRegistrySession(t) imgData := []*ImgData{ { ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37", }, { ID: "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d", Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2", }, } repoRef, err := reference.ParseNamed(REPO) if err != nil { t.Fatal(err) } repoData, err := r.PushImageJSONIndex(repoRef, imgData, false, nil) if err != nil { t.Fatal(err) } if repoData == nil { t.Fatal("Expected RepositoryData object") } repoData, err = r.PushImageJSONIndex(repoRef, imgData, true, []string{r.indexEndpoint.String()}) if err != nil { t.Fatal(err) } if repoData == nil { t.Fatal("Expected RepositoryData object") } }
func validateContainerSpec(container *api.ContainerSpec) error { if container == nil { return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec") } if err := validateHostname(container.Hostname); err != nil { return err } if container.Image == "" { return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided") } if _, err := reference.ParseNamed(container.Image); err != nil { return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image) } mountMap := make(map[string]bool) for _, mount := range container.Mounts { if _, exists := mountMap[mount.Target]; exists { return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: duplicate mount point: %s", mount.Target) } mountMap[mount.Target] = true } return nil }
func TestLoad(t *testing.T) { jsonFile, err := ioutil.TempFile("", "tag-store-test") if err != nil { t.Fatalf("error creating temp file: %v", err) } defer os.RemoveAll(jsonFile.Name()) // Write canned json to the temp file _, err = jsonFile.Write(marshalledSaveLoadTestCases) if err != nil { t.Fatalf("error writing to temp file: %v", err) } jsonFile.Close() store, err := NewTagStore(jsonFile.Name()) if err != nil { t.Fatalf("error creating tag store: %v", err) } for refStr, expectedID := range saveLoadTestCases { ref, err := reference.ParseNamed(refStr) if err != nil { t.Fatalf("failed to parse reference: %v", err) } id, err := store.Get(ref) if err != nil { t.Fatalf("could not find reference %s: %v", refStr, err) } if id != expectedID { t.Fatalf("expected %s - got %s", expectedID, id) } } }
// CmdPush pushes an image or repository to the registry. // // Usage: docker push NAME[:TAG] func (cli *DockerCli) CmdPush(args ...string) error { cmd := Cli.Subcmd("push", []string{"NAME[:TAG]"}, Cli.DockerCommands["push"].Description, true) addTrustedFlags(cmd, false) cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) ref, err := reference.ParseNamed(cmd.Arg(0)) if err != nil { return err } var tag string switch x := ref.(type) { case reference.Digested: return errors.New("cannot push a digest reference") case reference.Tagged: tag = x.Tag() } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(ref) if err != nil { return err } // Resolve the Auth config relevant for this server authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push") if isTrusted() { return cli.trustedPush(repoInfo, tag, authConfig, requestPrivilege) } return cli.imagePushPrivileged(authConfig, ref.Name(), tag, cli.out, requestPrivilege) }
func TestListener(t *testing.T) { ctx := context.Background() registry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableDelete, storage.EnableRedirect) if err != nil { t.Fatalf("error creating registry: %v", err) } tl := &testListener{ ops: make(map[string]int), } repoRef, _ := reference.ParseNamed("foo/bar") repository, err := registry.Repository(ctx, repoRef) if err != nil { t.Fatalf("unexpected error getting repo: %v", err) } repository = Listen(repository, tl) // Now take the registry through a number of operations checkExerciseRepository(t, repository) expectedOps := map[string]int{ "manifest:push": 1, "manifest:pull": 1, // "manifest:delete": 0, // deletes not supported for now "layer:push": 2, "layer:pull": 2, // "layer:delete": 0, // deletes not supported for now } if !reflect.DeepEqual(tl.ops, expectedOps) { t.Fatalf("counts do not match:\n%v\n !=\n%v", tl.ops, expectedOps) } }
func TestSave(t *testing.T) { jsonFile, err := ioutil.TempFile("", "tag-store-test") if err != nil { t.Fatalf("error creating temp file: %v", err) } _, err = jsonFile.Write([]byte(`{}`)) jsonFile.Close() defer os.RemoveAll(jsonFile.Name()) store, err := NewTagStore(jsonFile.Name()) if err != nil { t.Fatalf("error creating tag store: %v", err) } for refStr, id := range saveLoadTestCases { ref, err := reference.ParseNamed(refStr) if err != nil { t.Fatalf("failed to parse reference: %v", err) } err = store.Add(ref, id, false) if err != nil { t.Fatalf("could not add reference %s: %v", refStr, err) } } jsonBytes, err := ioutil.ReadFile(jsonFile.Name()) if err != nil { t.Fatalf("could not read json file: %v", err) } if !bytes.Equal(jsonBytes, marshalledSaveLoadTestCases) { t.Fatalf("save output did not match expectations\nexpected:\n%s\ngot:\n%s", marshalledSaveLoadTestCases, jsonBytes) } }
// GetImageID returns an image ID corresponding to the image referred to by // refOrID. func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) { // Treat as an ID if id, err := digest.ParseDigest(refOrID); err == nil { return image.ID(id), nil } // Treat it as a possible tag or digest reference if ref, err := reference.ParseNamed(refOrID); err == nil { ref = registry.NormalizeLocalReference(ref) if id, err := daemon.tagStore.Get(ref); err == nil { return id, nil } if tagged, ok := ref.(reference.Tagged); ok { if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil { for _, namedRef := range daemon.tagStore.References(id) { if namedRef.Name() == ref.Name() { return id, nil } } } } } // Search based on ID if id, err := daemon.imageStore.Search(refOrID); err == nil { return id, nil } return "", ErrImageDoesNotExist{refOrID} }
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv { nameRef, err := reference.ParseNamed(name) if err != nil { t.Fatalf("unable to parse reference: %s", err) } ctx := context.Background() truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider())) if err != nil { t.Fatalf("error creating registry: %v", err) } truthRepo, err := truthRegistry.Repository(ctx, nameRef) if err != nil { t.Fatalf("unexpected error getting repo: %v", err) } tr, err := truthRepo.Manifests(ctx) if err != nil { t.Fatal(err.Error()) } truthManifests := statsManifest{ manifests: tr, stats: make(map[string]int), } manifestDigest, err := populateRepo(t, ctx, truthRepo, name, tag) if err != nil { t.Fatalf(err.Error()) } localRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableRedirect, storage.DisableDigestResumption) if err != nil { t.Fatalf("error creating registry: %v", err) } localRepo, err := localRegistry.Repository(ctx, nameRef) if err != nil { t.Fatalf("unexpected error getting repo: %v", err) } lr, err := localRepo.Manifests(ctx) if err != nil { t.Fatal(err.Error()) } localManifests := statsManifest{ manifests: lr, stats: make(map[string]int), } s := scheduler.New(ctx, inmemory.New(), "/scheduler-state.json") return &manifestStoreTestEnv{ manifestDigest: manifestDigest, manifests: proxyManifestStore{ ctx: ctx, localManifests: localManifests, remoteManifests: truthManifests, scheduler: s, repositoryName: nameRef, authChallenger: &mockChallenger{}, }, } }
func TestManifestFetchWithEtag(t *testing.T) { repo, _ := reference.ParseNamed("test.example.com/repo/by/tag") _, d1, p1 := newRandomSchemaV1Manifest(repo, "latest", 6) var m testutil.RequestResponseMap addTestManifestWithEtag(repo, "latest", p1, &m, d1.String()) e, c := testServer(m) defer c() ctx := context.Background() r, err := NewRepository(ctx, repo, e, nil) if err != nil { t.Fatal(err) } ms, err := r.Manifests(ctx) if err != nil { t.Fatal(err) } clientManifestService, ok := ms.(*manifests) if !ok { panic("wrong type for client manifest service") } _, err = clientManifestService.Get(ctx, d1, distribution.WithTag("latest"), AddEtagToTag("latest", d1.String())) if err != distribution.ErrManifestNotModified { t.Fatal(err) } }
func TestBlobDelete(t *testing.T) { dgst, _ := newRandomBlob(1024) var m testutil.RequestResponseMap repo, _ := reference.ParseNamed("test.example.com/repo1") m = append(m, testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "DELETE", Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(), }, Response: testutil.Response{ StatusCode: http.StatusAccepted, Headers: http.Header(map[string][]string{ "Content-Length": {"0"}, }), }, }) e, c := testServer(m) defer c() ctx := context.Background() r, err := NewRepository(ctx, repo, e, nil) if err != nil { t.Fatal(err) } l := r.Blobs(ctx) err = l.Delete(ctx, dgst) if err != nil { t.Errorf("Error deleting blob: %s", err.Error()) } }
func TestBlobFetch(t *testing.T) { d1, b1 := newRandomBlob(1024) var m testutil.RequestResponseMap addTestFetch("test.example.com/repo1", d1, b1, &m) e, c := testServer(m) defer c() ctx := context.Background() repo, _ := reference.ParseNamed("test.example.com/repo1") r, err := NewRepository(ctx, repo, e, nil) if err != nil { t.Fatal(err) } l := r.Blobs(ctx) b, err := l.Get(ctx, d1) if err != nil { t.Fatal(err) } if bytes.Compare(b, b1) != 0 { t.Fatalf("Wrong bytes values fetched: [%d]byte != [%d]byte", len(b), len(b1)) } // TODO(dmcgowan): Test for unknown blob case }
func TestBlobExists(t *testing.T) { d1, b1 := newRandomBlob(1024) var m testutil.RequestResponseMap addTestFetch("test.example.com/repo1", d1, b1, &m) e, c := testServer(m) defer c() ctx := context.Background() repo, _ := reference.ParseNamed("test.example.com/repo1") r, err := NewRepository(ctx, repo, e, nil) if err != nil { t.Fatal(err) } l := r.Blobs(ctx) stat, err := l.Stat(ctx, d1) if err != nil { t.Fatal(err) } if stat.Digest != d1 { t.Fatalf("Unexpected digest: %s, expected %s", stat.Digest, d1) } if stat.Size != int64(len(b1)) { t.Fatalf("Unexpected length: %d, expected %d", stat.Size, len(b1)) } // TODO(dmcgowan): Test error cases and ErrBlobUnknown case }
func (store *store) reload() error { f, err := os.Open(store.jsonPath) if err != nil { return err } defer f.Close() if err := json.NewDecoder(f).Decode(&store); err != nil { return err } for _, repository := range store.Repositories { for refStr, refID := range repository { ref, err := reference.ParseNamed(refStr) if err != nil { // Should never happen continue } if store.referencesByIDCache[refID] == nil { store.referencesByIDCache[refID] = make(map[string]reference.Named) } store.referencesByIDCache[refID][refStr] = ref } } return nil }
// ImagePush requests the docker host to push an image to a remote registry. // It executes the privileged function if the operation is unauthorized // and it tries one more time. // It's up to the caller to handle the io.ReadCloser and close it properly. func (cli *Client) ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) { distributionRef, err := distreference.ParseNamed(ref) if err != nil { return nil, err } if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical { return nil, errors.New("cannot push a digest reference") } var tag = "" if nameTaggedRef, isNamedTagged := distributionRef.(distreference.NamedTagged); isNamedTagged { tag = nameTaggedRef.Tag() } query := url.Values{} query.Set("tag", tag) resp, err := cli.tryImagePush(ctx, distributionRef.Name(), query, options.RegistryAuth) if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { newAuthHeader, privilegeErr := options.PrivilegeFunc() if privilegeErr != nil { return nil, privilegeErr } resp, err = cli.tryImagePush(ctx, distributionRef.Name(), query, newAuthHeader) } if err != nil { return nil, err } return resp.body, nil }
// ReferencesByName returns the references for a given repository name. // If there are no references known for this repository name, // ReferencesByName returns nil. func (store *store) ReferencesByName(ref reference.Named) []Association { store.mu.RLock() defer store.mu.RUnlock() repository, exists := store.Repositories[ref.Name()] if !exists { return nil } var associations []Association for refStr, refID := range repository { ref, err := reference.ParseNamed(refStr) if err != nil { // Should never happen return nil } associations = append(associations, Association{ Ref: ref, ImageID: refID, }) } return associations }
func (m customImageMap) Set(value string) error { parts := strings.Split(value, ",") if len(parts) != 2 { return errors.New("invalid custome image format, expected \"name,reference\"") } ref, err := reference.Parse(parts[0]) if err != nil { return err } namedTagged, ok := ref.(reference.NamedTagged) if !ok { return fmt.Errorf("reference %s must contain name and tag", ref.String()) } source, err := reference.ParseNamed(parts[1]) if err != nil { return err } m[parts[0]] = CustomImage{ Source: source.String(), Target: namedTagged, } return nil }
func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idresolver.IDResolver, noTrunc bool) error { prevService := "" prevSlot := 0 for _, task := range tasks { name, err := resolver.Resolve(ctx, task, task.ID) nodeValue, err := resolver.Resolve(ctx, swarm.Node{}, task.NodeID) if err != nil { return err } // Indent the name if necessary indentedName := name // Since the new format of the task name is <ServiceName>.<Slot>.<taskID>, we should only compare // <ServiceName> and <Slot> here. if prevService == task.ServiceID && prevSlot == task.Slot { indentedName = fmt.Sprintf(" \\_ %s", indentedName) } prevService = task.ServiceID prevSlot = task.Slot // Trim and quote the error message. taskErr := task.Status.Err if !noTrunc && len(taskErr) > maxErrLength { taskErr = fmt.Sprintf("%s…", taskErr[:maxErrLength-1]) } if len(taskErr) > 0 { taskErr = fmt.Sprintf("\"%s\"", taskErr) } image := task.Spec.ContainerSpec.Image if !noTrunc { ref, err := distreference.ParseNamed(image) if err == nil { // update image string for display namedTagged, ok := ref.(distreference.NamedTagged) if ok { image = namedTagged.Name() + ":" + namedTagged.Tag() } } } fmt.Fprintf( out, psTaskItemFmt, indentedName, image, nodeValue, command.PrettyPrint(task.DesiredState), command.PrettyPrint(task.Status.State), strings.ToLower(units.HumanDuration(time.Since(task.Status.Timestamp))), taskErr, portStatus(task.Status.PortStatus), ) } return nil }
// Parse parses the given references and returns the repository and // tag (if present) from it. If there is an error during parsing, it will // return an error. func Parse(ref string) (string, string, error) { distributionRef, err := distreference.ParseNamed(ref) if err != nil { return "", "", err } tag := GetTagFromNamedRef(distributionRef) return distributionRef.Name(), tag, nil }
// CmdPull pulls an image or a repository from the registry. // // Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST] func (cli *DockerCli) CmdPull(args ...string) error { cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, Cli.DockerCommands["pull"].Description, true) allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository") addTrustedFlags(cmd, true) cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) remote := cmd.Arg(0) distributionRef, err := reference.ParseNamed(remote) if err != nil { return err } var tag string switch x := distributionRef.(type) { case reference.Digested: if *allTags { return errTagCantBeUsed } tag = x.Digest().String() case reference.Tagged: if *allTags { return errTagCantBeUsed } tag = x.Tag() default: if !*allTags { tag = tagpkg.DefaultTag distributionRef, err = reference.WithTag(distributionRef, tag) if err != nil { return err } fmt.Fprintf(cli.out, "Using default tag: %s\n", tag) } } ref := registry.ParseReference(tag) // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } if isTrusted() && !ref.HasDigest() { // Check if tag is digest authConfig := registry.ResolveAuthConfig(cli.configFile, repoInfo.Index) return cli.trustedPull(repoInfo, ref, authConfig) } v := url.Values{} v.Set("fromImage", distributionRef.String()) _, _, err = cli.clientRequestAttemptLogin("POST", "/images/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull") return err }
func splitHost(in string) (url string, ref reference.Named, err error) { ref, err = reference.ParseNamed(in) if err != nil { return } url, name := reference.SplitHostname(ref) ref, err = updateName(ref, name) return }
// Validation image reference. func ValidateImageReference(spec *ImageReferenceValiditySpec) (*ImageReferenceValidity, error) { log.Printf("Validating %s as a image reference", spec.Reference) s := spec.Reference _, err := distreference.ParseNamed(s) if err != nil { return &ImageReferenceValidity{Valid: false, Reason: err.Error()}, nil } return &ImageReferenceValidity{Valid: true}, nil }
func digestRef(ref reference.Named, digst string) (reference.Canonical, error) { rn, err := reference.ParseNamed(ref.Name()) if err != nil { return nil, err } d := digest.Digest(digst) return reference.WithDigest(rn, d) }