Skip to content

Commit

Permalink
Add CreatedAt filed to volume. Display when volume is inspected.
Browse files Browse the repository at this point in the history
Closes moby#32663 by adding CreatedAt field when volume is created.
Displaying CreatedAt value when volume is inspected
Adding tests to verfiy the new field is correctly populated

Signed-off-by: Marianna <[email protected]>

Moving CreatedAt tests from the CLI

Moving the tests added for the newly added CreatedAt field for Volume, from CLI to API tests

Signed-off-by: Marianna <[email protected]>
  • Loading branch information
mtesselH committed May 26, 2017
1 parent fa54c94 commit a46f757
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 3 deletions.
5 changes: 5 additions & 0 deletions api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,10 @@ definitions:
type: "string"
description: "Mount path of the volume on the host."
x-nullable: false
CreatedAt:
type: "string"
format: "dateTime"
description: "Time volume was created."
Status:
type: "object"
description: |
Expand Down Expand Up @@ -1100,6 +1104,7 @@ definitions:
com.example.some-label: "some-value"
com.example.some-other-label: "some-other-value"
Scope: "local"
CreatedAt: "2016-06-07T20:31:11.853781916Z"

Network:
type: "object"
Expand Down
3 changes: 3 additions & 0 deletions api/types/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ package types
// swagger:model Volume
type Volume struct {

// Time volume was created.
CreatedAt string `json:"CreatedAt,omitempty"`

// Name of the volume driver used by the volume.
// Required: true
Driver string `json:"Driver"`
Expand Down
7 changes: 5 additions & 2 deletions daemon/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/Sirupsen/logrus"
dockererrors "github.com/docker/docker/api/errors"
Expand All @@ -27,9 +28,11 @@ type mounts []container.Mount

// volumeToAPIType converts a volume.Volume to the type used by the Engine API
func volumeToAPIType(v volume.Volume) *types.Volume {
createdAt, _ := v.CreatedAt()
tv := &types.Volume{
Name: v.Name(),
Driver: v.DriverName(),
Name: v.Name(),
Driver: v.DriverName(),
CreatedAt: createdAt.Format(time.RFC3339),
}
if v, ok := v.(volume.DetailedVolume); ok {
tv.Labels = v.Labels()
Expand Down
13 changes: 13 additions & 0 deletions integration-cli/docker_api_volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package main

import (
"encoding/json"
"fmt"
"net/http"
"path/filepath"
"strings"
"time"

"github.com/docker/docker/api/types"
volumetypes "github.com/docker/docker/api/types/volume"
Expand Down Expand Up @@ -69,6 +72,8 @@ func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) {
config := volumetypes.VolumesCreateBody{
Name: "test",
}
// sampling current time minus a minute so to now have false positive in case of delays
now := time.Now().Truncate(time.Minute)
status, b, err := request.SockRequest("POST", "/volumes/create", config, daemonHost())
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b)))
Expand All @@ -87,4 +92,12 @@ func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) {
c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(b)))
c.Assert(json.Unmarshal(b, &vol), checker.IsNil)
c.Assert(vol.Name, checker.Equals, config.Name)

// comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive
testCreatedAt, err := time.Parse(time.RFC3339, strings.TrimSpace(vol.CreatedAt))
c.Assert(err, check.IsNil)
testCreatedAt = testCreatedAt.Truncate(time.Minute)
if !testCreatedAt.Equal(now) {
c.Assert(fmt.Errorf("Time Volume is CreatedAt not equal to current time"), check.NotNil)
}
}
9 changes: 8 additions & 1 deletion volume/drivers/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"path/filepath"
"strings"
"time"

"github.com/Sirupsen/logrus"
"github.com/docker/docker/volume"
Expand Down Expand Up @@ -82,6 +83,7 @@ func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) {
name: v.Name,
driverName: a.Name(),
eMount: v.Mountpoint,
createdAt: v.CreatedAt,
status: v.Status,
baseHostPath: a.baseHostPath,
}, nil
Expand Down Expand Up @@ -124,13 +126,15 @@ type volumeAdapter struct {
name string
baseHostPath string
driverName string
eMount string // ephemeral host volume path
eMount string // ephemeral host volume path
createdAt time.Time // time the directory was created
status map[string]interface{}
}

type proxyVolume struct {
Name string
Mountpoint string
CreatedAt time.Time
Status map[string]interface{}
}

Expand Down Expand Up @@ -168,6 +172,9 @@ func (a *volumeAdapter) Unmount(id string) error {
return err
}

func (a *volumeAdapter) CreatedAt() (time.Time, error) {
return a.createdAt, nil
}
func (a *volumeAdapter) Status() map[string]interface{} {
out := make(map[string]interface{}, len(a.status))
for k, v := range a.status {
Expand Down
12 changes: 12 additions & 0 deletions volume/local/local_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ package local
import (
"fmt"
"net"
"os"
"path/filepath"
"strings"
"syscall"
"time"

"github.com/pkg/errors"

Expand Down Expand Up @@ -85,3 +88,12 @@ func (v *localVolume) mount() error {
err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, mountOpts)
return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts)
}

func (v *localVolume) CreatedAt() (time.Time, error) {
fileInfo, err := os.Stat(v.path)
if err != nil {
return time.Time{}, err
}
sec, nsec := fileInfo.Sys().(*syscall.Stat_t).Ctim.Unix()
return time.Unix(sec, nsec), nil
}
12 changes: 12 additions & 0 deletions volume/local/local_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ package local

import (
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
"time"
)

type optsConfig struct{}
Expand All @@ -32,3 +35,12 @@ func setOpts(v *localVolume, opts map[string]string) error {
func (v *localVolume) mount() error {
return nil
}

func (v *localVolume) CreatedAt() (time.Time, error) {
fileInfo, err := os.Stat(v.path)
if err != nil {
return time.Time{}, err
}
ft := fileInfo.Sys().(*syscall.Win32FileAttributeData).CreationTime
return time.Unix(0, ft.Nanoseconds()), nil
}
7 changes: 7 additions & 0 deletions volume/testutils/testutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package testutils

import (
"fmt"
"time"

"github.com/docker/docker/volume"
)
Expand All @@ -27,6 +28,9 @@ func (NoopVolume) Unmount(_ string) error { return nil }
// Status proivdes low-level details about the volume
func (NoopVolume) Status() map[string]interface{} { return nil }

// CreatedAt provides the time the volume (directory) was created at
func (NoopVolume) CreatedAt() (time.Time, error) { return time.Now(), nil }

// FakeVolume is a fake volume with a random name
type FakeVolume struct {
name string
Expand Down Expand Up @@ -56,6 +60,9 @@ func (FakeVolume) Unmount(_ string) error { return nil }
// Status proivdes low-level details about the volume
func (FakeVolume) Status() map[string]interface{} { return nil }

// CreatedAt provides the time the volume (directory) was created at
func (FakeVolume) CreatedAt() (time.Time, error) { return time.Now(), nil }

// FakeDriver is a driver that generates fake volumes
type FakeDriver struct {
name string
Expand Down
3 changes: 3 additions & 0 deletions volume/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"strings"
"syscall"
"time"

mounttypes "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/pkg/idtools"
Expand Down Expand Up @@ -64,6 +65,8 @@ type Volume interface {
Mount(id string) (string, error)
// Unmount unmounts the volume when it is no longer in use.
Unmount(id string) error
// CreatedAt returns Volume Creation time
CreatedAt() (time.Time, error)
// Status returns low-level status information about a volume
Status() map[string]interface{}
}
Expand Down

0 comments on commit a46f757

Please sign in to comment.