func (t *mockTagAdder) AddTag(ref reference.Named, id image.ID, force bool) error { if t.refs == nil { t.refs = make(map[string]string) } t.refs[ref.String()] = id.String() return nil }
// TagImageWithReference adds the given reference to the image ID provided. func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.Named) error { if err := daemon.referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil { return err } daemon.LogImageEvent(imageID.String(), newTag.String(), "tag") return nil }
// imageDeleteHelper attempts to delete the given image from this daemon. If // the image has any hard delete conflicts (child images or running containers // using the image) then it cannot be deleted. If the image has any soft delete // conflicts (any tags/digests referencing the image or any stopped container // using the image) then it can only be deleted if force is true. If the delete // succeeds and prune is true, the parent images are also deleted if they do // not have any soft or hard delete conflicts themselves. Any deleted images // and untagged references are appended to the given records. If any error or // conflict is encountered, it will be returned immediately without deleting // the image. If quiet is true, any encountered conflicts will be ignored and // the function will return nil immediately without deleting the image. func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDelete, force, prune, quiet bool) error { // First, determine if this image has any conflicts. Ignore soft conflicts // if force is true. if conflict := daemon.checkImageDeleteConflict(imgID, force); conflict != nil { if quiet && !daemon.imageIsDangling(imgID) { // Ignore conflicts UNLESS the image is "dangling" in // which case we want the user to know. return nil } // There was a conflict and it's either a hard conflict OR we are not // forcing deletion on soft conflicts. return conflict } parent, err := daemon.imageStore.GetParent(imgID) if err != nil { // There may be no parent parent = "" } // Delete all repository tag/digest references to this image. if err := daemon.removeAllReferencesToImageID(imgID, records); err != nil { return err } removedLayers, err := daemon.imageStore.Delete(imgID) if err != nil { return err } daemon.EventsService.Log("delete", imgID.String(), "") *records = append(*records, types.ImageDelete{Deleted: imgID.String()}) for _, removedLayer := range removedLayers { *records = append(*records, types.ImageDelete{Deleted: removedLayer.ChainID.String()}) } if !prune || parent == "" { return nil } // We need to prune the parent image. This means delete it if there are // no tags/digests referencing it and there are no containers using it ( // either running or stopped). // Do not force prunings, but do so quietly (stopping on any encountered // conflicts). return daemon.imageDeleteHelper(parent, records, false, true, true) }
// removeAllReferencesToImageID attempts to remove every reference to the given // imgID from this daemon's store of repository tag/digest references. Returns // on the first encountered error. Removed references are logged to this // daemon's event service. An "Untagged" types.ImageDelete is added to the // given list of records. func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDelete) error { imageRefs := daemon.referenceStore.References(imgID) for _, imageRef := range imageRefs { parsedRef, err := daemon.removeImageRef(imageRef) if err != nil { return err } untaggedRecord := types.ImageDelete{Untagged: parsedRef.String()} daemon.LogImageEvent(imgID.String(), imgID.String(), "untag") *records = append(*records, untaggedRecord) } return nil }