// 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} }
// TagImage creates a tag in the repository reponame, pointing to the image named // imageName. func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error { imageID, err := daemon.GetImageID(imageName) if err != nil { return err } newTag = registry.NormalizeLocalReference(newTag) if err := daemon.tagStore.AddTag(newTag, imageID, true); err != nil { return err } daemon.EventsService.Log("tag", newTag.String(), "") return nil }
// TagImage creates a tag in the repository reponame, pointing to the image named // imageName. If force is true, an existing tag with the same name may be // overwritten. func (daemon *Daemon) TagImage(newTag reference.Named, imageName string, force bool) error { if _, isDigested := newTag.(reference.Digested); isDigested { return errors.New("refusing to create a tag with a digest reference") } if newTag.Name() == string(digest.Canonical) { return errors.New("refusing to create an ambiguous tag using digest algorithm as name") } newTag = registry.NormalizeLocalReference(newTag) imageID, err := daemon.GetImageID(imageName) if err != nil { return err } daemon.EventsService.Log("tag", newTag.String(), "") return daemon.tagStore.Add(newTag, imageID, force) }
func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor, error) { imgDescr := make(map[image.ID]*imageDescriptor) addAssoc := func(id image.ID, ref reference.Named) { if _, ok := imgDescr[id]; !ok { imgDescr[id] = &imageDescriptor{} } if ref != nil { var tagged reference.NamedTagged if _, ok := ref.(reference.Digested); ok { return } var ok bool if tagged, ok = ref.(reference.NamedTagged); !ok { var err error if tagged, err = reference.WithTag(ref, tag.DefaultTag); err != nil { return } } for _, t := range imgDescr[id].refs { if tagged.String() == t.String() { return } } imgDescr[id].refs = append(imgDescr[id].refs, tagged) } } for _, name := range names { ref, err := reference.ParseNamed(name) if err != nil { return nil, err } ref = registry.NormalizeLocalReference(ref) if ref.Name() == string(digest.Canonical) { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) continue } if _, ok := ref.(reference.Digested); !ok { if _, ok := ref.(reference.NamedTagged); !ok { assocs := l.ts.ReferencesByName(ref) for _, assoc := range assocs { addAssoc(assoc.ImageID, assoc.Ref) } if len(assocs) == 0 { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) } continue } } var imgID image.ID if imgID, err = l.ts.Get(ref); err != nil { return nil, err } addAssoc(imgID, ref) } return imgDescr, nil }
// Pull initiates a pull operation. image is the repository name to pull, and // tag may be either empty, or indicate a specific tag to pull. func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullConfig) error { // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := imagePullConfig.RegistryService.ResolveRepository(ref) if err != nil { return err } // makes sure name is not empty or `scratch` if err := validateRepoName(repoInfo.LocalName.Name()); err != nil { return err } endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(repoInfo.CanonicalName) if err != nil { return err } localName := registry.NormalizeLocalReference(ref) var ( // use a slice to append the error strings and return a joined string to caller errors []string // discardNoSupportErrors is used to track whether an endpoint encountered an error of type registry.ErrNoSupport // By default it is false, which means that if a ErrNoSupport error is encountered, it will be saved in errors. // As soon as another kind of error is encountered, discardNoSupportErrors is set to true, avoiding the saving of // any subsequent ErrNoSupport errors in errors. // It's needed for pull-by-digest on v1 endpoints: if there are only v1 endpoints configured, the error should be // returned and displayed, but if there was a v2 endpoint which supports pull-by-digest, then the last relevant // error is the ones from v2 endpoints not v1. discardNoSupportErrors bool ) for _, endpoint := range endpoints { logrus.Debugf("Trying to pull %s from %s %s", repoInfo.LocalName, endpoint.URL, endpoint.Version) puller, err := newPuller(endpoint, repoInfo, imagePullConfig) if err != nil { errors = append(errors, err.Error()) continue } if fallback, err := puller.Pull(ctx, ref); err != nil { // Was this pull cancelled? If so, don't try to fall // back. select { case <-ctx.Done(): fallback = false default: } if fallback { if _, ok := err.(registry.ErrNoSupport); !ok { // Because we found an error that's not ErrNoSupport, discard all subsequent ErrNoSupport errors. discardNoSupportErrors = true // append subsequent errors errors = append(errors, err.Error()) } else if !discardNoSupportErrors { // Save the ErrNoSupport error, because it's either the first error or all encountered errors // were also ErrNoSupport errors. // append subsequent errors errors = append(errors, err.Error()) } continue } errors = append(errors, err.Error()) logrus.Debugf("Not continuing with error: %v", fmt.Errorf(strings.Join(errors, "\n"))) if len(errors) > 0 { return fmt.Errorf(strings.Join(errors, "\n")) } } imagePullConfig.EventsService.Log("pull", localName.String(), "") return nil } if len(errors) == 0 { return fmt.Errorf("no endpoints found for %s", ref.String()) } if len(errors) > 0 { return fmt.Errorf(strings.Join(errors, "\n")) } return nil }