In 1.6.2 we were decoding inspect API response into interface{}.
time.Time fields were JSON encoded as RFC3339Nano in the response
and when decoded into interface{} they were just strings so the inspect
template treated them as just strings.
From 1.7 we are decoding into types.ContainerJSON and when the template
gets executed it now gets a time.Time and it's formatted as
2015-07-22 05:02:38.091530369 +0000 UTC.
This patch brings back the old behavior by typing time.Time fields
as string so they gets formatted as they were encoded in JSON -- RCF3339Nano
Signed-off-by: Antonio Murdaca <runcom@linux.com>
| ... | ... |
@@ -86,7 +86,7 @@ type ImageInspect struct {
|
| 86 | 86 |
Id string |
| 87 | 87 |
Parent string |
| 88 | 88 |
Comment string |
| 89 |
- Created time.Time |
|
| 89 |
+ Created string |
|
| 90 | 90 |
Container string |
| 91 | 91 |
ContainerConfig *runconfig.Config |
| 92 | 92 |
DockerVersion string |
| ... | ... |
@@ -215,14 +215,14 @@ type ContainerState struct {
|
| 215 | 215 |
Pid int |
| 216 | 216 |
ExitCode int |
| 217 | 217 |
Error string |
| 218 |
- StartedAt time.Time |
|
| 219 |
- FinishedAt time.Time |
|
| 218 |
+ StartedAt string |
|
| 219 |
+ FinishedAt string |
|
| 220 | 220 |
} |
| 221 | 221 |
|
| 222 | 222 |
// GET "/containers/{name:.*}/json"
|
| 223 | 223 |
type ContainerJSONBase struct {
|
| 224 | 224 |
Id string |
| 225 |
- Created time.Time |
|
| 225 |
+ Created string |
|
| 226 | 226 |
Path string |
| 227 | 227 |
Args []string |
| 228 | 228 |
State *ContainerState |
| ... | ... |
@@ -2,6 +2,7 @@ package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "time" |
|
| 5 | 6 |
|
| 6 | 7 |
"github.com/docker/docker/api/types" |
| 7 | 8 |
) |
| ... | ... |
@@ -91,13 +92,13 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON |
| 91 | 91 |
Pid: container.State.Pid, |
| 92 | 92 |
ExitCode: container.State.ExitCode, |
| 93 | 93 |
Error: container.State.Error, |
| 94 |
- StartedAt: container.State.StartedAt, |
|
| 95 |
- FinishedAt: container.State.FinishedAt, |
|
| 94 |
+ StartedAt: container.State.StartedAt.Format(time.RFC3339Nano), |
|
| 95 |
+ FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano), |
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 | 98 |
contJSONBase := &types.ContainerJSONBase{
|
| 99 | 99 |
Id: container.ID, |
| 100 |
- Created: container.Created, |
|
| 100 |
+ Created: container.Created.Format(time.RFC3339Nano), |
|
| 101 | 101 |
Path: container.Path, |
| 102 | 102 |
Args: container.Args, |
| 103 | 103 |
State: containerState, |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io" |
| 6 | 6 |
"runtime" |
| 7 |
+ "time" |
|
| 7 | 8 |
|
| 8 | 9 |
"github.com/Sirupsen/logrus" |
| 9 | 10 |
"github.com/docker/docker/api/types" |
| ... | ... |
@@ -34,7 +35,7 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
| 34 | 34 |
Id: image.ID, |
| 35 | 35 |
Parent: image.Parent, |
| 36 | 36 |
Comment: image.Comment, |
| 37 |
- Created: image.Created, |
|
| 37 |
+ Created: image.Created.Format(time.RFC3339Nano), |
|
| 38 | 38 |
Container: image.Container, |
| 39 | 39 |
ContainerConfig: &image.ContainerConfig, |
| 40 | 40 |
DockerVersion: image.DockerVersion, |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"os/exec" |
| 6 | 6 |
"strconv" |
| 7 | 7 |
"strings" |
| 8 |
+ "time" |
|
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/docker/api/types" |
| 10 | 11 |
"github.com/go-check/check" |
| ... | ... |
@@ -260,3 +261,28 @@ func (s *DockerSuite) TestInspectBindMountPoint(c *check.C) {
|
| 260 | 260 |
c.Fatalf("Expected rw to be false")
|
| 261 | 261 |
} |
| 262 | 262 |
} |
| 263 |
+ |
|
| 264 |
+// #14947 |
|
| 265 |
+func (s *DockerSuite) TestInspectTimesAsRFC3339Nano(c *check.C) {
|
|
| 266 |
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "true") |
|
| 267 |
+ id := strings.TrimSpace(out) |
|
| 268 |
+ startedAt, err := inspectField(id, "State.StartedAt") |
|
| 269 |
+ c.Assert(err, check.IsNil) |
|
| 270 |
+ finishedAt, err := inspectField(id, "State.FinishedAt") |
|
| 271 |
+ c.Assert(err, check.IsNil) |
|
| 272 |
+ created, err := inspectField(id, "Created") |
|
| 273 |
+ c.Assert(err, check.IsNil) |
|
| 274 |
+ |
|
| 275 |
+ _, err = time.Parse(time.RFC3339Nano, startedAt) |
|
| 276 |
+ c.Assert(err, check.IsNil) |
|
| 277 |
+ _, err = time.Parse(time.RFC3339Nano, finishedAt) |
|
| 278 |
+ c.Assert(err, check.IsNil) |
|
| 279 |
+ _, err = time.Parse(time.RFC3339Nano, created) |
|
| 280 |
+ c.Assert(err, check.IsNil) |
|
| 281 |
+ |
|
| 282 |
+ created, err = inspectField("busybox", "Created")
|
|
| 283 |
+ c.Assert(err, check.IsNil) |
|
| 284 |
+ |
|
| 285 |
+ _, err = time.Parse(time.RFC3339Nano, created) |
|
| 286 |
+ c.Assert(err, check.IsNil) |
|
| 287 |
+} |