Add CreatedAt filed to volume. Display when volume is inspected.
Closes #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 <mtesselh@gmail.com> 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 <mtesselh@gmail.com>
This commit is contained in:
parent
fa54c94b9d
commit
a46f757c40
9 changed files with 68 additions and 3 deletions
|
@ -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: |
|
||||
|
@ -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"
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
dockererrors "github.com/docker/docker/api/errors"
|
||||
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
@ -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)))
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/volume"
|
||||
|
@ -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
|
||||
|
@ -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{}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
|
|
@ -8,8 +8,11 @@ package local
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@ package local
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type optsConfig struct{}
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package testutils
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/volume"
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
|
@ -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{}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue