зеркало из https://github.com/microsoft/docker.git
Merge pull request #19170 from aaronlehmann/delete-prune-digests
Prune digest references when deleting by tag
This commit is contained in:
Коммит
c0c66c57b2
|
@ -90,8 +90,34 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||||
records = append(records, untaggedRecord)
|
records = append(records, untaggedRecord)
|
||||||
|
|
||||||
// If has remaining references then untag finishes the remove
|
repoRefs = daemon.referenceStore.References(imgID)
|
||||||
if len(repoRefs) > 1 {
|
|
||||||
|
// If this is a tag reference and all the remaining references
|
||||||
|
// to this image are digest references, delete the remaining
|
||||||
|
// references so that they don't prevent removal of the image.
|
||||||
|
if _, isCanonical := parsedRef.(reference.Canonical); !isCanonical {
|
||||||
|
foundTagRef := false
|
||||||
|
for _, repoRef := range repoRefs {
|
||||||
|
if _, repoRefIsCanonical := repoRef.(reference.Canonical); !repoRefIsCanonical {
|
||||||
|
foundTagRef = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundTagRef {
|
||||||
|
for _, repoRef := range repoRefs {
|
||||||
|
if _, err := daemon.removeImageRef(repoRef); err != nil {
|
||||||
|
return records, err
|
||||||
|
}
|
||||||
|
|
||||||
|
untaggedRecord := types.ImageDelete{Untagged: repoRef.String()}
|
||||||
|
records = append(records, untaggedRecord)
|
||||||
|
}
|
||||||
|
repoRefs = []reference.Named{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it has remaining references then the untag finished the remove
|
||||||
|
if len(repoRefs) > 0 {
|
||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,9 @@ parent = "smn_cli"
|
||||||
--no-prune Do not delete untagged parents
|
--no-prune Do not delete untagged parents
|
||||||
|
|
||||||
You can remove an image using its short or long ID, its tag, or its digest. If
|
You can remove an image using its short or long ID, its tag, or its digest. If
|
||||||
an image has one or more tag or digest reference, you must remove all of them
|
an image has one or more tag referencing it, you must remove all of them before
|
||||||
before the image is removed.
|
the image is removed. Digest references are removed automatically when an image
|
||||||
|
is removed by tag.
|
||||||
|
|
||||||
$ docker images
|
$ docker images
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
|
|
@ -395,6 +395,35 @@ func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C)
|
||||||
dockerCmd(c, "rmi", imageID)
|
dockerCmd(c, "rmi", imageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerRegistrySuite) TestDeleteImageWithDigestAndTag(c *check.C) {
|
||||||
|
pushDigest, err := setupImage(c)
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||||
|
|
||||||
|
// pull from the registry using the <name>@<digest> reference
|
||||||
|
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||||
|
dockerCmd(c, "pull", imageReference)
|
||||||
|
|
||||||
|
imageID, err := inspectField(imageReference, "Id")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("error inspecting image id"))
|
||||||
|
|
||||||
|
repoTag := repoName + ":sometag"
|
||||||
|
repoTag2 := repoName + ":othertag"
|
||||||
|
dockerCmd(c, "tag", imageReference, repoTag)
|
||||||
|
dockerCmd(c, "tag", imageReference, repoTag2)
|
||||||
|
|
||||||
|
dockerCmd(c, "rmi", repoTag2)
|
||||||
|
|
||||||
|
// rmi should have deleted only repoTag2, because there's another tag
|
||||||
|
_, err = inspectField(repoTag, "Id")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("repoTag should not have been removed"))
|
||||||
|
|
||||||
|
dockerCmd(c, "rmi", repoTag)
|
||||||
|
|
||||||
|
// rmi should have deleted the tag, the digest reference, and the image itself
|
||||||
|
_, err = inspectField(imageID, "Id")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
|
||||||
|
}
|
||||||
|
|
||||||
// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
|
// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
|
||||||
// we have modified a manifest blob and its digest cannot be verified.
|
// we have modified a manifest blob and its digest cannot be verified.
|
||||||
// This is the schema2 version of the test.
|
// This is the schema2 version of the test.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/integration/checker"
|
"github.com/docker/docker/pkg/integration/checker"
|
||||||
|
@ -200,3 +201,55 @@ func (s *DockerTrustSuite) TestTrustedOfflinePull(c *check.C) {
|
||||||
c.Assert(err, check.IsNil, check.Commentf(out))
|
c.Assert(err, check.IsNil, check.Commentf(out))
|
||||||
c.Assert(string(out), checker.Contains, "Tagging", check.Commentf(out))
|
c.Assert(string(out), checker.Contains, "Tagging", check.Commentf(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerTrustSuite) TestTrustedPullDelete(c *check.C) {
|
||||||
|
repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, "trusted-pull-delete")
|
||||||
|
// tag the image and upload it to the private registry
|
||||||
|
_, err := buildImage(repoName, `
|
||||||
|
FROM busybox
|
||||||
|
CMD echo trustedpulldelete
|
||||||
|
`, true)
|
||||||
|
|
||||||
|
pushCmd := exec.Command(dockerBinary, "push", repoName)
|
||||||
|
s.trustedCmd(pushCmd)
|
||||||
|
out, _, err := runCommandWithOutput(pushCmd)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Error running trusted push: %s\n%s", err, out)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(out), "Signing and pushing trust metadata") {
|
||||||
|
c.Fatalf("Missing expected output on trusted push:\n%s", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
if out, status := dockerCmd(c, "rmi", repoName); status != 0 {
|
||||||
|
c.Fatalf("Error removing image %q\n%s", repoName, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try pull
|
||||||
|
pullCmd := exec.Command(dockerBinary, "pull", repoName)
|
||||||
|
s.trustedCmd(pullCmd)
|
||||||
|
out, _, err = runCommandWithOutput(pullCmd)
|
||||||
|
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf(out))
|
||||||
|
|
||||||
|
matches := digestRegex.FindStringSubmatch(out)
|
||||||
|
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
||||||
|
pullDigest := matches[1]
|
||||||
|
|
||||||
|
imageID, err := inspectField(repoName, "Id")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("error inspecting image id"))
|
||||||
|
|
||||||
|
imageByDigest := repoName + "@" + pullDigest
|
||||||
|
byDigestID, err := inspectField(imageByDigest, "Id")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("error inspecting image id"))
|
||||||
|
|
||||||
|
c.Assert(byDigestID, checker.Equals, imageID)
|
||||||
|
|
||||||
|
// rmi of tag should also remove the digest reference
|
||||||
|
dockerCmd(c, "rmi", repoName)
|
||||||
|
|
||||||
|
_, err = inspectField(imageByDigest, "Id")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf("digest reference should have been removed"))
|
||||||
|
|
||||||
|
_, err = inspectField(imageID, "Id")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче