It closes #10139.
Signed-off-by: Rozhnov Alexandr <nox73@ya.ru>
| ... | ... |
@@ -81,6 +81,7 @@ This section lists each version from latest to oldest. Each listing includes a |
| 81 | 81 |
* `GET /volumes/(name)` get low-level information about a volume. |
| 82 | 82 |
* `DELETE /volumes/(name)`remove a volume with the specified name. |
| 83 | 83 |
* `VolumeDriver` has been moved from config to hostConfig to make the configuration portable. |
| 84 |
+* `GET /images/(name)/json` now returns information about tags of the image. |
|
| 84 | 85 |
|
| 85 | 86 |
|
| 86 | 87 |
### v1.20 API changes |
| ... | ... |
@@ -1433,7 +1433,7 @@ Return low-level information on the image `name` |
| 1433 | 1433 |
|
| 1434 | 1434 |
**Example request**: |
| 1435 | 1435 |
|
| 1436 |
- GET /images/ubuntu/json HTTP/1.1 |
|
| 1436 |
+ GET /images/example/json HTTP/1.1 |
|
| 1437 | 1437 |
|
| 1438 | 1438 |
**Example response**: |
| 1439 | 1439 |
|
| ... | ... |
@@ -1441,34 +1441,90 @@ Return low-level information on the image `name` |
| 1441 | 1441 |
Content-Type: application/json |
| 1442 | 1442 |
|
| 1443 | 1443 |
{
|
| 1444 |
- "Created": "2013-03-23T22:24:18.818426-07:00", |
|
| 1445 |
- "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", |
|
| 1446 |
- "ContainerConfig": |
|
| 1447 |
- {
|
|
| 1448 |
- "Hostname": "", |
|
| 1449 |
- "User": "", |
|
| 1450 |
- "AttachStdin": false, |
|
| 1451 |
- "AttachStdout": false, |
|
| 1452 |
- "AttachStderr": false, |
|
| 1453 |
- "Tty": true, |
|
| 1454 |
- "OpenStdin": true, |
|
| 1455 |
- "StdinOnce": false, |
|
| 1456 |
- "Env": null, |
|
| 1457 |
- "Cmd": ["/bin/bash"], |
|
| 1458 |
- "Dns": null, |
|
| 1459 |
- "Image": "ubuntu", |
|
| 1460 |
- "Labels": {
|
|
| 1461 |
- "com.example.vendor": "Acme", |
|
| 1462 |
- "com.example.license": "GPL", |
|
| 1463 |
- "com.example.version": "1.0" |
|
| 1464 |
- }, |
|
| 1465 |
- "Volumes": null, |
|
| 1466 |
- "VolumesFrom": "", |
|
| 1467 |
- "WorkingDir": "" |
|
| 1468 |
- }, |
|
| 1469 |
- "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", |
|
| 1470 |
- "Parent": "27cf784147099545", |
|
| 1471 |
- "Size": 6824592 |
|
| 1444 |
+ "Id" : "85f05633ddc1c50679be2b16a0479ab6f7637f8884e0cfe0f4d20e1ebb3d6e7c", |
|
| 1445 |
+ "Container" : "cb91e48a60d01f1e27028b4fc6819f4f290b3cf12496c8176ec714d0d390984a", |
|
| 1446 |
+ "Comment" : "", |
|
| 1447 |
+ "Os" : "linux", |
|
| 1448 |
+ "Architecture" : "amd64", |
|
| 1449 |
+ "Parent" : "91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c", |
|
| 1450 |
+ "ContainerConfig" : {
|
|
| 1451 |
+ "Tty" : false, |
|
| 1452 |
+ "Hostname" : "e611e15f9c9d", |
|
| 1453 |
+ "Volumes" : null, |
|
| 1454 |
+ "Domainname" : "", |
|
| 1455 |
+ "AttachStdout" : false, |
|
| 1456 |
+ "PublishService" : "", |
|
| 1457 |
+ "AttachStdin" : false, |
|
| 1458 |
+ "OpenStdin" : false, |
|
| 1459 |
+ "StdinOnce" : false, |
|
| 1460 |
+ "NetworkDisabled" : false, |
|
| 1461 |
+ "OnBuild" : [], |
|
| 1462 |
+ "Image" : "91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c", |
|
| 1463 |
+ "User" : "", |
|
| 1464 |
+ "WorkingDir" : "", |
|
| 1465 |
+ "Entrypoint" : null, |
|
| 1466 |
+ "MacAddress" : "", |
|
| 1467 |
+ "AttachStderr" : false, |
|
| 1468 |
+ "Labels" : {
|
|
| 1469 |
+ "com.example.license" : "GPL", |
|
| 1470 |
+ "com.example.version" : "1.0", |
|
| 1471 |
+ "com.example.vendor" : "Acme" |
|
| 1472 |
+ }, |
|
| 1473 |
+ "Env" : [ |
|
| 1474 |
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
|
| 1475 |
+ ], |
|
| 1476 |
+ "ExposedPorts" : null, |
|
| 1477 |
+ "Cmd" : [ |
|
| 1478 |
+ "/bin/sh", |
|
| 1479 |
+ "-c", |
|
| 1480 |
+ "#(nop) LABEL com.example.vendor=Acme com.example.license=GPL com.example.version=1.0" |
|
| 1481 |
+ ] |
|
| 1482 |
+ }, |
|
| 1483 |
+ "DockerVersion" : "1.9.0-dev", |
|
| 1484 |
+ "VirtualSize" : 188359297, |
|
| 1485 |
+ "Size" : 0, |
|
| 1486 |
+ "Author" : "", |
|
| 1487 |
+ "Created" : "2015-09-10T08:30:53.26995814Z", |
|
| 1488 |
+ "GraphDriver" : {
|
|
| 1489 |
+ "Name" : "aufs", |
|
| 1490 |
+ "Data" : null |
|
| 1491 |
+ }, |
|
| 1492 |
+ "Tags" : [ |
|
| 1493 |
+ "example:1.0", |
|
| 1494 |
+ "example:latest", |
|
| 1495 |
+ "example:stable" |
|
| 1496 |
+ ], |
|
| 1497 |
+ "Config" : {
|
|
| 1498 |
+ "Image" : "91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c", |
|
| 1499 |
+ "NetworkDisabled" : false, |
|
| 1500 |
+ "OnBuild" : [], |
|
| 1501 |
+ "StdinOnce" : false, |
|
| 1502 |
+ "PublishService" : "", |
|
| 1503 |
+ "AttachStdin" : false, |
|
| 1504 |
+ "OpenStdin" : false, |
|
| 1505 |
+ "Domainname" : "", |
|
| 1506 |
+ "AttachStdout" : false, |
|
| 1507 |
+ "Tty" : false, |
|
| 1508 |
+ "Hostname" : "e611e15f9c9d", |
|
| 1509 |
+ "Volumes" : null, |
|
| 1510 |
+ "Cmd" : [ |
|
| 1511 |
+ "/bin/bash" |
|
| 1512 |
+ ], |
|
| 1513 |
+ "ExposedPorts" : null, |
|
| 1514 |
+ "Env" : [ |
|
| 1515 |
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
|
| 1516 |
+ ], |
|
| 1517 |
+ "Labels" : {
|
|
| 1518 |
+ "com.example.vendor" : "Acme", |
|
| 1519 |
+ "com.example.version" : "1.0", |
|
| 1520 |
+ "com.example.license" : "GPL" |
|
| 1521 |
+ }, |
|
| 1522 |
+ "Entrypoint" : null, |
|
| 1523 |
+ "MacAddress" : "", |
|
| 1524 |
+ "AttachStderr" : false, |
|
| 1525 |
+ "WorkingDir" : "", |
|
| 1526 |
+ "User" : "" |
|
| 1527 |
+ } |
|
| 1472 | 1528 |
} |
| 1473 | 1529 |
|
| 1474 | 1530 |
Status Codes: |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
"github.com/Sirupsen/logrus" |
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 |
+ "github.com/docker/docker/utils" |
|
| 11 | 12 |
) |
| 12 | 13 |
|
| 13 | 14 |
// lookupRaw looks up an image by name in a TagStore and returns the raw JSON |
| ... | ... |
@@ -34,8 +35,22 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
| 34 | 34 |
return nil, fmt.Errorf("No such image: %s", name)
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 |
+ var tags = make([]string, 0) |
|
| 38 |
+ |
|
| 39 |
+ s.Lock() |
|
| 40 |
+ for repoName, repository := range s.Repositories {
|
|
| 41 |
+ for ref, id := range repository {
|
|
| 42 |
+ if id == image.ID {
|
|
| 43 |
+ imgRef := utils.ImageReference(repoName, ref) |
|
| 44 |
+ tags = append(tags, imgRef) |
|
| 45 |
+ } |
|
| 46 |
+ } |
|
| 47 |
+ } |
|
| 48 |
+ s.Unlock() |
|
| 49 |
+ |
|
| 37 | 50 |
imageInspect := &types.ImageInspect{
|
| 38 | 51 |
ID: image.ID, |
| 52 |
+ Tags: tags, |
|
| 39 | 53 |
Parent: image.Parent, |
| 40 | 54 |
Comment: image.Comment, |
| 41 | 55 |
Created: image.Created.Format(time.RFC3339Nano), |
| ... | ... |
@@ -6,6 +6,8 @@ import ( |
| 6 | 6 |
"net/http" |
| 7 | 7 |
"strings" |
| 8 | 8 |
|
| 9 |
+ "github.com/docker/docker/api/types" |
|
| 10 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 9 | 11 |
"github.com/go-check/check" |
| 10 | 12 |
) |
| 11 | 13 |
|
| ... | ... |
@@ -111,3 +113,23 @@ func (s *DockerSuite) TestInspectApiContainerVolumeDriver(c *check.C) {
|
| 111 | 111 |
c.Fatal("Api version 1.21 expected to include VolumeDriver in 'HostConfig'")
|
| 112 | 112 |
} |
| 113 | 113 |
} |
| 114 |
+ |
|
| 115 |
+func (s *DockerSuite) TestInspectApiImageResponse(c *check.C) {
|
|
| 116 |
+ dockerCmd(c, "tag", "busybox:latest", "busybox:mytag") |
|
| 117 |
+ |
|
| 118 |
+ endpoint := "/images/busybox/json" |
|
| 119 |
+ status, body, err := sockRequest("GET", endpoint, nil)
|
|
| 120 |
+ |
|
| 121 |
+ c.Assert(err, check.IsNil) |
|
| 122 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 123 |
+ |
|
| 124 |
+ var imageJSON types.ImageInspect |
|
| 125 |
+ if err = json.Unmarshal(body, &imageJSON); err != nil {
|
|
| 126 |
+ c.Fatalf("unable to unmarshal body for latest version: %v", err)
|
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ c.Assert(len(imageJSON.Tags), check.Equals, 2) |
|
| 130 |
+ |
|
| 131 |
+ c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:latest"), check.Equals, true) |
|
| 132 |
+ c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:mytag"), check.Equals, true) |
|
| 133 |
+} |