LEFT | RIGHT |
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package provisioner | 4 package provisioner |
5 | 5 |
6 import ( | 6 import ( |
7 "launchpad.net/juju-core/constraints" | 7 "launchpad.net/juju-core/constraints" |
8 "launchpad.net/juju-core/instance" | 8 "launchpad.net/juju-core/instance" |
9 "launchpad.net/juju-core/names" | 9 "launchpad.net/juju-core/names" |
10 "launchpad.net/juju-core/state" | 10 "launchpad.net/juju-core/state" |
(...skipping 10 matching lines...) Expand all Loading... |
21 *common.DeadEnsurer | 21 *common.DeadEnsurer |
22 *common.PasswordChanger | 22 *common.PasswordChanger |
23 *common.LifeGetter | 23 *common.LifeGetter |
24 *common.StateAddresser | 24 *common.StateAddresser |
25 *common.APIAddresser | 25 *common.APIAddresser |
26 *common.ToolsGetter | 26 *common.ToolsGetter |
27 *common.EnvironWatcher | 27 *common.EnvironWatcher |
28 *common.EnvironMachinesWatcher | 28 *common.EnvironMachinesWatcher |
29 *common.InstanceIdGetter | 29 *common.InstanceIdGetter |
30 | 30 |
31 » st *state.State | 31 » st *state.State |
32 » resources *common.Resources | 32 » resources *common.Resources |
33 » authorizer common.Authorizer | 33 » authorizer common.Authorizer |
34 » getAuthFunc common.GetAuthFunc | 34 » getAuthFunc common.GetAuthFunc |
| 35 » getCanWatchMachines common.GetAuthFunc |
35 } | 36 } |
36 | 37 |
37 // NewProvisionerAPI creates a new server-side ProvisionerAPI facade. | 38 // NewProvisionerAPI creates a new server-side ProvisionerAPI facade. |
38 func NewProvisionerAPI( | 39 func NewProvisionerAPI( |
39 st *state.State, | 40 st *state.State, |
40 resources *common.Resources, | 41 resources *common.Resources, |
41 authorizer common.Authorizer, | 42 authorizer common.Authorizer, |
42 ) (*ProvisionerAPI, error) { | 43 ) (*ProvisionerAPI, error) { |
43 if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() { | 44 if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() { |
44 return nil, common.ErrPerm | 45 return nil, common.ErrPerm |
(...skipping 27 matching lines...) Expand all Loading... |
72 getCanWatch := common.AuthAlways(true) | 73 getCanWatch := common.AuthAlways(true) |
73 // Only the environment provisioner can read secrets. | 74 // Only the environment provisioner can read secrets. |
74 getCanReadSecrets := common.AuthAlways(authorizer.AuthEnvironManager()) | 75 getCanReadSecrets := common.AuthAlways(authorizer.AuthEnvironManager()) |
75 return &ProvisionerAPI{ | 76 return &ProvisionerAPI{ |
76 Remover: common.NewRemover(st, false, getAuthFunc
), | 77 Remover: common.NewRemover(st, false, getAuthFunc
), |
77 StatusSetter: common.NewStatusSetter(st, getAuthFunc), | 78 StatusSetter: common.NewStatusSetter(st, getAuthFunc), |
78 DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), | 79 DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), |
79 PasswordChanger: common.NewPasswordChanger(st, getAuthFun
c), | 80 PasswordChanger: common.NewPasswordChanger(st, getAuthFun
c), |
80 LifeGetter: common.NewLifeGetter(st, getAuthFunc), | 81 LifeGetter: common.NewLifeGetter(st, getAuthFunc), |
81 StateAddresser: common.NewStateAddresser(st), | 82 StateAddresser: common.NewStateAddresser(st), |
82 » » APIAddresser: common.NewAPIAddresser(st), | 83 » » APIAddresser: common.NewAPIAddresser(st, resources), |
83 ToolsGetter: common.NewToolsGetter(st, getAuthFunc), | 84 ToolsGetter: common.NewToolsGetter(st, getAuthFunc), |
84 EnvironWatcher: common.NewEnvironWatcher(st, resources,
getCanWatch, getCanReadSecrets), | 85 EnvironWatcher: common.NewEnvironWatcher(st, resources,
getCanWatch, getCanReadSecrets), |
85 EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, res
ources, getCanReadSecrets), | 86 EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, res
ources, getCanReadSecrets), |
86 InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFu
nc), | 87 InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFu
nc), |
87 st: st, | 88 st: st, |
88 resources: resources, | 89 resources: resources, |
89 authorizer: authorizer, | 90 authorizer: authorizer, |
90 getAuthFunc: getAuthFunc, | 91 getAuthFunc: getAuthFunc, |
| 92 getCanWatchMachines: getCanReadSecrets, |
91 }, nil | 93 }, nil |
92 } | 94 } |
93 | 95 |
94 func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag string) (*sta
te.Machine, error) { | 96 func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag string) (*sta
te.Machine, error) { |
95 if !canAccess(tag) { | 97 if !canAccess(tag) { |
96 return nil, common.ErrPerm | 98 return nil, common.ErrPerm |
97 } | 99 } |
98 entity, err := p.st.FindEntity(tag) | 100 entity, err := p.st.FindEntity(tag) |
99 if err != nil { | 101 if err != nil { |
100 return nil, err | 102 return nil, err |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 Results: make([]params.StatusResult, len(args.Entities)), | 210 Results: make([]params.StatusResult, len(args.Entities)), |
209 } | 211 } |
210 canAccess, err := p.getAuthFunc() | 212 canAccess, err := p.getAuthFunc() |
211 if err != nil { | 213 if err != nil { |
212 return result, err | 214 return result, err |
213 } | 215 } |
214 for i, entity := range args.Entities { | 216 for i, entity := range args.Entities { |
215 machine, err := p.getMachine(canAccess, entity.Tag) | 217 machine, err := p.getMachine(canAccess, entity.Tag) |
216 if err == nil { | 218 if err == nil { |
217 r := &result.Results[i] | 219 r := &result.Results[i] |
218 » » » r.Status, r.Info, _, err = machine.Status() | 220 » » » r.Status, r.Info, r.Data, err = machine.Status() |
219 » » } | 221 » » } |
220 » » result.Results[i].Error = common.ServerError(err) | 222 » » result.Results[i].Error = common.ServerError(err) |
221 » } | 223 » } |
222 » return result, nil | 224 » return result, nil |
| 225 } |
| 226 |
| 227 // MachinesWithTransientErrors returns status data for machines with provisionin
g |
| 228 // errors which are transient. |
| 229 func (p *ProvisionerAPI) MachinesWithTransientErrors() (params.StatusResults, er
ror) { |
| 230 » results := params.StatusResults{} |
| 231 » canAccessFunc, err := p.getAuthFunc() |
| 232 » if err != nil { |
| 233 » » return results, err |
| 234 » } |
| 235 » // TODO (wallyworld) - add state.State API for more efficient machines q
uery |
| 236 » machines, err := p.st.AllMachines() |
| 237 » if err != nil { |
| 238 » » return results, err |
| 239 » } |
| 240 » for _, machine := range machines { |
| 241 » » if !canAccessFunc(machine.Tag()) { |
| 242 » » » continue |
| 243 » » } |
| 244 » » if _, provisionedErr := machine.InstanceId(); provisionedErr ==
nil { |
| 245 » » » // Machine may have been provisioned but machiner hasn't
set the |
| 246 » » » // status to Started yet. |
| 247 » » » continue |
| 248 » » } |
| 249 » » result := params.StatusResult{} |
| 250 » » if result.Status, result.Info, result.Data, err = machine.Status
(); err != nil { |
| 251 » » » continue |
| 252 » » } |
| 253 » » if result.Status != params.StatusError { |
| 254 » » » continue |
| 255 » » } |
| 256 » » // Transient errors are marked as such in the status data. |
| 257 » » if transient, ok := result.Data["transient"].(bool); !ok || !tra
nsient { |
| 258 » » » continue |
| 259 » » } |
| 260 » » result.Id = machine.Id() |
| 261 » » result.Life = params.Life(machine.Life().String()) |
| 262 » » results.Results = append(results.Results, result) |
| 263 » } |
| 264 » return results, nil |
223 } | 265 } |
224 | 266 |
225 // Series returns the deployed series for each given machine entity. | 267 // Series returns the deployed series for each given machine entity. |
226 func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, err
or) { | 268 func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, err
or) { |
227 result := params.StringResults{ | 269 result := params.StringResults{ |
228 Results: make([]params.StringResult, len(args.Entities)), | 270 Results: make([]params.StringResult, len(args.Entities)), |
229 } | 271 } |
230 canAccess, err := p.getAuthFunc() | 272 canAccess, err := p.getAuthFunc() |
231 if err != nil { | 273 if err != nil { |
232 return result, err | 274 return result, err |
233 } | 275 } |
234 for i, entity := range args.Entities { | 276 for i, entity := range args.Entities { |
235 machine, err := p.getMachine(canAccess, entity.Tag) | 277 machine, err := p.getMachine(canAccess, entity.Tag) |
236 if err == nil { | 278 if err == nil { |
237 result.Results[i].Result = machine.Series() | 279 result.Results[i].Result = machine.Series() |
238 } | 280 } |
239 result.Results[i].Error = common.ServerError(err) | 281 result.Results[i].Error = common.ServerError(err) |
240 } | 282 } |
241 return result, nil | 283 return result, nil |
242 } | 284 } |
243 | 285 |
244 // CommonServiceInstances returns, for each given machine entity, | 286 // DistributionGroup returns, for each given machine entity, |
245 // the instances that contain units of the services deployed to | 287 // a slice of instance.Ids that belong to the same distribution |
246 // that machine. | 288 // group as that machine. This information may be used to |
247 func (p *ProvisionerAPI) CommonServiceInstances(args params.Entities) (params.Co
mmonServiceInstancesResults, error) { | 289 // distribute instances for high availability. |
248 » result := params.CommonServiceInstancesResults{ | 290 func (p *ProvisionerAPI) DistributionGroup(args params.Entities) (params.Distrib
utionGroupResults, error) { |
249 » » Results: make([]params.CommonServiceInstancesResult, len(args.En
tities)), | 291 » result := params.DistributionGroupResults{ |
250 » } | 292 » » Results: make([]params.DistributionGroupResult, len(args.Entitie
s)), |
251 » canAccess, err := p.getAuthFunc() | 293 » } |
252 » if err != nil { | 294 » canAccess, err := p.getAuthFunc() |
253 » » return result, err | 295 » if err != nil { |
254 » } | 296 » » return result, err |
255 | 297 » } |
256 » cache := make(map[string][]instance.Id) // service -> []instance.Id | 298 » for i, entity := range args.Entities { |
257 » getInstanceIds := func(m *state.Machine) ([]instance.Id, error) { | 299 » » machine, err := p.getMachine(canAccess, entity.Tag) |
258 » » units, err := m.Units() | 300 » » if err == nil { |
| 301 » » » // If the machine is an environment manager, return |
| 302 » » » // environment manager instances. Otherwise, return |
| 303 » » » // instances with services in common with the machine |
| 304 » » » // being provisioned. |
| 305 » » » if machine.IsManager() { |
| 306 » » » » result.Results[i].Result, err = environManagerIn
stances(p.st) |
| 307 » » » } else { |
| 308 » » » » result.Results[i].Result, err = commonServiceIns
tances(p.st, machine) |
| 309 » » » } |
| 310 » » } |
| 311 » » result.Results[i].Error = common.ServerError(err) |
| 312 » } |
| 313 » return result, nil |
| 314 } |
| 315 |
| 316 // environManagerInstances returns all environ manager instances. |
| 317 func environManagerInstances(st *state.State) ([]instance.Id, error) { |
| 318 » info, err := st.StateServerInfo() |
| 319 » if err != nil { |
| 320 » » return nil, err |
| 321 » } |
| 322 » instances := make([]instance.Id, 0, len(info.MachineIds)) |
| 323 » for _, id := range info.MachineIds { |
| 324 » » machine, err := st.Machine(id) |
259 if err != nil { | 325 if err != nil { |
260 return nil, err | 326 return nil, err |
261 } | 327 } |
262 » » var instanceIdSet set.Strings | 328 » » instanceId, err := machine.InstanceId() |
263 » » for _, unit := range units { | 329 » » if err == nil { |
264 » » » if !unit.IsPrincipal() { | 330 » » » instances = append(instances, instanceId) |
| 331 » » } else if !state.IsNotProvisionedError(err) { |
| 332 » » » return nil, err |
| 333 » » } |
| 334 » } |
| 335 » return instances, nil |
| 336 } |
| 337 |
| 338 // commonServiceInstances returns instances with |
| 339 // services in common with the specified machine. |
| 340 func commonServiceInstances(st *state.State, m *state.Machine) ([]instance.Id, e
rror) { |
| 341 » units, err := m.Units() |
| 342 » if err != nil { |
| 343 » » return nil, err |
| 344 » } |
| 345 » var instanceIdSet set.Strings |
| 346 » for _, unit := range units { |
| 347 » » if !unit.IsPrincipal() { |
| 348 » » » continue |
| 349 » » } |
| 350 » » service, err := unit.Service() |
| 351 » » if err != nil { |
| 352 » » » return nil, err |
| 353 » » } |
| 354 » » allUnits, err := service.AllUnits() |
| 355 » » if err != nil { |
| 356 » » » return nil, err |
| 357 » » } |
| 358 » » for _, unit := range allUnits { |
| 359 » » » machineId, err := unit.AssignedMachineId() |
| 360 » » » if state.IsNotAssigned(err) { |
265 continue | 361 continue |
266 » » » } | 362 » » » } else if err != nil { |
267 » » » service, err := unit.Service() | 363 » » » » return nil, err |
| 364 » » » } |
| 365 » » » machine, err := st.Machine(machineId) |
268 if err != nil { | 366 if err != nil { |
269 return nil, err | 367 return nil, err |
270 } | 368 } |
271 » » » instanceIds, ok := cache[service.Name()] | 369 » » » instanceId, err := machine.InstanceId() |
272 » » » if !ok { | 370 » » » if err == nil { |
273 » » » » allUnits, err := service.AllUnits() | |
274 » » » » if err != nil { | |
275 » » » » » return nil, err | |
276 » » » » } | |
277 » » » » for _, unit := range allUnits { | |
278 » » » » » machineId, err := unit.AssignedMachineId
() | |
279 » » » » » if state.IsNotAssigned(err) { | |
280 » » » » » » continue | |
281 » » » » » } else if err != nil { | |
282 » » » » » » return nil, err | |
283 » » » » » } | |
284 » » » » » machine, err := p.st.Machine(machineId) | |
285 » » » » » if err != nil { | |
286 » » » » » » return nil, err | |
287 » » » » » } | |
288 » » » » » instanceId, err := machine.InstanceId() | |
289 » » » » » if err == nil { | |
290 » » » » » » instanceIds = append(instanceIds
, instanceId) | |
291 » » » » » } else if state.IsNotProvisionedError(er
r) { | |
292 » » » » » » continue | |
293 » » » » » } else { | |
294 » » » » » » return nil, err | |
295 » » » » » } | |
296 » » » » } | |
297 » » » » cache[service.Name()] = instanceIds | |
298 » » » } | |
299 » » » for _, instanceId := range instanceIds { | |
300 instanceIdSet.Add(string(instanceId)) | 371 instanceIdSet.Add(string(instanceId)) |
301 » » » } | 372 » » » } else if state.IsNotProvisionedError(err) { |
302 » » } | 373 » » » » continue |
303 » » instanceIds := make([]instance.Id, instanceIdSet.Size()) | 374 » » » } else { |
304 » » // Sort values to simplify testing. | 375 » » » » return nil, err |
305 » » for i, instanceId := range instanceIdSet.SortedValues() { | 376 » » » } |
306 » » » instanceIds[i] = instance.Id(instanceId) | 377 » » } |
307 » » } | 378 » } |
308 » » return instanceIds, nil | 379 » instanceIds := make([]instance.Id, instanceIdSet.Size()) |
309 » } | 380 » // Sort values to simplify testing. |
310 | 381 » for i, instanceId := range instanceIdSet.SortedValues() { |
311 » for i, entity := range args.Entities { | 382 » » instanceIds[i] = instance.Id(instanceId) |
312 » » machine, err := p.getMachine(canAccess, entity.Tag) | 383 » } |
313 » » if err == nil { | 384 » return instanceIds, nil |
314 » » » result.Results[i].Result, err = getInstanceIds(machine) | |
315 » » } | |
316 » » result.Results[i].Error = common.ServerError(err) | |
317 » } | |
318 » return result, nil | |
319 } | 385 } |
320 | 386 |
321 // Constraints returns the constraints for each given machine entity. | 387 // Constraints returns the constraints for each given machine entity. |
322 func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsRe
sults, error) { | 388 func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsRe
sults, error) { |
323 result := params.ConstraintsResults{ | 389 result := params.ConstraintsResults{ |
324 Results: make([]params.ConstraintsResult, len(args.Entities)), | 390 Results: make([]params.ConstraintsResult, len(args.Entities)), |
325 } | 391 } |
326 canAccess, err := p.getAuthFunc() | 392 canAccess, err := p.getAuthFunc() |
327 if err != nil { | 393 if err != nil { |
328 return result, err | 394 return result, err |
329 } | 395 } |
330 for i, entity := range args.Entities { | 396 for i, entity := range args.Entities { |
331 machine, err := p.getMachine(canAccess, entity.Tag) | 397 machine, err := p.getMachine(canAccess, entity.Tag) |
332 if err == nil { | 398 if err == nil { |
333 var cons constraints.Value | 399 var cons constraints.Value |
334 cons, err = machine.Constraints() | 400 cons, err = machine.Constraints() |
335 if err == nil { | 401 if err == nil { |
336 result.Results[i].Constraints = cons | 402 result.Results[i].Constraints = cons |
| 403 } |
| 404 } |
| 405 result.Results[i].Error = common.ServerError(err) |
| 406 } |
| 407 return result, nil |
| 408 } |
| 409 |
| 410 // Networks returns the networks for each given machine entity. |
| 411 func (p *ProvisionerAPI) Networks(args params.Entities) (params.NetworksResults,
error) { |
| 412 result := params.NetworksResults{ |
| 413 Results: make([]params.NetworkResult, len(args.Entities)), |
| 414 } |
| 415 canAccess, err := p.getAuthFunc() |
| 416 if err != nil { |
| 417 return result, err |
| 418 } |
| 419 for i, entity := range args.Entities { |
| 420 machine, err := p.getMachine(canAccess, entity.Tag) |
| 421 if err == nil { |
| 422 var includeNetworks []string |
| 423 var excludeNetworks []string |
| 424 includeNetworks, excludeNetworks, err = machine.Networks
() |
| 425 if err == nil { |
| 426 result.Results[i].IncludeNetworks = includeNetwo
rks |
| 427 result.Results[i].ExcludeNetworks = excludeNetwo
rks |
337 } | 428 } |
338 } | 429 } |
339 result.Results[i].Error = common.ServerError(err) | 430 result.Results[i].Error = common.ServerError(err) |
340 } | 431 } |
341 return result, nil | 432 return result, nil |
342 } | 433 } |
343 | 434 |
344 // SetProvisioned sets the provider specific machine id, nonce and | 435 // SetProvisioned sets the provider specific machine id, nonce and |
345 // metadata for each given machine. Once set, the instance id cannot | 436 // metadata for each given machine. Once set, the instance id cannot |
346 // be changed. | 437 // be changed. |
347 func (p *ProvisionerAPI) SetProvisioned(args params.SetProvisioned) (params.Erro
rResults, error) { | 438 func (p *ProvisionerAPI) SetProvisioned(args params.SetProvisioned) (params.Erro
rResults, error) { |
348 result := params.ErrorResults{ | 439 result := params.ErrorResults{ |
349 Results: make([]params.ErrorResult, len(args.Machines)), | 440 Results: make([]params.ErrorResult, len(args.Machines)), |
350 } | 441 } |
351 canAccess, err := p.getAuthFunc() | 442 canAccess, err := p.getAuthFunc() |
352 if err != nil { | 443 if err != nil { |
353 return result, err | 444 return result, err |
354 } | 445 } |
355 for i, arg := range args.Machines { | 446 for i, arg := range args.Machines { |
356 machine, err := p.getMachine(canAccess, arg.Tag) | 447 machine, err := p.getMachine(canAccess, arg.Tag) |
357 if err == nil { | 448 if err == nil { |
358 err = machine.SetProvisioned(arg.InstanceId, arg.Nonce,
arg.Characteristics) | 449 err = machine.SetProvisioned(arg.InstanceId, arg.Nonce,
arg.Characteristics) |
359 } | 450 } |
360 result.Results[i].Error = common.ServerError(err) | 451 result.Results[i].Error = common.ServerError(err) |
361 } | 452 } |
362 return result, nil | 453 return result, nil |
363 } | 454 } |
| 455 |
| 456 // WatchMachineErrorRetry returns a NotifyWatcher that notifies when |
| 457 // the provisioner should retry provisioning machines with transient errors. |
| 458 func (p *ProvisionerAPI) WatchMachineErrorRetry() (params.NotifyWatchResult, err
or) { |
| 459 result := params.NotifyWatchResult{} |
| 460 canWatch, err := p.getCanWatchMachines() |
| 461 if err != nil { |
| 462 return params.NotifyWatchResult{}, err |
| 463 } |
| 464 if !canWatch("") { |
| 465 return result, common.ErrPerm |
| 466 } |
| 467 watch := newWatchMachineErrorRetry() |
| 468 // Consume any initial event and forward it to the result. |
| 469 if _, ok := <-watch.Changes(); ok { |
| 470 result.NotifyWatcherId = p.resources.Register(watch) |
| 471 } else { |
| 472 return result, watcher.MustErr(watch) |
| 473 } |
| 474 return result, nil |
| 475 } |
LEFT | RIGHT |