github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 "fmt" 8 "io" 9 "sort" 10 "strings" 11 12 "github.com/dustin/go-humanize" 13 14 "github.com/juju/juju/cmd/output" 15 ) 16 17 // formatVolumeListTabular returns a tabular summary of volume instances. 18 func formatVolumeListTabular(writer io.Writer, infos map[string]VolumeInfo) error { 19 tw := output.TabWriter(writer) 20 21 print := func(values ...string) { 22 fmt.Fprintln(tw, strings.Join(values, "\t")) 23 } 24 25 haveMachines := false 26 volumeAttachmentInfos := make(volumeAttachmentInfos, 0, len(infos)) 27 for volumeId, info := range infos { 28 volumeAttachmentInfo := volumeAttachmentInfo{ 29 VolumeId: volumeId, 30 VolumeInfo: info, 31 } 32 if info.Attachments == nil { 33 volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo) 34 continue 35 } 36 // Each unit attachment must have a corresponding volume 37 // attachment. Enumerate each of the volume attachments, 38 // and locate the corresponding unit attachment if any. 39 // Each volume attachment has at most one corresponding 40 // unit attachment. 41 for machineId, machineInfo := range info.Attachments.Machines { 42 volumeAttachmentInfo := volumeAttachmentInfo 43 volumeAttachmentInfo.MachineId = machineId 44 volumeAttachmentInfo.VolumeAttachment = machineInfo 45 for unitId, unitInfo := range info.Attachments.Units { 46 if unitInfo.MachineId == machineId { 47 volumeAttachmentInfo.UnitId = unitId 48 volumeAttachmentInfo.UnitStorageAttachment = unitInfo 49 break 50 } 51 } 52 haveMachines = true 53 volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo) 54 } 55 56 for hostId, containerInfo := range info.Attachments.Containers { 57 volumeAttachmentInfo := volumeAttachmentInfo 58 volumeAttachmentInfo.VolumeAttachment = containerInfo 59 for unitId, unitInfo := range info.Attachments.Units { 60 if hostId == unitId { 61 volumeAttachmentInfo.UnitId = unitId 62 volumeAttachmentInfo.UnitStorageAttachment = unitInfo 63 break 64 } 65 } 66 volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo) 67 } 68 } 69 sort.Sort(volumeAttachmentInfos) 70 71 if haveMachines { 72 print("Machine", "Unit", "Storage id", "Volume id", "Provider Id", "Device", "Size", "State", "Message") 73 } else { 74 print("Unit", "Storage id", "Volume id", "Provider Id", "Size", "State", "Message") 75 } 76 77 for _, info := range volumeAttachmentInfos { 78 var size string 79 if info.Size > 0 { 80 size = humanize.IBytes(info.Size * humanize.MiByte) 81 } 82 if haveMachines { 83 print( 84 info.MachineId, info.UnitId, info.Storage, 85 info.VolumeId, info.ProviderVolumeId, 86 info.DeviceName, size, 87 string(info.Status.Current), info.Status.Message, 88 ) 89 } else { 90 print( 91 info.UnitId, info.Storage, 92 info.VolumeId, info.ProviderVolumeId, size, 93 string(info.Status.Current), info.Status.Message, 94 ) 95 } 96 } 97 98 return tw.Flush() 99 } 100 101 type volumeAttachmentInfo struct { 102 VolumeId string 103 VolumeInfo 104 105 MachineId string 106 VolumeAttachment 107 108 UnitId string 109 UnitStorageAttachment 110 } 111 112 type volumeAttachmentInfos []volumeAttachmentInfo 113 114 func (v volumeAttachmentInfos) Len() int { 115 return len(v) 116 } 117 118 func (v volumeAttachmentInfos) Swap(i, j int) { 119 v[i], v[j] = v[j], v[i] 120 } 121 122 func (v volumeAttachmentInfos) Less(i, j int) bool { 123 switch compareStrings(v[i].MachineId, v[j].MachineId) { 124 case -1: 125 return true 126 case 1: 127 return false 128 } 129 130 switch compareSlashSeparated(v[i].UnitId, v[j].UnitId) { 131 case -1: 132 return true 133 case 1: 134 return false 135 } 136 137 switch compareSlashSeparated(v[i].Storage, v[j].Storage) { 138 case -1: 139 return true 140 case 1: 141 return false 142 } 143 144 return v[i].VolumeId < v[j].VolumeId 145 }