github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/provisioner/provisioner.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 "github.com/juju/utils/set" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/common/networkingcommon" 16 "github.com/juju/juju/apiserver/common/storagecommon" 17 "github.com/juju/juju/apiserver/facade" 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/constraints" 20 "github.com/juju/juju/container" 21 "github.com/juju/juju/environs" 22 "github.com/juju/juju/instance" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/state/stateenvirons" 26 "github.com/juju/juju/state/watcher" 27 "github.com/juju/juju/status" 28 "github.com/juju/juju/storage" 29 "github.com/juju/juju/storage/poolmanager" 30 ) 31 32 var logger = loggo.GetLogger("juju.apiserver.provisioner") 33 34 func init() { 35 common.RegisterStandardFacade("Provisioner", 3, NewProvisionerAPI) 36 } 37 38 // ProvisionerAPI provides access to the Provisioner API facade. 39 type ProvisionerAPI struct { 40 *common.ControllerConfigAPI 41 *common.Remover 42 *common.StatusSetter 43 *common.StatusGetter 44 *common.DeadEnsurer 45 *common.PasswordChanger 46 *common.LifeGetter 47 *common.StateAddresser 48 *common.APIAddresser 49 *common.ModelWatcher 50 *common.ModelMachinesWatcher 51 *common.InstanceIdGetter 52 *common.ToolsFinder 53 *common.ToolsGetter 54 55 st *state.State 56 resources facade.Resources 57 authorizer facade.Authorizer 58 storageProviderRegistry storage.ProviderRegistry 59 storagePoolManager poolmanager.PoolManager 60 configGetter environs.EnvironConfigGetter 61 getAuthFunc common.GetAuthFunc 62 } 63 64 // NewProvisionerAPI creates a new server-side ProvisionerAPI facade. 65 func NewProvisionerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*ProvisionerAPI, error) { 66 if !authorizer.AuthMachineAgent() && !authorizer.AuthModelManager() { 67 return nil, common.ErrPerm 68 } 69 getAuthFunc := func() (common.AuthFunc, error) { 70 isModelManager := authorizer.AuthModelManager() 71 isMachineAgent := authorizer.AuthMachineAgent() 72 authEntityTag := authorizer.GetAuthTag() 73 74 return func(tag names.Tag) bool { 75 if isMachineAgent && tag == authEntityTag { 76 // A machine agent can always access its own machine. 77 return true 78 } 79 switch tag := tag.(type) { 80 case names.MachineTag: 81 parentId := state.ParentId(tag.Id()) 82 if parentId == "" { 83 // All top-level machines are accessible by the 84 // environment manager. 85 return isModelManager 86 } 87 // All containers with the authenticated machine as a 88 // parent are accessible by it. 89 // TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is 90 // only equal to nil, but it suggests someone is passing an authorizer 91 // with a nil tag. 92 return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag 93 default: 94 return false 95 } 96 }, nil 97 } 98 getAuthOwner := func() (common.AuthFunc, error) { 99 return authorizer.AuthOwner, nil 100 } 101 model, err := st.Model() 102 if err != nil { 103 return nil, err 104 } 105 configGetter := stateenvirons.EnvironConfigGetter{st} 106 env, err := environs.GetEnviron(configGetter, environs.New) 107 if err != nil { 108 return nil, err 109 } 110 urlGetter := common.NewToolsURLGetter(model.UUID(), st) 111 storageProviderRegistry := stateenvirons.NewStorageProviderRegistry(env) 112 return &ProvisionerAPI{ 113 Remover: common.NewRemover(st, false, getAuthFunc), 114 StatusSetter: common.NewStatusSetter(st, getAuthFunc), 115 StatusGetter: common.NewStatusGetter(st, getAuthFunc), 116 DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), 117 PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), 118 LifeGetter: common.NewLifeGetter(st, getAuthFunc), 119 StateAddresser: common.NewStateAddresser(st), 120 APIAddresser: common.NewAPIAddresser(st, resources), 121 ModelWatcher: common.NewModelWatcher(st, resources, authorizer), 122 ModelMachinesWatcher: common.NewModelMachinesWatcher(st, resources, authorizer), 123 ControllerConfigAPI: common.NewControllerConfig(st), 124 InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFunc), 125 ToolsFinder: common.NewToolsFinder(configGetter, st, urlGetter), 126 ToolsGetter: common.NewToolsGetter(st, configGetter, st, urlGetter, getAuthOwner), 127 st: st, 128 resources: resources, 129 authorizer: authorizer, 130 configGetter: configGetter, 131 storageProviderRegistry: storageProviderRegistry, 132 storagePoolManager: poolmanager.New(state.NewStateSettings(st), storageProviderRegistry), 133 getAuthFunc: getAuthFunc, 134 }, nil 135 } 136 137 func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag names.MachineTag) (*state.Machine, error) { 138 if !canAccess(tag) { 139 return nil, common.ErrPerm 140 } 141 entity, err := p.st.FindEntity(tag) 142 if err != nil { 143 return nil, err 144 } 145 // The authorization function guarantees that the tag represents a 146 // machine. 147 return entity.(*state.Machine), nil 148 } 149 150 func (p *ProvisionerAPI) watchOneMachineContainers(arg params.WatchContainer) (params.StringsWatchResult, error) { 151 nothing := params.StringsWatchResult{} 152 canAccess, err := p.getAuthFunc() 153 if err != nil { 154 return nothing, common.ErrPerm 155 } 156 tag, err := names.ParseMachineTag(arg.MachineTag) 157 if err != nil { 158 return nothing, common.ErrPerm 159 } 160 if !canAccess(tag) { 161 return nothing, common.ErrPerm 162 } 163 machine, err := p.st.Machine(tag.Id()) 164 if err != nil { 165 return nothing, err 166 } 167 var watch state.StringsWatcher 168 if arg.ContainerType != "" { 169 watch = machine.WatchContainers(instance.ContainerType(arg.ContainerType)) 170 } else { 171 watch = machine.WatchAllContainers() 172 } 173 // Consume the initial event and forward it to the result. 174 if changes, ok := <-watch.Changes(); ok { 175 return params.StringsWatchResult{ 176 StringsWatcherId: p.resources.Register(watch), 177 Changes: changes, 178 }, nil 179 } 180 return nothing, watcher.EnsureErr(watch) 181 } 182 183 // WatchContainers starts a StringsWatcher to watch containers deployed to 184 // any machine passed in args. 185 func (p *ProvisionerAPI) WatchContainers(args params.WatchContainers) (params.StringsWatchResults, error) { 186 result := params.StringsWatchResults{ 187 Results: make([]params.StringsWatchResult, len(args.Params)), 188 } 189 for i, arg := range args.Params { 190 watcherResult, err := p.watchOneMachineContainers(arg) 191 result.Results[i] = watcherResult 192 result.Results[i].Error = common.ServerError(err) 193 } 194 return result, nil 195 } 196 197 // WatchAllContainers starts a StringsWatcher to watch all containers deployed to 198 // any machine passed in args. 199 func (p *ProvisionerAPI) WatchAllContainers(args params.WatchContainers) (params.StringsWatchResults, error) { 200 return p.WatchContainers(args) 201 } 202 203 // SetSupportedContainers updates the list of containers supported by the machines passed in args. 204 func (p *ProvisionerAPI) SetSupportedContainers(args params.MachineContainersParams) (params.ErrorResults, error) { 205 result := params.ErrorResults{ 206 Results: make([]params.ErrorResult, len(args.Params)), 207 } 208 209 canAccess, err := p.getAuthFunc() 210 if err != nil { 211 return result, err 212 } 213 for i, arg := range args.Params { 214 tag, err := names.ParseMachineTag(arg.MachineTag) 215 if err != nil { 216 result.Results[i].Error = common.ServerError(common.ErrPerm) 217 continue 218 } 219 machine, err := p.getMachine(canAccess, tag) 220 if err != nil { 221 result.Results[i].Error = common.ServerError(err) 222 continue 223 } 224 if len(arg.ContainerTypes) == 0 { 225 err = machine.SupportsNoContainers() 226 } else { 227 err = machine.SetSupportedContainers(arg.ContainerTypes) 228 } 229 if err != nil { 230 result.Results[i].Error = common.ServerError(err) 231 } 232 } 233 return result, nil 234 } 235 236 // ContainerManagerConfig returns information from the environment config that is 237 // needed for configuring the container manager. 238 func (p *ProvisionerAPI) ContainerManagerConfig(args params.ContainerManagerConfigParams) (params.ContainerManagerConfig, error) { 239 var result params.ContainerManagerConfig 240 cfg := make(map[string]string) 241 cfg[container.ConfigModelUUID] = p.st.ModelUUID() 242 243 switch args.Type { 244 case instance.LXD: 245 // TODO(jam): DefaultMTU needs to be handled here 246 // TODO(jam): Do we want to handle ImageStream here, or do we 247 // hide it from them? (all cached images must come from the 248 // same image stream?) 249 } 250 251 result.ManagerConfig = cfg 252 return result, nil 253 } 254 255 // ContainerConfig returns information from the environment config that is 256 // needed for container cloud-init. 257 func (p *ProvisionerAPI) ContainerConfig() (params.ContainerConfig, error) { 258 result := params.ContainerConfig{} 259 config, err := p.st.ModelConfig() 260 if err != nil { 261 return result, err 262 } 263 264 result.UpdateBehavior = ¶ms.UpdateBehavior{ 265 config.EnableOSRefreshUpdate(), 266 config.EnableOSUpgrade(), 267 } 268 result.ProviderType = config.Type() 269 result.AuthorizedKeys = config.AuthorizedKeys() 270 result.SSLHostnameVerification = config.SSLHostnameVerification() 271 result.Proxy = config.ProxySettings() 272 result.AptProxy = config.AptProxySettings() 273 result.AptMirror = config.AptMirror() 274 275 return result, nil 276 } 277 278 // MachinesWithTransientErrors returns status data for machines with provisioning 279 // errors which are transient. 280 func (p *ProvisionerAPI) MachinesWithTransientErrors() (params.StatusResults, error) { 281 var results params.StatusResults 282 canAccessFunc, err := p.getAuthFunc() 283 if err != nil { 284 return results, err 285 } 286 // TODO (wallyworld) - add state.State API for more efficient machines query 287 machines, err := p.st.AllMachines() 288 if err != nil { 289 return results, err 290 } 291 for _, machine := range machines { 292 if !canAccessFunc(machine.Tag()) { 293 continue 294 } 295 if _, provisionedErr := machine.InstanceId(); provisionedErr == nil { 296 // Machine may have been provisioned but machiner hasn't set the 297 // status to Started yet. 298 continue 299 } 300 var result params.StatusResult 301 statusInfo, err := machine.Status() 302 if err != nil { 303 continue 304 } 305 result.Status = statusInfo.Status.String() 306 result.Info = statusInfo.Message 307 result.Data = statusInfo.Data 308 if statusInfo.Status != status.Error { 309 continue 310 } 311 // Transient errors are marked as such in the status data. 312 if transient, ok := result.Data["transient"].(bool); !ok || !transient { 313 continue 314 } 315 result.Id = machine.Id() 316 result.Life = params.Life(machine.Life().String()) 317 results.Results = append(results.Results, result) 318 } 319 return results, nil 320 } 321 322 // Series returns the deployed series for each given machine entity. 323 func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, error) { 324 result := params.StringResults{ 325 Results: make([]params.StringResult, len(args.Entities)), 326 } 327 canAccess, err := p.getAuthFunc() 328 if err != nil { 329 return result, err 330 } 331 for i, entity := range args.Entities { 332 tag, err := names.ParseMachineTag(entity.Tag) 333 if err != nil { 334 result.Results[i].Error = common.ServerError(common.ErrPerm) 335 continue 336 } 337 machine, err := p.getMachine(canAccess, tag) 338 if err == nil { 339 result.Results[i].Result = machine.Series() 340 } 341 result.Results[i].Error = common.ServerError(err) 342 } 343 return result, nil 344 } 345 346 // DistributionGroup returns, for each given machine entity, 347 // a slice of instance.Ids that belong to the same distribution 348 // group as that machine. This information may be used to 349 // distribute instances for high availability. 350 func (p *ProvisionerAPI) DistributionGroup(args params.Entities) (params.DistributionGroupResults, error) { 351 result := params.DistributionGroupResults{ 352 Results: make([]params.DistributionGroupResult, len(args.Entities)), 353 } 354 canAccess, err := p.getAuthFunc() 355 if err != nil { 356 return result, err 357 } 358 for i, entity := range args.Entities { 359 tag, err := names.ParseMachineTag(entity.Tag) 360 if err != nil { 361 result.Results[i].Error = common.ServerError(common.ErrPerm) 362 continue 363 } 364 machine, err := p.getMachine(canAccess, tag) 365 if err == nil { 366 // If the machine is an environment manager, return 367 // environment manager instances. Otherwise, return 368 // instances with services in common with the machine 369 // being provisioned. 370 if machine.IsManager() { 371 result.Results[i].Result, err = environManagerInstances(p.st) 372 } else { 373 result.Results[i].Result, err = commonServiceInstances(p.st, machine) 374 } 375 } 376 result.Results[i].Error = common.ServerError(err) 377 } 378 return result, nil 379 } 380 381 // environManagerInstances returns all environ manager instances. 382 func environManagerInstances(st *state.State) ([]instance.Id, error) { 383 info, err := st.ControllerInfo() 384 if err != nil { 385 return nil, err 386 } 387 instances := make([]instance.Id, 0, len(info.MachineIds)) 388 for _, id := range info.MachineIds { 389 machine, err := st.Machine(id) 390 if err != nil { 391 return nil, err 392 } 393 instanceId, err := machine.InstanceId() 394 if err == nil { 395 instances = append(instances, instanceId) 396 } else if !errors.IsNotProvisioned(err) { 397 return nil, err 398 } 399 } 400 return instances, nil 401 } 402 403 // commonServiceInstances returns instances with 404 // services in common with the specified machine. 405 func commonServiceInstances(st *state.State, m *state.Machine) ([]instance.Id, error) { 406 units, err := m.Units() 407 if err != nil { 408 return nil, err 409 } 410 instanceIdSet := make(set.Strings) 411 for _, unit := range units { 412 if !unit.IsPrincipal() { 413 continue 414 } 415 instanceIds, err := state.ServiceInstances(st, unit.ApplicationName()) 416 if err != nil { 417 return nil, err 418 } 419 for _, instanceId := range instanceIds { 420 instanceIdSet.Add(string(instanceId)) 421 } 422 } 423 instanceIds := make([]instance.Id, instanceIdSet.Size()) 424 // Sort values to simplify testing. 425 for i, instanceId := range instanceIdSet.SortedValues() { 426 instanceIds[i] = instance.Id(instanceId) 427 } 428 return instanceIds, nil 429 } 430 431 // Constraints returns the constraints for each given machine entity. 432 func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) { 433 result := params.ConstraintsResults{ 434 Results: make([]params.ConstraintsResult, len(args.Entities)), 435 } 436 canAccess, err := p.getAuthFunc() 437 if err != nil { 438 return result, err 439 } 440 for i, entity := range args.Entities { 441 tag, err := names.ParseMachineTag(entity.Tag) 442 if err != nil { 443 result.Results[i].Error = common.ServerError(common.ErrPerm) 444 continue 445 } 446 machine, err := p.getMachine(canAccess, tag) 447 if err == nil { 448 var cons constraints.Value 449 cons, err = machine.Constraints() 450 if err == nil { 451 result.Results[i].Constraints = cons 452 } 453 } 454 result.Results[i].Error = common.ServerError(err) 455 } 456 return result, nil 457 } 458 459 // SetInstanceInfo sets the provider specific machine id, nonce, 460 // metadata and network info for each given machine. Once set, the 461 // instance id cannot be changed. 462 func (p *ProvisionerAPI) SetInstanceInfo(args params.InstancesInfo) (params.ErrorResults, error) { 463 result := params.ErrorResults{ 464 Results: make([]params.ErrorResult, len(args.Machines)), 465 } 466 canAccess, err := p.getAuthFunc() 467 if err != nil { 468 return result, err 469 } 470 setInstanceInfo := func(arg params.InstanceInfo) error { 471 tag, err := names.ParseMachineTag(arg.Tag) 472 if err != nil { 473 return common.ErrPerm 474 } 475 machine, err := p.getMachine(canAccess, tag) 476 if err != nil { 477 return err 478 } 479 volumes, err := storagecommon.VolumesToState(arg.Volumes) 480 if err != nil { 481 return err 482 } 483 volumeAttachments, err := storagecommon.VolumeAttachmentInfosToState(arg.VolumeAttachments) 484 if err != nil { 485 return err 486 } 487 488 devicesArgs, devicesAddrs := networkingcommon.NetworkConfigsToStateArgs(arg.NetworkConfig) 489 490 err = machine.SetInstanceInfo( 491 arg.InstanceId, arg.Nonce, arg.Characteristics, 492 devicesArgs, devicesAddrs, 493 volumes, volumeAttachments, 494 ) 495 if err != nil { 496 return errors.Annotatef(err, "cannot record provisioning info for %q", arg.InstanceId) 497 } 498 return nil 499 } 500 for i, arg := range args.Machines { 501 err := setInstanceInfo(arg) 502 result.Results[i].Error = common.ServerError(err) 503 } 504 return result, nil 505 } 506 507 // WatchMachineErrorRetry returns a NotifyWatcher that notifies when 508 // the provisioner should retry provisioning machines with transient errors. 509 func (p *ProvisionerAPI) WatchMachineErrorRetry() (params.NotifyWatchResult, error) { 510 result := params.NotifyWatchResult{} 511 if !p.authorizer.AuthModelManager() { 512 return result, common.ErrPerm 513 } 514 watch := newWatchMachineErrorRetry() 515 // Consume any initial event and forward it to the result. 516 if _, ok := <-watch.Changes(); ok { 517 result.NotifyWatcherId = p.resources.Register(watch) 518 } else { 519 return result, watcher.EnsureErr(watch) 520 } 521 return result, nil 522 } 523 524 // ReleaseContainerAddresses finds addresses allocated to a container and marks 525 // them as Dead, to be released and removed. It accepts container tags as 526 // arguments. 527 func (p *ProvisionerAPI) ReleaseContainerAddresses(args params.Entities) (params.ErrorResults, error) { 528 result := params.ErrorResults{ 529 Results: make([]params.ErrorResult, len(args.Entities)), 530 } 531 532 canAccess, err := p.getAuthFunc() 533 if err != nil { 534 logger.Errorf("failed to get an authorisation function: %v", err) 535 return result, errors.Trace(err) 536 } 537 // Loop over the passed container tags. 538 for i, entity := range args.Entities { 539 tag, err := names.ParseMachineTag(entity.Tag) 540 if err != nil { 541 logger.Warningf("failed to parse machine tag %q: %v", entity.Tag, err) 542 result.Results[i].Error = common.ServerError(common.ErrPerm) 543 continue 544 } 545 546 // The auth function (canAccess) checks that the machine is a 547 // top level machine (we filter those out next) or that the 548 // machine has the host as a parent. 549 container, err := p.getMachine(canAccess, tag) 550 if err != nil { 551 logger.Warningf("failed to get machine %q: %v", tag, err) 552 result.Results[i].Error = common.ServerError(err) 553 continue 554 } else if !container.IsContainer() { 555 err = errors.Errorf("cannot mark addresses for removal for %q: not a container", tag) 556 result.Results[i].Error = common.ServerError(err) 557 continue 558 } 559 560 // TODO(dimitern): Release those via the provider once we have 561 // Environ.ReleaseContainerAddresses. See LP bug http://pad.lv/1585878 562 err = container.RemoveAllAddresses() 563 if err != nil { 564 logger.Warningf("failed to remove container %q addresses: %v", tag, err) 565 result.Results[i].Error = common.ServerError(err) 566 continue 567 } 568 } 569 570 return result, nil 571 } 572 573 // PrepareContainerInterfaceInfo allocates an address and returns information to 574 // configure networking for a container. It accepts container tags as arguments. 575 func (p *ProvisionerAPI) PrepareContainerInterfaceInfo(args params.Entities) ( 576 params.MachineNetworkConfigResults, 577 error, 578 ) { 579 return p.prepareOrGetContainerInterfaceInfo(args, false) 580 } 581 582 // GetContainerInterfaceInfo returns information to configure networking for a 583 // container. It accepts container tags as arguments. 584 func (p *ProvisionerAPI) GetContainerInterfaceInfo(args params.Entities) ( 585 params.MachineNetworkConfigResults, 586 error, 587 ) { 588 return p.prepareOrGetContainerInterfaceInfo(args, true) 589 } 590 591 func (p *ProvisionerAPI) prepareOrGetContainerInterfaceInfo(args params.Entities, maintain bool) (params.MachineNetworkConfigResults, error) { 592 result := params.MachineNetworkConfigResults{ 593 Results: make([]params.MachineNetworkConfigResult, len(args.Entities)), 594 } 595 596 netEnviron, hostMachine, canAccess, err := p.prepareContainerAccessEnvironment() 597 if err != nil { 598 return result, errors.Trace(err) 599 } 600 instId, err := hostMachine.InstanceId() 601 if errors.IsNotProvisioned(err) { 602 err = errors.NotProvisionedf("cannot prepare container network config: host machine %q", hostMachine) 603 return result, err 604 } else if err != nil { 605 return result, errors.Trace(err) 606 } 607 608 for i, entity := range args.Entities { 609 machineTag, err := names.ParseMachineTag(entity.Tag) 610 if err != nil { 611 result.Results[i].Error = common.ServerError(err) 612 continue 613 } 614 // The auth function (canAccess) checks that the machine is a 615 // top level machine (we filter those out next) or that the 616 // machine has the host as a parent. 617 container, err := p.getMachine(canAccess, machineTag) 618 if err != nil { 619 result.Results[i].Error = common.ServerError(err) 620 continue 621 } else if !container.IsContainer() { 622 err = errors.Errorf("cannot prepare network config for %q: not a container", machineTag) 623 result.Results[i].Error = common.ServerError(err) 624 continue 625 } else if ciid, cerr := container.InstanceId(); maintain == true && cerr == nil { 626 // Since we want to configure and create NICs on the 627 // container before it starts, it must also be not 628 // provisioned yet. 629 err = errors.Errorf("container %q already provisioned as %q", container, ciid) 630 result.Results[i].Error = common.ServerError(err) 631 continue 632 } else if cerr != nil && !errors.IsNotProvisioned(cerr) { 633 // Any other error needs to be reported. 634 result.Results[i].Error = common.ServerError(cerr) 635 continue 636 } 637 638 if err := hostMachine.SetContainerLinkLayerDevices(container); err != nil { 639 result.Results[i].Error = common.ServerError(err) 640 continue 641 } 642 643 containerDevices, err := container.AllLinkLayerDevices() 644 if err != nil { 645 result.Results[i].Error = common.ServerError(err) 646 continue 647 } 648 649 preparedInfo := make([]network.InterfaceInfo, len(containerDevices)) 650 preparedOK := true 651 for j, device := range containerDevices { 652 parentDevice, err := device.ParentDevice() 653 if err != nil || parentDevice == nil { 654 err = errors.Errorf( 655 "cannot get parent %q of container device %q: %v", 656 device.ParentName(), device.Name(), err, 657 ) 658 result.Results[i].Error = common.ServerError(err) 659 preparedOK = false 660 break 661 } 662 parentAddrs, err := parentDevice.Addresses() 663 if err != nil { 664 result.Results[i].Error = common.ServerError(err) 665 preparedOK = false 666 break 667 } 668 669 info := network.InterfaceInfo{ 670 InterfaceName: device.Name(), 671 MACAddress: device.MACAddress(), 672 ConfigType: network.ConfigManual, 673 InterfaceType: network.InterfaceType(device.Type()), 674 NoAutoStart: !device.IsAutoStart(), 675 Disabled: !device.IsUp(), 676 MTU: int(device.MTU()), 677 ParentInterfaceName: parentDevice.Name(), 678 } 679 680 if len(parentAddrs) > 0 { 681 logger.Infof("host machine device %q has addresses %v", parentDevice.Name(), parentAddrs) 682 683 firstAddress := parentAddrs[0] 684 parentDeviceSubnet, err := firstAddress.Subnet() 685 if err != nil { 686 err = errors.Annotatef(err, 687 "cannot get subnet %q used by address %q of host machine device %q", 688 firstAddress.SubnetCIDR(), firstAddress.Value(), parentDevice.Name(), 689 ) 690 result.Results[i].Error = common.ServerError(err) 691 preparedOK = false 692 break 693 } 694 info.ConfigType = network.ConfigStatic 695 info.CIDR = parentDeviceSubnet.CIDR() 696 info.ProviderSubnetId = parentDeviceSubnet.ProviderId() 697 info.VLANTag = parentDeviceSubnet.VLANTag() 698 } else { 699 logger.Infof("host machine device %q has no addresses %v", parentDevice.Name(), parentAddrs) 700 } 701 702 logger.Tracef("prepared info for container interface %q: %+v", info.InterfaceName, info) 703 preparedOK = true 704 preparedInfo[j] = info 705 } 706 707 if !preparedOK { 708 // Error result is already set. 709 continue 710 } 711 712 allocatedInfo, err := netEnviron.AllocateContainerAddresses(instId, machineTag, preparedInfo) 713 if err != nil { 714 result.Results[i].Error = common.ServerError(err) 715 continue 716 } 717 logger.Debugf("got allocated info from provider: %+v", allocatedInfo) 718 719 allocatedConfig := networkingcommon.NetworkConfigFromInterfaceInfo(allocatedInfo) 720 logger.Tracef("allocated network config: %+v", allocatedConfig) 721 result.Results[i].Config = allocatedConfig 722 } 723 return result, nil 724 } 725 726 // prepareContainerAccessEnvironment retrieves the environment, host machine, and access 727 // for working with containers. 728 func (p *ProvisionerAPI) prepareContainerAccessEnvironment() (environs.NetworkingEnviron, *state.Machine, common.AuthFunc, error) { 729 netEnviron, err := networkingcommon.NetworkingEnvironFromModelConfig(p.configGetter) 730 if err != nil { 731 return nil, nil, nil, errors.Trace(err) 732 } 733 734 canAccess, err := p.getAuthFunc() 735 if err != nil { 736 return nil, nil, nil, errors.Annotate(err, "cannot authenticate request") 737 } 738 hostAuthTag := p.authorizer.GetAuthTag() 739 if hostAuthTag == nil { 740 return nil, nil, nil, errors.Errorf("authenticated entity tag is nil") 741 } 742 hostTag, err := names.ParseMachineTag(hostAuthTag.String()) 743 if err != nil { 744 return nil, nil, nil, errors.Trace(err) 745 } 746 host, err := p.getMachine(canAccess, hostTag) 747 if err != nil { 748 return nil, nil, nil, errors.Trace(err) 749 } 750 return netEnviron, host, canAccess, nil 751 } 752 753 // InstanceStatus returns the instance status for each given entity. 754 // Only machine tags are accepted. 755 func (p *ProvisionerAPI) InstanceStatus(args params.Entities) (params.StatusResults, error) { 756 result := params.StatusResults{ 757 Results: make([]params.StatusResult, len(args.Entities)), 758 } 759 canAccess, err := p.getAuthFunc() 760 if err != nil { 761 logger.Errorf("failed to get an authorisation function: %v", err) 762 return result, errors.Trace(err) 763 } 764 for i, arg := range args.Entities { 765 mTag, err := names.ParseMachineTag(arg.Tag) 766 if err != nil { 767 result.Results[i].Error = common.ServerError(err) 768 continue 769 } 770 machine, err := p.getMachine(canAccess, mTag) 771 if err == nil { 772 var statusInfo status.StatusInfo 773 statusInfo, err = machine.InstanceStatus() 774 result.Results[i].Status = statusInfo.Status.String() 775 result.Results[i].Info = statusInfo.Message 776 result.Results[i].Data = statusInfo.Data 777 result.Results[i].Since = statusInfo.Since 778 } 779 result.Results[i].Error = common.ServerError(err) 780 } 781 return result, nil 782 } 783 784 // SetInstanceStatus updates the instance status for each given 785 // entity. Only machine tags are accepted. 786 func (p *ProvisionerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) { 787 result := params.ErrorResults{ 788 Results: make([]params.ErrorResult, len(args.Entities)), 789 } 790 canAccess, err := p.getAuthFunc() 791 if err != nil { 792 logger.Errorf("failed to get an authorisation function: %v", err) 793 return result, errors.Trace(err) 794 } 795 for i, arg := range args.Entities { 796 mTag, err := names.ParseMachineTag(arg.Tag) 797 if err != nil { 798 result.Results[i].Error = common.ServerError(err) 799 continue 800 } 801 machine, err := p.getMachine(canAccess, mTag) 802 if err == nil { 803 // TODO(perrito666) 2016-05-02 lp:1558657 804 now := time.Now() 805 s := status.StatusInfo{ 806 Status: status.Status(arg.Status), 807 Message: arg.Info, 808 Data: arg.Data, 809 Since: &now, 810 } 811 err = machine.SetInstanceStatus(s) 812 } 813 result.Results[i].Error = common.ServerError(err) 814 } 815 return result, nil 816 } 817 818 // MarkMachinesForRemoval indicates that the specified machines are 819 // ready to have any provider-level resources cleaned up and then be 820 // removed. 821 func (p *ProvisionerAPI) MarkMachinesForRemoval(machines params.Entities) (params.ErrorResults, error) { 822 results := make([]params.ErrorResult, len(machines.Entities)) 823 canAccess, err := p.getAuthFunc() 824 if err != nil { 825 logger.Errorf("failed to get an authorisation function: %v", err) 826 return params.ErrorResults{}, errors.Trace(err) 827 } 828 for i, machine := range machines.Entities { 829 results[i].Error = common.ServerError(p.markOneMachineForRemoval(machine.Tag, canAccess)) 830 } 831 return params.ErrorResults{Results: results}, nil 832 } 833 834 func (p *ProvisionerAPI) markOneMachineForRemoval(machineTag string, canAccess common.AuthFunc) error { 835 mTag, err := names.ParseMachineTag(machineTag) 836 if err != nil { 837 return errors.Trace(err) 838 } 839 machine, err := p.getMachine(canAccess, mTag) 840 if err != nil { 841 return errors.Trace(err) 842 } 843 return machine.MarkForRemoval() 844 }