From 945fc9d882324ac87505e34bb74e6ebe30be1309 Mon Sep 17 00:00:00 2001 From: Hu Keping Date: Wed, 25 Mar 2015 02:00:29 +0800 Subject: [PATCH] Fix inconsistent date formats in API Prior to this patch, the response of - GET /images/json - GET /containers/json - GET /images/(name)/history display the Created Time as UNIX format which doesn't make sense. These should be more readable as CLI command `docker inspect` shows. Due to the case that an older client with a newer version daemon, we need the version check for now. Signed-off-by: Hu Keping --- api/client/history.go | 4 +- api/client/images.go | 4 +- api/client/ps.go | 2 +- api/server/server.go | 95 +++++++++++++++++++ api/types/types.go | 6 +- daemon/list.go | 2 +- .../reference/api/docker_remote_api.md | 18 ++++ .../reference/api/docker_remote_api_v1.19.md | 18 ++-- graph/history.go | 2 +- graph/list.go | 6 +- 10 files changed, 135 insertions(+), 22 deletions(-) diff --git a/api/client/history.go b/api/client/history.go index 31b8535031..b86351ab8f 100644 --- a/api/client/history.go +++ b/api/client/history.go @@ -47,9 +47,9 @@ func (cli *DockerCli) CmdHistory(args ...string) error { } if !*quiet { if *human { - fmt.Fprintf(w, "\t%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(entry.Created, 0)))) + fmt.Fprintf(w, "\t%s ago\t", units.HumanDuration(time.Now().UTC().Sub(entry.Created))) } else { - fmt.Fprintf(w, "\t%s\t", time.Unix(entry.Created, 0).Format(time.RFC3339)) + fmt.Fprintf(w, "\t%s\t", entry.Created.Format(time.RFC3339)) } if *noTrunc { diff --git a/api/client/images.go b/api/client/images.go index e39c473749..7f3db94c2b 100644 --- a/api/client/images.go +++ b/api/client/images.go @@ -109,9 +109,9 @@ func (cli *DockerCli) CmdImages(args ...string) error { if !*quiet { if *showDigests { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", repo, tag, digest, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize))) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", repo, tag, digest, ID, units.HumanDuration(time.Now().UTC().Sub(image.Created)), units.HumanSize(float64(image.VirtualSize))) } else { - fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize))) + fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, ID, units.HumanDuration(time.Now().UTC().Sub(image.Created)), units.HumanSize(float64(image.VirtualSize))) } } else { fmt.Fprintln(w, ID) diff --git a/api/client/ps.go b/api/client/ps.go index 6c40c6867b..0df31b1e1a 100644 --- a/api/client/ps.go +++ b/api/client/ps.go @@ -151,7 +151,7 @@ func (cli *DockerCli) CmdPs(args ...string) error { } fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", ID, image, command, - units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(container.Created), 0))), + units.HumanDuration(time.Now().UTC().Sub(container.Created)), container.Status, api.DisplayablePorts(container.Ports), strings.Join(names, ",")) if *size { diff --git a/api/server/server.go b/api/server/server.go index dd5c2c89d2..7fd4cc0f74 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -353,6 +353,37 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r return err } + // For version >= 1.19 the Created filed of image will change + // from int64 to time.Time. + // This is for legacy data format. + if version.LessThan("1.19") { + type legacyImage struct { + ID string `json:"Id"` + ParentId string + RepoTags []string + RepoDigests []string + Created int64 + Size int + VirtualSize int + Labels map[string]string + } + + legacy := []*legacyImage{} + for _, img := range images { + l := &legacyImage{ + ID: img.ID, + ParentId: img.ParentId, + RepoTags: img.RepoTags, + RepoDigests: img.RepoDigests, + Created: img.Created.Unix(), + Size: img.Size, + VirtualSize: img.VirtualSize, + Labels: img.Labels, + } + legacy = append(legacy, l) + } + return writeJSON(w, http.StatusOK, legacy) + } return writeJSON(w, http.StatusOK, images) } @@ -482,6 +513,34 @@ func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter return err } + // For version >= 1.19 the Created filed of image will change + // from int64 to time.Time. + // This is for legacy data format. + if version.LessThan("1.19") { + type legacyImageHistory struct { + ID string `json:"Id"` + Created int64 + CreatedBy string + Tags []string + Size int64 + Comment string + } + + legacy := []*legacyImageHistory{} + for _, img := range history { + l := &legacyImageHistory{ + ID: img.ID, + Created: img.Created.Unix(), + CreatedBy: img.CreatedBy, + Tags: img.Tags, + Size: img.Size, + Comment: img.Comment, + } + legacy = append(legacy, l) + } + return writeJSON(w, http.StatusOK, legacy) + } + return writeJSON(w, http.StatusOK, history) } @@ -541,6 +600,42 @@ func (s *Server) getContainersJSON(version version.Version, w http.ResponseWrite return err } + // For version >= 1.19 the Created filed of container will change + // from int64 to time.Time. + // This is for legacy data format. + if version.LessThan("1.19") { + type legacyContainer struct { + ID string `json:"Id"` + Names []string `json:",omitempty"` + Image string `json:",omitempty"` + Command string `json:",omitempty"` + Created int64 `json:",omitempty"` + Ports []types.Port `json:",omitempty"` + SizeRw int `json:",omitempty"` + SizeRootFs int `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Status string `json:",omitempty"` + } + + legacyContainers := []*legacyContainer{} + for _, c := range containers { + lc := &legacyContainer{ + ID: c.ID, + Names: c.Names, + Image: c.Image, + Command: c.Command, + Created: c.Created.Unix(), + Ports: c.Ports, + SizeRw: c.SizeRw, + SizeRootFs: c.SizeRootFs, + Labels: c.Labels, + Status: c.Status, + } + legacyContainers = append(legacyContainers, lc) + } + return writeJSON(w, http.StatusOK, legacyContainers) + } + return writeJSON(w, http.StatusOK, containers) } diff --git a/api/types/types.go b/api/types/types.go index 56219f845e..9a5594af06 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -50,7 +50,7 @@ type ContainerChange struct { // GET "/images/{name:.*}/history" type ImageHistory struct { ID string `json:"Id"` - Created int64 + Created time.Time CreatedBy string Tags []string Size int64 @@ -69,7 +69,7 @@ type Image struct { ParentId string RepoTags []string RepoDigests []string - Created int + Created time.Time Size int VirtualSize int Labels map[string]string @@ -105,7 +105,7 @@ type Container struct { Names []string `json:",omitempty"` Image string `json:",omitempty"` Command string `json:",omitempty"` - Created int `json:",omitempty"` + Created time.Time `json:",omitempty"` Ports []Port `json:",omitempty"` SizeRw int `json:",omitempty"` SizeRootFs int `json:",omitempty"` diff --git a/daemon/list.go b/daemon/list.go index 99242988b0..7d02ab6aaf 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -149,7 +149,7 @@ func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, } else { newC.Command = fmt.Sprintf("%s", container.Path) } - newC.Created = int(container.Created.Unix()) + newC.Created = container.Created.UTC() newC.Status = container.State.String() newC.Ports = []types.Port{} diff --git a/docs/sources/reference/api/docker_remote_api.md b/docs/sources/reference/api/docker_remote_api.md index 9ca8edd512..1991ca7dda 100644 --- a/docs/sources/reference/api/docker_remote_api.md +++ b/docs/sources/reference/api/docker_remote_api.md @@ -58,6 +58,24 @@ disconnect This endpoint now accepts a `since` timestamp parameter. +`GET /images/json` + +**New!** +The `Created` field is now formatted as a RFC3339 string instead of a UNIX +timestamp, to be consistent with other parts of the API. + +`GET /containers/json` + +**New!** +The `Created` field is now formatted as a RFC3339 string instead of a UNIX +timestamp, to be consistent with other parts of the API. + +`GET /images/(name)/history` + +**New!** +The `Created` field is now formatted as a RFC3339 string instead of a UNIX +timestamp, to be consistent with other parts of the API. + ## v1.18 ### Full documentation diff --git a/docs/sources/reference/api/docker_remote_api_v1.19.md b/docs/sources/reference/api/docker_remote_api_v1.19.md index 0d2ef93449..c5d83747d8 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.19.md +++ b/docs/sources/reference/api/docker_remote_api_v1.19.md @@ -38,7 +38,7 @@ List containers "Id": "8dfafdbc3a40", "Image": "ubuntu:latest", "Command": "echo 1", - "Created": 1367854155, + "Created": "2015-03-28T08:19:30.820225442Z", "Status": "Exit 0", "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], "SizeRw": 12288, @@ -48,7 +48,7 @@ List containers "Id": "9cd87474be90", "Image": "ubuntu:latest", "Command": "echo 222222", - "Created": 1367854155, + "Created": "2015-01-05T19:42:44.334772611Z", "Status": "Exit 0", "Ports": [], "SizeRw": 12288, @@ -58,7 +58,7 @@ List containers "Id": "3176a2479c92", "Image": "ubuntu:latest", "Command": "echo 3333333333333333", - "Created": 1367854154, + "Created": "2014-11-26T20:35:41.514880809Z", "Status": "Exit 0", "Ports":[], "SizeRw":12288, @@ -68,7 +68,7 @@ List containers "Id": "4cb07b47f9fb", "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", - "Created": 1367854152, + "Created": "2014-11-26T15:35:05.538305907Z", "Status": "Exit 0", "Ports": [], "SizeRw": 12288, @@ -1148,7 +1148,7 @@ Status Codes: "ubuntu:latest" ], "Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c", - "Created": 1365714795, + "Created": "2014-11-26T15:35:05.538305907Z", "Size": 131506275, "VirtualSize": 131506275 }, @@ -1159,7 +1159,7 @@ Status Codes: ], "ParentId": "27cf784147099545", "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Created": 1364102658, + "Created": "2014-11-21T10:18:46.654545839Z", "Size": 24653, "VirtualSize": 180116135 } @@ -1176,7 +1176,7 @@ Status Codes: [ { - "Created": 1420064636, + "Created": "2015-03-23T15:58:07.610802612Z", "Id": "4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125", "ParentId": "ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2", "RepoDigests": [ @@ -1392,12 +1392,12 @@ Return the history of the image `name` [ { "Id": "b750fe79269d", - "Created": 1364102658, + "Created": "2014-12-15T19:52:48.480875289Z", "CreatedBy": "/bin/bash" }, { "Id": "27cf78414709", - "Created": 1364068391, + "Created": "2013-06-13T21:03:50.821769Z", "CreatedBy": "" } ] diff --git a/graph/history.go b/graph/history.go index 56e759a8eb..e673ba564c 100644 --- a/graph/history.go +++ b/graph/history.go @@ -30,7 +30,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) { err = foundImage.WalkHistory(func(img *image.Image) error { history = append(history, &types.ImageHistory{ ID: img.ID, - Created: img.Created.Unix(), + Created: img.Created.UTC(), CreatedBy: strings.Join(img.ContainerConfig.Cmd.Slice(), " "), Tags: lookupMap[img.ID], Size: img.Size, diff --git a/graph/list.go b/graph/list.go index f95508e950..547f069914 100644 --- a/graph/list.go +++ b/graph/list.go @@ -28,7 +28,7 @@ type ByCreated []*types.Image func (r ByCreated) Len() int { return len(r) } func (r ByCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } -func (r ByCreated) Less(i, j int) bool { return r[i].Created < r[j].Created } +func (r ByCreated) Less(i, j int) bool { return r[i].Created.Before(r[j].Created) } func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) { var ( @@ -101,7 +101,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) { newImage := new(types.Image) newImage.ParentId = image.Parent newImage.ID = image.ID - newImage.Created = int(image.Created.Unix()) + newImage.Created = image.Created.UTC() newImage.Size = int(image.Size) newImage.VirtualSize = int(image.GetParentsSize(0) + image.Size) newImage.Labels = image.ContainerConfig.Labels @@ -138,7 +138,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) { newImage.RepoTags = []string{":"} newImage.RepoDigests = []string{"@"} newImage.ID = image.ID - newImage.Created = int(image.Created.Unix()) + newImage.Created = image.Created.UTC() newImage.Size = int(image.Size) newImage.VirtualSize = int(image.GetParentsSize(0) + image.Size) newImage.Labels = image.ContainerConfig.Labels