Initial commit
This commit is contained in:
74
vendor/github.com/hyperhq/hypercli/volume/store/errors.go
generated
vendored
Normal file
74
vendor/github.com/hyperhq/hypercli/volume/store/errors.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// errVolumeInUse is a typed error returned when trying to remove a volume that is currently in use by a container
|
||||
errVolumeInUse = errors.New("volume is in use")
|
||||
// errNoSuchVolume is a typed error returned if the requested volume doesn't exist in the volume store
|
||||
errNoSuchVolume = errors.New("no such volume")
|
||||
// errInvalidName is a typed error returned when creating a volume with a name that is not valid on the platform
|
||||
errInvalidName = errors.New("volume name is not valid on this platform")
|
||||
// errNameConflict is a typed error returned on create when a volume exists with the given name, but for a different driver
|
||||
errNameConflict = errors.New("conflict: volume name must be unique")
|
||||
)
|
||||
|
||||
// OpErr is the error type returned by functions in the store package. It describes
|
||||
// the operation, volume name, and error.
|
||||
type OpErr struct {
|
||||
// Err is the error that occurred during the operation.
|
||||
Err error
|
||||
// Op is the operation which caused the error, such as "create", or "list".
|
||||
Op string
|
||||
// Name is the name of the resource being requested for this op, typically the volume name or the driver name.
|
||||
Name string
|
||||
// Refs is the list of references associated with the resource.
|
||||
Refs []string
|
||||
}
|
||||
|
||||
// Error satisfies the built-in error interface type.
|
||||
func (e *OpErr) Error() string {
|
||||
if e == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
s := e.Op
|
||||
if e.Name != "" {
|
||||
s = s + " " + e.Name
|
||||
}
|
||||
|
||||
s = s + ": " + e.Err.Error()
|
||||
if len(e.Refs) > 0 {
|
||||
s = s + " - " + "[" + strings.Join(e.Refs, ", ") + "]"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsInUse returns a boolean indicating whether the error indicates that a
|
||||
// volume is in use
|
||||
func IsInUse(err error) bool {
|
||||
return isErr(err, errVolumeInUse)
|
||||
}
|
||||
|
||||
// IsNotExist returns a boolean indicating whether the error indicates that the volume does not exist
|
||||
func IsNotExist(err error) bool {
|
||||
return isErr(err, errNoSuchVolume)
|
||||
}
|
||||
|
||||
// IsNameConflict returns a boolean indicating whether the error indicates that a
|
||||
// volume name is already taken
|
||||
func IsNameConflict(err error) bool {
|
||||
return isErr(err, errNameConflict)
|
||||
}
|
||||
|
||||
func isErr(err error, expected error) bool {
|
||||
switch pe := err.(type) {
|
||||
case nil:
|
||||
return false
|
||||
case *OpErr:
|
||||
err = pe.Err
|
||||
}
|
||||
return err == expected
|
||||
}
|
||||
366
vendor/github.com/hyperhq/hypercli/volume/store/store.go
generated
vendored
Normal file
366
vendor/github.com/hyperhq/hypercli/volume/store/store.go
generated
vendored
Normal file
@@ -0,0 +1,366 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/locker"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
)
|
||||
|
||||
// New initializes a VolumeStore to keep
|
||||
// reference counting of volumes in the system.
|
||||
func New() *VolumeStore {
|
||||
return &VolumeStore{
|
||||
locks: &locker.Locker{},
|
||||
names: make(map[string]volume.Volume),
|
||||
refs: make(map[string][]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
|
||||
s.globalLock.Lock()
|
||||
v, exists := s.names[name]
|
||||
s.globalLock.Unlock()
|
||||
return v, exists
|
||||
}
|
||||
|
||||
func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
|
||||
s.globalLock.Lock()
|
||||
s.names[v.Name()] = v
|
||||
if len(ref) > 0 {
|
||||
s.refs[v.Name()] = append(s.refs[v.Name()], ref)
|
||||
}
|
||||
s.globalLock.Unlock()
|
||||
}
|
||||
|
||||
func (s *VolumeStore) purge(name string) {
|
||||
s.globalLock.Lock()
|
||||
delete(s.names, name)
|
||||
delete(s.refs, name)
|
||||
s.globalLock.Unlock()
|
||||
}
|
||||
|
||||
// VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
|
||||
type VolumeStore struct {
|
||||
locks *locker.Locker
|
||||
globalLock sync.Mutex
|
||||
// names stores the volume name -> driver name relationship.
|
||||
// This is used for making lookups faster so we don't have to probe all drivers
|
||||
names map[string]volume.Volume
|
||||
// refs stores the volume name and the list of things referencing it
|
||||
refs map[string][]string
|
||||
}
|
||||
|
||||
// List proxies to all registered volume drivers to get the full list of volumes
|
||||
// If a driver returns a volume that has name which conflicts with a another volume from a different driver,
|
||||
// the first volume is chosen and the conflicting volume is dropped.
|
||||
func (s *VolumeStore) List() ([]volume.Volume, []string, error) {
|
||||
vols, warnings, err := s.list()
|
||||
if err != nil {
|
||||
return nil, nil, &OpErr{Err: err, Op: "list"}
|
||||
}
|
||||
var out []volume.Volume
|
||||
|
||||
for _, v := range vols {
|
||||
name := normaliseVolumeName(v.Name())
|
||||
|
||||
s.locks.Lock(name)
|
||||
storedV, exists := s.getNamed(name)
|
||||
if !exists {
|
||||
s.setNamed(v, "")
|
||||
}
|
||||
if exists && storedV.DriverName() != v.DriverName() {
|
||||
logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName())
|
||||
s.locks.Unlock(v.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, v)
|
||||
s.locks.Unlock(v.Name())
|
||||
}
|
||||
return out, warnings, nil
|
||||
}
|
||||
|
||||
// list goes through each volume driver and asks for its list of volumes.
|
||||
func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
|
||||
drivers, err := volumedrivers.GetAllDrivers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var (
|
||||
ls []volume.Volume
|
||||
warnings []string
|
||||
)
|
||||
|
||||
type vols struct {
|
||||
vols []volume.Volume
|
||||
err error
|
||||
driverName string
|
||||
}
|
||||
chVols := make(chan vols, len(drivers))
|
||||
|
||||
for _, vd := range drivers {
|
||||
go func(d volume.Driver) {
|
||||
vs, err := d.List()
|
||||
if err != nil {
|
||||
chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}}
|
||||
return
|
||||
}
|
||||
chVols <- vols{vols: vs}
|
||||
}(vd)
|
||||
}
|
||||
|
||||
badDrivers := make(map[string]struct{})
|
||||
for i := 0; i < len(drivers); i++ {
|
||||
vs := <-chVols
|
||||
|
||||
if vs.err != nil {
|
||||
warnings = append(warnings, vs.err.Error())
|
||||
badDrivers[vs.driverName] = struct{}{}
|
||||
logrus.Warn(vs.err)
|
||||
}
|
||||
ls = append(ls, vs.vols...)
|
||||
}
|
||||
|
||||
if len(badDrivers) > 0 {
|
||||
for _, v := range s.names {
|
||||
if _, exists := badDrivers[v.DriverName()]; exists {
|
||||
ls = append(ls, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ls, warnings, nil
|
||||
}
|
||||
|
||||
// CreateWithRef creates a volume with the given name and driver and stores the ref
|
||||
// This is just like Create() except we store the reference while holding the lock.
|
||||
// This ensures there's no race between creating a volume and then storing a reference.
|
||||
func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[string]string) (volume.Volume, error) {
|
||||
name = normaliseVolumeName(name)
|
||||
s.locks.Lock(name)
|
||||
defer s.locks.Unlock(name)
|
||||
|
||||
v, err := s.create(name, driverName, opts)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
||||
}
|
||||
|
||||
s.setNamed(v, ref)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Create creates a volume with the given name and driver.
|
||||
func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) {
|
||||
name = normaliseVolumeName(name)
|
||||
s.locks.Lock(name)
|
||||
defer s.locks.Unlock(name)
|
||||
|
||||
v, err := s.create(name, driverName, opts)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
||||
}
|
||||
s.setNamed(v, "")
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// create asks the given driver to create a volume with the name/opts.
|
||||
// If a volume with the name is already known, it will ask the stored driver for the volume.
|
||||
// If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned.
|
||||
// It is expected that callers of this function hold any neccessary locks.
|
||||
func (s *VolumeStore) create(name, driverName string, opts map[string]string) (volume.Volume, error) {
|
||||
// Validate the name in a platform-specific manner
|
||||
valid, err := volume.IsVolumeNameValid(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !valid {
|
||||
return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
|
||||
}
|
||||
|
||||
if v, exists := s.getNamed(name); exists {
|
||||
if v.DriverName() != driverName && driverName != "" && driverName != volume.DefaultDriverName {
|
||||
return nil, errNameConflict
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
logrus.Debugf("Registering new volume reference: driver %s, name %s", driverName, name)
|
||||
vd, err := volumedrivers.GetDriver(driverName)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Op: "create", Name: name, Err: err}
|
||||
}
|
||||
|
||||
if v, err := vd.Get(name); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return vd.Create(name, opts)
|
||||
}
|
||||
|
||||
// GetWithRef gets a volume with the given name from the passed in driver and stores the ref
|
||||
// This is just like Get(), but we store the reference while holding the lock.
|
||||
// This makes sure there are no races between checking for the existance of a volume and adding a reference for it
|
||||
func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) {
|
||||
name = normaliseVolumeName(name)
|
||||
s.locks.Lock(name)
|
||||
defer s.locks.Unlock(name)
|
||||
|
||||
vd, err := volumedrivers.GetDriver(driverName)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "get"}
|
||||
}
|
||||
|
||||
v, err := vd.Get(name)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "get"}
|
||||
}
|
||||
|
||||
s.setNamed(v, ref)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Get looks if a volume with the given name exists and returns it if so
|
||||
func (s *VolumeStore) Get(name string) (volume.Volume, error) {
|
||||
name = normaliseVolumeName(name)
|
||||
s.locks.Lock(name)
|
||||
defer s.locks.Unlock(name)
|
||||
|
||||
v, err := s.getVolume(name)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "get"}
|
||||
}
|
||||
s.setNamed(v, "")
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// get requests the volume, if the driver info is stored it just access that driver,
|
||||
// if the driver is unknown it probes all drivers until it finds the first volume with that name.
|
||||
// it is expected that callers of this function hold any neccessary locks
|
||||
func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
|
||||
logrus.Debugf("Getting volume reference for name: %s", name)
|
||||
if v, exists := s.names[name]; exists {
|
||||
vd, err := volumedrivers.GetDriver(v.DriverName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vd.Get(name)
|
||||
}
|
||||
|
||||
logrus.Debugf("Probing all drivers for volume with name: %s", name)
|
||||
drivers, err := volumedrivers.GetAllDrivers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, d := range drivers {
|
||||
v, err := d.Get(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
return nil, errNoSuchVolume
|
||||
}
|
||||
|
||||
// Remove removes the requested volume. A volume is not removed if it has any refs
|
||||
func (s *VolumeStore) Remove(v volume.Volume) error {
|
||||
name := normaliseVolumeName(v.Name())
|
||||
s.locks.Lock(name)
|
||||
defer s.locks.Unlock(name)
|
||||
|
||||
if refs, exists := s.refs[name]; exists && len(refs) > 0 {
|
||||
return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs}
|
||||
}
|
||||
|
||||
vd, err := volumedrivers.GetDriver(v.DriverName())
|
||||
if err != nil {
|
||||
return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
|
||||
}
|
||||
|
||||
logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
|
||||
if err := vd.Remove(v); err != nil {
|
||||
return &OpErr{Err: err, Name: name, Op: "remove"}
|
||||
}
|
||||
|
||||
s.purge(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dereference removes the specified reference to the volume
|
||||
func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
|
||||
s.locks.Lock(v.Name())
|
||||
defer s.locks.Unlock(v.Name())
|
||||
|
||||
s.globalLock.Lock()
|
||||
defer s.globalLock.Unlock()
|
||||
refs, exists := s.refs[v.Name()]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
for i, r := range refs {
|
||||
if r == ref {
|
||||
s.refs[v.Name()] = append(s.refs[v.Name()][:i], s.refs[v.Name()][i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refs gets the current list of refs for the given volume
|
||||
func (s *VolumeStore) Refs(v volume.Volume) []string {
|
||||
s.locks.Lock(v.Name())
|
||||
defer s.locks.Unlock(v.Name())
|
||||
|
||||
s.globalLock.Lock()
|
||||
defer s.globalLock.Unlock()
|
||||
refs, exists := s.refs[v.Name()]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
refsOut := make([]string, len(refs))
|
||||
copy(refsOut, refs)
|
||||
return refsOut
|
||||
}
|
||||
|
||||
// FilterByDriver returns the available volumes filtered by driver name
|
||||
func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
|
||||
vd, err := volumedrivers.GetDriver(name)
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "list"}
|
||||
}
|
||||
ls, err := vd.List()
|
||||
if err != nil {
|
||||
return nil, &OpErr{Err: err, Name: name, Op: "list"}
|
||||
}
|
||||
return ls, nil
|
||||
}
|
||||
|
||||
// FilterByUsed returns the available volumes filtered by if they are in use or not.
|
||||
// `used=true` returns only volumes that are being used, while `used=false` returns
|
||||
// only volumes that are not being used.
|
||||
func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
|
||||
return s.filter(vols, func(v volume.Volume) bool {
|
||||
s.locks.Lock(v.Name())
|
||||
l := len(s.refs[v.Name()])
|
||||
s.locks.Unlock(v.Name())
|
||||
if (used && l > 0) || (!used && l == 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// filterFunc defines a function to allow filter volumes in the store
|
||||
type filterFunc func(vol volume.Volume) bool
|
||||
|
||||
// filter returns the available volumes filtered by a filterFunc function
|
||||
func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume {
|
||||
var ls []volume.Volume
|
||||
for _, v := range vols {
|
||||
if f(v) {
|
||||
ls = append(ls, v)
|
||||
}
|
||||
}
|
||||
return ls
|
||||
}
|
||||
159
vendor/github.com/hyperhq/hypercli/volume/store/store_test.go
generated
vendored
Normal file
159
vendor/github.com/hyperhq/hypercli/volume/store/store_test.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
vt "github.com/docker/docker/volume/testutils"
|
||||
)
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||
defer volumedrivers.Unregister("fake")
|
||||
s := New()
|
||||
v, err := s.Create("fake1", "fake", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.Name() != "fake1" {
|
||||
t.Fatalf("Expected fake1 volume, got %v", v)
|
||||
}
|
||||
if l, _, _ := s.List(); len(l) != 1 {
|
||||
t.Fatalf("Expected 1 volume in the store, got %v: %v", len(l), l)
|
||||
}
|
||||
|
||||
if _, err := s.Create("none", "none", nil); err == nil {
|
||||
t.Fatalf("Expected unknown driver error, got nil")
|
||||
}
|
||||
|
||||
_, err = s.Create("fakeerror", "fake", map[string]string{"error": "create error"})
|
||||
expected := &OpErr{Op: "create", Name: "fakeerror", Err: errors.New("create error")}
|
||||
if err != nil && err.Error() != expected.Error() {
|
||||
t.Fatalf("Expected create fakeError: create error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||
defer volumedrivers.Unregister("fake")
|
||||
defer volumedrivers.Unregister("noop")
|
||||
s := New()
|
||||
|
||||
// doing string compare here since this error comes directly from the driver
|
||||
expected := "no such volume"
|
||||
if err := s.Remove(vt.NoopVolume{}); err == nil || !strings.Contains(err.Error(), expected) {
|
||||
t.Fatalf("Expected error %q, got %v", expected, err)
|
||||
}
|
||||
|
||||
v, err := s.CreateWithRef("fake1", "fake", "fake", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Remove(v); !IsInUse(err) {
|
||||
t.Fatalf("Expected ErrVolumeInUse error, got %v", err)
|
||||
}
|
||||
s.Dereference(v, "fake")
|
||||
if err := s.Remove(v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if l, _, _ := s.List(); len(l) != 0 {
|
||||
t.Fatalf("Expected 0 volumes in the store, got %v, %v", len(l), l)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake2"), "fake2")
|
||||
defer volumedrivers.Unregister("fake")
|
||||
defer volumedrivers.Unregister("fake2")
|
||||
|
||||
s := New()
|
||||
if _, err := s.Create("test", "fake", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.Create("test2", "fake2", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ls, _, err := s.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ls) != 2 {
|
||||
t.Fatalf("expected 2 volumes, got: %d", len(ls))
|
||||
}
|
||||
|
||||
// and again with a new store
|
||||
s = New()
|
||||
ls, _, err = s.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ls) != 2 {
|
||||
t.Fatalf("expected 2 volumes, got: %d", len(ls))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByDriver(t *testing.T) {
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||
defer volumedrivers.Unregister("fake")
|
||||
defer volumedrivers.Unregister("noop")
|
||||
s := New()
|
||||
|
||||
if _, err := s.Create("fake1", "fake", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.Create("fake2", "fake", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.Create("fake3", "noop", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, _ := s.FilterByDriver("fake"); len(l) != 2 {
|
||||
t.Fatalf("Expected 2 volumes, got %v, %v", len(l), l)
|
||||
}
|
||||
|
||||
if l, _ := s.FilterByDriver("noop"); len(l) != 1 {
|
||||
t.Fatalf("Expected 1 volume, got %v, %v", len(l), l)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterByUsed(t *testing.T) {
|
||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||
|
||||
s := New()
|
||||
if _, err := s.CreateWithRef("fake1", "fake", "volReference", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.Create("fake2", "fake", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vols, _, err := s.List()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dangling := s.FilterByUsed(vols, false)
|
||||
if len(dangling) != 1 {
|
||||
t.Fatalf("expected 1 danging volume, got %v", len(dangling))
|
||||
}
|
||||
if dangling[0].Name() != "fake2" {
|
||||
t.Fatalf("expected danging volume fake2, got %s", dangling[0].Name())
|
||||
}
|
||||
|
||||
used := s.FilterByUsed(vols, true)
|
||||
if len(used) != 1 {
|
||||
t.Fatalf("expected 1 used volume, got %v", len(used))
|
||||
}
|
||||
if used[0].Name() != "fake1" {
|
||||
t.Fatalf("expected used volume fake1, got %s", used[0].Name())
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/hyperhq/hypercli/volume/store/store_unix.go
generated
vendored
Normal file
9
vendor/github.com/hyperhq/hypercli/volume/store/store_unix.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// +build linux freebsd
|
||||
|
||||
package store
|
||||
|
||||
// normaliseVolumeName is a platform specific function to normalise the name
|
||||
// of a volume. This is a no-op on Unix-like platforms
|
||||
func normaliseVolumeName(name string) string {
|
||||
return name
|
||||
}
|
||||
12
vendor/github.com/hyperhq/hypercli/volume/store/store_windows.go
generated
vendored
Normal file
12
vendor/github.com/hyperhq/hypercli/volume/store/store_windows.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package store
|
||||
|
||||
import "strings"
|
||||
|
||||
// normaliseVolumeName is a platform specific function to normalise the name
|
||||
// of a volume. On Windows, as NTFS is case insensitive, under
|
||||
// c:\ProgramData\Docker\Volumes\, the folders John and john would be synonymous.
|
||||
// Hence we can't allow the volume "John" and "john" to be created as separate
|
||||
// volumes.
|
||||
func normaliseVolumeName(name string) string {
|
||||
return strings.ToLower(name)
|
||||
}
|
||||
Reference in New Issue
Block a user