diff --git a/daemon/mgr/container_storage.go b/daemon/mgr/container_storage.go index bc7929f0ca..ebf0ab6d1f 100644 --- a/daemon/mgr/container_storage.go +++ b/daemon/mgr/container_storage.go @@ -173,22 +173,29 @@ func (mgr *ContainerManager) getMountPointFromBinds(ctx context.Context, c *Cont // volume bind. name := mp.Source if _, exist := volumeSet[name]; !exist { - mp.Name = name - mp.Source, mp.Driver, err = mgr.attachVolume(ctx, name, c) + _, mp.Driver, err = mgr.attachVolume(ctx, name, c) if err != nil { logrus.Errorf("failed to bind volume(%s): %v", name, err) return errors.Wrap(err, "failed to bind volume") } - volumeSet[mp.Name] = struct{}{} + volumeSet[name] = struct{}{} } - if mp.Replace != "" { - mp.Source, err = mgr.VolumeMgr.Path(ctx, name) - if err != nil { - return err - } + volume, err := mgr.VolumeMgr.Get(ctx, name) + if err != nil || volume == nil { + logrus.Errorf("failed to get volume: (%s), err: (%v)", name, err) + return errors.Wrapf(err, "failed to get volume: (%s)", name) + } + mp.Driver = volume.Driver() + mp.Name = name + mp.Source, err = mgr.VolumeMgr.Path(ctx, name) + if err != nil { + return err + } + + if mp.Replace != "" { switch mp.Replace { case "dr": mp.Source = path.Join(mp.Source, mp.Destination) diff --git a/daemon/mgr/volume.go b/daemon/mgr/volume.go index b241a84cef..2f3fd433a9 100644 --- a/daemon/mgr/volume.go +++ b/daemon/mgr/volume.go @@ -7,6 +7,7 @@ import ( "github.com/alibaba/pouch/daemon/events" "github.com/alibaba/pouch/pkg/errtypes" "github.com/alibaba/pouch/storage/volume" + volerr "github.com/alibaba/pouch/storage/volume/error" "github.com/alibaba/pouch/storage/volume/types" "github.com/pkg/errors" @@ -65,12 +66,11 @@ func (vm *VolumeManager) Create(ctx context.Context, name, driver string, option driver = types.DefaultBackend } - id := types.VolumeID{ - Name: name, - Driver: driver, - Options: map[string]string{}, - Selectors: map[string]string{}, - Labels: map[string]string{}, + id := types.VolumeContext{ + Name: name, + Driver: driver, + Options: map[string]string{}, + Labels: map[string]string{}, } if labels != nil { @@ -83,6 +83,9 @@ func (vm *VolumeManager) Create(ctx context.Context, name, driver string, option v, err := vm.core.CreateVolume(id) if err != nil { + if e, ok := err.(*volerr.CoreError); ok && e.IsVolumeExisted() { + return v, nil + } return nil, err } @@ -93,7 +96,7 @@ func (vm *VolumeManager) Create(ctx context.Context, name, driver string, option // Get returns the information of volume that specified name/id. func (vm *VolumeManager) Get(ctx context.Context, name string) (*types.Volume, error) { - id := types.VolumeID{ + id := types.VolumeContext{ Name: name, } vol, err := vm.core.GetVolume(id) @@ -123,7 +126,7 @@ func (vm *VolumeManager) Remove(ctx context.Context, name string) error { return errors.Wrapf(errtypes.ErrVolumeInUse, "failed to remove volume(%s)", name) } - id := types.VolumeID{ + id := types.VolumeContext{ Name: name, } if err := vm.core.RemoveVolume(id); err != nil { @@ -140,7 +143,7 @@ func (vm *VolumeManager) Remove(ctx context.Context, name string) error { // Path returns the mount path of volume. func (vm *VolumeManager) Path(ctx context.Context, name string) (string, error) { - id := types.VolumeID{ + id := types.VolumeContext{ Name: name, } return vm.core.VolumePath(id) @@ -148,7 +151,7 @@ func (vm *VolumeManager) Path(ctx context.Context, name string) (string, error) // Attach is used to bind a volume to container. func (vm *VolumeManager) Attach(ctx context.Context, name string, options map[string]string) (*types.Volume, error) { - id := types.VolumeID{ + id := types.VolumeContext{ Name: name, } @@ -176,7 +179,7 @@ func (vm *VolumeManager) Attach(ctx context.Context, name string, options map[st // Detach is used to unbind a volume from container. func (vm *VolumeManager) Detach(ctx context.Context, name string, options map[string]string) (*types.Volume, error) { - id := types.VolumeID{ + id := types.VolumeContext{ Name: name, } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 3305886e9b..9378b928f3 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -361,3 +361,18 @@ func StringDefault(s string, val string) string { } return val } + +// ToStringMap changes the map[string]interface{} to map[string]string, +// If the interface is not string, it will be ignore. +func ToStringMap(in map[string]interface{}) map[string]string { + if in == nil { + return nil + } + out := make(map[string]string, 0) + for k, v := range in { + if s, ok := v.(string); ok { + out[k] = s + } + } + return out +} diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 6cb7c7a521..78d3499d9e 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -576,3 +576,32 @@ func TestMergeMap(t *testing.T) { } } } + +func TestToStringMap(t *testing.T) { + type Expect struct { + isNil bool + key string + value string + } + tests := []struct { + m1 map[string]interface{} + expect Expect + }{ + {nil, Expect{true, "", ""}}, + {map[string]interface{}{"a": "a", "b": "b"}, Expect{false, "a", "a"}}, + {map[string]interface{}{"a": "a", "b": "b"}, Expect{false, "b", "b"}}, + {map[string]interface{}{"a": map[string]string{"aa": "aa"}, "b": "b"}, Expect{false, "a", ""}}, + {map[string]interface{}{"a": map[string]string{"aa": "aa"}, "b": "b"}, Expect{false, "b", "b"}}, + } + + for _, test := range tests { + m2 := ToStringMap(test.m1) + if (test.expect.isNil && m2 != nil) || (!test.expect.isNil && m2 == nil) { + t.Fatalf("ToStringMap(%v) expected: %v, but got %v", test.m1, test.expect, m2) + } + if m2[test.expect.key] != test.expect.value { + t.Fatalf("ToStringMap(%v) expected: %v, but got %v", test.m1, test.expect.value, m2[test.expect.key]) + } + + } +} diff --git a/storage/quota/grpquota.go b/storage/quota/grpquota.go index 7cb8f6a161..ea2df9ad93 100644 --- a/storage/quota/grpquota.go +++ b/storage/quota/grpquota.go @@ -233,14 +233,6 @@ func (quota *GrpQuotaDriver) SetDiskQuota(dir string, size string, quotaID uint3 return errors.Errorf("failed to find mountpoint, dir: (%s)", dir) } - id, err := quota.SetSubtree(dir, quotaID) - if err != nil { - return errors.Wrapf(err, "failed to set subtree, dir: (%s), quota id: (%d)", dir, quotaID) - } - if id == 0 { - return errors.Errorf("failed to find quota id to set subtree") - } - // transfer limit from kbyte to byte limit, err := bytefmt.ToKilobytes(size) if err != nil { @@ -251,6 +243,14 @@ func (quota *GrpQuotaDriver) SetDiskQuota(dir string, size string, quotaID uint3 return err } + id, err := quota.SetSubtree(dir, quotaID) + if err != nil { + return errors.Wrapf(err, "failed to set subtree, dir: (%s), quota id: (%d)", dir, quotaID) + } + if id == 0 { + return errors.Errorf("failed to find quota id to set subtree") + } + return quota.setQuota(id, limit, mountPoint) } diff --git a/storage/quota/prjquota.go b/storage/quota/prjquota.go index c69be0fc96..8c6f9c2440 100644 --- a/storage/quota/prjquota.go +++ b/storage/quota/prjquota.go @@ -136,14 +136,6 @@ func (quota *PrjQuotaDriver) SetDiskQuota(dir string, size string, quotaID uint3 return errors.Errorf("failed to find mountpoint, dir: (%s)", dir) } - id, err := quota.SetSubtree(dir, quotaID) - if err != nil { - return errors.Wrapf(err, "failed to set subtree, dir: (%s), quota id: (%d)", dir, quotaID) - } - if id == 0 { - return errors.Errorf("failed to find quota id to set subtree") - } - // transfer limit from kbyte to byte limit, err := bytefmt.ToKilobytes(size) if err != nil { @@ -154,6 +146,14 @@ func (quota *PrjQuotaDriver) SetDiskQuota(dir string, size string, quotaID uint3 return errors.Wrapf(err, "failed to check device limit, dir: (%s), limit: (%d)kb", dir, limit) } + id, err := quota.SetSubtree(dir, quotaID) + if err != nil { + return errors.Wrapf(err, "failed to set subtree, dir: (%s), quota id: (%d)", dir, quotaID) + } + if id == 0 { + return errors.Errorf("failed to find quota id to set subtree") + } + return quota.setQuota(id, limit, mountPoint) } diff --git a/storage/quota/quota.go b/storage/quota/quota.go index 3019147484..00af0378da 100644 --- a/storage/quota/quota.go +++ b/storage/quota/quota.go @@ -127,7 +127,7 @@ func SetSubtree(dir string, qid uint32) (uint32, error) { // SetDiskQuota is used to set quota for directory. func SetDiskQuota(dir string, size string, quotaID uint32) error { - logrus.Infof("set disk quota, dir: (%s), size: (%s), quotaID: (%d)", dir, size, quotaID) + logrus.Infof("set disk quota, dir(%s), size(%s), quotaID(%d)", dir, size, quotaID) return GQuotaDriver.SetDiskQuota(dir, size, quotaID) } @@ -156,6 +156,21 @@ func GetNextQuotaID() (uint32, error) { return GQuotaDriver.GetNextQuotaID() } +// GetQuotaID returns the quota id of directory, +// if no quota id, it will alloc the next available quota id. +func GetQuotaID(dir string) (uint32, error) { + id := GetQuotaIDInFileAttr(dir) + if id > 0 { + return id, nil + } + id, err := GetNextQuotaID() + if err != nil { + return 0, errors.Wrapf(err, "failed to get file(%s) quota id", dir) + } + + return id, nil +} + //GetDefaultQuota returns the default quota size. func GetDefaultQuota(quotas map[string]string) string { if quotas == nil { @@ -181,22 +196,24 @@ func GetDefaultQuota(quotas map[string]string) string { func SetRootfsDiskQuota(basefs, size string, quotaID uint32) (uint32, error) { overlayMountInfo, err := getOverlayMountInfo(basefs) if err != nil { - return 0, fmt.Errorf("failed to get overlay mount info: %v", err) + return 0, errors.Wrapf(err, "failed to get overlay(%s) mount info", basefs) } for _, dir := range []string{overlayMountInfo.Upper, overlayMountInfo.Work} { _, err = StartQuotaDriver(dir) if err != nil { - return 0, fmt.Errorf("failed to start quota driver: %v", err) + return 0, errors.Wrapf(err, "failed to start dir(%s) quota driver", dir) } - quotaID, err = SetSubtree(dir, quotaID) - if err != nil { - return 0, fmt.Errorf("failed to set subtree: %v", err) + if quotaID == 0 { + quotaID, err = GetQuotaID(dir) + if err != nil { + return 0, errors.Wrapf(err, "failed to get dir(%s) quota id", dir) + } } if err := SetDiskQuota(dir, size, quotaID); err != nil { - return 0, fmt.Errorf("failed to set disk quota: %v", err) + return 0, errors.Wrapf(err, "failed to set dir(%s) disk quota", dir) } } @@ -222,7 +239,7 @@ func SetQuotaForDir(src string, quotaID uint32) error { func getOverlayMountInfo(basefs string) (*OverlayMount, error) { output, err := ioutil.ReadFile(procMountFile) if err != nil { - logrus.Warnf("failed to ReadFile %s: %v", procMountFile, err) + logrus.Warnf("failed to read file(%s), err(%v)", procMountFile, err) return nil, err } @@ -323,7 +340,7 @@ func loadQuotaIDs(repquotaOpt string) (map[uint32]struct{}, uint32, error) { } } } - logrus.Infof("Load repquota ids: %d, list: %v", len(quotaIDs), quotaIDs) + logrus.Infof("Load repquota ids(%d), list(%v)", len(quotaIDs), quotaIDs) return quotaIDs, minID, nil } @@ -334,15 +351,15 @@ func getMountpoint(dir string) (string, error) { output, err := ioutil.ReadFile(procMountFile) if err != nil { - logrus.Warnf("failed to read file: (%s), err: (%v)", procMountFile, err) - return "", errors.Wrapf(err, "failed to read file: (%s)", procMountFile) + logrus.Warnf("failed to read file(%s), err(%v)", procMountFile, err) + return "", errors.Wrapf(err, "failed to read file(%s)", procMountFile) } devID, err := system.GetDevID(dir) if err != nil { - return "", errors.Wrapf(err, "failed to get device id for dir: (%s)", dir) + return "", errors.Wrapf(err, "failed to get device id for dir(%s)", dir) } - logrus.Debugf("get directory(%s) device id: (%d)", dir, devID) + logrus.Debugf("get dir(%s) device id(%d)", dir, devID) // /dev/sdb1 /home/pouch ext4 rw,relatime,prjquota,data=ordered 0 0 for _, line := range strings.Split(string(output), "\n") { @@ -372,10 +389,10 @@ func getMountpoint(dir string) (string, error) { } if mountPoint == "" { - return "", errors.Errorf("failed to get mount point of directory: (%s)", dir) + return "", errors.Errorf("failed to get mount point of dir(%s)", dir) } - logrus.Debugf("get the directory: (%s) mountpoint: (%s)", dir, mountPoint) + logrus.Debugf("get the dir(%s)'s mountpoint(%s)", dir, mountPoint) return mountPoint, nil } @@ -391,20 +408,20 @@ func setDevLimit(dir string, devID uint64) (uint64, error) { mp, err := getMountpoint(dir) if err != nil { - return 0, errors.Wrapf(err, "failed to set device limit, dir: (%s), devID: (%d)", dir, devID) + return 0, errors.Wrapf(err, "failed to set device limit, dir(%s), devID(%d)", dir, devID) } newDevID, _ := system.GetDevID(mp) if newDevID != devID { - return 0, errors.Errorf("failed to set device limit, no such device id: (%d), checked id: (%d)", + return 0, errors.Errorf("failed to set device limit, no such device id(%d), checked id(%d)", devID, newDevID) } // get storage upper limit of the device which the dir is on. var stfs syscall.Statfs_t if err := syscall.Statfs(mp, &stfs); err != nil { - logrus.Errorf("failed to get path: (%s) limit, err: (%v)", mp, err) - return 0, errors.Wrapf(err, "failed to get path: (%s) limit", mp) + logrus.Errorf("failed to get path(%s) limit, err(%v)", mp, err) + return 0, errors.Wrapf(err, "failed to get path(%s) limit", mp) } limit = stfs.Blocks * uint64(stfs.Bsize) @@ -412,7 +429,7 @@ func setDevLimit(dir string, devID uint64) (uint64, error) { devLimits[devID] = limit lock.Unlock() - logrus.Debugf("SetDevLimit: dir: (%s), mountpoint: (%s), limit: (%v) B", dir, mp, limit) + logrus.Debugf("SetDevLimit: dir(%s), mountpoint(%s), limit(%v) B", dir, mp, limit) return limit, nil } @@ -420,7 +437,7 @@ func setDevLimit(dir string, devID uint64) (uint64, error) { func checkDevLimit(dir string, size uint64) error { devID, err := system.GetDevID(dir) if err != nil { - return errors.Wrapf(err, "failed to get device id, dir: (%s)", dir) + return errors.Wrapf(err, "failed to get device id, dir(%s)", dir) } lock.Lock() @@ -429,7 +446,7 @@ func checkDevLimit(dir string, size uint64) error { if !exist { // if has not recorded, just add (dir, device, limit) to driver. if limit, err = setDevLimit(dir, devID); err != nil { - return errors.Wrapf(err, "failed to set device limit, dir: (%s), devID: (%d)", dir, devID) + return errors.Wrapf(err, "failed to set device limit, dir(%s), devID: (%d)", dir, devID) } } diff --git a/storage/volume/README.md b/storage/volume/README.md index 4b4542ff49..6b4cf4f5bd 100644 --- a/storage/volume/README.md +++ b/storage/volume/README.md @@ -52,26 +52,26 @@ Core provides these functions is as following: ```go // GetVolume return a volume's info with specified name, If not errors. -func (c *Core) GetVolume(id types.VolumeID) (*types.Volume, error) +func (c *Core) GetVolume(id types.VolumeContext) (*types.Volume, error) // CreateVolume use to create a volume, if failed, will return error info. -func (c *Core) CreateVolume(id types.VolumeID) error +func (c *Core) CreateVolume(id types.VolumeContext) error // ListVolumeName return the name of all volumes only. // Param 'labels' use to filter the volume's names, only return those you want. func (c *Core) ListVolumeName(labels map[string]string) ([]string, error) // RemoveVolume remove volume from storage and meta information, if not success return error. -func (c *Core) RemoveVolume(id types.VolumeID) error +func (c *Core) RemoveVolume(id types.VolumeContext) error // VolumePath return the path of volume on node host. -func (c *Core) VolumePath(id types.VolumeID) (string, error) +func (c *Core) VolumePath(id types.VolumeContext) (string, error) // AttachVolume to enable a volume on local host. -func (c *Core) AttachVolume(id types.VolumeID, extra map[string]string) (*types.Volume, error) +func (c *Core) AttachVolume(id types.VolumeContext, extra map[string]string) (*types.Volume, error) // DetachVolume to disable a volume on local host. -func (c *Core) DetachVolume(id types.VolumeID, extra map[string]string) (*types.Volume, error) +func (c *Core) DetachVolume(id types.VolumeContext, extra map[string]string) (*types.Volume, error) ``` ### Driver diff --git a/storage/volume/core.go b/storage/volume/core.go index ede2db9cea..2d8418daad 100644 --- a/storage/volume/core.go +++ b/storage/volume/core.go @@ -81,7 +81,7 @@ func NewCore(cfg Config) (*Core, error) { } // getVolume return a volume's info with specified name, If not errors. -func (c *Core) getVolume(id types.VolumeID) (*types.Volume, error) { +func (c *Core) getVolume(id types.VolumeContext) (*types.Volume, error) { ctx := driver.Contexts() // first, try to get volume from local store. @@ -105,7 +105,7 @@ func (c *Core) getVolume(id types.VolumeID) (*types.Volume, error) { return nil, volerr.ErrVolumeNotFound } - v.Status.MountPoint = curV.Status.MountPoint + return curV, nil } return v, nil @@ -146,7 +146,7 @@ func (c *Core) getVolume(id types.VolumeID) (*types.Volume, error) { } // getVolumeDriver return the backend driver and volume with specified volume's id. -func (c *Core) getVolumeDriver(id types.VolumeID) (*types.Volume, driver.Driver, error) { +func (c *Core) getVolumeDriver(id types.VolumeContext) (*types.Volume, driver.Driver, error) { v, err := c.getVolume(id) if err != nil { return nil, nil, err @@ -159,19 +159,19 @@ func (c *Core) getVolumeDriver(id types.VolumeID) (*types.Volume, driver.Driver, } // existVolume return 'true' if volume be found and not errors. -func (c *Core) existVolume(id types.VolumeID) (bool, error) { - _, err := c.getVolume(id) +func (c *Core) existVolume(id types.VolumeContext) (*types.Volume, bool, error) { + v, err := c.getVolume(id) if err != nil { if ec, ok := err.(volerr.CoreError); ok && ec.IsVolumeNotFound() { - return false, nil + return nil, false, nil } - return false, err + return nil, false, err } - return true, nil + return v, true, nil } // GetVolume return a volume's info with specified name, If not errors. -func (c *Core) GetVolume(id types.VolumeID) (*types.Volume, error) { +func (c *Core) GetVolume(id types.VolumeContext) (*types.Volume, error) { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) @@ -179,15 +179,15 @@ func (c *Core) GetVolume(id types.VolumeID) (*types.Volume, error) { } // CreateVolume use to create a volume, if failed, will return error info. -func (c *Core) CreateVolume(id types.VolumeID) (*types.Volume, error) { +func (c *Core) CreateVolume(id types.VolumeContext) (*types.Volume, error) { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) - exist, err := c.existVolume(id) + volume, exist, err := c.existVolume(id) if err != nil { return nil, err } else if exist { - return nil, volerr.ErrVolumeExisted + return volume, volerr.ErrVolumeExisted } dv, err := driver.Get(id.Driver) @@ -195,7 +195,7 @@ func (c *Core) CreateVolume(id types.VolumeID) (*types.Volume, error) { return nil, err } - volume, err := dv.Create(driver.Contexts(), id) + volume, err = dv.Create(driver.Contexts(), id) if err != nil { return nil, err } @@ -323,7 +323,7 @@ func (c *Core) ListVolumeName(labels map[string]string) ([]string, error) { } // RemoveVolume remove volume from storage and meta information, if not success return error. -func (c *Core) RemoveVolume(id types.VolumeID) error { +func (c *Core) RemoveVolume(id types.VolumeContext) error { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) @@ -341,7 +341,7 @@ func (c *Core) RemoveVolume(id types.VolumeID) error { } // VolumePath return the path of volume on node host. -func (c *Core) VolumePath(id types.VolumeID) (string, error) { +func (c *Core) VolumePath(id types.VolumeContext) (string, error) { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) @@ -354,7 +354,7 @@ func (c *Core) VolumePath(id types.VolumeID) (string, error) { } // AttachVolume to enable a volume on local host. -func (c *Core) AttachVolume(id types.VolumeID, extra map[string]string) (*types.Volume, error) { +func (c *Core) AttachVolume(id types.VolumeContext, extra map[string]string) (*types.Volume, error) { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) @@ -385,7 +385,7 @@ func (c *Core) AttachVolume(id types.VolumeID, extra map[string]string) (*types. } // DetachVolume to disable a volume on local host. -func (c *Core) DetachVolume(id types.VolumeID, extra map[string]string) (*types.Volume, error) { +func (c *Core) DetachVolume(id types.VolumeContext, extra map[string]string) (*types.Volume, error) { c.lock.Lock(id.Name) defer c.lock.Unlock(id.Name) diff --git a/storage/volume/core_test.go b/storage/volume/core_test.go index 5e18665e26..93a441ecbc 100644 --- a/storage/volume/core_test.go +++ b/storage/volume/core_test.go @@ -39,7 +39,7 @@ func TestCreateVolume(t *testing.T) { driver.Register(driver.NewFakeDriver(volumeDriverName)) defer driver.Unregister(volumeDriverName) - v, err := core.CreateVolume(types.VolumeID{Name: "test1", Driver: volumeDriverName}) + v, err := core.CreateVolume(types.VolumeContext{Name: "test1", Driver: volumeDriverName}) if err != nil { t.Fatalf("create volume error: %v", err) } @@ -51,7 +51,7 @@ func TestCreateVolume(t *testing.T) { t.Fatalf("expect volume driver is %s, but got %s", volumeDriverName, v.Driver()) } - _, err = core.CreateVolume(types.VolumeID{Name: "none", Driver: "none"}) + _, err = core.CreateVolume(types.VolumeContext{Name: "none", Driver: "none"}) if err == nil { t.Fatal("expect get driver not found error, but err is nil") } @@ -74,7 +74,7 @@ func TestGetVolume(t *testing.T) { // add one volume and get driverName1 := "fake1" volumeName1 := "test1" - vID1 := types.VolumeID{Name: volumeName1, Driver: driverName1} + vID1 := types.VolumeContext{Name: volumeName1, Driver: driverName1} driver.Register(driver.NewFakeDriver(driverName1)) defer driver.Unregister(driverName1) @@ -107,7 +107,7 @@ func TestGetVolume(t *testing.T) { // add two volumes and get driverName2 := "fake1" volumeName2 := "test1" - vID2 := types.VolumeID{Name: volumeName2, Driver: driverName2} + vID2 := types.VolumeContext{Name: volumeName2, Driver: driverName2} driver.Register(driver.NewFakeDriver(driverName2)) defer driver.Unregister(driverName2) @@ -158,7 +158,7 @@ func TestListVolumes(t *testing.T) { volmap := map[string]*types.Volume{} for i = 0; i < 6; i++ { volName := strconv.FormatInt(i, 10) - volid := types.VolumeID{Name: volName, Driver: driverName} + volid := types.VolumeContext{Name: volName, Driver: driverName} v, err := core.CreateVolume(volid) if err != nil { t.Fatalf("create volume error: %v", err) @@ -195,7 +195,7 @@ func TestListVolumesWithLabels(t *testing.T) { var i int64 for i = 0; i < 6; i++ { volName := strconv.FormatInt(i, 10) - volid := types.VolumeID{Name: volName, Driver: driverName, Labels: map[string]string{fmt.Sprintf("label-%v", i): fmt.Sprintf("value-%v", i)}} + volid := types.VolumeContext{Name: volName, Driver: driverName, Labels: map[string]string{fmt.Sprintf("label-%v", i): fmt.Sprintf("value-%v", i)}} _, err := core.CreateVolume(volid) if err != nil { t.Fatalf("create volume error: %v", err) @@ -204,7 +204,7 @@ func TestListVolumesWithLabels(t *testing.T) { testLabels := map[string]string{"test-label": "test-value"} - testVolume, err := core.CreateVolume(types.VolumeID{Name: "test-volume", Driver: driverName, Labels: testLabels}) + testVolume, err := core.CreateVolume(types.VolumeContext{Name: "test-volume", Driver: driverName, Labels: testLabels}) if err != nil { t.Fatalf("create volume error: %v", err) } @@ -237,7 +237,7 @@ func TestListVolumeName(t *testing.T) { volmap := map[string]*types.Volume{} for i = 0; i < 6; i++ { volName := strconv.FormatInt(i, 10) - volid := types.VolumeID{Name: volName, Driver: driverName} + volid := types.VolumeContext{Name: volName, Driver: driverName} v, err := core.CreateVolume(volid) if err != nil { t.Fatalf("create volume fail: %v", err) @@ -275,7 +275,7 @@ func TestListVolumeName(t *testing.T) { func TestRemoveVolume(t *testing.T) { volName1 := "vol2" driverName1 := "fake_driver12" - volid1 := types.VolumeID{Name: volName1, Driver: driverName1} + volid1 := types.VolumeContext{Name: volName1, Driver: driverName1} dir, err := ioutil.TempDir("", "TestGetVolume") if err != nil { @@ -316,7 +316,7 @@ func TestRemoveVolume(t *testing.T) { func TestVolumePath(t *testing.T) { volName1 := "vol3" driverName1 := "fake_dirver" - volid1 := types.VolumeID{Name: volName1, Driver: driverName1} + volid1 := types.VolumeContext{Name: volName1, Driver: driverName1} expectPath := path.Join("/fake/", volName1) //keep consist with the path API in fake_driver.go dir, err := ioutil.TempDir("", "TestVolumePath") @@ -370,7 +370,7 @@ func TestAttachVolume(t *testing.T) { driverName1 := "fake1" volumeName1 := "test1" - vID1 := types.VolumeID{Name: volumeName1, Driver: driverName1} + vID1 := types.VolumeContext{Name: volumeName1, Driver: driverName1} driver.Register(driver.NewFakeDriver(volumeDriverName)) defer driver.Unregister(volumeDriverName) @@ -388,7 +388,7 @@ func TestAttachVolume(t *testing.T) { } } - core.CreateVolume(types.VolumeID{Name: "test1", Driver: volumeDriverName}) + core.CreateVolume(types.VolumeContext{Name: "test1", Driver: volumeDriverName}) v1, err1 := core.AttachVolume(vID1, extra) if err1 != nil { @@ -406,7 +406,7 @@ func TestAttachVolume(t *testing.T) { func TestDetachVolume(t *testing.T) { volName1 := "vol2" driverName1 := "fake_driver12" - volid1 := types.VolumeID{Name: volName1, Driver: driverName1} + volid1 := types.VolumeContext{Name: volName1, Driver: driverName1} extra1 := map[string]string{} dir, err := ioutil.TempDir("", "TestDetachVolume") @@ -441,7 +441,7 @@ func TestDetachVolume(t *testing.T) { } //detach a null volume - _, err = core.DetachVolume(types.VolumeID{Name: "none", Driver: "none"}, nil) + _, err = core.DetachVolume(types.VolumeContext{Name: "none", Driver: "none"}, nil) if err == nil { t.Fatal("expect get driver not found error, but err is nil") } diff --git a/storage/volume/driver/driver_interface.go b/storage/volume/driver/driver_interface.go index 5eb5f90cf8..3534f2c1ff 100644 --- a/storage/volume/driver/driver_interface.go +++ b/storage/volume/driver/driver_interface.go @@ -13,7 +13,7 @@ type Driver interface { StoreMode(Context) VolumeStoreMode // Create a volume. - Create(Context, types.VolumeID) (*types.Volume, error) + Create(Context, types.VolumeContext) (*types.Volume, error) // Remove a volume. Remove(Context, *types.Volume) error diff --git a/storage/volume/driver/fake_driver.go b/storage/volume/driver/fake_driver.go index 9d70e023a1..1012806524 100644 --- a/storage/volume/driver/fake_driver.go +++ b/storage/volume/driver/fake_driver.go @@ -29,11 +29,11 @@ func (f *FakeDriver) StoreMode(ctx Context) VolumeStoreMode { } // Create a fake volume -func (f *FakeDriver) Create(ctx Context, id types.VolumeID) (*types.Volume, error) { +func (f *FakeDriver) Create(ctx Context, id types.VolumeContext) (*types.Volume, error) { // generate the mountPath mountPath := path.Join("/fake", id.Name) - return types.NewVolumeFromID(mountPath, "", id), nil + return types.NewVolumeFromContext(mountPath, "", id), nil } // Remove a fake volume diff --git a/storage/volume/driver/remote.go b/storage/volume/driver/remote.go index 8c4c969e1b..1f426875dd 100644 --- a/storage/volume/driver/remote.go +++ b/storage/volume/driver/remote.go @@ -1,6 +1,7 @@ package driver import ( + "github.com/alibaba/pouch/pkg/utils" "github.com/alibaba/pouch/plugins" "github.com/alibaba/pouch/storage/volume/types" ) @@ -33,7 +34,7 @@ func (r *remoteDriverWrapper) StoreMode(ctx Context) VolumeStoreMode { } // Create a remote volume. -func (r *remoteDriverWrapper) Create(ctx Context, id types.VolumeID) (*types.Volume, error) { +func (r *remoteDriverWrapper) Create(ctx Context, id types.VolumeContext) (*types.Volume, error) { ctx.Log.Debugf("driver wrapper [%s] creates volume: %s", r.Name(ctx), id.Name) ctx.Log.Debugf("driver wrapper gets options: %v", id.Options) @@ -47,7 +48,7 @@ func (r *remoteDriverWrapper) Create(ctx Context, id types.VolumeID) (*types.Vol mountPath = "" } - return types.NewVolumeFromID(mountPath, "", id), nil + return types.NewVolumeFromContext(mountPath, "", id), nil } // Remove a remote volume. @@ -66,9 +67,9 @@ func (r *remoteDriverWrapper) Get(ctx Context, name string) (*types.Volume, erro return nil, err } - id := types.NewVolumeID(name, r.Name(ctx)) + id := types.NewVolumeContext(name, r.Name(ctx), utils.ToStringMap(rv.Status), nil) - return types.NewVolumeFromID(rv.Mountpoint, "", id), nil + return types.NewVolumeFromContext(rv.Mountpoint, "", id), nil } // List all volumes from remote driver. @@ -83,8 +84,8 @@ func (r *remoteDriverWrapper) List(ctx Context) ([]*types.Volume, error) { var vList []*types.Volume for _, rv := range rvList { - id := types.NewVolumeID(rv.Name, r.Name(ctx)) - volume := types.NewVolumeFromID(rv.Mountpoint, "", id) + id := types.NewVolumeContext(rv.Name, r.Name(ctx), utils.ToStringMap(rv.Status), nil) + volume := types.NewVolumeFromContext(rv.Mountpoint, "", id) vList = append(vList, volume) } diff --git a/storage/volume/examples/demo/demo.go b/storage/volume/examples/demo/demo.go deleted file mode 100644 index 80581dea00..0000000000 --- a/storage/volume/examples/demo/demo.go +++ /dev/null @@ -1,46 +0,0 @@ -package demo - -import ( - "path" - - "github.com/alibaba/pouch/storage/volume/driver" - "github.com/alibaba/pouch/storage/volume/types" -) - -func init() { - if err := driver.Register(&Demo{}); err != nil { - panic(err) - } -} - -// Demo represents demo volume driver. -type Demo struct { -} - -// Name returns volume driver's name. -func (d *Demo) Name(ctx driver.Context) string { - return "demo" -} - -// StoreMode returns demo driver's store mode. -func (d *Demo) StoreMode(ctx driver.Context) driver.VolumeStoreMode { - return driver.RemoteStore -} - -// Create a demo volume. -func (d *Demo) Create(ctx driver.Context, ID types.VolumeID) (*types.Volume, error) { - ctx.Log.Infof("Demo create volume: %s", ID) - return nil, nil -} - -// Remove a demo volume. -func (d *Demo) Remove(ctx driver.Context, v *types.Volume) error { - ctx.Log.Infof("Demo Remove volume: %s", v.Name) - return nil -} - -// Path returns demo volume path. -func (d *Demo) Path(ctx driver.Context, v *types.Volume) (string, error) { - ctx.Log.Infof("Demo volume path: %s", v.Name) - return path.Join("/mnt", d.Name(ctx), v.Name), nil -} diff --git a/storage/volume/modules/local/local.go b/storage/volume/modules/local/local.go index 73a48bc363..fd373bcbaf 100644 --- a/storage/volume/modules/local/local.go +++ b/storage/volume/modules/local/local.go @@ -40,7 +40,7 @@ func (p *Local) StoreMode(ctx driver.Context) driver.VolumeStoreMode { } // Create a local volume. -func (p *Local) Create(ctx driver.Context, id types.VolumeID) (*types.Volume, error) { +func (p *Local) Create(ctx driver.Context, id types.VolumeContext) (*types.Volume, error) { ctx.Log.Debugf("Local create volume: %s", id.Name) dataPath := defaultDataPath @@ -76,7 +76,7 @@ func (p *Local) Create(ctx driver.Context, id types.VolumeID) (*types.Volume, er return nil, fmt.Errorf("mount path is not a dir %s", mountPath) } - return types.NewVolumeFromID(mountPath, size, id), nil + return types.NewVolumeFromContext(mountPath, size, id), nil } // Remove a local volume. diff --git a/storage/volume/modules/tmpfs/tmpfs.go b/storage/volume/modules/tmpfs/tmpfs.go index eecbece1b9..5887dbd891 100644 --- a/storage/volume/modules/tmpfs/tmpfs.go +++ b/storage/volume/modules/tmpfs/tmpfs.go @@ -41,13 +41,13 @@ func (p *Tmpfs) StoreMode(ctx driver.Context) driver.VolumeStoreMode { } // Create a tmpfs volume. -func (p *Tmpfs) Create(ctx driver.Context, id types.VolumeID) (*types.Volume, error) { +func (p *Tmpfs) Create(ctx driver.Context, id types.VolumeContext) (*types.Volume, error) { ctx.Log.Debugf("Tmpfs create volume: %s", id.Name) // parse the mount path mountPath := path.Join(dataDir, id.Name) - return types.NewVolumeFromID(mountPath, "", id), nil + return types.NewVolumeFromContext(mountPath, "", id), nil } // Remove a tmpfs volume. diff --git a/storage/volume/types/meta/meta.go b/storage/volume/types/meta/meta.go index 2378e2a713..b2802faf5a 100644 --- a/storage/volume/types/meta/meta.go +++ b/storage/volume/types/meta/meta.go @@ -26,15 +26,6 @@ type ObjectMetaAccessor interface { GetObjectMeta() Object } -// GetListMeta returns ListMeta instance. -func (meta *ListMeta) GetListMeta() List { return meta } - -// GetResourceVersion returns ListMeta's resource version. -func (meta *ListMeta) GetResourceVersion() int64 { return meta.ResourceVersion } - -// SetResourceVersion is used to set ListMeta's resource version. -func (meta *ListMeta) SetResourceVersion(version int64) { meta.ResourceVersion = version } - // GetUID returns meta's uid. func (meta *ObjectMeta) GetUID() string { return meta.UID } diff --git a/storage/volume/types/meta/types.go b/storage/volume/types/meta/types.go index 30bf04fb54..9d4761abc4 100644 --- a/storage/volume/types/meta/types.go +++ b/storage/volume/types/meta/types.go @@ -7,15 +7,6 @@ import ( "k8s.io/apimachinery/pkg/labels" ) -// ListMeta represents list meta. -type ListMeta struct { - // An opaque value that represents the version of this resource. May be used for optimistic - // concurrency, change detection, and the watch operation on a resource or set of resources. - // Clients must treat these values as opaque and values may only be valid for a particular - // resource or set of resources. Only servers will generate resource versions. - ResourceVersion int64 `json:"ResourceVersion,omitempty"` -} - // ObjectPhase is a int type, specific generation of an object state. type ObjectPhase string diff --git a/storage/volume/types/selector.go b/storage/volume/types/selector.go deleted file mode 100644 index d5860b9510..0000000000 --- a/storage/volume/types/selector.go +++ /dev/null @@ -1,45 +0,0 @@ -package types - -import ( - log "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" -) - -// Selector defines SelectorRequirement slice type. -type Selector []SelectorRequirement - -// SelectorRequirement is a selector that contains values, a key, and an operator -// that relates the key and values. -type SelectorRequirement struct { - // The label key that the selector applies to. - Key string `json:"key"` - // Represents a key's relationship to a set of values. - // Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - Operator selection.Operator `json:"operator"` - // An array of string values. If the operator is In or NotIn, - // the values array must be non-empty. If the operator is Exists or DoesNotExist, - // the values array must be empty. If the operator is Gt or Lt, the values - // array must have a single element. - Values []string `json:"values,omitempty"` -} - -// AsSelector returns selector. -func (n *Selector) AsSelector() labels.Selector { - requirements := n.AsRequirement() - return labels.NewSelector().Add(requirements...) -} - -// AsRequirement returns requirement. -func (n *Selector) AsRequirement() []labels.Requirement { - var requirements []labels.Requirement - for _, sel := range *n { - requirement, err := labels.NewRequirement(sel.Key, sel.Operator, sel.Values) - if err != nil { - log.Infof("selector sel: %v as requirement error: %v", sel, err) - continue - } - requirements = append(requirements, *requirement) - } - return requirements -} diff --git a/storage/volume/types/volume.go b/storage/volume/types/volume.go index 9b20819c5f..8da4dbe1cd 100644 --- a/storage/volume/types/volume.go +++ b/storage/volume/types/volume.go @@ -83,11 +83,10 @@ type VolumeConfig struct { // VolumeSpec represents volume spec. type VolumeSpec struct { - ClusterID string `json:"clusterid"` - Selector Selector `json:"selector"` - Operable bool `json:"operable"` - Backend string `json:"backend,omitempty"` - MountMode string `json:"mountMode,omitempty"` + ClusterID string `json:"clusterid"` + Operable bool `json:"operable"` + Backend string `json:"backend,omitempty"` + MountMode string `json:"mountMode,omitempty"` *VolumeConfig `json:"config,inline"` Extra map[string]string `json:"extra"` } @@ -104,12 +103,6 @@ type VolumeStatus struct { Message string `json:"message"` } -// VolumeList represents volume list. -type VolumeList struct { - meta.ListMeta `json:",inline,omitempty"` - Items []Volume `json:"Items,omitempty"` -} - // Volume defined volume struct. type Volume struct { meta.ObjectMeta `json:",inline"` @@ -147,9 +140,9 @@ func (v *Volume) Driver() string { return v.Spec.Backend } -// VolumeID return volume's identity. -func (v *Volume) VolumeID() VolumeID { - return NewVolumeID(v.Name, v.Driver()) +// VolumeContext return volume's context. +func (v *Volume) VolumeContext() VolumeContext { + return NewVolumeContext(v.Name, v.Driver(), v.Spec.Extra, v.Labels) } // Label returns volume's label. @@ -164,7 +157,14 @@ func (v *Volume) SetLabel(label, value string) { // Size returns volume's size(MB). func (v *Volume) Size() string { - return v.Spec.Size + if v.Spec.Size != "" { + return v.Spec.Size + } + + if s, ok := v.Spec.Extra["Size"]; ok { + return s + } + return "" } // FileSystem returns volume's file system. @@ -191,37 +191,41 @@ func (v *Volume) CreateTime() string { return v.CreationTimestamp.Format("2006-1-2 15:04:05") } -// VolumeID use to define the volume's identity. -type VolumeID struct { - Name string - Driver string - Options map[string]string - Labels map[string]string - Selectors map[string]string +// VolumeContext use to define the volume's identity. +type VolumeContext struct { + Name string + Driver string + Options map[string]string + Labels map[string]string } -// NewVolumeID returns VolumeID instance. -func NewVolumeID(name, driver string) VolumeID { - return VolumeID{ - Name: name, - Driver: driver, - Options: map[string]string{}, - Labels: map[string]string{}, - Selectors: map[string]string{}, +// NewVolumeContext returns VolumeContext instance. +func NewVolumeContext(name, driver string, options, labels map[string]string) VolumeContext { + if options == nil { + options = map[string]string{} + } + if labels == nil { + labels = map[string]string{} + } + return VolumeContext{ + Name: name, + Driver: driver, + Options: options, + Labels: labels, } } -// Equal check VolumeID is equal or not. -func (v VolumeID) Equal(v1 VolumeID) bool { +// Equal check VolumeContext is equal or not. +func (v VolumeContext) Equal(v1 VolumeContext) bool { return (v.Name == v1.Name) && (v.Driver == v1.Driver) } -// String return VolumeID with string. -func (v VolumeID) String() string { +// String return VolumeContext with string. +func (v VolumeContext) String() string { return fmt.Sprintf("<%s, %s>", v.Name, v.Driver) } -// Invalid is used to check VolumeID's name is valid or not. -func (v VolumeID) Invalid() bool { +// Invalid is used to check VolumeContext's name is valid or not. +func (v VolumeContext) Invalid() bool { return v.Name == "" } diff --git a/storage/volume/types/volume_util.go b/storage/volume/types/volume_util.go index 3f06120eb4..947c94fc82 100644 --- a/storage/volume/types/volume_util.go +++ b/storage/volume/types/volume_util.go @@ -1,36 +1,21 @@ package types import ( - "strings" "time" "github.com/alibaba/pouch/storage/volume/types/meta" "github.com/pborman/uuid" - "k8s.io/apimachinery/pkg/selection" ) -func translateSelector(k, v string) SelectorRequirement { - values := strings.Split(v, ",") - - return SelectorRequirement{ - Key: k, - Operator: selection.In, - Values: values, - } -} - -// NewVolumeFromID will create an Volume using mountPath, size and VolumeID. -func NewVolumeFromID(mountPath, size string, id VolumeID) *Volume { +// NewVolumeFromContext will create an Volume using mountPath, size and VolumeContext. +func NewVolumeFromContext(mountPath, size string, id VolumeContext) *Volume { if id.Options == nil { id.Options = map[string]string{} } if id.Labels == nil { id.Labels = map[string]string{} } - if id.Selectors == nil { - id.Selectors = map[string]string{} - } now := time.Now() v := &Volume{ @@ -45,9 +30,8 @@ func NewVolumeFromID(mountPath, size string, id VolumeID) *Volume { ModifyTimestamp: &now, }, Spec: &VolumeSpec{ - Backend: id.Driver, - Extra: id.Options, - Selector: make(Selector, 0), + Backend: id.Driver, + Extra: id.Options, VolumeConfig: &VolumeConfig{ Size: size, }, @@ -57,10 +41,5 @@ func NewVolumeFromID(mountPath, size string, id VolumeID) *Volume { }, } - for n, selector := range id.Selectors { - requirement := translateSelector(n, strings.ToLower(selector)) - v.Spec.Selector = append(v.Spec.Selector, requirement) - } - return v } diff --git a/storage/volume/types/volume_util_test.go b/storage/volume/types/volume_util_test.go index 069aa49813..30f4116be8 100644 --- a/storage/volume/types/volume_util_test.go +++ b/storage/volume/types/volume_util_test.go @@ -2,7 +2,7 @@ package types import "testing" -func TestNewVolumeFromID(t *testing.T) { +func TestNewVolumeFromContext(t *testing.T) { tests := []struct { Name string Driver string @@ -24,22 +24,22 @@ func TestNewVolumeFromID(t *testing.T) { } for _, tt := range tests { - volumeID := NewVolumeID(tt.Name, tt.Driver) - v := NewVolumeFromID(tt.MountPoint, tt.Size, volumeID) + volumeID := NewVolumeContext(tt.Name, tt.Driver, nil, nil) + v := NewVolumeFromContext(tt.MountPoint, tt.Size, volumeID) if v.Name != tt.Name { - t.Errorf("NewVolumeFromID, volume's name: (%v), want (%v)", v.Name, tt.Name) + t.Errorf("NewVolumeFromContext, volume's name: (%v), want (%v)", v.Name, tt.Name) } if v.Driver() != tt.Driver { - t.Errorf("NewVolumeFromID, volume's driver: (%v), want (%v)", v.Driver(), tt.Driver) + t.Errorf("NewVolumeFromContext, volume's driver: (%v), want (%v)", v.Driver(), tt.Driver) } if v.Path() != tt.MountPoint { - t.Errorf("NewVolumeFromID, volume's driver: (%v), want (%v)", v.Path(), tt.MountPoint) + t.Errorf("NewVolumeFromContext, volume's driver: (%v), want (%v)", v.Path(), tt.MountPoint) } if v.Size() != tt.Size { - t.Errorf("NewVolumeFromID, volume's size: (%v), want (%v)", v.Size(), tt.Size) + t.Errorf("NewVolumeFromContext, volume's size: (%v), want (%v)", v.Size(), tt.Size) } } }