github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/storage.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // The storage command provides a storage management interface, 5 // for manipulating and inspecting storage entities (volumes, 6 // filesystems, charm storage). 7 package storage 8 9 import ( 10 "github.com/juju/errors" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/api/storage" 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/cmd/juju/common" 16 "github.com/juju/juju/cmd/modelcmd" 17 ) 18 19 // StorageCommandBase is a helper base structure that has a method to get the 20 // storage managing client. 21 type StorageCommandBase struct { 22 modelcmd.ModelCommandBase 23 } 24 25 // NewStorageAPI returns a storage api for the root api endpoint 26 // that the environment command returns. 27 func (c *StorageCommandBase) NewStorageAPI() (*storage.Client, error) { 28 root, err := c.NewAPIRoot() 29 if err != nil { 30 return nil, err 31 } 32 return storage.NewClient(root), nil 33 } 34 35 // StorageInfo defines the serialization behaviour of the storage information. 36 type StorageInfo struct { 37 Kind string `yaml:"kind" json:"kind"` 38 Life string `yaml:"life,omitempty" json:"life,omitempty"` 39 Status EntityStatus `yaml:"status" json:"status"` 40 Persistent bool `yaml:"persistent" json:"persistent"` 41 Attachments *StorageAttachments `yaml:"attachments,omitempty" json:"attachments,omitempty"` 42 } 43 44 // StorageAttachments contains details about all attachments to a storage 45 // instance. 46 type StorageAttachments struct { 47 // Units is a mapping from unit ID to unit storage attachment details. 48 Units map[string]UnitStorageAttachment `yaml:"units" json:"units"` 49 } 50 51 // UnitStorageAttachment contains details of a unit storage attachment. 52 type UnitStorageAttachment struct { 53 // MachineId is the ID of the machine that the unit is assigned to. 54 // 55 // This is omitempty to cater for legacy results, where the machine 56 // information is not available. 57 MachineId string `yaml:"machine,omitempty" json:"machine,omitempty"` 58 59 // Location is the location of the storage attachment. 60 Location string `yaml:"location,omitempty" json:"location,omitempty"` 61 62 // Life is the lifecycle state of the storage attachment. 63 Life string `yaml:"life,omitempty" json:"life,omitempty"` 64 65 // TODO(axw) per-unit status when we have it in state. 66 } 67 68 // formatStorageDetails takes a set of StorageDetail and 69 // creates a mapping from storage ID to storage details. 70 func formatStorageDetails(storages []params.StorageDetails) (map[string]StorageInfo, error) { 71 if len(storages) == 0 { 72 return nil, nil 73 } 74 output := make(map[string]StorageInfo) 75 for _, details := range storages { 76 storageTag, storageInfo, err := createStorageInfo(details) 77 if err != nil { 78 return nil, errors.Trace(err) 79 } 80 output[storageTag.Id()] = storageInfo 81 } 82 return output, nil 83 } 84 85 func createStorageInfo(details params.StorageDetails) (names.StorageTag, StorageInfo, error) { 86 storageTag, err := names.ParseStorageTag(details.StorageTag) 87 if err != nil { 88 return names.StorageTag{}, StorageInfo{}, errors.Trace(err) 89 } 90 91 info := StorageInfo{ 92 Kind: details.Kind.String(), 93 Life: string(details.Life), 94 Status: EntityStatus{ 95 details.Status.Status, 96 details.Status.Info, 97 // TODO(axw) we should support formatting as ISO time 98 common.FormatTime(details.Status.Since, false), 99 }, 100 Persistent: details.Persistent, 101 } 102 103 if len(details.Attachments) > 0 { 104 unitStorageAttachments := make(map[string]UnitStorageAttachment) 105 for unitTagString, attachmentDetails := range details.Attachments { 106 unitTag, err := names.ParseUnitTag(unitTagString) 107 if err != nil { 108 return names.StorageTag{}, StorageInfo{}, errors.Trace(err) 109 } 110 var machineId string 111 if attachmentDetails.MachineTag != "" { 112 machineTag, err := names.ParseMachineTag(attachmentDetails.MachineTag) 113 if err != nil { 114 return names.StorageTag{}, StorageInfo{}, errors.Trace(err) 115 } 116 machineId = machineTag.Id() 117 } 118 unitStorageAttachments[unitTag.Id()] = UnitStorageAttachment{ 119 machineId, 120 attachmentDetails.Location, 121 string(attachmentDetails.Life), 122 } 123 } 124 info.Attachments = &StorageAttachments{unitStorageAttachments} 125 } 126 127 return storageTag, info, nil 128 }