github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/storage/volumelistformatters.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"sort"
    10  	"strings"
    11  	"text/tabwriter"
    12  
    13  	"github.com/dustin/go-humanize"
    14  	"github.com/juju/errors"
    15  )
    16  
    17  // formatVolumeListTabular returns a tabular summary of volume instances.
    18  func formatVolumeListTabular(value interface{}) ([]byte, error) {
    19  	infos, ok := value.(map[string]VolumeInfo)
    20  	if !ok {
    21  		return nil, errors.Errorf("expected value of type %T, got %T", infos, value)
    22  	}
    23  	return formatVolumeListTabularTyped(infos), nil
    24  }
    25  
    26  func formatVolumeListTabularTyped(infos map[string]VolumeInfo) []byte {
    27  	var out bytes.Buffer
    28  	const (
    29  		// To format things into columns.
    30  		minwidth = 0
    31  		tabwidth = 1
    32  		padding  = 2
    33  		padchar  = ' '
    34  		flags    = 0
    35  	)
    36  	tw := tabwriter.NewWriter(&out, minwidth, tabwidth, padding, padchar, flags)
    37  
    38  	print := func(values ...string) {
    39  		fmt.Fprintln(tw, strings.Join(values, "\t"))
    40  	}
    41  	print("MACHINE", "UNIT", "STORAGE", "ID", "PROVIDER-ID", "DEVICE", "SIZE", "STATE", "MESSAGE")
    42  
    43  	volumeAttachmentInfos := make(volumeAttachmentInfos, 0, len(infos))
    44  	for volumeId, info := range infos {
    45  		volumeAttachmentInfo := volumeAttachmentInfo{
    46  			VolumeId:   volumeId,
    47  			VolumeInfo: info,
    48  		}
    49  		if info.Attachments == nil {
    50  			volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo)
    51  			continue
    52  		}
    53  		// Each unit attachment must have a corresponding volume
    54  		// attachment. Enumerate each of the volume attachments,
    55  		// and locate the corresponding unit attachment if any.
    56  		// Each volume attachment has at most one corresponding
    57  		// unit attachment.
    58  		for machineId, machineInfo := range info.Attachments.Machines {
    59  			volumeAttachmentInfo := volumeAttachmentInfo
    60  			volumeAttachmentInfo.MachineId = machineId
    61  			volumeAttachmentInfo.MachineVolumeAttachment = machineInfo
    62  			for unitId, unitInfo := range info.Attachments.Units {
    63  				if unitInfo.MachineId == machineId {
    64  					volumeAttachmentInfo.UnitId = unitId
    65  					volumeAttachmentInfo.UnitStorageAttachment = unitInfo
    66  					break
    67  				}
    68  			}
    69  			volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo)
    70  		}
    71  	}
    72  	sort.Sort(volumeAttachmentInfos)
    73  
    74  	for _, info := range volumeAttachmentInfos {
    75  		var size string
    76  		if info.Size > 0 {
    77  			size = humanize.IBytes(info.Size * humanize.MiByte)
    78  		}
    79  		print(
    80  			info.MachineId, info.UnitId, info.Storage,
    81  			info.VolumeId, info.ProviderVolumeId,
    82  			info.DeviceName, size,
    83  			string(info.Status.Current), info.Status.Message,
    84  		)
    85  	}
    86  
    87  	tw.Flush()
    88  	return out.Bytes()
    89  }
    90  
    91  type volumeAttachmentInfo struct {
    92  	VolumeId string
    93  	VolumeInfo
    94  
    95  	MachineId string
    96  	MachineVolumeAttachment
    97  
    98  	UnitId string
    99  	UnitStorageAttachment
   100  }
   101  
   102  type volumeAttachmentInfos []volumeAttachmentInfo
   103  
   104  func (v volumeAttachmentInfos) Len() int {
   105  	return len(v)
   106  }
   107  
   108  func (v volumeAttachmentInfos) Swap(i, j int) {
   109  	v[i], v[j] = v[j], v[i]
   110  }
   111  
   112  func (v volumeAttachmentInfos) Less(i, j int) bool {
   113  	switch compareStrings(v[i].MachineId, v[j].MachineId) {
   114  	case -1:
   115  		return true
   116  	case 1:
   117  		return false
   118  	}
   119  
   120  	switch compareSlashSeparated(v[i].UnitId, v[j].UnitId) {
   121  	case -1:
   122  		return true
   123  	case 1:
   124  		return false
   125  	}
   126  
   127  	switch compareSlashSeparated(v[i].Storage, v[j].Storage) {
   128  	case -1:
   129  		return true
   130  	case 1:
   131  		return false
   132  	}
   133  
   134  	return v[i].VolumeId < v[j].VolumeId
   135  }