Skip to content

Commit

Permalink
feature: add options when using volume list
Browse files Browse the repository at this point in the history
Add options when using volume list, add volume driver into default
volume list information. Add list volumes function in volume core module.

Signed-off-by: Rudy Zhang <rudyflyzhang@gmail.com>
  • Loading branch information
rudyfly committed Apr 2, 2018
1 parent ec48e96 commit 19932e8
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 18 deletions.
29 changes: 24 additions & 5 deletions apis/server/volume_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (s *Server) getVolume(ctx context.Context, rw http.ResponseWriter, req *htt
Name: volume.Name,
Driver: volume.Driver(),
Mountpoint: volume.Path(),
CreatedAt: volume.CreationTimestamp.Format("2006-1-2 15:04:05"),
CreatedAt: volume.CreateTime(),
Labels: volume.Labels,
}

Expand All @@ -100,12 +100,12 @@ func (s *Server) getVolume(ctx context.Context, rw http.ResponseWriter, req *htt
func (s *Server) removeVolume(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
name := mux.Vars(req)["name"]

v, err := s.VolumeMgr.Get(ctx, name)
volume, err := s.VolumeMgr.Get(ctx, name)
if err != nil {
return err
}

ref := v.Option("ref")
ref := volume.Option("ref")
if ref != "" {
return fmt.Errorf("failed to remove volume: %s, using by: %s", name, ref)
}
Expand All @@ -124,8 +124,27 @@ func (s *Server) listVolume(ctx context.Context, rw http.ResponseWriter, req *ht
}

respVolumes := types.VolumeListResp{Volumes: []*types.VolumeInfo{}, Warnings: nil}
for _, name := range volumes {
respVolumes.Volumes = append(respVolumes.Volumes, &types.VolumeInfo{Name: name})
for _, volume := range volumes {
respVolume := &types.VolumeInfo{
Name: volume.Name,
Driver: volume.Driver(),
Mountpoint: volume.Path(),
CreatedAt: volume.CreateTime(),
Labels: volume.Labels,
}

var status map[string]interface{}
for k, v := range volume.Options() {
if k != "" && v != "" {
if status == nil {
status = make(map[string]interface{})
}
status[k] = v
}
}
respVolume.Status = status

respVolumes.Volumes = append(respVolumes.Volumes, respVolume)
}
return EncodeResponse(rw, http.StatusOK, respVolumes)
}
43 changes: 34 additions & 9 deletions cli/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ var volumeListDescription = "List volumes in pouchd. " +
// VolumeListCommand is used to implement 'volume rm' command.
type VolumeListCommand struct {
baseCommand

size bool
mountPoint bool
}

// Init initializes VolumeListCommand command.
Expand All @@ -289,7 +292,11 @@ func (v *VolumeListCommand) Init(c *Cli) {
}

// addFlags adds flags for specific command.
func (v *VolumeListCommand) addFlags() {}
func (v *VolumeListCommand) addFlags() {
flagSet := v.cmd.Flags()
flagSet.BoolVar(&v.size, "size", false, "Display volume size")
flagSet.BoolVar(&v.mountPoint, "mountpoint", false, "Display volume mountpoint")
}

// runVolumeList is the entry of VolumeListCommand command.
func (v *VolumeListCommand) runVolumeList(args []string) error {
Expand All @@ -304,10 +311,28 @@ func (v *VolumeListCommand) runVolumeList(args []string) error {
}

display := v.cli.NewTableDisplay()
display.AddRow([]string{"Name:"})

for _, v := range volumeList.Volumes {
display.AddRow([]string{v.Name})
displayHead := []string{"DRIVER", "VOLUME NAME"}
if v.size {
displayHead = append(displayHead, "SIZE")
}
if v.mountPoint {
displayHead = append(displayHead, "MOUNT POINT")
}
display.AddRow(displayHead)

for _, volume := range volumeList.Volumes {
displayLine := []string{volume.Driver, volume.Name}
if v.size {
if s, ok := volume.Status["size"]; ok {
displayLine = append(displayLine, s.(string))
} else {
displayLine = append(displayLine, "ulimit")
}
}
if v.mountPoint {
displayLine = append(displayLine, volume.Mountpoint)
}
display.AddRow(displayLine)
}

display.Flush()
Expand All @@ -318,8 +343,8 @@ func (v *VolumeListCommand) runVolumeList(args []string) error {
// volumeListExample shows examples in volume list command, and is used in auto-generated cli docs.
func volumeListExample() string {
return `$ pouch volume list
Name:
pouch-volume-1
pouch-volume-2
pouch-volume-3`
DRIVER VOLUME NAME
local pouch-volume-1
local pouch-volume-2
local pouch-volume-3`
}
6 changes: 3 additions & 3 deletions daemon/mgr/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type VolumeMgr interface {
Remove(ctx context.Context, name string) error

// List returns all volumes on this host.
List(ctx context.Context, labels map[string]string) ([]string, error)
List(ctx context.Context, labels map[string]string) ([]*types.Volume, error)

// Get returns the information of volume that specified name/id.
Get(ctx context.Context, name string) (*types.Volume, error)
Expand Down Expand Up @@ -100,7 +100,7 @@ func (vm *VolumeManager) Remove(ctx context.Context, name string) error {
}

// List returns all volumes on this host.
func (vm *VolumeManager) List(ctx context.Context, labels map[string]string) ([]string, error) {
func (vm *VolumeManager) List(ctx context.Context, labels map[string]string) ([]*types.Volume, error) {
if _, ok := labels["hostname"]; !ok {
hostname, err := os.Hostname()
if err != nil {
Expand All @@ -110,7 +110,7 @@ func (vm *VolumeManager) List(ctx context.Context, labels map[string]string) ([]
labels["hostname"] = hostname
}

return vm.core.ListVolumeName(labels)
return vm.core.ListVolumes(labels)
}

// Get returns the information of volume that specified name/id.
Expand Down
72 changes: 72 additions & 0 deletions test/cli_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,75 @@ func (suite *PouchVolumeSuite) TestVolumeBindReplaceMode(c *check.C) {
}
c.Assert(found, check.Equals, true)
}

// TestVolumeList tests the volume list.
func (suite *PouchVolumeSuite) TestVolumeList(c *check.C) {
pc, _, _, _ := runtime.Caller(0)
tmpname := strings.Split(runtime.FuncForPC(pc).Name(), ".")
var funcname string
for i := range tmpname {
funcname = tmpname[i]
}

volumeName := "volume_" + funcname
volumeName1 := "volume_" + funcname + "_1"
command.PouchRun("volume", "create", "--name", volumeName1, "-o", "size=1g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName1)

volumeName2 := "volume_" + funcname + "_2"
command.PouchRun("volume", "create", "--name", volumeName2, "-o", "size=2g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName2)

volumeName3 := "volume_" + funcname + "_3"
command.PouchRun("volume", "create", "--name", volumeName3, "-o", "size=3g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName3)

ret := command.PouchRun("volume", "list")
ret.Assert(c, icmd.Success)

for _, line := range strings.Split(ret.Stdout(), "\n") {
if strings.Contains(line, volumeName) {
if !strings.Contains(line, "local") {
c.Errorf("list result have no driver or name or size or mountpoint, line: %s", line)
break
}
}
}
}

// TestVolumeList tests the volume list with options: size and mountpoint.
func (suite *PouchVolumeSuite) TestVolumeListOptions(c *check.C) {
pc, _, _, _ := runtime.Caller(0)
tmpname := strings.Split(runtime.FuncForPC(pc).Name(), ".")
var funcname string
for i := range tmpname {
funcname = tmpname[i]
}

volumeName := "volume_" + funcname
volumeName1 := "volume_" + funcname + "_1"
command.PouchRun("volume", "create", "--name", volumeName1, "-o", "size=1g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName1)

volumeName2 := "volume_" + funcname + "_2"
command.PouchRun("volume", "create", "--name", volumeName2, "-o", "size=2g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName2)

volumeName3 := "volume_" + funcname + "_3"
command.PouchRun("volume", "create", "--name", volumeName3, "-o", "size=3g").Assert(c, icmd.Success)
defer command.PouchRun("volume", "rm", volumeName3)

ret := command.PouchRun("volume", "list", "--size", "--mountpoint")
ret.Assert(c, icmd.Success)

for _, line := range strings.Split(ret.Stdout(), "\n") {
if strings.Contains(line, volumeName) {
if !strings.Contains(line, "local") ||
!strings.Contains(line, "g") ||
!strings.Contains(line, "/mnt/local") {
c.Errorf("list result have no driver or name or size or mountpoint, line: %s", line)
break
}
}
}
}
38 changes: 37 additions & 1 deletion volume/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,42 @@ func (c *Core) CreateVolume(id types.VolumeID) error {
return nil
}

// ListVolumes return all volumes.
// Param 'labels' use to filter the volumes, only return those you want.
func (c *Core) ListVolumes(labels map[string]string) ([]*types.Volume, error) {
var ls = make([]*types.Volume, 0)

// first, list local meta store.
list, err := c.store.List()
if err != nil {
return nil, err
}

// then, list central store.
if c.EnableControl {
url, err := c.listVolumeURL(labels)
if err != nil {
return nil, errors.Wrap(err, "List volume's name")
}

logrus.Debugf("List volume URL: %s, labels: %s", url, labels)

if err := client.New().ListKeys(url, &ls); err != nil {
return nil, errors.Wrap(err, "List volume's name")
}
}

for _, obj := range list {
v, ok := obj.(*types.Volume)
if !ok {
return nil, fmt.Errorf("failed to get volumes in store")
}
ls = append(ls, v)
}

return ls, nil
}

// 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) {
Expand All @@ -205,7 +241,7 @@ func (c *Core) ListVolumeName(labels map[string]string) ([]string, error) {
return nil, errors.Wrap(err, "List volume's name")
}

logrus.Debugf("List volume URL: %s, labels: %s", url, labels)
logrus.Debugf("List volume name URL: %s, labels: %s", url, labels)

if err := client.New().ListKeys(url, &names); err != nil {
return nil, errors.Wrap(err, "List volume's name")
Expand Down
18 changes: 18 additions & 0 deletions volume/core_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,24 @@ func (c *Core) volumeURL(id ...types.VolumeID) (string, error) {
return client.JoinURL(c.BaseURL, types.APIVersion, client.VolumePath, id[0].Name)
}

func (c *Core) listVolumeURL(labels map[string]string) (string, error) {
if c.BaseURL == "" {
return "", volerr.ErrDisableControl
}
url, err := client.JoinURL(c.BaseURL, types.APIVersion, client.VolumePath)
if err != nil {
return "", err
}

querys := make([]string, 0, len(labels))
for k, v := range labels {
querys = append(querys, fmt.Sprintf("labels=%s=%s", k, v))
}

url = url + "?" + strings.Join(querys, "&")
return url, nil
}

func (c *Core) listVolumeNameURL(labels map[string]string) (string, error) {
if c.BaseURL == "" {
return "", volerr.ErrDisableControl
Expand Down
9 changes: 9 additions & 0 deletions volume/types/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ func (v *Volume) Key() string {
return v.Name
}

//CreateTime returns the volume's create time.
func (v *Volume) CreateTime() string {
if v.CreationTimestamp == nil {
return ""
}

return v.CreationTimestamp.Format("2006-1-2 15:04:05")
}

// VolumeID use to define the volume's identity.
type VolumeID struct {
Name string
Expand Down

0 comments on commit 19932e8

Please sign in to comment.