package formatter import ( "fmt" "strconv" "strings" "github.com/docker/docker/api/types/volume" units "github.com/docker/go-units" ) const ( defaultVolumeQuietFormat = "{{.Name}}" defaultVolumeTableFormat = "table {{.Driver}}\t{{.Name}}" idHeader = "ID" volumeNameHeader = "VOLUME NAME" mountpointHeader = "MOUNTPOINT" linksHeader = "LINKS" groupHeader = "GROUP" availabilityHeader = "AVAILABILITY" statusHeader = "STATUS" ) // NewVolumeFormat returns a format for use with a volume Context func NewVolumeFormat(source string, quiet bool) Format { switch source { case TableFormatKey: if quiet { return defaultVolumeQuietFormat } return defaultVolumeTableFormat case RawFormatKey: if quiet { return `name: {{.Name}}` } return `name: {{.Name}}\ndriver: {{.Driver}}\n` } return Format(source) } // VolumeWrite writes formatted volumes using the Context func VolumeWrite(ctx Context, volumes []*volume.Volume) error { render := func(format func(subContext SubContext) error) error { for _, vol := range volumes { if err := format(&volumeContext{v: *vol}); err != nil { return err } } return nil } return ctx.Write(newVolumeContext(), render) } type volumeContext struct { HeaderContext v volume.Volume } func newVolumeContext() *volumeContext { volumeCtx := volumeContext{} volumeCtx.Header = SubHeaderContext{ "ID": idHeader, "Name": volumeNameHeader, "Group": groupHeader, "Driver": DriverHeader, "Scope": ScopeHeader, "Availability": availabilityHeader, "Mountpoint": mountpointHeader, "Labels": LabelsHeader, "Links": linksHeader, "Size": SizeHeader, "Status": statusHeader, } return &volumeCtx } func (c *volumeContext) MarshalJSON() ([]byte, error) { return MarshalJSON(c) } func (c *volumeContext) Name() string { return c.v.Name } func (c *volumeContext) Driver() string { return c.v.Driver } func (c *volumeContext) Scope() string { return c.v.Scope } func (c *volumeContext) Mountpoint() string { return c.v.Mountpoint } func (c *volumeContext) Labels() string { if c.v.Labels == nil { return "" } joinLabels := make([]string, 0, len(c.v.Labels)) for k, v := range c.v.Labels { joinLabels = append(joinLabels, k+"="+v) } return strings.Join(joinLabels, ",") } func (c *volumeContext) Label(name string) string { if c.v.Labels == nil { return "" } return c.v.Labels[name] } func (c *volumeContext) Links() string { if c.v.UsageData == nil { return "N/A" } return strconv.FormatInt(c.v.UsageData.RefCount, 10) } func (c *volumeContext) Size() string { if c.v.UsageData == nil { return "N/A" } return units.HumanSize(float64(c.v.UsageData.Size)) } func (c *volumeContext) Group() string { if c.v.ClusterVolume == nil { return "N/A" } return c.v.ClusterVolume.Spec.Group } func (c *volumeContext) Availability() string { if c.v.ClusterVolume == nil { return "N/A" } return string(c.v.ClusterVolume.Spec.Availability) } func (c *volumeContext) Status() string { if c.v.ClusterVolume == nil { return "N/A" } if c.v.ClusterVolume.Info == nil || c.v.ClusterVolume.Info.VolumeID == "" { return "pending creation" } l := len(c.v.ClusterVolume.PublishStatus) switch l { case 0: return "created" case 1: return "in use (1 node)" default: return fmt.Sprintf("in use (%d nodes)", l) } }