github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/machinemanager/machinemanager.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package machinemanager 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/api/base" 11 apiwatcher "github.com/juju/juju/api/watcher" 12 "github.com/juju/juju/apiserver/common" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/core/watcher" 15 ) 16 17 const machineManagerFacade = "MachineManager" 18 19 // Client provides access to the machinemanager, used to add machines to state. 20 type Client struct { 21 base.ClientFacade 22 facade base.FacadeCaller 23 } 24 25 // ConstructClient is a constructor function for a machine manager client 26 func ConstructClient(clientFacade base.ClientFacade, facadeCaller base.FacadeCaller) *Client { 27 return &Client{ClientFacade: clientFacade, facade: facadeCaller} 28 } 29 30 // NewClient returns a new machinemanager client. 31 func NewClient(st base.APICallCloser) *Client { 32 frontend, backend := base.NewClientFacade(st, machineManagerFacade) 33 return ConstructClient(frontend, backend) 34 } 35 36 // AddMachines adds new machines with the supplied parameters, creating any requested disks. 37 func (client *Client) AddMachines(machineParams []params.AddMachineParams) ([]params.AddMachinesResult, error) { 38 args := params.AddMachines{ 39 MachineParams: machineParams, 40 } 41 results := new(params.AddMachinesResults) 42 err := client.facade.FacadeCall("AddMachines", args, results) 43 if len(results.Machines) != len(machineParams) { 44 return nil, errors.Errorf("expected %d result, got %d", len(machineParams), len(results.Machines)) 45 } 46 return results.Machines, err 47 } 48 49 // DestroyMachines removes a given set of machines. 50 func (client *Client) DestroyMachines(machines ...string) ([]params.DestroyMachineResult, error) { 51 return client.destroyMachines("DestroyMachine", machines) 52 } 53 54 // ForceDestroyMachines removes a given set of machines and all 55 // associated units. 56 func (client *Client) ForceDestroyMachines(machines ...string) ([]params.DestroyMachineResult, error) { 57 return client.destroyMachines("ForceDestroyMachine", machines) 58 } 59 60 // DestroyMachinesWithParams removes the given set of machines, the semantics of which 61 // is determined by the force and keep parameters. 62 // TODO(wallyworld) - for Juju 3.0, this should be the preferred api to use. 63 func (client *Client) DestroyMachinesWithParams(force, keep bool, machines ...string) ([]params.DestroyMachineResult, error) { 64 args := params.DestroyMachinesParams{ 65 Force: force, 66 Keep: keep, 67 MachineTags: make([]string, 0, len(machines)), 68 } 69 allResults := make([]params.DestroyMachineResult, len(machines)) 70 index := make([]int, 0, len(machines)) 71 for i, machineId := range machines { 72 if !names.IsValidMachine(machineId) { 73 allResults[i].Error = ¶ms.Error{ 74 Message: errors.NotValidf("machine ID %q", machineId).Error(), 75 } 76 continue 77 } 78 index = append(index, i) 79 args.MachineTags = append(args.MachineTags, names.NewMachineTag(machineId).String()) 80 } 81 if len(args.MachineTags) > 0 { 82 var result params.DestroyMachineResults 83 if err := client.facade.FacadeCall("DestroyMachineWithParams", args, &result); err != nil { 84 return nil, errors.Trace(err) 85 } 86 if n := len(result.Results); n != len(args.MachineTags) { 87 return nil, errors.Errorf("expected %d result(s), got %d", len(args.MachineTags), n) 88 } 89 for i, result := range result.Results { 90 allResults[index[i]] = result 91 } 92 } 93 return allResults, nil 94 } 95 96 func (client *Client) destroyMachines(method string, machines []string) ([]params.DestroyMachineResult, error) { 97 args := params.Entities{ 98 Entities: make([]params.Entity, 0, len(machines)), 99 } 100 allResults := make([]params.DestroyMachineResult, len(machines)) 101 index := make([]int, 0, len(machines)) 102 for i, machineId := range machines { 103 if !names.IsValidMachine(machineId) { 104 allResults[i].Error = ¶ms.Error{ 105 Message: errors.NotValidf("machine ID %q", machineId).Error(), 106 } 107 continue 108 } 109 index = append(index, i) 110 args.Entities = append(args.Entities, params.Entity{ 111 Tag: names.NewMachineTag(machineId).String(), 112 }) 113 } 114 if len(args.Entities) > 0 { 115 var result params.DestroyMachineResults 116 if err := client.facade.FacadeCall(method, args, &result); err != nil { 117 return nil, errors.Trace(err) 118 } 119 if n := len(result.Results); n != len(args.Entities) { 120 return nil, errors.Errorf("expected %d result(s), got %d", len(args.Entities), n) 121 } 122 for i, result := range result.Results { 123 allResults[index[i]] = result 124 } 125 } 126 return allResults, nil 127 } 128 129 // UpgradeSeriesPrepare notifies the controller that a series upgrade is taking 130 // place for a given machine and as such the machine is guarded against 131 // operations that would impede, fail, or interfere with the upgrade process. 132 func (client *Client) UpgradeSeriesPrepare(machineName, series string, force bool) error { 133 if client.BestAPIVersion() < 5 { 134 return errors.NotSupportedf("upgrade-series prepare") 135 } 136 args := params.UpdateSeriesArg{ 137 Entity: params.Entity{ 138 Tag: names.NewMachineTag(machineName).String()}, 139 Series: series, 140 Force: force, 141 } 142 result := params.ErrorResult{} 143 if err := client.facade.FacadeCall("UpgradeSeriesPrepare", args, &result); err != nil { 144 return errors.Trace(err) 145 } 146 147 err := result.Error 148 if err != nil { 149 return common.RestoreError(err) 150 } 151 return nil 152 } 153 154 // UpgradeSeriesComplete notifies the controller that a given machine has 155 // successfully completed the managed series upgrade process. 156 func (client *Client) UpgradeSeriesComplete(machineName string) error { 157 if client.BestAPIVersion() < 5 { 158 return errors.NotSupportedf("UpgradeSeriesComplete") 159 } 160 args := params.UpdateSeriesArg{ 161 Entity: params.Entity{Tag: names.NewMachineTag(machineName).String()}, 162 } 163 result := new(params.ErrorResult) 164 err := client.facade.FacadeCall("UpgradeSeriesComplete", args, result) 165 if err != nil { 166 return errors.Trace(err) 167 } 168 if result.Error != nil { 169 return result.Error 170 } 171 172 return nil 173 } 174 175 func (client *Client) UpgradeSeriesValidate(machineName, series string) ([]string, error) { 176 if client.BestAPIVersion() < 5 { 177 return nil, errors.NotSupportedf("UpgradeSeriesValidate") 178 } 179 args := params.UpdateSeriesArgs{ 180 Args: []params.UpdateSeriesArg{ 181 { 182 Entity: params.Entity{Tag: names.NewMachineTag(machineName).String()}, 183 Series: series, 184 }, 185 }, 186 } 187 results := new(params.UpgradeSeriesUnitsResults) 188 err := client.facade.FacadeCall("UpgradeSeriesValidate", args, results) 189 if err != nil { 190 return nil, err 191 } 192 if n := len(results.Results); n != 1 { 193 return nil, errors.Errorf("expected 1 result, got %d", n) 194 } 195 if results.Results[0].Error != nil { 196 return nil, results.Results[0].Error 197 } 198 return results.Results[0].UnitNames, nil 199 } 200 201 // WatchUpgradeSeriesNotifications returns a NotifyWatcher for observing the state of 202 // a series upgrade. 203 func (client *Client) WatchUpgradeSeriesNotifications(machineName string) (watcher.NotifyWatcher, string, error) { 204 if client.BestAPIVersion() < 5 { 205 return nil, "", errors.NotSupportedf("WatchUpgradeSeriesNotifications") 206 } 207 var results params.NotifyWatchResults 208 args := params.Entities{ 209 Entities: []params.Entity{{Tag: names.NewMachineTag(machineName).String()}}, 210 } 211 err := client.facade.FacadeCall("WatchUpgradeSeriesNotifications", args, &results) 212 if err != nil { 213 return nil, "", errors.Trace(err) 214 } 215 if len(results.Results) != 1 { 216 return nil, "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 217 } 218 result := results.Results[0] 219 if result.Error != nil { 220 return nil, "", result.Error 221 } 222 w := apiwatcher.NewNotifyWatcher(client.facade.RawAPICaller(), result) 223 return w, result.NotifyWatcherId, nil 224 } 225 226 // GetUpgradeSeriesMessages returns a StringsWatcher for observing the state of 227 // a series upgrade. 228 func (client *Client) GetUpgradeSeriesMessages(machineName, watcherId string) ([]string, error) { 229 if client.BestAPIVersion() < 5 { 230 return nil, errors.NotSupportedf("GetUpgradeSeriesMessages") 231 } 232 var results params.StringsResults 233 args := params.UpgradeSeriesNotificationParams{ 234 Params: []params.UpgradeSeriesNotificationParam{ 235 { 236 Entity: params.Entity{Tag: names.NewMachineTag(machineName).String()}, 237 WatcherId: watcherId, 238 }, 239 }, 240 } 241 err := client.facade.FacadeCall("GetUpgradeSeriesMessages", args, &results) 242 if err != nil { 243 return nil, errors.Trace(err) 244 } 245 if len(results.Results) != 1 { 246 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 247 } 248 result := results.Results[0] 249 if result.Error != nil { 250 return nil, result.Error 251 } 252 253 return result.Result, nil 254 }