github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/storage/add.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 "strings" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "github.com/juju/names" 13 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/storage" 16 ) 17 18 const ( 19 addCommandDoc = ` 20 Add storage instances to a unit dynamically using provided storage directives. 21 Specify a unit and a storage specification in the same format 22 as passed to juju deploy --storage=”...”. 23 24 A storage directive consists of a storage name as per charm specification 25 and storage constraints, e.g. pool, count, size. 26 27 The acceptable format for storage constraints is a comma separated 28 sequence of: POOL, COUNT, and SIZE, where 29 30 POOL identifies the storage pool. POOL can be a string 31 starting with a letter, followed by zero or more digits 32 or letters optionally separated by hyphens. 33 34 COUNT is a positive integer indicating how many instances 35 of the storage to create. If unspecified, and SIZE is 36 specified, COUNT defaults to 1. 37 38 SIZE describes the minimum size of the storage instances to 39 create. SIZE is a floating point number and multiplier from 40 the set (M, G, T, P, E, Z, Y), which are all treated as 41 powers of 1024. 42 43 Storage constraints can be optionally ommitted. 44 Environment default values will be used for all ommitted constraint values. 45 There is no need to comma-separate ommitted constraints. 46 47 Example: 48 Add 3 ebs storage instances for "data" storage to unit u/0: 49 50 juju storage add u/0 data=ebs,1024,3 51 or 52 juju storage add u/0 data=ebs,3 53 or 54 juju storage add u/0 data=ebs,,3 55 56 57 Add 1 storage instances for "data" storage to unit u/0 58 using default environment provider pool: 59 60 juju storage add u/0 data=1 61 or 62 juju storage add u/0 data 63 ` 64 addCommandAgs = ` 65 <unit name> <storage directive> ... 66 where storage directive is 67 <charm storage name>=<storage constraints> 68 or 69 <charm storage name> 70 ` 71 ) 72 73 // AddCommand adds unit storage instances dynamically. 74 type AddCommand struct { 75 StorageCommandBase 76 unitTag string 77 78 // storageCons is a map of storage constraints, keyed on the storage name 79 // defined in charm storage metadata. 80 storageCons map[string]storage.Constraints 81 } 82 83 // Init implements Command.Init. 84 func (c *AddCommand) Init(args []string) (err error) { 85 if len(args) < 2 { 86 return errors.New("storage add requires a unit and a storage directive") 87 } 88 89 u := args[0] 90 if !names.IsValidUnit(u) { 91 return errors.NotValidf("unit name %q", u) 92 } 93 c.unitTag = names.NewUnitTag(u).String() 94 95 c.storageCons, err = storage.ParseConstraintsMap(args[1:], false) 96 return 97 } 98 99 // Info implements Command.Info. 100 func (c *AddCommand) Info() *cmd.Info { 101 return &cmd.Info{ 102 Name: "add", 103 Purpose: "adds unit storage dynamically", 104 Doc: addCommandDoc, 105 Args: addCommandAgs, 106 } 107 } 108 109 // Run implements Command.Run. 110 func (c *AddCommand) Run(ctx *cmd.Context) (err error) { 111 api, err := getStorageAddAPI(c) 112 if err != nil { 113 return err 114 } 115 defer api.Close() 116 117 storages := c.createStorageAddParams() 118 results, err := api.AddToUnit(storages) 119 if err != nil { 120 return err 121 } 122 // If there are any failures, display them first. 123 // Then display all added storage. 124 // If there are no failures, then there is no need to display all successes. 125 var added []string 126 127 for i, one := range results { 128 us := storages[i] 129 if one.Error != nil { 130 fmt.Fprintf(ctx.Stderr, fail+": %v\n", us.StorageName, one.Error) 131 continue 132 } 133 added = append(added, fmt.Sprintf(success, us.StorageName)) 134 } 135 if len(added) < len(storages) { 136 fmt.Fprintf(ctx.Stderr, strings.Join(added, "\n")) 137 } 138 return nil 139 } 140 141 var ( 142 getStorageAddAPI = (*AddCommand).getStorageAddAPI 143 storageName = "storage %q" 144 success = "success: " + storageName 145 fail = "fail: " + storageName 146 ) 147 148 // StorageAddAPI defines the API methods that the storage commands use. 149 type StorageAddAPI interface { 150 Close() error 151 AddToUnit(storages []params.StorageAddParams) ([]params.ErrorResult, error) 152 } 153 154 func (c *AddCommand) getStorageAddAPI() (StorageAddAPI, error) { 155 return c.NewStorageAPI() 156 } 157 158 func (c *AddCommand) createStorageAddParams() []params.StorageAddParams { 159 all := make([]params.StorageAddParams, 0, len(c.storageCons)) 160 for one, cons := range c.storageCons { 161 all = append(all, 162 params.StorageAddParams{ 163 UnitTag: c.unitTag, 164 StorageName: one, 165 Constraints: params.StorageConstraints{ 166 cons.Pool, 167 &cons.Size, 168 &cons.Count, 169 }, 170 }) 171 } 172 return all 173 }