diff --git a/api/types/types.go b/api/types/types.go index 0c19c6fc94..efe5ea28be 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -96,7 +96,8 @@ type GraphDriverData struct { // GET "/images/{name:.*}/json" type ImageInspect struct { ID string `json:"Id"` - Tags []string + RepoTags []string + RepoDigests []string Parent string Comment string Created string diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index 89c0bebce8..255597ee6f 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -104,7 +104,7 @@ This section lists each version from latest to oldest. Each listing includes a * `GET /volumes/(name)` get low-level information about a volume. * `DELETE /volumes/(name)`remove a volume with the specified name. * `VolumeDriver` has been moved from config to hostConfig to make the configuration portable. -* `GET /images/(name)/json` now returns information about tags of the image. +* `GET /images/(name)/json` now returns information about tags and digests of the image. * The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container. * `GET /containers/(id)/stats` will return networking information respectively for each interface. * The `hostConfig` option now accepts the field `DnsOptions`, which specifies a diff --git a/docs/reference/api/docker_remote_api_v1.21.md b/docs/reference/api/docker_remote_api_v1.21.md index f7e0f62c18..2e2d25d0fa 100644 --- a/docs/reference/api/docker_remote_api_v1.21.md +++ b/docs/reference/api/docker_remote_api_v1.21.md @@ -1550,7 +1550,10 @@ Return low-level information on the image `name` "Name" : "aufs", "Data" : null }, - "Tags" : [ + "RepoDigests" : [ + "localhost:5000/test/busybox/example@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf" + ], + "RepoTags" : [ "example:1.0", "example:latest", "example:stable" diff --git a/docs/reference/api/docker_remote_api_v1.22.md b/docs/reference/api/docker_remote_api_v1.22.md index 0742638bc6..29e8ec4117 100644 --- a/docs/reference/api/docker_remote_api_v1.22.md +++ b/docs/reference/api/docker_remote_api_v1.22.md @@ -1547,7 +1547,10 @@ Return low-level information on the image `name` "Name" : "aufs", "Data" : null }, - "Tags" : [ + "RepoDigests" : [ + "localhost:5000/test/busybox/example@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf" + ], + "RepoTags" : [ "example:1.0", "example:latest", "example:stable" diff --git a/graph/service.go b/graph/service.go index 98a935c8d9..3f83ea999c 100644 --- a/graph/service.go +++ b/graph/service.go @@ -19,14 +19,19 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) { return nil, fmt.Errorf("No such image: %s", name) } - var tags = make([]string, 0) + var repoTags = make([]string, 0) + var repoDigests = make([]string, 0) s.Lock() for repoName, repository := range s.Repositories { for ref, id := range repository { if id == image.ID { imgRef := utils.ImageReference(repoName, ref) - tags = append(tags, imgRef) + if utils.DigestReference(ref) { + repoDigests = append(repoDigests, imgRef) + } else { + repoTags = append(repoTags, imgRef) + } } } } @@ -34,7 +39,8 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) { imageInspect := &types.ImageInspect{ ID: image.ID, - Tags: tags, + RepoTags: repoTags, + RepoDigests: repoDigests, Parent: image.Parent, Comment: image.Comment, Created: image.Created.Format(time.RFC3339Nano), diff --git a/integration-cli/docker_api_inspect_test.go b/integration-cli/docker_api_inspect_test.go index 4654bb8f7e..6cfab51b65 100644 --- a/integration-cli/docker_api_inspect_test.go +++ b/integration-cli/docker_api_inspect_test.go @@ -128,10 +128,10 @@ func (s *DockerSuite) TestInspectApiImageResponse(c *check.C) { c.Fatalf("unable to unmarshal body for latest version: %v", err) } - c.Assert(len(imageJSON.Tags), check.Equals, 2) + c.Assert(len(imageJSON.RepoTags), check.Equals, 2) - c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:latest"), check.Equals, true) - c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:mytag"), check.Equals, true) + c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:latest"), check.Equals, true) + c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:mytag"), check.Equals, true) } // #17131, #17139, #17173 diff --git a/integration-cli/docker_cli_by_digest_test.go b/integration-cli/docker_cli_by_digest_test.go index 90f2246018..ad6e65bbc3 100644 --- a/integration-cli/docker_cli_by_digest_test.go +++ b/integration-cli/docker_cli_by_digest_test.go @@ -8,6 +8,8 @@ import ( "github.com/docker/distribution/digest" "github.com/docker/distribution/manifest" + "github.com/docker/docker/api/types" + "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/utils" "github.com/go-check/check" ) @@ -390,6 +392,27 @@ func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) { } } +func (s *DockerRegistrySuite) TestInspectImageWithDigests(c *check.C) { + digest, err := setupImage(c) + c.Assert(err, check.IsNil, check.Commentf("error setting up image: %v", err)) + + imageReference := fmt.Sprintf("%s@%s", repoName, digest) + + // pull from the registry using the @ reference + dockerCmd(c, "pull", imageReference) + + out, _ := dockerCmd(c, "inspect", imageReference) + + var imageJSON []types.ImageInspect + if err = json.Unmarshal([]byte(out), &imageJSON); err != nil { + c.Fatalf("unable to unmarshal body for latest version: %v", err) + } + + c.Assert(len(imageJSON), check.Equals, 1) + c.Assert(len(imageJSON[0].RepoDigests), check.Equals, 1) + c.Assert(stringutils.InSlice(imageJSON[0].RepoDigests, imageReference), check.Equals, true) +} + func (s *DockerRegistrySuite) TestPsListContainersFilterAncestorImageByDigest(c *check.C) { digest, err := setupImage(c) c.Assert(err, check.IsNil, check.Commentf("error setting up image: %v", err))