// GetImageID returns an image ID corresponding to the image referred to by // refOrID. func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) { id, ref, err := reference.ParseIDOrReference(refOrID) if err != nil { return "", err } if id != "" { if _, err := daemon.imageStore.Get(image.IDFromDigest(id)); err != nil { return "", ErrImageDoesNotExist{refOrID} } return image.IDFromDigest(id), nil } if id, err := daemon.referenceStore.Get(ref); err == nil { return image.IDFromDigest(id), nil } if tagged, ok := ref.(reference.NamedTagged); ok { if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil { for _, namedRef := range daemon.referenceStore.References(id.Digest()) { 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 (s *imageConfigStore) Get(d digest.Digest) ([]byte, error) { img, err := s.Store.Get(image.IDFromDigest(d)) if err != nil { return nil, err } return img.RawJSON(), nil }
// GetImageID returns an image ID corresponding to the image referred to by // refOrID. func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) { id, ref, err := reference.ParseIDOrReference(refOrID) if err != nil { return "", err } if id != "" { if _, err := daemon.imageStore.Get(image.IDFromDigest(id)); err != nil { return "", ErrImageDoesNotExist{refOrID} } return image.IDFromDigest(id), nil } if id, err := daemon.referenceStore.Get(ref); err == nil { return image.IDFromDigest(id), nil } // deprecated: repo:shortid https://github.com/docker/docker/pull/799 if tagged, ok := ref.(reference.NamedTagged); ok { if tag := tagged.Tag(); stringid.IsShortID(stringid.TruncateID(tag)) { if id, err := daemon.imageStore.Search(tag); err == nil { for _, namedRef := range daemon.referenceStore.References(id.Digest()) { 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 (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.Canonical); ok { return } var ok bool if tagged, ok = ref.(reference.NamedTagged); !ok { var err error if tagged, err = reference.WithTag(ref, reference.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 { id, ref, err := reference.ParseIDOrReference(name) if err != nil { return nil, err } if id != "" { _, err := l.is.Get(image.IDFromDigest(id)) if err != nil { return nil, err } addAssoc(image.IDFromDigest(id), nil) continue } if ref.Name() == string(digest.Canonical) { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) continue } if reference.IsNameOnly(ref) { assocs := l.rs.ReferencesByName(ref) for _, assoc := range assocs { addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref) } if len(assocs) == 0 { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) } continue } id, err = l.rs.Get(ref) if err != nil { return nil, err } addAssoc(image.IDFromDigest(id), ref) } return imgDescr, nil }
func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *schema2.DeserializedManifest) (id digest.Digest, manifestDigest digest.Digest, err error) { manifestDigest, err = schema2ManifestDigest(ref, mfst) if err != nil { return "", "", err } target := mfst.Target() if _, err := p.config.ImageStore.Get(image.IDFromDigest(target.Digest)); err == nil { // If the image already exists locally, no need to pull // anything. return target.Digest, manifestDigest, nil } var descriptors []xfer.DownloadDescriptor // Note that the order of this loop is in the direction of bottom-most // to top-most, so that the downloads slice gets ordered correctly. for _, d := range mfst.Layers { layerDescriptor := &v2LayerDescriptor{ digest: d.Digest, repo: p.repo, repoInfo: p.repoInfo, V2MetadataService: p.V2MetadataService, src: d, } descriptors = append(descriptors, layerDescriptor) } configChan := make(chan []byte, 1) errChan := make(chan error, 1) var cancel func() ctx, cancel = context.WithCancel(ctx) // Pull the image config go func() { configJSON, err := p.pullSchema2Config(ctx, target.Digest) if err != nil { errChan <- ImageConfigPullError{Err: err} cancel() return } configChan <- configJSON }() var ( configJSON []byte // raw serialized image config unmarshalledConfig image.Image // deserialized image config downloadRootFS image.RootFS // rootFS to use for registering layers. ) // https://github.com/docker/docker/issues/24766 - Err on the side of caution, // explicitly blocking images intended for linux from the Windows daemon. On // Windows, we do this before the attempt to download, effectively serialising // the download slightly slowing it down. We have to do it this way, as // chances are the download of layers itself would fail due to file names // which aren't suitable for NTFS. At some point in the future, if a similar // check to block Windows images being pulled on Linux is implemented, it // may be necessary to perform the same type of serialisation. if runtime.GOOS == "windows" { configJSON, unmarshalledConfig, err = receiveConfig(configChan, errChan) if err != nil { return "", "", err } if unmarshalledConfig.RootFS == nil { return "", "", errRootFSInvalid } if unmarshalledConfig.OS == "linux" { return "", "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS) } } downloadRootFS = *image.NewRootFS() rootFS, release, err := p.config.DownloadManager.Download(ctx, downloadRootFS, descriptors, p.config.ProgressOutput) if err != nil { if configJSON != nil { // Already received the config return "", "", err } select { case err = <-errChan: return "", "", err default: cancel() select { case <-configChan: case <-errChan: } return "", "", err } } defer release() if configJSON == nil { configJSON, unmarshalledConfig, err = receiveConfig(configChan, errChan) if err != nil { return "", "", err } if unmarshalledConfig.RootFS == nil { return "", "", errRootFSInvalid } } // The DiffIDs returned in rootFS MUST match those in the config. // Otherwise the image config could be referencing layers that aren't // included in the manifest. if len(rootFS.DiffIDs) != len(unmarshalledConfig.RootFS.DiffIDs) { return "", "", errRootFSMismatch } for i := range rootFS.DiffIDs { if rootFS.DiffIDs[i] != unmarshalledConfig.RootFS.DiffIDs[i] { return "", "", errRootFSMismatch } } imageID, err := p.config.ImageStore.Create(configJSON) if err != nil { return "", "", err } return imageID.Digest(), manifestDigest, nil }
func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id digest.Digest) error { logrus.Debugf("Pushing repository: %s", ref.String()) img, err := p.config.ImageStore.Get(image.IDFromDigest(id)) if err != nil { return fmt.Errorf("could not find image from tag %s: %v", ref.String(), err) } var l layer.Layer topLayerID := img.RootFS.ChainID() if topLayerID == "" { l = layer.EmptyLayer } else { l, err = p.config.LayerStore.Get(topLayerID) if err != nil { return fmt.Errorf("failed to get top layer from image: %v", err) } defer layer.ReleaseAndLog(p.config.LayerStore, l) } var descriptors []xfer.UploadDescriptor descriptorTemplate := v2PushDescriptor{ v2MetadataService: p.v2MetadataService, repoInfo: p.repoInfo, ref: p.ref, repo: p.repo, pushState: &p.pushState, } // Loop bounds condition is to avoid pushing the base layer on Windows. for i := 0; i < len(img.RootFS.DiffIDs); i++ { descriptor := descriptorTemplate descriptor.layer = l descriptors = append(descriptors, &descriptor) l = l.Parent() } if err := p.config.UploadManager.Upload(ctx, descriptors, p.config.ProgressOutput); err != nil { return err } // Try schema2 first builder := schema2.NewManifestBuilder(p.repo.Blobs(ctx), img.RawJSON()) manifest, err := manifestFromBuilder(ctx, builder, descriptors) if err != nil { return err } manSvc, err := p.repo.Manifests(ctx) if err != nil { return err } putOptions := []distribution.ManifestServiceOption{distribution.WithTag(ref.Tag())} if _, err = manSvc.Put(ctx, manifest, putOptions...); err != nil { if runtime.GOOS == "windows" { logrus.Warnf("failed to upload schema2 manifest: %v", err) return err } logrus.Warnf("failed to upload schema2 manifest: %v - falling back to schema1", err) manifestRef, err := distreference.WithTag(p.repo.Named(), ref.Tag()) if err != nil { return err } builder = schema1.NewConfigManifestBuilder(p.repo.Blobs(ctx), p.config.TrustKey, manifestRef, img.RawJSON()) manifest, err = manifestFromBuilder(ctx, builder, descriptors) if err != nil { return err } if _, err = manSvc.Put(ctx, manifest, putOptions...); err != nil { return err } } var canonicalManifest []byte switch v := manifest.(type) { case *schema1.SignedManifest: canonicalManifest = v.Canonical case *schema2.DeserializedManifest: _, canonicalManifest, err = v.Payload() if err != nil { return err } } manifestDigest := digest.FromBytes(canonicalManifest) progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", ref.Tag(), manifestDigest, len(canonicalManifest)) if err := addDigestReference(p.config.ReferenceStore, ref, manifestDigest, id); err != nil { return err } // Signal digest to the trust client so it can sign the // push, if appropriate. progress.Aux(p.config.ProgressOutput, PushResult{Tag: ref.Tag(), Digest: manifestDigest, Size: len(canonicalManifest)}) return nil }
// Retrieve the all the images to be uploaded in the correct order func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID][]string, referencedLayers []PushLayer, err error) { tagsByImage = make(map[image.ID][]string) // Ignore digest references if _, isCanonical := p.ref.(reference.Canonical); isCanonical { return } tagged, isTagged := p.ref.(reference.NamedTagged) if isTagged { // Push a specific tag var imgID image.ID var dgst digest.Digest dgst, err = p.config.ReferenceStore.Get(p.ref) if err != nil { return } imgID = image.IDFromDigest(dgst) imageList, err = p.imageListForTag(imgID, nil, &referencedLayers) if err != nil { return } tagsByImage[imgID] = []string{tagged.Tag()} return } imagesSeen := make(map[digest.Digest]struct{}) dependenciesSeen := make(map[layer.ChainID]*v1DependencyImage) associations := p.config.ReferenceStore.ReferencesByName(p.ref) for _, association := range associations { if tagged, isTagged = association.Ref.(reference.NamedTagged); !isTagged { // Ignore digest references. continue } imgID := image.IDFromDigest(association.ID) tagsByImage[imgID] = append(tagsByImage[imgID], tagged.Tag()) if _, present := imagesSeen[association.ID]; present { // Skip generating image list for already-seen image continue } imagesSeen[association.ID] = struct{}{} imageListForThisTag, err := p.imageListForTag(imgID, dependenciesSeen, &referencedLayers) if err != nil { return nil, nil, nil, err } // append to main image list imageList = append(imageList, imageListForThisTag...) } if len(imageList) == 0 { return nil, nil, nil, fmt.Errorf("No images found for the requested repository / tag") } logrus.Debugf("Image list: %v", imageList) logrus.Debugf("Tags by image: %v", tagsByImage) return }