github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/uniter/uniter.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package uniter implements the API interface used by the uniter worker. 5 package uniter 6 7 import ( 8 "fmt" 9 "strings" 10 11 "github.com/juju/collections/set" 12 "github.com/juju/errors" 13 "github.com/juju/juju/environs" 14 "github.com/juju/loggo" 15 "gopkg.in/juju/charm.v6" 16 "gopkg.in/juju/names.v2" 17 18 "github.com/juju/juju/apiserver/common" 19 "github.com/juju/juju/apiserver/common/cloudspec" 20 "github.com/juju/juju/apiserver/common/networkingcommon" 21 "github.com/juju/juju/apiserver/facade" 22 leadershipapiserver "github.com/juju/juju/apiserver/facades/agent/leadership" 23 "github.com/juju/juju/apiserver/facades/agent/meterstatus" 24 "github.com/juju/juju/apiserver/facades/client/application" 25 "github.com/juju/juju/apiserver/params" 26 "github.com/juju/juju/caas" 27 "github.com/juju/juju/core/leadership" 28 corenetwork "github.com/juju/juju/core/network" 29 "github.com/juju/juju/core/status" 30 "github.com/juju/juju/network" 31 "github.com/juju/juju/state" 32 "github.com/juju/juju/state/multiwatcher" 33 "github.com/juju/juju/state/watcher" 34 ) 35 36 var logger = loggo.GetLogger("juju.apiserver.uniter") 37 38 // UniterAPI implements the latest version (v9) of the Uniter API, 39 // which adds WatchConfigSettingsHash, WatchTrustConfigSettingsHash 40 // and WatchUnitAddressesHash. 41 type UniterAPI struct { 42 *common.LifeGetter 43 *StatusAPI 44 *common.DeadEnsurer 45 *common.AgentEntityWatcher 46 *common.APIAddresser 47 *common.ModelWatcher 48 *common.RebootRequester 49 *common.UpgradeSeriesAPI 50 *LXDProfileAPI 51 *leadershipapiserver.LeadershipSettingsAccessor 52 meterstatus.MeterStatus 53 m *state.Model 54 st *state.State 55 auth facade.Authorizer 56 resources facade.Resources 57 leadershipChecker leadership.Checker 58 accessUnit common.GetAuthFunc 59 accessApplication common.GetAuthFunc 60 accessMachine common.GetAuthFunc 61 *StorageAPI 62 63 // A cloud spec can only be accessed for the model of the unit or 64 // application that is authorised for this API facade. 65 // We do not need to use an AuthFunc, because we do not need to pass a tag. 66 accessCloudSpec func() (func() bool, error) 67 cloudSpec cloudspec.CloudSpecAPI 68 } 69 70 // UniterAPIV8 adds SetContainerSpec, GoalStates, CloudSpec, 71 // WatchTrustConfigSettings, WatchActionNotifications, 72 // UpgradeSeriesStatus, SetUpgradeSeriesStatus. 73 type UniterAPIV8 struct { 74 UniterAPI 75 } 76 77 // UniterAPIV7 adds CMR support to NetworkInfo. 78 type UniterAPIV7 struct { 79 UniterAPIV8 80 } 81 82 // UniterAPIV6 adds NetworkInfo as a preferred method to calling NetworkConfig. 83 type UniterAPIV6 struct { 84 UniterAPIV7 85 } 86 87 // UniterAPIV5 returns a RelationResultsV5 instead of RelationResults 88 // from Relation and RelationById - elements don't have an 89 // OtherApplication field. 90 type UniterAPIV5 struct { 91 UniterAPIV6 92 } 93 94 // UniterAPIV4 has old WatchApplicationRelations and NetworkConfig 95 // methods, and doesn't have the new SLALevel, NetworkInfo or 96 // WatchUnitRelations methods. 97 type UniterAPIV4 struct { 98 UniterAPIV5 99 } 100 101 // NewUniterAPI creates a new instance of the core Uniter API. 102 func NewUniterAPI(context facade.Context) (*UniterAPI, error) { 103 authorizer := context.Auth() 104 if !authorizer.AuthUnitAgent() && !authorizer.AuthApplicationAgent() { 105 return nil, common.ErrPerm 106 } 107 st := context.State() 108 resources := context.Resources() 109 leadershipChecker, err := context.LeadershipChecker() 110 if err != nil { 111 return nil, errors.Trace(err) 112 } 113 accessUnit := func() (common.AuthFunc, error) { 114 switch tag := authorizer.GetAuthTag().(type) { 115 case names.ApplicationTag: 116 // If called by an application agent, any of the units 117 // belonging to that application can be accessed. 118 app, err := st.Application(tag.Name) 119 if err != nil { 120 return nil, errors.Trace(err) 121 } 122 allUnits, err := app.AllUnits() 123 if err != nil { 124 return nil, errors.Trace(err) 125 } 126 return func(tag names.Tag) bool { 127 for _, u := range allUnits { 128 if u.Tag() == tag { 129 return true 130 } 131 } 132 return false 133 }, nil 134 case names.UnitTag: 135 return func(tag names.Tag) bool { 136 return authorizer.AuthOwner(tag) 137 }, nil 138 default: 139 return nil, errors.Errorf("expected names.UnitTag or names.ApplicationTag, got %T", tag) 140 } 141 } 142 accessApplication := func() (common.AuthFunc, error) { 143 switch tag := authorizer.GetAuthTag().(type) { 144 case names.ApplicationTag: 145 return func(applicationTag names.Tag) bool { 146 return tag == applicationTag 147 }, nil 148 case names.UnitTag: 149 entity, err := st.Unit(tag.Id()) 150 if err != nil { 151 return nil, errors.Trace(err) 152 } 153 applicationName := entity.ApplicationName() 154 applicationTag := names.NewApplicationTag(applicationName) 155 return func(tag names.Tag) bool { 156 return tag == applicationTag 157 }, nil 158 default: 159 return nil, errors.Errorf("expected names.UnitTag or names.ApplicationTag, got %T", tag) 160 } 161 } 162 accessMachine := func() (common.AuthFunc, error) { 163 switch tag := authorizer.GetAuthTag().(type) { 164 // Application agents can't access machines. 165 case names.ApplicationTag: 166 return func(tag names.Tag) bool { 167 return false 168 }, nil 169 case names.UnitTag: 170 entity, err := st.Unit(tag.Id()) 171 if err != nil { 172 return nil, errors.Trace(err) 173 } 174 machineId, err := entity.AssignedMachineId() 175 if err != nil { 176 return nil, errors.Trace(err) 177 } 178 machineTag := names.NewMachineTag(machineId) 179 return func(tag names.Tag) bool { 180 return tag == machineTag 181 }, nil 182 default: 183 return nil, errors.Errorf("expected names.UnitTag or names.ApplicationTag, got %T", tag) 184 } 185 } 186 accessCloudSpec := func() (func() bool, error) { 187 var appName string 188 var err error 189 190 switch tag := authorizer.GetAuthTag().(type) { 191 case names.ApplicationTag: 192 appName = tag.String() 193 case names.UnitTag: 194 entity, err := st.Unit(tag.Id()) 195 if err != nil { 196 return nil, errors.Trace(err) 197 } 198 appName = entity.ApplicationName() 199 default: 200 return nil, errors.Errorf("expected names.UnitTag or names.ApplicationTag, got %T", tag) 201 } 202 203 app, err := st.Application(appName) 204 if err != nil { 205 return nil, errors.Trace(err) 206 } 207 config, err := app.ApplicationConfig() 208 if err != nil { 209 return nil, errors.Trace(err) 210 } 211 return func() bool { 212 return config.GetBool(application.TrustConfigOptionName, false) 213 }, nil 214 } 215 216 m, err := st.Model() 217 if err != nil { 218 return nil, errors.Trace(err) 219 } 220 221 storageAccessor, err := getStorageState(st) 222 storageAPI, err := newStorageAPI( 223 stateShim{st}, storageAccessor, resources, accessUnit) 224 if err != nil { 225 return nil, err 226 } 227 msAPI, err := meterstatus.NewMeterStatusAPI(st, resources, authorizer) 228 if err != nil { 229 return nil, errors.Annotate(err, "could not create meter status API handler") 230 } 231 accessUnitOrApplication := common.AuthAny(accessUnit, accessApplication) 232 233 cloudSpec := cloudspec.NewCloudSpec( 234 cloudspec.MakeCloudSpecGetterForModel(st), 235 common.AuthFuncForTag(m.ModelTag()), 236 ) 237 238 return &UniterAPI{ 239 LifeGetter: common.NewLifeGetter(st, accessUnitOrApplication), 240 DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), 241 AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrApplication), 242 APIAddresser: common.NewAPIAddresser(st, resources), 243 ModelWatcher: common.NewModelWatcher(m, resources, authorizer), 244 RebootRequester: common.NewRebootRequester(st, accessMachine), 245 UpgradeSeriesAPI: common.NewExternalUpgradeSeriesAPI(st, resources, authorizer, accessMachine, accessUnit, logger), 246 LXDProfileAPI: NewExternalLXDProfileAPI(st, resources, authorizer, accessMachine, accessUnit, logger), 247 LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, leadershipChecker, resources, authorizer), 248 MeterStatus: msAPI, 249 // TODO(fwereade): so *every* unit should be allowed to get/set its 250 // own status *and* its application's? This is not a pleasing arrangement. 251 StatusAPI: NewStatusAPI(st, accessUnitOrApplication), 252 253 st: st, 254 m: m, 255 auth: authorizer, 256 resources: resources, 257 leadershipChecker: leadershipChecker, 258 accessUnit: accessUnit, 259 accessApplication: accessApplication, 260 accessMachine: accessMachine, 261 accessCloudSpec: accessCloudSpec, 262 cloudSpec: cloudSpec, 263 StorageAPI: storageAPI, 264 }, nil 265 } 266 267 // NewUniterAPIV8 creates an instance of the V8 uniter API. 268 func NewUniterAPIV8(context facade.Context) (*UniterAPIV8, error) { 269 uniterAPI, err := NewUniterAPI(context) 270 if err != nil { 271 return nil, err 272 } 273 return &UniterAPIV8{ 274 UniterAPI: *uniterAPI, 275 }, nil 276 } 277 278 // NewUniterAPIV7 creates an instance of the V7 uniter API. 279 func NewUniterAPIV7(context facade.Context) (*UniterAPIV7, error) { 280 uniterAPI, err := NewUniterAPIV8(context) 281 if err != nil { 282 return nil, err 283 } 284 return &UniterAPIV7{ 285 UniterAPIV8: *uniterAPI, 286 }, nil 287 } 288 289 // NewUniterAPIV6 creates an instance of the V6 uniter API. 290 func NewUniterAPIV6(context facade.Context) (*UniterAPIV6, error) { 291 uniterAPI, err := NewUniterAPIV7(context) 292 if err != nil { 293 return nil, err 294 } 295 return &UniterAPIV6{ 296 UniterAPIV7: *uniterAPI, 297 }, nil 298 } 299 300 // NewUniterAPIV5 creates an instance of the V5 uniter API. 301 func NewUniterAPIV5(context facade.Context) (*UniterAPIV5, error) { 302 uniterAPI, err := NewUniterAPIV6(context) 303 if err != nil { 304 return nil, err 305 } 306 return &UniterAPIV5{ 307 UniterAPIV6: *uniterAPI, 308 }, nil 309 } 310 311 // NewUniterAPIV4 creates an instance of the V4 uniter API. 312 func NewUniterAPIV4(context facade.Context) (*UniterAPIV4, error) { 313 uniterAPI, err := NewUniterAPIV5(context) 314 if err != nil { 315 return nil, err 316 } 317 return &UniterAPIV4{ 318 UniterAPIV5: *uniterAPI, 319 }, nil 320 } 321 322 // AllMachinePorts returns all opened port ranges for each given 323 // machine (on all networks). 324 func (u *UniterAPI) AllMachinePorts(args params.Entities) (params.MachinePortsResults, error) { 325 result := params.MachinePortsResults{ 326 Results: make([]params.MachinePortsResult, len(args.Entities)), 327 } 328 canAccess, err := u.accessMachine() 329 if err != nil { 330 return params.MachinePortsResults{}, err 331 } 332 for i, entity := range args.Entities { 333 result.Results[i] = u.getOneMachinePorts(canAccess, entity.Tag) 334 } 335 return result, nil 336 } 337 338 // AssignedMachine returns the machine tag for each given unit tag, or 339 // an error satisfying params.IsCodeNotAssigned when a unit has no 340 // assigned machine. 341 func (u *UniterAPI) AssignedMachine(args params.Entities) (params.StringResults, error) { 342 result := params.StringResults{ 343 Results: make([]params.StringResult, len(args.Entities)), 344 } 345 canAccess, err := u.accessUnit() 346 if err != nil { 347 return params.StringResults{}, err 348 } 349 for i, entity := range args.Entities { 350 tag, err := names.ParseUnitTag(entity.Tag) 351 if err != nil { 352 result.Results[i].Error = common.ServerError(common.ErrPerm) 353 continue 354 } 355 if !canAccess(tag) { 356 result.Results[i].Error = common.ServerError(common.ErrPerm) 357 continue 358 } 359 unit, err := u.getUnit(tag) 360 if err != nil { 361 result.Results[i].Error = common.ServerError(err) 362 continue 363 } 364 machineId, err := unit.AssignedMachineId() 365 if err != nil { 366 result.Results[i].Error = common.ServerError(err) 367 } else { 368 result.Results[i].Result = names.NewMachineTag(machineId).String() 369 } 370 } 371 return result, nil 372 } 373 374 func (u *UniterAPI) getMachine(tag names.MachineTag) (*state.Machine, error) { 375 return u.st.Machine(tag.Id()) 376 } 377 378 func (u *UniterAPI) getOneMachinePorts(canAccess common.AuthFunc, machineTag string) params.MachinePortsResult { 379 tag, err := names.ParseMachineTag(machineTag) 380 if err != nil { 381 return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)} 382 } 383 if !canAccess(tag) { 384 return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)} 385 } 386 machine, err := u.getMachine(tag) 387 if err != nil { 388 return params.MachinePortsResult{Error: common.ServerError(err)} 389 } 390 allPorts, err := machine.AllPorts() 391 if err != nil { 392 return params.MachinePortsResult{Error: common.ServerError(err)} 393 } 394 var resultPorts []params.MachinePortRange 395 for _, ports := range allPorts { 396 // AllPortRanges gives a map, but apis require a stable order 397 // for results, so sort the port ranges. 398 portRangesToUnits := ports.AllPortRanges() 399 portRanges := make([]corenetwork.PortRange, 0, len(portRangesToUnits)) 400 for portRange := range portRangesToUnits { 401 portRanges = append(portRanges, portRange) 402 } 403 corenetwork.SortPortRanges(portRanges) 404 for _, portRange := range portRanges { 405 unitName := portRangesToUnits[portRange] 406 resultPorts = append(resultPorts, params.MachinePortRange{ 407 UnitTag: names.NewUnitTag(unitName).String(), 408 PortRange: params.FromNetworkPortRange(portRange), 409 }) 410 } 411 } 412 return params.MachinePortsResult{ 413 Ports: resultPorts, 414 } 415 } 416 417 // PublicAddress returns the public address for each given unit, if set. 418 func (u *UniterAPI) PublicAddress(args params.Entities) (params.StringResults, error) { 419 result := params.StringResults{ 420 Results: make([]params.StringResult, len(args.Entities)), 421 } 422 canAccess, err := u.accessUnit() 423 if err != nil { 424 return params.StringResults{}, err 425 } 426 for i, entity := range args.Entities { 427 tag, err := names.ParseUnitTag(entity.Tag) 428 if err != nil { 429 result.Results[i].Error = common.ServerError(common.ErrPerm) 430 continue 431 } 432 err = common.ErrPerm 433 if canAccess(tag) { 434 var unit *state.Unit 435 unit, err = u.getUnit(tag) 436 if err == nil { 437 var address network.Address 438 address, err = unit.PublicAddress() 439 if err == nil { 440 result.Results[i].Result = address.Value 441 } else if network.IsNoAddressError(err) { 442 err = common.NoAddressSetError(tag, "public") 443 } 444 } 445 } 446 result.Results[i].Error = common.ServerError(err) 447 } 448 return result, nil 449 } 450 451 // PrivateAddress returns the private address for each given unit, if set. 452 func (u *UniterAPI) PrivateAddress(args params.Entities) (params.StringResults, error) { 453 result := params.StringResults{ 454 Results: make([]params.StringResult, len(args.Entities)), 455 } 456 canAccess, err := u.accessUnit() 457 if err != nil { 458 return params.StringResults{}, err 459 } 460 for i, entity := range args.Entities { 461 tag, err := names.ParseUnitTag(entity.Tag) 462 if err != nil { 463 result.Results[i].Error = common.ServerError(common.ErrPerm) 464 continue 465 } 466 err = common.ErrPerm 467 if canAccess(tag) { 468 var unit *state.Unit 469 unit, err = u.getUnit(tag) 470 if err == nil { 471 var address network.Address 472 address, err = unit.PrivateAddress() 473 if err == nil { 474 result.Results[i].Result = address.Value 475 } else if network.IsNoAddressError(err) { 476 err = common.NoAddressSetError(tag, "private") 477 } 478 } 479 } 480 result.Results[i].Error = common.ServerError(err) 481 } 482 return result, nil 483 } 484 485 // TODO(ericsnow) Factor out the common code amongst the many methods here. 486 487 var getZone = func(st *state.State, tag names.Tag) (string, error) { 488 unit, err := st.Unit(tag.Id()) 489 if err != nil { 490 return "", errors.Trace(err) 491 } 492 zone, err := unit.AvailabilityZone() 493 return zone, errors.Trace(err) 494 } 495 496 // AvailabilityZone returns the availability zone for each given unit, if applicable. 497 func (u *UniterAPI) AvailabilityZone(args params.Entities) (params.StringResults, error) { 498 var results params.StringResults 499 500 canAccess, err := u.accessUnit() 501 if err != nil { 502 return results, errors.Trace(err) 503 } 504 505 // Prep the results. 506 results = params.StringResults{ 507 Results: make([]params.StringResult, len(args.Entities)), 508 } 509 510 // Collect the zones. No zone will be collected for any entity where 511 // the tag is invalid or not authorized. Instead the corresponding 512 // result will be updated with the error. 513 for i, entity := range args.Entities { 514 tag, err := names.ParseUnitTag(entity.Tag) 515 if err != nil { 516 results.Results[i].Error = common.ServerError(common.ErrPerm) 517 continue 518 } 519 err = common.ErrPerm 520 if canAccess(tag) { 521 var zone string 522 zone, err = getZone(u.st, tag) 523 if err == nil { 524 results.Results[i].Result = zone 525 } 526 } 527 results.Results[i].Error = common.ServerError(err) 528 } 529 530 return results, nil 531 } 532 533 // Resolved returns the current resolved setting for each given unit. 534 func (u *UniterAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) { 535 result := params.ResolvedModeResults{ 536 Results: make([]params.ResolvedModeResult, len(args.Entities)), 537 } 538 canAccess, err := u.accessUnit() 539 if err != nil { 540 return params.ResolvedModeResults{}, err 541 } 542 for i, entity := range args.Entities { 543 tag, err := names.ParseUnitTag(entity.Tag) 544 if err != nil { 545 result.Results[i].Error = common.ServerError(common.ErrPerm) 546 continue 547 } 548 err = common.ErrPerm 549 if canAccess(tag) { 550 var unit *state.Unit 551 unit, err = u.getUnit(tag) 552 if err == nil { 553 result.Results[i].Mode = params.ResolvedMode(unit.Resolved()) 554 } 555 } 556 result.Results[i].Error = common.ServerError(err) 557 } 558 return result, nil 559 } 560 561 // ClearResolved removes any resolved setting from each given unit. 562 func (u *UniterAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) { 563 result := params.ErrorResults{ 564 Results: make([]params.ErrorResult, len(args.Entities)), 565 } 566 canAccess, err := u.accessUnit() 567 if err != nil { 568 return params.ErrorResults{}, err 569 } 570 for i, entity := range args.Entities { 571 tag, err := names.ParseUnitTag(entity.Tag) 572 if err != nil { 573 result.Results[i].Error = common.ServerError(common.ErrPerm) 574 continue 575 } 576 err = common.ErrPerm 577 if canAccess(tag) { 578 var unit *state.Unit 579 unit, err = u.getUnit(tag) 580 if err == nil { 581 err = unit.ClearResolved() 582 } 583 } 584 result.Results[i].Error = common.ServerError(err) 585 } 586 return result, nil 587 } 588 589 // GetPrincipal returns the result of calling PrincipalName() and 590 // converting it to a tag, on each given unit. 591 func (u *UniterAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) { 592 result := params.StringBoolResults{ 593 Results: make([]params.StringBoolResult, len(args.Entities)), 594 } 595 canAccess, err := u.accessUnit() 596 if err != nil { 597 return params.StringBoolResults{}, err 598 } 599 for i, entity := range args.Entities { 600 tag, err := names.ParseUnitTag(entity.Tag) 601 if err != nil { 602 result.Results[i].Error = common.ServerError(common.ErrPerm) 603 continue 604 } 605 err = common.ErrPerm 606 if canAccess(tag) { 607 var unit *state.Unit 608 unit, err = u.getUnit(tag) 609 if err == nil { 610 principal, ok := unit.PrincipalName() 611 if principal != "" { 612 result.Results[i].Result = names.NewUnitTag(principal).String() 613 } 614 result.Results[i].Ok = ok 615 } 616 } 617 result.Results[i].Error = common.ServerError(err) 618 } 619 return result, nil 620 } 621 622 // Destroy advances all given Alive units' lifecycles as far as 623 // possible. See state/Unit.Destroy(). 624 func (u *UniterAPI) Destroy(args params.Entities) (params.ErrorResults, error) { 625 result := params.ErrorResults{ 626 Results: make([]params.ErrorResult, len(args.Entities)), 627 } 628 canAccess, err := u.accessUnit() 629 if err != nil { 630 return params.ErrorResults{}, err 631 } 632 for i, entity := range args.Entities { 633 tag, err := names.ParseUnitTag(entity.Tag) 634 if err != nil { 635 result.Results[i].Error = common.ServerError(common.ErrPerm) 636 continue 637 } 638 err = common.ErrPerm 639 if canAccess(tag) { 640 var unit *state.Unit 641 unit, err = u.getUnit(tag) 642 if err == nil { 643 err = unit.Destroy() 644 } 645 } 646 result.Results[i].Error = common.ServerError(err) 647 } 648 return result, nil 649 } 650 651 // DestroyAllSubordinates destroys all subordinates of each given unit. 652 func (u *UniterAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) { 653 result := params.ErrorResults{ 654 Results: make([]params.ErrorResult, len(args.Entities)), 655 } 656 canAccess, err := u.accessUnit() 657 if err != nil { 658 return params.ErrorResults{}, err 659 } 660 for i, entity := range args.Entities { 661 tag, err := names.ParseUnitTag(entity.Tag) 662 if err != nil { 663 result.Results[i].Error = common.ServerError(common.ErrPerm) 664 continue 665 } 666 err = common.ErrPerm 667 if canAccess(tag) { 668 var unit *state.Unit 669 unit, err = u.getUnit(tag) 670 if err == nil { 671 err = u.destroySubordinates(unit) 672 } 673 } 674 result.Results[i].Error = common.ServerError(err) 675 } 676 return result, nil 677 } 678 679 // HasSubordinates returns the whether each given unit has any subordinates. 680 func (u *UniterAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) { 681 result := params.BoolResults{ 682 Results: make([]params.BoolResult, len(args.Entities)), 683 } 684 canAccess, err := u.accessUnit() 685 if err != nil { 686 return params.BoolResults{}, err 687 } 688 for i, entity := range args.Entities { 689 tag, err := names.ParseUnitTag(entity.Tag) 690 if err != nil { 691 result.Results[i].Error = common.ServerError(common.ErrPerm) 692 continue 693 } 694 err = common.ErrPerm 695 if canAccess(tag) { 696 var unit *state.Unit 697 unit, err = u.getUnit(tag) 698 if err == nil { 699 subordinates := unit.SubordinateNames() 700 result.Results[i].Result = len(subordinates) > 0 701 } 702 } 703 result.Results[i].Error = common.ServerError(err) 704 } 705 return result, nil 706 } 707 708 // CharmModifiedVersion returns the most CharmModifiedVersion for all given 709 // units or applications. 710 func (u *UniterAPI) CharmModifiedVersion(args params.Entities) (params.IntResults, error) { 711 results := params.IntResults{ 712 Results: make([]params.IntResult, len(args.Entities)), 713 } 714 715 accessUnitOrApplication := common.AuthAny(u.accessUnit, u.accessApplication) 716 canAccess, err := accessUnitOrApplication() 717 if err != nil { 718 return results, err 719 } 720 for i, entity := range args.Entities { 721 ver, err := u.charmModifiedVersion(entity.Tag, canAccess) 722 if err != nil { 723 results.Results[i].Error = common.ServerError(err) 724 continue 725 } 726 results.Results[i].Result = ver 727 } 728 return results, nil 729 } 730 731 func (u *UniterAPI) charmModifiedVersion(tagStr string, canAccess func(names.Tag) bool) (int, error) { 732 tag, err := names.ParseTag(tagStr) 733 if err != nil { 734 return -1, common.ErrPerm 735 } 736 if !canAccess(tag) { 737 return -1, common.ErrPerm 738 } 739 unitOrApplication, err := u.st.FindEntity(tag) 740 if err != nil { 741 return -1, err 742 } 743 var application *state.Application 744 switch entity := unitOrApplication.(type) { 745 case *state.Application: 746 application = entity 747 case *state.Unit: 748 application, err = entity.Application() 749 if err != nil { 750 return -1, err 751 } 752 default: 753 return -1, errors.BadRequestf("type %T does not have a CharmModifiedVersion", entity) 754 } 755 return application.CharmModifiedVersion(), nil 756 } 757 758 // CharmURL returns the charm URL for all given units or applications. 759 func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) { 760 result := params.StringBoolResults{ 761 Results: make([]params.StringBoolResult, len(args.Entities)), 762 } 763 accessUnitOrApplication := common.AuthAny(u.accessUnit, u.accessApplication) 764 canAccess, err := accessUnitOrApplication() 765 if err != nil { 766 return params.StringBoolResults{}, err 767 } 768 for i, entity := range args.Entities { 769 tag, err := names.ParseTag(entity.Tag) 770 if err != nil { 771 result.Results[i].Error = common.ServerError(common.ErrPerm) 772 continue 773 } 774 err = common.ErrPerm 775 if canAccess(tag) { 776 var unitOrApplication state.Entity 777 unitOrApplication, err = u.st.FindEntity(tag) 778 if err == nil { 779 charmURLer := unitOrApplication.(interface { 780 CharmURL() (*charm.URL, bool) 781 }) 782 curl, ok := charmURLer.CharmURL() 783 if curl != nil { 784 result.Results[i].Result = curl.String() 785 result.Results[i].Ok = ok 786 } 787 } 788 } 789 result.Results[i].Error = common.ServerError(err) 790 } 791 return result, nil 792 } 793 794 // SetCharmURL sets the charm URL for each given unit. An error will 795 // be returned if a unit is dead, or the charm URL is not know. 796 func (u *UniterAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) { 797 result := params.ErrorResults{ 798 Results: make([]params.ErrorResult, len(args.Entities)), 799 } 800 canAccess, err := u.accessUnit() 801 if err != nil { 802 return params.ErrorResults{}, err 803 } 804 for i, entity := range args.Entities { 805 tag, err := names.ParseUnitTag(entity.Tag) 806 if err != nil { 807 result.Results[i].Error = common.ServerError(common.ErrPerm) 808 continue 809 } 810 err = common.ErrPerm 811 if canAccess(tag) { 812 var unit *state.Unit 813 unit, err = u.getUnit(tag) 814 if err == nil { 815 var curl *charm.URL 816 curl, err = charm.ParseURL(entity.CharmURL) 817 if err == nil { 818 err = unit.SetCharmURL(curl) 819 } 820 } 821 } 822 result.Results[i].Error = common.ServerError(err) 823 } 824 return result, nil 825 } 826 827 // WorkloadVersion returns the workload version for all given units or applications. 828 func (u *UniterAPI) WorkloadVersion(args params.Entities) (params.StringResults, error) { 829 result := params.StringResults{ 830 Results: make([]params.StringResult, len(args.Entities)), 831 } 832 canAccess, err := u.accessUnit() 833 if err != nil { 834 return params.StringResults{}, err 835 } 836 for i, entity := range args.Entities { 837 resultItem := &result.Results[i] 838 tag, err := names.ParseUnitTag(entity.Tag) 839 if err != nil { 840 resultItem.Error = common.ServerError(err) 841 continue 842 } 843 if !canAccess(tag) { 844 resultItem.Error = common.ServerError(common.ErrPerm) 845 continue 846 } 847 unit, err := u.getUnit(tag) 848 if err != nil { 849 resultItem.Error = common.ServerError(err) 850 continue 851 } 852 version, err := unit.WorkloadVersion() 853 if err != nil { 854 resultItem.Error = common.ServerError(err) 855 continue 856 } 857 resultItem.Result = version 858 } 859 return result, nil 860 } 861 862 // SetWorkloadVersion sets the workload version for each given unit. An error will 863 // be returned if a unit is dead. 864 func (u *UniterAPI) SetWorkloadVersion(args params.EntityWorkloadVersions) (params.ErrorResults, error) { 865 result := params.ErrorResults{ 866 Results: make([]params.ErrorResult, len(args.Entities)), 867 } 868 canAccess, err := u.accessUnit() 869 if err != nil { 870 return params.ErrorResults{}, err 871 } 872 for i, entity := range args.Entities { 873 resultItem := &result.Results[i] 874 tag, err := names.ParseUnitTag(entity.Tag) 875 if err != nil { 876 resultItem.Error = common.ServerError(err) 877 continue 878 } 879 if !canAccess(tag) { 880 resultItem.Error = common.ServerError(common.ErrPerm) 881 continue 882 } 883 unit, err := u.getUnit(tag) 884 if err != nil { 885 resultItem.Error = common.ServerError(err) 886 continue 887 } 888 err = unit.SetWorkloadVersion(entity.WorkloadVersion) 889 if err != nil { 890 resultItem.Error = common.ServerError(err) 891 } 892 } 893 return result, nil 894 } 895 896 // OpenPorts sets the policy of the port range with protocol to be 897 // opened, for all given units. 898 func (u *UniterAPI) OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 899 result := params.ErrorResults{ 900 Results: make([]params.ErrorResult, len(args.Entities)), 901 } 902 canAccess, err := u.accessUnit() 903 if err != nil { 904 return params.ErrorResults{}, err 905 } 906 for i, entity := range args.Entities { 907 tag, err := names.ParseUnitTag(entity.Tag) 908 if err != nil { 909 result.Results[i].Error = common.ServerError(common.ErrPerm) 910 continue 911 } 912 err = common.ErrPerm 913 if canAccess(tag) { 914 var unit *state.Unit 915 unit, err = u.getUnit(tag) 916 if err == nil { 917 err = unit.OpenPorts(entity.Protocol, entity.FromPort, entity.ToPort) 918 } 919 } 920 result.Results[i].Error = common.ServerError(err) 921 } 922 return result, nil 923 } 924 925 // ClosePorts sets the policy of the port range with protocol to be 926 // closed, for all given units. 927 func (u *UniterAPI) ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 928 result := params.ErrorResults{ 929 Results: make([]params.ErrorResult, len(args.Entities)), 930 } 931 canAccess, err := u.accessUnit() 932 if err != nil { 933 return params.ErrorResults{}, err 934 } 935 for i, entity := range args.Entities { 936 tag, err := names.ParseUnitTag(entity.Tag) 937 if err != nil { 938 result.Results[i].Error = common.ServerError(common.ErrPerm) 939 continue 940 } 941 err = common.ErrPerm 942 if canAccess(tag) { 943 var unit *state.Unit 944 unit, err = u.getUnit(tag) 945 if err == nil { 946 err = unit.ClosePorts(entity.Protocol, entity.FromPort, entity.ToPort) 947 } 948 } 949 result.Results[i].Error = common.ServerError(err) 950 } 951 return result, nil 952 } 953 954 // WatchConfigSettings returns a NotifyWatcher for observing changes 955 // to each unit's application configuration settings. See also 956 // state/watcher.go:Unit.WatchConfigSettings(). 957 func (u *UniterAPIV8) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 958 watcherFn := func(u *state.Unit) (state.NotifyWatcher, error) { 959 return u.WatchConfigSettings() 960 } 961 result, err := u.WatchSettings(args, watcherFn) 962 if err != nil { 963 return params.NotifyWatchResults{}, errors.Trace(err) 964 } 965 966 return result, nil 967 } 968 969 func (u *UniterAPIV8) WatchTrustConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 970 watcherFn := func(u *state.Unit) (state.NotifyWatcher, error) { 971 return u.WatchApplicationConfigSettings() 972 } 973 result, err := u.WatchSettings(args, watcherFn) 974 if err != nil { 975 return params.NotifyWatchResults{}, errors.Trace(err) 976 } 977 978 return result, nil 979 } 980 981 func (u *UniterAPIV8) WatchSettings(args params.Entities, configWatcherFn func(u *state.Unit) (state.NotifyWatcher, error)) (params.NotifyWatchResults, error) { 982 result := params.NotifyWatchResults{ 983 Results: make([]params.NotifyWatchResult, len(args.Entities)), 984 } 985 canAccess, err := u.accessUnit() 986 if err != nil { 987 return params.NotifyWatchResults{}, err 988 } 989 for i, entity := range args.Entities { 990 tag, err := names.ParseUnitTag(entity.Tag) 991 if err != nil { 992 result.Results[i].Error = common.ServerError(common.ErrPerm) 993 continue 994 } 995 err = common.ErrPerm 996 watcherId := "" 997 if canAccess(tag) { 998 watcherId, err = u.watchOneUnitConfigSettings(tag, configWatcherFn) 999 } 1000 result.Results[i].NotifyWatcherId = watcherId 1001 result.Results[i].Error = common.ServerError(err) 1002 } 1003 return result, nil 1004 } 1005 1006 // WatchActionNotifications returns a StringsWatcher for observing 1007 // incoming action calls to a unit. See also state/watcher.go 1008 // Unit.WatchActionNotifications(). This method is called from 1009 // api/uniter/uniter.go WatchActionNotifications(). 1010 func (u *UniterAPI) WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) { 1011 tagToActionReceiver := common.TagToActionReceiverFn(u.st.FindEntity) 1012 watchOne := common.WatchOneActionReceiverNotifications(tagToActionReceiver, u.resources.Register) 1013 canAccess, err := u.accessUnit() 1014 if err != nil { 1015 return params.StringsWatchResults{}, err 1016 } 1017 return common.WatchActionNotifications(args, canAccess, watchOne), nil 1018 } 1019 1020 // ConfigSettings returns the complete set of application charm config 1021 // settings available to each given unit. 1022 func (u *UniterAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) { 1023 result := params.ConfigSettingsResults{ 1024 Results: make([]params.ConfigSettingsResult, len(args.Entities)), 1025 } 1026 canAccess, err := u.accessUnit() 1027 if err != nil { 1028 return params.ConfigSettingsResults{}, err 1029 } 1030 for i, entity := range args.Entities { 1031 tag, err := names.ParseUnitTag(entity.Tag) 1032 if err != nil { 1033 result.Results[i].Error = common.ServerError(common.ErrPerm) 1034 continue 1035 } 1036 err = common.ErrPerm 1037 if canAccess(tag) { 1038 var unit *state.Unit 1039 unit, err = u.getUnit(tag) 1040 if err == nil { 1041 var settings charm.Settings 1042 settings, err = unit.ConfigSettings() 1043 if err == nil { 1044 result.Results[i].Settings = params.ConfigSettings(settings) 1045 } 1046 } 1047 } 1048 result.Results[i].Error = common.ServerError(err) 1049 } 1050 return result, nil 1051 } 1052 1053 // CharmArchiveSha256 returns the SHA256 digest of the charm archive 1054 // (bundle) data for each charm url in the given parameters. 1055 func (u *UniterAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) { 1056 result := params.StringResults{ 1057 Results: make([]params.StringResult, len(args.URLs)), 1058 } 1059 for i, arg := range args.URLs { 1060 curl, err := charm.ParseURL(arg.URL) 1061 if err != nil { 1062 err = common.ErrPerm 1063 } else { 1064 var sch *state.Charm 1065 sch, err = u.st.Charm(curl) 1066 if errors.IsNotFound(err) { 1067 err = common.ErrPerm 1068 } 1069 if err == nil { 1070 result.Results[i].Result = sch.BundleSha256() 1071 } 1072 } 1073 result.Results[i].Error = common.ServerError(err) 1074 } 1075 return result, nil 1076 } 1077 1078 // Relation returns information about all given relation/unit pairs, 1079 // including their id, key and the local endpoint. 1080 func (u *UniterAPI) Relation(args params.RelationUnits) (params.RelationResults, error) { 1081 result := params.RelationResults{ 1082 Results: make([]params.RelationResult, len(args.RelationUnits)), 1083 } 1084 canAccess, err := u.accessUnit() 1085 if err != nil { 1086 return params.RelationResults{}, err 1087 } 1088 for i, rel := range args.RelationUnits { 1089 relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit) 1090 if err == nil { 1091 result.Results[i] = relParams 1092 } 1093 result.Results[i].Error = common.ServerError(err) 1094 } 1095 return result, nil 1096 } 1097 1098 // Actions returns the Actions by Tags passed and ensures that the Unit asking 1099 // for them is the same Unit that has the Actions. 1100 func (u *UniterAPI) Actions(args params.Entities) (params.ActionResults, error) { 1101 canAccess, err := u.accessUnit() 1102 if err != nil { 1103 return params.ActionResults{}, err 1104 } 1105 1106 m, err := u.st.Model() 1107 if err != nil { 1108 return params.ActionResults{}, errors.Trace(err) 1109 } 1110 1111 actionFn := common.AuthAndActionFromTagFn(canAccess, m.ActionByTag) 1112 return common.Actions(args, actionFn), nil 1113 } 1114 1115 // BeginActions marks the actions represented by the passed in Tags as running. 1116 func (u *UniterAPI) BeginActions(args params.Entities) (params.ErrorResults, error) { 1117 canAccess, err := u.accessUnit() 1118 if err != nil { 1119 return params.ErrorResults{}, err 1120 } 1121 1122 m, err := u.st.Model() 1123 if err != nil { 1124 return params.ErrorResults{}, errors.Trace(err) 1125 } 1126 1127 actionFn := common.AuthAndActionFromTagFn(canAccess, m.ActionByTag) 1128 return common.BeginActions(args, actionFn), nil 1129 } 1130 1131 // FinishActions saves the result of a completed Action 1132 func (u *UniterAPI) FinishActions(args params.ActionExecutionResults) (params.ErrorResults, error) { 1133 canAccess, err := u.accessUnit() 1134 if err != nil { 1135 return params.ErrorResults{}, err 1136 } 1137 1138 m, err := u.st.Model() 1139 if err != nil { 1140 return params.ErrorResults{}, errors.Trace(err) 1141 } 1142 1143 actionFn := common.AuthAndActionFromTagFn(canAccess, m.ActionByTag) 1144 return common.FinishActions(args, actionFn), nil 1145 } 1146 1147 // RelationById returns information about all given relations, 1148 // specified by their ids, including their key and the local 1149 // endpoint. 1150 func (u *UniterAPI) RelationById(args params.RelationIds) (params.RelationResults, error) { 1151 result := params.RelationResults{ 1152 Results: make([]params.RelationResult, len(args.RelationIds)), 1153 } 1154 for i, relId := range args.RelationIds { 1155 relParams, err := u.getOneRelationById(relId) 1156 if err == nil { 1157 result.Results[i] = relParams 1158 } 1159 result.Results[i].Error = common.ServerError(err) 1160 } 1161 return result, nil 1162 } 1163 1164 // JoinedRelations returns the tags of all relations for which each supplied unit 1165 // has entered scope. 1166 // TODO(wallyworld) - this API is replaced by RelationsStatus 1167 func (u *UniterAPIV6) JoinedRelations(args params.Entities) (params.StringsResults, error) { 1168 result := params.StringsResults{ 1169 Results: make([]params.StringsResult, len(args.Entities)), 1170 } 1171 if len(args.Entities) == 0 { 1172 return result, nil 1173 } 1174 canRead, err := u.accessUnit() 1175 if err != nil { 1176 return params.StringsResults{}, err 1177 } 1178 for i, entity := range args.Entities { 1179 tag, err := names.ParseUnitTag(entity.Tag) 1180 if err != nil { 1181 result.Results[i].Error = common.ServerError(common.ErrPerm) 1182 continue 1183 } 1184 err = common.ErrPerm 1185 if canRead(tag) { 1186 var unit *state.Unit 1187 unit, err = u.getUnit(tag) 1188 if err == nil { 1189 result.Results[i].Result, err = relationsInScopeTags(unit) 1190 } 1191 } 1192 result.Results[i].Error = common.ServerError(err) 1193 } 1194 return result, nil 1195 } 1196 1197 // RelationsStatus returns for each unit the corresponding relation and status information. 1198 func (u *UniterAPI) RelationsStatus(args params.Entities) (params.RelationUnitStatusResults, error) { 1199 result := params.RelationUnitStatusResults{ 1200 Results: make([]params.RelationUnitStatusResult, len(args.Entities)), 1201 } 1202 if len(args.Entities) == 0 { 1203 return result, nil 1204 } 1205 canRead, err := u.accessUnit() 1206 if err != nil { 1207 return params.RelationUnitStatusResults{}, err 1208 } 1209 1210 oneRelationUnitStatus := func(rel *state.Relation, unit *state.Unit) (params.RelationUnitStatus, error) { 1211 rus := params.RelationUnitStatus{ 1212 RelationTag: rel.Tag().String(), 1213 Suspended: rel.Suspended(), 1214 } 1215 ru, err := rel.Unit(unit) 1216 if err != nil { 1217 return params.RelationUnitStatus{}, errors.Trace(err) 1218 } 1219 inScope, err := ru.InScope() 1220 if err != nil { 1221 return params.RelationUnitStatus{}, errors.Trace(err) 1222 } 1223 rus.InScope = inScope 1224 return rus, nil 1225 } 1226 1227 relationResults := func(unit *state.Unit) ([]params.RelationUnitStatus, error) { 1228 var ruStatus []params.RelationUnitStatus 1229 app, err := unit.Application() 1230 if err != nil { 1231 return nil, errors.Trace(err) 1232 } 1233 relations, err := app.Relations() 1234 for _, rel := range relations { 1235 rus, err := oneRelationUnitStatus(rel, unit) 1236 if err != nil { 1237 return nil, errors.Trace(err) 1238 } 1239 ruStatus = append(ruStatus, rus) 1240 } 1241 return ruStatus, nil 1242 } 1243 1244 for i, entity := range args.Entities { 1245 tag, err := names.ParseUnitTag(entity.Tag) 1246 if err != nil { 1247 result.Results[i].Error = common.ServerError(common.ErrPerm) 1248 continue 1249 } 1250 err = common.ErrPerm 1251 if canRead(tag) { 1252 var unit *state.Unit 1253 unit, err = u.getUnit(tag) 1254 if err == nil { 1255 result.Results[i].RelationResults, err = relationResults(unit) 1256 } 1257 } 1258 result.Results[i].Error = common.ServerError(err) 1259 } 1260 return result, nil 1261 } 1262 1263 // Refresh retrieves the latest values for attributes on this unit. 1264 func (u *UniterAPI) Refresh(args params.Entities) (params.UnitRefreshResults, error) { 1265 result := params.UnitRefreshResults{ 1266 Results: make([]params.UnitRefreshResult, len(args.Entities)), 1267 } 1268 if len(args.Entities) == 0 { 1269 return result, nil 1270 } 1271 canRead, err := u.accessUnit() 1272 if err != nil { 1273 return params.UnitRefreshResults{}, err 1274 } 1275 for i, entity := range args.Entities { 1276 tag, err := names.ParseUnitTag(entity.Tag) 1277 if err != nil { 1278 result.Results[i].Error = common.ServerError(common.ErrPerm) 1279 continue 1280 } 1281 err = common.ErrPerm 1282 if canRead(tag) { 1283 var unit *state.Unit 1284 if unit, err = u.getUnit(tag); err == nil { 1285 result.Results[i].Life = params.Life(unit.Life().String()) 1286 result.Results[i].Resolved = params.ResolvedMode(unit.Resolved()) 1287 } 1288 } 1289 result.Results[i].Error = common.ServerError(err) 1290 } 1291 return result, nil 1292 } 1293 1294 // CurrentModel returns the name and UUID for the current juju model. 1295 func (u *UniterAPI) CurrentModel() (params.ModelResult, error) { 1296 result := params.ModelResult{} 1297 model, err := u.st.Model() 1298 if err == nil { 1299 result.Name = model.Name() 1300 result.UUID = model.UUID() 1301 result.Type = string(model.Type()) 1302 } 1303 return result, err 1304 } 1305 1306 // ProviderType returns the provider type used by the current juju 1307 // model. 1308 // 1309 // TODO(dimitern): Refactor the uniter to call this instead of calling 1310 // ModelConfig() just to get the provider type. Once we have machine 1311 // addresses, this might be completely unnecessary though. 1312 func (u *UniterAPI) ProviderType() (params.StringResult, error) { 1313 result := params.StringResult{} 1314 cfg, err := u.m.ModelConfig() 1315 if err == nil { 1316 result.Result = cfg.Type() 1317 } 1318 return result, err 1319 } 1320 1321 // EnterScope ensures each unit has entered its scope in the relation, 1322 // for all of the given relation/unit pairs. See also 1323 // state.RelationUnit.EnterScope(). 1324 func (u *UniterAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) { 1325 result := params.ErrorResults{ 1326 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1327 } 1328 canAccess, err := u.accessUnit() 1329 if err != nil { 1330 return params.ErrorResults{}, err 1331 } 1332 one := func(relTag string, unitTag names.UnitTag, modelSubnets []string) error { 1333 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 1334 if err != nil { 1335 return err 1336 } 1337 relUnit, err := rel.Unit(unit) 1338 if err != nil { 1339 return err 1340 } 1341 1342 valid, err := relUnit.Valid() 1343 if err != nil { 1344 return err 1345 } 1346 if !valid { 1347 principalName, _ := unit.PrincipalName() 1348 logger.Debugf("ignoring %q EnterScope for %q - unit has invalid principal %q", 1349 unit.Name(), rel.String(), principalName) 1350 return nil 1351 } 1352 1353 settings := map[string]interface{}{} 1354 _, ingressAddresses, egressSubnets, err := state.NetworksForRelation(relUnit.Endpoint().Name, unit, rel, modelSubnets) 1355 if err == nil && len(ingressAddresses) > 0 { 1356 ingressAddress := ingressAddresses[0] 1357 // private-address is historically a cloud local address for the machine. 1358 // Existing charms are built to ask for this attribute from relation 1359 // settings to find out what address to use to connect to the app 1360 // on the other side of a relation. For cross model scenarios, we'll 1361 // replace this with possibly a public address; we expect to fix more 1362 // charms than we break - breakage will not occur for correctly written 1363 // charms, since the semantics of this value dictates the use case described. 1364 // Any other use goes against the intended purpose of this value. 1365 settings["private-address"] = ingressAddress 1366 // ingress-address is the preferred settings attribute name as it more accurately 1367 // reflects the purpose of the attribute value. We'll deprecate private-address. 1368 settings["ingress-address"] = ingressAddress 1369 } else { 1370 logger.Warningf("cannot set ingress/egress addresses for unit %v in relation %v: %v", unitTag.Id(), relTag, err) 1371 } 1372 if len(egressSubnets) > 0 { 1373 settings["egress-subnets"] = strings.Join(egressSubnets, ",") 1374 } 1375 return relUnit.EnterScope(settings) 1376 } 1377 cfg, err := u.m.ModelConfig() 1378 if err != nil { 1379 return params.ErrorResults{}, errors.Trace(err) 1380 } 1381 for i, arg := range args.RelationUnits { 1382 tag, err := names.ParseUnitTag(arg.Unit) 1383 if err != nil { 1384 result.Results[i].Error = common.ServerError(common.ErrPerm) 1385 continue 1386 } 1387 err = one(arg.Relation, tag, cfg.EgressSubnets()) 1388 if err != nil { 1389 result.Results[i].Error = common.ServerError(err) 1390 } 1391 } 1392 return result, nil 1393 } 1394 1395 // LeaveScope signals each unit has left its scope in the relation, 1396 // for all of the given relation/unit pairs. See also 1397 // state.RelationUnit.LeaveScope(). 1398 func (u *UniterAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) { 1399 result := params.ErrorResults{ 1400 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1401 } 1402 canAccess, err := u.accessUnit() 1403 if err != nil { 1404 return params.ErrorResults{}, err 1405 } 1406 for i, arg := range args.RelationUnits { 1407 unit, err := names.ParseUnitTag(arg.Unit) 1408 if err != nil { 1409 result.Results[i].Error = common.ServerError(common.ErrPerm) 1410 continue 1411 } 1412 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1413 if err == nil { 1414 err = relUnit.LeaveScope() 1415 } 1416 result.Results[i].Error = common.ServerError(err) 1417 } 1418 return result, nil 1419 } 1420 1421 // ReadSettings returns the local settings of each given set of 1422 // relation/unit. 1423 func (u *UniterAPI) ReadSettings(args params.RelationUnits) (params.SettingsResults, error) { 1424 result := params.SettingsResults{ 1425 Results: make([]params.SettingsResult, len(args.RelationUnits)), 1426 } 1427 canAccess, err := u.accessUnit() 1428 if err != nil { 1429 return params.SettingsResults{}, err 1430 } 1431 for i, arg := range args.RelationUnits { 1432 unit, err := names.ParseUnitTag(arg.Unit) 1433 if err != nil { 1434 result.Results[i].Error = common.ServerError(common.ErrPerm) 1435 continue 1436 } 1437 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1438 if err == nil { 1439 var settings *state.Settings 1440 settings, err = relUnit.Settings() 1441 if err == nil { 1442 result.Results[i].Settings, err = convertRelationSettings(settings.Map()) 1443 } 1444 } 1445 result.Results[i].Error = common.ServerError(err) 1446 } 1447 return result, nil 1448 } 1449 1450 // ReadRemoteSettings returns the remote settings of each given set of 1451 // relation/local unit/remote unit. 1452 func (u *UniterAPI) ReadRemoteSettings(args params.RelationUnitPairs) (params.SettingsResults, error) { 1453 result := params.SettingsResults{ 1454 Results: make([]params.SettingsResult, len(args.RelationUnitPairs)), 1455 } 1456 canAccess, err := u.accessUnit() 1457 if err != nil { 1458 return params.SettingsResults{}, err 1459 } 1460 for i, arg := range args.RelationUnitPairs { 1461 unit, err := names.ParseUnitTag(arg.LocalUnit) 1462 if err != nil { 1463 result.Results[i].Error = common.ServerError(common.ErrPerm) 1464 continue 1465 } 1466 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1467 if err == nil { 1468 // TODO(dfc) rework this logic 1469 remoteUnit := "" 1470 remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit) 1471 if err == nil { 1472 var settings map[string]interface{} 1473 settings, err = relUnit.ReadSettings(remoteUnit) 1474 if err == nil { 1475 result.Results[i].Settings, err = convertRelationSettings(settings) 1476 } 1477 } 1478 } 1479 result.Results[i].Error = common.ServerError(err) 1480 } 1481 return result, nil 1482 } 1483 1484 // UpdateSettings persists all changes made to the local settings of 1485 // all given pairs of relation and unit. Keys with empty values are 1486 // considered a signal to delete these values. 1487 func (u *UniterAPI) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) { 1488 result := params.ErrorResults{ 1489 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1490 } 1491 canAccess, err := u.accessUnit() 1492 if err != nil { 1493 return params.ErrorResults{}, err 1494 } 1495 for i, arg := range args.RelationUnits { 1496 unit, err := names.ParseUnitTag(arg.Unit) 1497 if err != nil { 1498 result.Results[i].Error = common.ServerError(common.ErrPerm) 1499 continue 1500 } 1501 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1502 if err == nil { 1503 var settings *state.Settings 1504 settings, err = relUnit.Settings() 1505 if err == nil { 1506 for k, v := range arg.Settings { 1507 if v == "" { 1508 settings.Delete(k) 1509 } else { 1510 settings.Set(k, v) 1511 } 1512 } 1513 _, err = settings.Write() 1514 } 1515 } 1516 result.Results[i].Error = common.ServerError(err) 1517 } 1518 return result, nil 1519 } 1520 1521 // WatchRelationUnits returns a RelationUnitsWatcher for observing 1522 // changes to every unit in the supplied relation that is visible to 1523 // the supplied unit. See also state/watcher.go:RelationUnit.Watch(). 1524 func (u *UniterAPI) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) { 1525 result := params.RelationUnitsWatchResults{ 1526 Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)), 1527 } 1528 canAccess, err := u.accessUnit() 1529 if err != nil { 1530 return params.RelationUnitsWatchResults{}, err 1531 } 1532 for i, arg := range args.RelationUnits { 1533 unit, err := names.ParseUnitTag(arg.Unit) 1534 if err != nil { 1535 result.Results[i].Error = common.ServerError(common.ErrPerm) 1536 continue 1537 } 1538 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1539 if err == nil { 1540 result.Results[i], err = u.watchOneRelationUnit(relUnit) 1541 } 1542 result.Results[i].Error = common.ServerError(err) 1543 } 1544 return result, nil 1545 } 1546 1547 // SetRelationStatus updates the status of the specified relations. 1548 func (u *UniterAPI) SetRelationStatus(args params.RelationStatusArgs) (params.ErrorResults, error) { 1549 var statusResults params.ErrorResults 1550 1551 unitCache := make(map[string]*state.Unit) 1552 getUnit := func(tag string) (*state.Unit, error) { 1553 if unit, ok := unitCache[tag]; ok { 1554 return unit, nil 1555 } 1556 unitTag, err := names.ParseUnitTag(tag) 1557 if err != nil { 1558 return nil, errors.Trace(err) 1559 } 1560 unit, err := u.st.Unit(unitTag.Id()) 1561 if errors.IsNotFound(err) { 1562 return nil, common.ErrPerm 1563 } 1564 if err != nil { 1565 return nil, errors.Trace(err) 1566 } 1567 unitCache[tag] = unit 1568 return unit, nil 1569 } 1570 1571 checker := u.leadershipChecker 1572 changeOne := func(arg params.RelationStatusArg) error { 1573 // TODO(wallyworld) - the token should be passed to SetStatus() but the 1574 // interface method doesn't allow for that yet. 1575 unitTag := arg.UnitTag 1576 if unitTag == "" { 1577 // Older clients don't pass in the unit tag explicitly. 1578 unitTag = u.auth.GetAuthTag().String() 1579 } 1580 unit, err := getUnit(unitTag) 1581 if err != nil { 1582 return err 1583 } 1584 token := checker.LeadershipCheck(unit.ApplicationName(), unit.Name()) 1585 if err := token.Check(0, nil); err != nil { 1586 return errors.Trace(err) 1587 } 1588 1589 rel, err := u.st.Relation(arg.RelationId) 1590 if errors.IsNotFound(err) { 1591 return common.ErrPerm 1592 } else if err != nil { 1593 return errors.Trace(err) 1594 } 1595 _, err = rel.Unit(unit) 1596 if errors.IsNotFound(err) { 1597 return common.ErrPerm 1598 } else if err != nil { 1599 return errors.Trace(err) 1600 } 1601 // If we are transitioning from "suspending" to "suspended", 1602 // we retain any existing message so that if the user has 1603 // previously specified a reason for suspending, it is retained. 1604 message := arg.Message 1605 if message == "" && arg.Status == params.Suspended { 1606 current, err := rel.Status() 1607 if err != nil { 1608 return errors.Trace(err) 1609 } 1610 if current.Status == status.Suspending { 1611 message = current.Message 1612 } 1613 } 1614 return rel.SetStatus(status.StatusInfo{ 1615 Status: status.Status(arg.Status), 1616 Message: message, 1617 }) 1618 } 1619 results := make([]params.ErrorResult, len(args.Args)) 1620 for i, arg := range args.Args { 1621 err := changeOne(arg) 1622 results[i].Error = common.ServerError(err) 1623 } 1624 statusResults.Results = results 1625 return statusResults, nil 1626 } 1627 1628 // WatchUnitAddresses returns a NotifyWatcher for observing changes 1629 // to each unit's addresses. 1630 func (u *UniterAPIV8) WatchUnitAddresses(args params.Entities) (params.NotifyWatchResults, error) { 1631 result := params.NotifyWatchResults{ 1632 Results: make([]params.NotifyWatchResult, len(args.Entities)), 1633 } 1634 canAccess, err := u.accessUnit() 1635 if err != nil { 1636 return params.NotifyWatchResults{}, err 1637 } 1638 for i, entity := range args.Entities { 1639 unit, err := names.ParseUnitTag(entity.Tag) 1640 if err != nil { 1641 result.Results[i].Error = common.ServerError(common.ErrPerm) 1642 continue 1643 } 1644 err = common.ErrPerm 1645 watcherId := "" 1646 if canAccess(unit) { 1647 watcherId, err = u.watchOneUnitAddresses(unit) 1648 } 1649 result.Results[i].NotifyWatcherId = watcherId 1650 result.Results[i].Error = common.ServerError(err) 1651 } 1652 return result, nil 1653 } 1654 1655 func (u *UniterAPI) getUnit(tag names.UnitTag) (*state.Unit, error) { 1656 return u.st.Unit(tag.Id()) 1657 } 1658 1659 func (u *UniterAPI) getApplication(tag names.ApplicationTag) (*state.Application, error) { 1660 return u.st.Application(tag.Id()) 1661 } 1662 1663 func (u *UniterAPI) getRelationUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.RelationUnit, error) { 1664 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 1665 if err != nil { 1666 return nil, err 1667 } 1668 return rel.Unit(unit) 1669 } 1670 1671 func (u *UniterAPI) getOneRelationById(relId int) (params.RelationResult, error) { 1672 nothing := params.RelationResult{} 1673 rel, err := u.st.Relation(relId) 1674 if errors.IsNotFound(err) { 1675 return nothing, common.ErrPerm 1676 } else if err != nil { 1677 return nothing, err 1678 } 1679 var applicationName string 1680 tag := u.auth.GetAuthTag() 1681 switch tag.(type) { 1682 case names.UnitTag: 1683 unit, err := u.st.Unit(tag.Id()) 1684 if err != nil { 1685 return nothing, err 1686 } 1687 applicationName = unit.ApplicationName() 1688 case names.ApplicationTag: 1689 applicationName = tag.Id() 1690 default: 1691 panic("authenticated entity is not a unit or application") 1692 } 1693 // Use the currently authenticated unit to get the endpoint. 1694 result, err := u.prepareRelationResult(rel, applicationName) 1695 if err != nil { 1696 // An error from prepareRelationResult means the authenticated 1697 // unit's application is not part of the requested 1698 // relation. That's why it's appropriate to return ErrPerm 1699 // here. 1700 return nothing, common.ErrPerm 1701 } 1702 return result, nil 1703 } 1704 1705 func (u *UniterAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.Relation, *state.Unit, error) { 1706 tag, err := names.ParseRelationTag(relTag) 1707 if err != nil { 1708 return nil, nil, common.ErrPerm 1709 } 1710 rel, err := u.st.KeyRelation(tag.Id()) 1711 if errors.IsNotFound(err) { 1712 return nil, nil, common.ErrPerm 1713 } else if err != nil { 1714 return nil, nil, err 1715 } 1716 if !canAccess(unitTag) { 1717 return nil, nil, common.ErrPerm 1718 } 1719 unit, err := u.getUnit(unitTag) 1720 return rel, unit, err 1721 } 1722 1723 func (u *UniterAPI) prepareRelationResult(rel *state.Relation, applicationName string) (params.RelationResult, error) { 1724 nothing := params.RelationResult{} 1725 ep, err := rel.Endpoint(applicationName) 1726 if err != nil { 1727 // An error here means the unit's application is not part of the 1728 // relation. 1729 return nothing, err 1730 } 1731 var otherAppName string 1732 otherEndpoints, err := rel.RelatedEndpoints(applicationName) 1733 if err != nil { 1734 return nothing, err 1735 } 1736 for _, otherEp := range otherEndpoints { 1737 otherAppName = otherEp.ApplicationName 1738 } 1739 return params.RelationResult{ 1740 Id: rel.Id(), 1741 Key: rel.String(), 1742 Life: params.Life(rel.Life().String()), 1743 Suspended: rel.Suspended(), 1744 Endpoint: multiwatcher.Endpoint{ 1745 ApplicationName: ep.ApplicationName, 1746 Relation: multiwatcher.NewCharmRelation(ep.Relation), 1747 }, 1748 OtherApplication: otherAppName, 1749 }, nil 1750 } 1751 1752 func (u *UniterAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) { 1753 nothing := params.RelationResult{} 1754 tag, err := names.ParseUnitTag(unitTag) 1755 if err != nil { 1756 return nothing, common.ErrPerm 1757 } 1758 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, tag) 1759 if err != nil { 1760 return nothing, err 1761 } 1762 return u.prepareRelationResult(rel, unit.ApplicationName()) 1763 } 1764 1765 func (u *UniterAPI) destroySubordinates(principal *state.Unit) error { 1766 subordinates := principal.SubordinateNames() 1767 for _, subName := range subordinates { 1768 unit, err := u.getUnit(names.NewUnitTag(subName)) 1769 if err != nil { 1770 return err 1771 } 1772 if err = unit.Destroy(); err != nil { 1773 return err 1774 } 1775 } 1776 return nil 1777 } 1778 1779 func (u *UniterAPIV8) watchOneUnitConfigSettings(tag names.UnitTag, configWatcherFn func(u *state.Unit) (state.NotifyWatcher, error)) (string, error) { 1780 unit, err := u.getUnit(tag) 1781 if err != nil { 1782 return "", err 1783 } 1784 configWatcher, err := configWatcherFn(unit) 1785 if err != nil { 1786 return "", errors.Trace(err) 1787 } 1788 // Consume the initial event. Technically, API 1789 // calls to Watch 'transmit' the initial event 1790 // in the Watch response. But NotifyWatchers 1791 // have no state to transmit. 1792 if _, ok := <-configWatcher.Changes(); ok { 1793 return u.resources.Register(configWatcher), nil 1794 } 1795 return "", watcher.EnsureErr(configWatcher) 1796 } 1797 1798 func (u *UniterAPIV8) watchOneUnitAddresses(tag names.UnitTag) (string, error) { 1799 unit, err := u.getUnit(tag) 1800 if err != nil { 1801 return "", err 1802 } 1803 var watch state.NotifyWatcher 1804 if unit.ShouldBeAssigned() { 1805 machineId, err := unit.AssignedMachineId() 1806 if err != nil { 1807 return "", err 1808 } 1809 machine, err := u.st.Machine(machineId) 1810 if err != nil { 1811 return "", err 1812 } 1813 watch = machine.WatchAddresses() 1814 } else { 1815 watch = unit.WatchContainerAddresses() 1816 } 1817 // Consume the initial event. Technically, API 1818 // calls to Watch 'transmit' the initial event 1819 // in the Watch response. But NotifyWatchers 1820 // have no state to transmit. 1821 if _, ok := <-watch.Changes(); ok { 1822 return u.resources.Register(watch), nil 1823 } 1824 return "", watcher.EnsureErr(watch) 1825 } 1826 1827 func (u *UniterAPI) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) { 1828 watch := relUnit.Watch() 1829 // Consume the initial event and forward it to the result. 1830 if changes, ok := <-watch.Changes(); ok { 1831 return params.RelationUnitsWatchResult{ 1832 RelationUnitsWatcherId: u.resources.Register(watch), 1833 Changes: changes, 1834 }, nil 1835 } 1836 return params.RelationUnitsWatchResult{}, watcher.EnsureErr(watch) 1837 } 1838 1839 func (u *UniterAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) { 1840 // Make sure the unit is indeed remote. 1841 switch tag := u.auth.GetAuthTag().(type) { 1842 case names.UnitTag: 1843 if remoteUnitTag == tag.String() { 1844 return "", common.ErrPerm 1845 } 1846 case names.ApplicationTag: 1847 // If called by an application agent, we need 1848 // to check the units of the application. 1849 app, err := u.st.Application(tag.Name) 1850 if err != nil { 1851 return "", errors.Trace(err) 1852 } 1853 allUnits, err := app.AllUnits() 1854 if err != nil { 1855 return "", errors.Trace(err) 1856 } 1857 for _, unit := range allUnits { 1858 if remoteUnitTag == unit.Tag().String() { 1859 return "", common.ErrPerm 1860 } 1861 } 1862 } 1863 1864 // Check remoteUnit is indeed related. Note that we don't want to actually get 1865 // the *Unit, because it might have been removed; but its relation settings will 1866 // persist until the relation itself has been removed (and must remain accessible 1867 // because the local unit's view of reality may be time-shifted). 1868 tag, err := names.ParseUnitTag(remoteUnitTag) 1869 if err != nil { 1870 return "", common.ErrPerm 1871 } 1872 remoteUnitName := tag.Id() 1873 remoteApplicationName, err := names.UnitApplication(remoteUnitName) 1874 if err != nil { 1875 return "", common.ErrPerm 1876 } 1877 rel := relUnit.Relation() 1878 _, err = rel.RelatedEndpoints(remoteApplicationName) 1879 if err != nil { 1880 return "", common.ErrPerm 1881 } 1882 return remoteUnitName, nil 1883 } 1884 1885 func convertRelationSettings(settings map[string]interface{}) (params.Settings, error) { 1886 result := make(params.Settings) 1887 for k, v := range settings { 1888 // All relation settings should be strings. 1889 sval, ok := v.(string) 1890 if !ok { 1891 return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v) 1892 } 1893 result[k] = sval 1894 } 1895 return result, nil 1896 } 1897 1898 func relationsInScopeTags(unit *state.Unit) ([]string, error) { 1899 relations, err := unit.RelationsInScope() 1900 if err != nil { 1901 return nil, err 1902 } 1903 tags := make([]string, len(relations)) 1904 for i, relation := range relations { 1905 tags[i] = relation.Tag().String() 1906 } 1907 return tags, nil 1908 } 1909 1910 func leadershipSettingsAccessorFactory( 1911 st *state.State, 1912 checker leadership.Checker, 1913 resources facade.Resources, 1914 auth facade.Authorizer, 1915 ) *leadershipapiserver.LeadershipSettingsAccessor { 1916 registerWatcher := func(applicationId string) (string, error) { 1917 application, err := st.Application(applicationId) 1918 if err != nil { 1919 return "", err 1920 } 1921 w := application.WatchLeaderSettings() 1922 if _, ok := <-w.Changes(); ok { 1923 return resources.Register(w), nil 1924 } 1925 return "", watcher.EnsureErr(w) 1926 } 1927 getSettings := func(applicationId string) (map[string]string, error) { 1928 application, err := st.Application(applicationId) 1929 if err != nil { 1930 return nil, err 1931 } 1932 return application.LeaderSettings() 1933 } 1934 writeSettings := func(token leadership.Token, applicationId string, settings map[string]string) error { 1935 application, err := st.Application(applicationId) 1936 if err != nil { 1937 return err 1938 } 1939 return application.UpdateLeaderSettings(token, settings) 1940 } 1941 return leadershipapiserver.NewLeadershipSettingsAccessor( 1942 auth, 1943 registerWatcher, 1944 getSettings, 1945 checker.LeadershipCheck, 1946 writeSettings, 1947 ) 1948 } 1949 1950 // AddMetricBatches adds the metrics for the specified unit. 1951 func (u *UniterAPI) AddMetricBatches(args params.MetricBatchParams) (params.ErrorResults, error) { 1952 result := params.ErrorResults{ 1953 Results: make([]params.ErrorResult, len(args.Batches)), 1954 } 1955 canAccess, err := u.accessUnit() 1956 if err != nil { 1957 logger.Warningf("failed to check unit access: %v", err) 1958 return params.ErrorResults{}, common.ErrPerm 1959 } 1960 for i, batch := range args.Batches { 1961 tag, err := names.ParseUnitTag(batch.Tag) 1962 if err != nil { 1963 result.Results[i].Error = common.ServerError(err) 1964 continue 1965 } 1966 if !canAccess(tag) { 1967 result.Results[i].Error = common.ServerError(common.ErrPerm) 1968 continue 1969 } 1970 metrics := make([]state.Metric, len(batch.Batch.Metrics)) 1971 for j, metric := range batch.Batch.Metrics { 1972 metrics[j] = state.Metric{ 1973 Key: metric.Key, 1974 Value: metric.Value, 1975 Time: metric.Time, 1976 Labels: metric.Labels, 1977 } 1978 } 1979 _, err = u.st.AddMetrics(state.BatchParam{ 1980 UUID: batch.Batch.UUID, 1981 Created: batch.Batch.Created, 1982 CharmURL: batch.Batch.CharmURL, 1983 Metrics: metrics, 1984 Unit: tag, 1985 }) 1986 result.Results[i].Error = common.ServerError(err) 1987 } 1988 return result, nil 1989 } 1990 1991 // V4 specific methods. 1992 1993 // specific methods - the new SLALevel, NetworkInfo and 1994 // WatchUnitRelations methods. 1995 1996 // SLALevel returns the model's SLA level. 1997 func (u *UniterAPI) SLALevel() (params.StringResult, error) { 1998 result := params.StringResult{} 1999 sla, err := u.st.SLALevel() 2000 if err == nil { 2001 result.Result = sla 2002 } 2003 return result, err 2004 } 2005 2006 // NetworkInfo returns network interfaces/addresses for specified bindings. 2007 func (u *UniterAPI) NetworkInfo(args params.NetworkInfoParams) (params.NetworkInfoResults, error) { 2008 canAccess, err := u.accessUnit() 2009 if err != nil { 2010 return params.NetworkInfoResults{}, err 2011 } 2012 2013 unitTag, err := names.ParseUnitTag(args.Unit) 2014 if err != nil { 2015 return params.NetworkInfoResults{}, err 2016 } 2017 2018 if !canAccess(unitTag) { 2019 return params.NetworkInfoResults{}, common.ErrPerm 2020 } 2021 2022 unit, err := u.getUnit(unitTag) 2023 if err != nil { 2024 return params.NetworkInfoResults{}, err 2025 } 2026 2027 result := params.NetworkInfoResults{ 2028 Results: make(map[string]params.NetworkInfoResult), 2029 } 2030 2031 spaces := set.NewStrings() 2032 bindingsToSpace := make(map[string]string) 2033 bindingsToEgressSubnets := make(map[string][]string) 2034 bindingsToIngressAddresses := make(map[string][]string) 2035 2036 model, err := u.st.Model() 2037 if err != nil { 2038 return params.NetworkInfoResults{}, err 2039 } 2040 modelCfg, err := model.ModelConfig() 2041 if err != nil { 2042 return params.NetworkInfoResults{}, err 2043 } 2044 for _, binding := range args.Bindings { 2045 if boundSpace, err := unit.GetSpaceForBinding(binding); err != nil { 2046 result.Results[binding] = params.NetworkInfoResult{Error: common.ServerError(err)} 2047 } else { 2048 spaces.Add(boundSpace) 2049 bindingsToSpace[binding] = boundSpace 2050 } 2051 bindingsToEgressSubnets[binding] = modelCfg.EgressSubnets() 2052 } 2053 2054 if args.RelationId != nil { 2055 // We're in a relation context. 2056 rel, err := u.st.Relation(*args.RelationId) 2057 if err != nil { 2058 return params.NetworkInfoResults{}, err 2059 } 2060 endpoint, err := rel.Endpoint(unit.ApplicationName()) 2061 if err != nil { 2062 return params.NetworkInfoResults{}, err 2063 } 2064 boundSpace, ingress, egress, err := state.NetworksForRelation(endpoint.Name, unit, rel, modelCfg.EgressSubnets()) 2065 if err != nil { 2066 return params.NetworkInfoResults{}, err 2067 } 2068 spaces.Add(boundSpace) 2069 if len(egress) > 0 { 2070 bindingsToEgressSubnets[endpoint.Name] = egress 2071 } 2072 bindingsToIngressAddresses[endpoint.Name] = ingress 2073 } 2074 2075 var ( 2076 networkInfos map[string]state.MachineNetworkInfoResult 2077 defaultIngressAddresses []string 2078 ) 2079 2080 if unit.ShouldBeAssigned() { 2081 machineID, err := unit.AssignedMachineId() 2082 if err != nil { 2083 return params.NetworkInfoResults{}, err 2084 } 2085 machine, err := u.st.Machine(machineID) 2086 if err != nil { 2087 return params.NetworkInfoResults{}, err 2088 } 2089 networkInfos = machine.GetNetworkInfoForSpaces(spaces) 2090 } else { 2091 // For CAAS units, we build up a minimal result struct 2092 // based on the default space and unit public/private addresses, 2093 // ie the addresses of the CAAS service. 2094 addr, err := unit.AllAddresses() 2095 if err != nil { 2096 return params.NetworkInfoResults{}, err 2097 } 2098 network.SortAddresses(addr) 2099 2100 // We record the interface addresses as the machine local ones - these 2101 // are used later as the binding addresses. 2102 // For CAAS models, we need to default ingress addresses to all available 2103 // addresses so record those in the default ingress address slice. 2104 var interfaceAddr []network.InterfaceAddress 2105 for _, a := range addr { 2106 if a.Scope == network.ScopeMachineLocal { 2107 interfaceAddr = append(interfaceAddr, network.InterfaceAddress{Address: a.Value}) 2108 } 2109 defaultIngressAddresses = append(defaultIngressAddresses, a.Value) 2110 } 2111 networkInfos = make(map[string]state.MachineNetworkInfoResult) 2112 networkInfos[environs.DefaultSpaceName] = state.MachineNetworkInfoResult{ 2113 NetworkInfos: []network.NetworkInfo{{Addresses: interfaceAddr}}, 2114 } 2115 } 2116 2117 for binding, space := range bindingsToSpace { 2118 // The binding address information based on link layer devices. 2119 info := networkingcommon.MachineNetworkInfoResultToNetworkInfoResult(networkInfos[space]) 2120 2121 // Set egress and ingress address information. 2122 info.EgressSubnets = bindingsToEgressSubnets[binding] 2123 info.IngressAddresses = bindingsToIngressAddresses[binding] 2124 2125 // If there is no ingress address explicitly defined for a given binding, 2126 // set the ingress addresses to either any defaults set above, or the binding addresses. 2127 if len(info.IngressAddresses) == 0 { 2128 for _, addr := range defaultIngressAddresses { 2129 info.IngressAddresses = append(info.IngressAddresses, addr) 2130 } 2131 } 2132 if len(info.IngressAddresses) == 0 { 2133 for _, nwInfo := range info.Info { 2134 for _, addr := range nwInfo.Addresses { 2135 info.IngressAddresses = append(info.IngressAddresses, addr.Address) 2136 } 2137 } 2138 } 2139 2140 // If there is no egress subnet explicitly defined for a given binding, 2141 // default to the first ingress address. This matches the behaviour when 2142 // there's a relation in place. 2143 if len(info.EgressSubnets) == 0 && len(info.IngressAddresses) > 0 { 2144 info.EgressSubnets, err = network.FormatAsCIDR([]string{info.IngressAddresses[0]}) 2145 if err != nil { 2146 return result, errors.Trace(err) 2147 } 2148 } 2149 2150 result.Results[binding] = info 2151 } 2152 2153 return result, nil 2154 } 2155 2156 // WatchUnitRelations returns a StringsWatcher, for each given 2157 // unit, that notifies of changes to the lifecycles of relations 2158 // relevant to that unit. For principal units, this will be all of the 2159 // relations for the application. For subordinate units, only 2160 // relations with the principal unit's application will be monitored. 2161 func (u *UniterAPI) WatchUnitRelations(args params.Entities) (params.StringsWatchResults, error) { 2162 result := params.StringsWatchResults{ 2163 Results: make([]params.StringsWatchResult, len(args.Entities)), 2164 } 2165 canAccess, err := u.accessUnit() 2166 if err != nil { 2167 return params.StringsWatchResults{}, err 2168 } 2169 for i, entity := range args.Entities { 2170 tag, err := names.ParseUnitTag(entity.Tag) 2171 if err != nil { 2172 result.Results[i].Error = common.ServerError(common.ErrPerm) 2173 continue 2174 } 2175 err = common.ErrPerm 2176 if canAccess(tag) { 2177 result.Results[i], err = u.watchOneUnitRelations(tag) 2178 } 2179 result.Results[i].Error = common.ServerError(err) 2180 } 2181 return result, nil 2182 } 2183 2184 func (u *UniterAPI) watchOneUnitRelations(tag names.UnitTag) (params.StringsWatchResult, error) { 2185 nothing := params.StringsWatchResult{} 2186 unit, err := u.getUnit(tag) 2187 if err != nil { 2188 return nothing, err 2189 } 2190 app, err := unit.Application() 2191 if err != nil { 2192 return nothing, err 2193 } 2194 principalName, isSubordinate := unit.PrincipalName() 2195 var watch state.StringsWatcher 2196 if isSubordinate { 2197 principalUnit, err := u.st.Unit(principalName) 2198 if err != nil { 2199 return nothing, errors.Trace(err) 2200 } 2201 principalApp, err := principalUnit.Application() 2202 if err != nil { 2203 return nothing, errors.Trace(err) 2204 } 2205 watch, err = newSubordinateRelationsWatcher(u.st, app, principalApp.Name()) 2206 if err != nil { 2207 return nothing, errors.Trace(err) 2208 } 2209 } else { 2210 watch = app.WatchRelations() 2211 } 2212 // Consume the initial event and forward it to the result. 2213 if changes, ok := <-watch.Changes(); ok { 2214 return params.StringsWatchResult{ 2215 StringsWatcherId: u.resources.Register(watch), 2216 Changes: changes, 2217 }, nil 2218 } 2219 return nothing, watcher.EnsureErr(watch) 2220 } 2221 2222 // NetworkConfig returns information about all given relation/unit pairs, 2223 // including their id, key and the local endpoint. 2224 // It's not included in APIv5 2225 // TODO(wpk): NetworkConfig API is obsoleted by Uniter.NetworkInfo 2226 func (u *UniterAPIV4) NetworkConfig(args params.UnitsNetworkConfig) (params.UnitNetworkConfigResults, error) { 2227 result := params.UnitNetworkConfigResults{ 2228 Results: make([]params.UnitNetworkConfigResult, len(args.Args)), 2229 } 2230 2231 canAccess, err := u.accessUnit() 2232 if err != nil { 2233 return params.UnitNetworkConfigResults{}, err 2234 } 2235 2236 for i, arg := range args.Args { 2237 netConfig, err := u.getOneNetworkConfig(canAccess, arg.UnitTag, arg.BindingName) 2238 if err == nil { 2239 result.Results[i].Config = netConfig 2240 } else { 2241 result.Results[i].Error = common.ServerError(err) 2242 } 2243 } 2244 return result, nil 2245 } 2246 2247 func (u *UniterAPIV4) getOneNetworkConfig(canAccess common.AuthFunc, unitTagArg, bindingName string) ([]params.NetworkConfig, error) { 2248 unitTag, err := names.ParseUnitTag(unitTagArg) 2249 if err != nil { 2250 return nil, errors.Trace(err) 2251 } 2252 2253 if bindingName == "" { 2254 return nil, errors.Errorf("binding name cannot be empty") 2255 } 2256 2257 if !canAccess(unitTag) { 2258 return nil, common.ErrPerm 2259 } 2260 2261 unit, err := u.getUnit(unitTag) 2262 if err != nil { 2263 return nil, errors.Trace(err) 2264 } 2265 2266 application, err := unit.Application() 2267 if err != nil { 2268 return nil, errors.Trace(err) 2269 } 2270 2271 bindings, err := application.EndpointBindings() 2272 if err != nil { 2273 return nil, errors.Trace(err) 2274 } 2275 boundSpace, known := bindings[bindingName] 2276 if !known { 2277 return nil, errors.Errorf("binding name %q not defined by the unit's charm", bindingName) 2278 } 2279 2280 machineID, err := unit.AssignedMachineId() 2281 if err != nil { 2282 return nil, errors.Trace(err) 2283 } 2284 2285 machine, err := u.st.Machine(machineID) 2286 if err != nil { 2287 return nil, errors.Trace(err) 2288 } 2289 2290 var results []params.NetworkConfig 2291 if boundSpace == "" { 2292 logger.Debugf( 2293 "endpoint %q not explicitly bound to a space, using preferred private address for machine %q", 2294 bindingName, machineID, 2295 ) 2296 2297 privateAddress, err := machine.PrivateAddress() 2298 if err != nil { 2299 return nil, errors.Annotatef(err, "getting machine %q preferred private address", machineID) 2300 } 2301 2302 results = append(results, params.NetworkConfig{ 2303 Address: privateAddress.Value, 2304 }) 2305 return results, nil 2306 } else { 2307 logger.Debugf("endpoint %q is explicitly bound to space %q", bindingName, boundSpace) 2308 } 2309 2310 // TODO(dimitern): Use NetworkInterfaces() instead later, this is just for 2311 // the PoC to enable minimal network-get implementation returning just the 2312 // primary address. 2313 // 2314 // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119258804 2315 addresses, err := machine.AllAddresses() 2316 if err != nil { 2317 return nil, errors.Annotate(err, "cannot get devices addresses") 2318 } 2319 logger.Debugf( 2320 "getting network config for machine %q with addresses %+v, hosting unit %q of application %q, with bindings %+v", 2321 machineID, addresses, unit.Name(), application.Name(), bindings, 2322 ) 2323 2324 for _, addr := range addresses { 2325 subnet, err := addr.Subnet() 2326 if errors.IsNotFound(err) { 2327 logger.Debugf("skipping %s: not linked to a known subnet (%v)", addr, err) 2328 continue 2329 } else if err != nil { 2330 return nil, errors.Annotatef(err, "cannot get subnet for address %q", addr) 2331 } 2332 2333 if space := subnet.SpaceName(); space != boundSpace { 2334 logger.Debugf("skipping %s: want bound to space %q, got space %q", addr, boundSpace, space) 2335 continue 2336 } 2337 logger.Debugf("endpoint %q bound to space %q has address %q", bindingName, boundSpace, addr) 2338 2339 // TODO(dimitern): Fill in the rest later (see linked LKK card above). 2340 results = append(results, params.NetworkConfig{ 2341 Address: addr.Value(), 2342 }) 2343 } 2344 2345 return results, nil 2346 } 2347 2348 func relationResultsToV5(v6Results params.RelationResults) params.RelationResultsV5 { 2349 results := make([]params.RelationResultV5, len(v6Results.Results)) 2350 for i, v6Result := range v6Results.Results { 2351 results[i].Error = v6Result.Error 2352 results[i].Life = v6Result.Life 2353 results[i].Id = v6Result.Id 2354 results[i].Key = v6Result.Key 2355 results[i].Endpoint = v6Result.Endpoint 2356 } 2357 return params.RelationResultsV5{Results: results} 2358 } 2359 2360 // Relation returns information about all given relation/unit pairs, 2361 // including their id, key and the local endpoint (without other 2362 // application name). 2363 func (u *UniterAPIV5) Relation(args params.RelationUnits) (params.RelationResultsV5, error) { 2364 v6Results, err := u.UniterAPI.Relation(args) 2365 if err != nil { 2366 return params.RelationResultsV5{}, errors.Trace(err) 2367 } 2368 return relationResultsToV5(v6Results), nil 2369 } 2370 2371 // RelationById returns information about all given relations, 2372 // specified by their ids, including their key and the local 2373 // endpoint (without other application name). 2374 func (u *UniterAPIV5) RelationById(args params.RelationIds) (params.RelationResultsV5, error) { 2375 v6Results, err := u.UniterAPI.RelationById(args) 2376 if err != nil { 2377 return params.RelationResultsV5{}, errors.Trace(err) 2378 } 2379 return relationResultsToV5(v6Results), nil 2380 } 2381 2382 // WatchApplicationRelations returns a StringsWatcher, for each given 2383 // application, that notifies of changes to the lifecycles of 2384 // relations involving that application. This method is obsolete - 2385 // it's been replaced by WatchUnitRelations in V5 of the uniter API. 2386 func (u *UniterAPIV4) WatchApplicationRelations(args params.Entities) (params.StringsWatchResults, error) { 2387 result := params.StringsWatchResults{ 2388 Results: make([]params.StringsWatchResult, len(args.Entities)), 2389 } 2390 canAccess, err := u.accessApplication() 2391 if err != nil { 2392 return params.StringsWatchResults{}, err 2393 } 2394 for i, entity := range args.Entities { 2395 tag, err := names.ParseApplicationTag(entity.Tag) 2396 if err != nil { 2397 result.Results[i].Error = common.ServerError(common.ErrPerm) 2398 continue 2399 } 2400 err = common.ErrPerm 2401 if canAccess(tag) { 2402 result.Results[i], err = u.watchOneApplicationRelations(tag) 2403 } 2404 result.Results[i].Error = common.ServerError(err) 2405 } 2406 return result, nil 2407 } 2408 2409 func (u *UniterAPIV4) watchOneApplicationRelations(tag names.ApplicationTag) (params.StringsWatchResult, error) { 2410 nothing := params.StringsWatchResult{} 2411 application, err := u.getApplication(tag) 2412 if err != nil { 2413 return nothing, err 2414 } 2415 watch := application.WatchRelations() 2416 // Consume the initial event and forward it to the result. 2417 if changes, ok := <-watch.Changes(); ok { 2418 return params.StringsWatchResult{ 2419 StringsWatcherId: u.resources.Register(watch), 2420 Changes: changes, 2421 }, nil 2422 } 2423 return nothing, watcher.EnsureErr(watch) 2424 } 2425 2426 // Mask the new methods from the V4 API. The API reflection code in 2427 // rpc/rpcreflect/type.go:newMethod skips 2-argument methods, so this 2428 // removes the method as far as the RPC machinery is concerned. 2429 2430 // SLALevel isn't on the V4 API. 2431 func (u *UniterAPIV4) SLALevel(_, _ struct{}) {} 2432 2433 // NetworkInfo isn't on the V4 API. 2434 func (u *UniterAPIV4) NetworkInfo(_, _ struct{}) {} 2435 2436 // WatchUnitRelations isn't on the V4 API. 2437 func (u *UniterAPIV4) WatchUnitRelations(_, _ struct{}) {} 2438 2439 func networkInfoResultsToV6(v7Results params.NetworkInfoResults) params.NetworkInfoResultsV6 { 2440 results := make(map[string]params.NetworkInfoResultV6) 2441 for k, v6Result := range v7Results.Results { 2442 results[k] = params.NetworkInfoResultV6{Error: v6Result.Error, Info: v6Result.Info} 2443 } 2444 return params.NetworkInfoResultsV6{Results: results} 2445 } 2446 2447 // Network Info implements UniterAPIV6 version of NetworkInfo by constructing an API V6 compatible result. 2448 func (u *UniterAPIV6) NetworkInfo(args params.NetworkInfoParams) (params.NetworkInfoResultsV6, error) { 2449 v6Results, err := u.UniterAPI.NetworkInfo(args) 2450 if err != nil { 2451 return params.NetworkInfoResultsV6{}, errors.Trace(err) 2452 } 2453 return networkInfoResultsToV6(v6Results), nil 2454 } 2455 2456 // Mask the SetPodSpec method from the v7 API. The API reflection code 2457 // in rpc/rpcreflect/type.go:newMethod skips 2-argument methods, so 2458 // this removes the method as far as the RPC machinery is concerned. 2459 2460 // SetPodSpec isn't on the v7 API. 2461 func (u *UniterAPIV7) SetPodSpec(_, _ struct{}) {} 2462 2463 // SetPodSpec sets the pod specs for a set of applications. 2464 func (u *UniterAPI) SetPodSpec(args params.SetPodSpecParams) (params.ErrorResults, error) { 2465 results := params.ErrorResults{ 2466 Results: make([]params.ErrorResult, len(args.Specs)), 2467 } 2468 authTag := u.auth.GetAuthTag() 2469 canAccess := func(tag names.Tag) bool { 2470 if tag, ok := tag.(names.ApplicationTag); ok { 2471 switch authTag.(type) { 2472 case names.UnitTag: 2473 appName, err := names.UnitApplication(authTag.Id()) 2474 return err == nil && appName == tag.Id() 2475 case names.ApplicationTag: 2476 return tag == authTag 2477 } 2478 } 2479 return false 2480 } 2481 2482 cfg, err := u.m.ModelConfig() 2483 if err != nil { 2484 return params.ErrorResults{}, errors.Trace(err) 2485 } 2486 provider, err := environs.Provider(cfg.Type()) 2487 if err != nil { 2488 return params.ErrorResults{}, errors.Trace(err) 2489 } 2490 cassProvider, ok := provider.(caas.ContainerEnvironProvider) 2491 if !ok { 2492 return params.ErrorResults{}, errors.NotValidf("container environ provider %T", provider) 2493 } 2494 2495 for i, arg := range args.Specs { 2496 tag, err := names.ParseApplicationTag(arg.Tag) 2497 if err != nil { 2498 results.Results[i].Error = common.ServerError(err) 2499 continue 2500 } 2501 if !canAccess(tag) { 2502 results.Results[i].Error = common.ServerError(common.ErrPerm) 2503 continue 2504 } 2505 if _, err := cassProvider.ParsePodSpec(arg.Value); err != nil { 2506 results.Results[i].Error = common.ServerError(errors.Annotate(err, "invalid pod spec")) 2507 continue 2508 } 2509 cm, err := u.m.CAASModel() 2510 if err != nil { 2511 results.Results[i].Error = common.ServerError(err) 2512 continue 2513 } 2514 results.Results[i].Error = common.ServerError( 2515 cm.SetPodSpec(tag, arg.Value), 2516 ) 2517 } 2518 return results, nil 2519 } 2520 2521 // CloudSpec returns the cloud spec used by the model in which the 2522 // authenticated unit or application resides. 2523 // A check is made beforehand to ensure that the request is made by an entity 2524 // that has been granted the appropriate trust. 2525 func (u *UniterAPI) CloudSpec() (params.CloudSpecResult, error) { 2526 canAccess, err := u.accessCloudSpec() 2527 if err != nil { 2528 return params.CloudSpecResult{}, err 2529 } 2530 if !canAccess() { 2531 return params.CloudSpecResult{Error: common.ServerError(common.ErrPerm)}, nil 2532 } 2533 2534 return u.cloudSpec.GetCloudSpec(u.m.Tag().(names.ModelTag)), nil 2535 } 2536 2537 // GoalStates returns information of charm units and relations. 2538 func (u *UniterAPI) GoalStates(args params.Entities) (params.GoalStateResults, error) { 2539 result := params.GoalStateResults{ 2540 Results: make([]params.GoalStateResult, len(args.Entities)), 2541 } 2542 2543 canAccess, err := u.accessUnit() 2544 if err != nil { 2545 return params.GoalStateResults{}, err 2546 } 2547 for i, entity := range args.Entities { 2548 tag, err := names.ParseUnitTag(entity.Tag) 2549 if err != nil { 2550 result.Results[i].Error = common.ServerError(common.ErrPerm) 2551 continue 2552 } 2553 if !canAccess(tag) { 2554 result.Results[i].Error = common.ServerError(common.ErrPerm) 2555 continue 2556 } 2557 unit, err := u.getUnit(tag) 2558 if err != nil { 2559 result.Results[i].Error = common.ServerError(err) 2560 continue 2561 } 2562 result.Results[i].Result, err = u.oneGoalState(unit) 2563 if err != nil { 2564 result.Results[i].Error = common.ServerError(err) 2565 } 2566 } 2567 return result, nil 2568 } 2569 2570 // oneGoalState creates the goal state for a given unit. 2571 func (u *UniterAPI) oneGoalState(unit *state.Unit) (*params.GoalState, error) { 2572 app, err := unit.Application() 2573 if err != nil { 2574 return nil, err 2575 } 2576 2577 gs := params.GoalState{} 2578 gs.Units, err = u.goalStateUnits(app, unit.Name()) 2579 if err != nil { 2580 return nil, err 2581 } 2582 allRelations, err := app.Relations() 2583 if err != nil { 2584 return nil, err 2585 } 2586 if allRelations != nil { 2587 gs.Relations, err = u.goalStateRelations(app.Name(), unit.Name(), allRelations) 2588 if err != nil { 2589 return nil, err 2590 } 2591 } 2592 return &gs, nil 2593 } 2594 2595 // goalStateRelations creates the structure with all the relations between endpoints in an application. 2596 func (u *UniterAPI) goalStateRelations(appName, principalName string, allRelations []*state.Relation) (map[string]params.UnitsGoalState, error) { 2597 2598 result := map[string]params.UnitsGoalState{} 2599 2600 for _, r := range allRelations { 2601 statusInfo, err := r.Status() 2602 if err != nil { 2603 return nil, errors.Annotate(err, "getting relation status") 2604 } 2605 endPoints := r.Endpoints() 2606 for _, e := range endPoints { 2607 if e.Relation.Role == "peer" { 2608 continue 2609 } 2610 var key string 2611 app, err := u.st.Application(e.ApplicationName) 2612 if err == nil { 2613 key = app.Name() 2614 } else if errors.IsNotFound(err) { 2615 logger.Debugf("application %q must be a remote application.", e.ApplicationName) 2616 remoteApplication, err := u.st.RemoteApplication(e.ApplicationName) 2617 if err != nil { 2618 return nil, err 2619 } 2620 var ok bool 2621 key, ok = remoteApplication.URL() 2622 if !ok { 2623 // If we are on the offering side of a remote relation, don't show anything 2624 // in goal state for that relation. 2625 continue 2626 } 2627 } else { 2628 return nil, err 2629 } 2630 2631 // We don't show units for the same application as we are currently processing. 2632 if key == appName { 2633 continue 2634 } 2635 2636 goalState := params.GoalStateStatus{} 2637 goalState.Status = statusInfo.Status.String() 2638 goalState.Since = statusInfo.Since 2639 relationGoalState := result[e.Name] 2640 if relationGoalState == nil { 2641 relationGoalState = params.UnitsGoalState{} 2642 } 2643 relationGoalState[key] = goalState 2644 2645 // For local applications, add in the status of units as well. 2646 if app != nil { 2647 units, err := u.goalStateUnits(app, principalName) 2648 if err != nil { 2649 return nil, err 2650 } 2651 for unitName, unitGS := range units { 2652 relationGoalState[unitName] = unitGS 2653 } 2654 } 2655 2656 result[e.Name] = relationGoalState 2657 } 2658 } 2659 return result, nil 2660 } 2661 2662 // goalStateUnits loops through all application units related to principalName, 2663 // and stores the goal state status in UnitsGoalState. 2664 func (u *UniterAPI) goalStateUnits(app *state.Application, principalName string) (params.UnitsGoalState, error) { 2665 2666 allUnits, err := app.AllUnits() 2667 if err != nil { 2668 return nil, err 2669 } 2670 unitsGoalState := params.UnitsGoalState{} 2671 for _, unit := range allUnits { 2672 // Ignore subordinates belonging to other units. 2673 pn, ok := unit.PrincipalName() 2674 if ok && pn != principalName { 2675 continue 2676 } 2677 unitLife := unit.Life() 2678 if unitLife == state.Dead { 2679 // only show Alive and Dying units 2680 logger.Debugf("unit %q is dead, ignore it.", unit.Name()) 2681 continue 2682 } 2683 unitGoalState := params.GoalStateStatus{} 2684 statusInfo, err := unit.Status() 2685 if err != nil { 2686 return nil, errors.Trace(err) 2687 } 2688 unitGoalState.Status = statusInfo.Status.String() 2689 if unitLife == state.Dying { 2690 unitGoalState.Status = unitLife.String() 2691 } 2692 unitGoalState.Since = statusInfo.Since 2693 unitsGoalState[unit.Name()] = unitGoalState 2694 } 2695 2696 return unitsGoalState, nil 2697 } 2698 2699 // WatchConfigSettingsHash returns a StringsWatcher that yields a hash 2700 // of the config values every time the config changes. The uniter can 2701 // save this hash and use it to decide whether the config-changed hook 2702 // needs to be run (or whether this was just an agent restart with no 2703 // substantive config change). 2704 func (u *UniterAPI) WatchConfigSettingsHash(args params.Entities) (params.StringsWatchResults, error) { 2705 getWatcher := func(unit *state.Unit) (state.StringsWatcher, error) { 2706 return unit.WatchConfigSettingsHash() 2707 } 2708 result, err := u.watchHashes(args, getWatcher) 2709 if err != nil { 2710 return params.StringsWatchResults{}, errors.Trace(err) 2711 } 2712 return result, nil 2713 } 2714 2715 // WatchTrustConfigSettingsHash returns a StringsWatcher that yields a 2716 // hash of the application config values whenever they change. The 2717 // uniter can use the hash to determine whether the actual values have 2718 // changed since it last saw the config. 2719 func (u *UniterAPI) WatchTrustConfigSettingsHash(args params.Entities) (params.StringsWatchResults, error) { 2720 getWatcher := func(unit *state.Unit) (state.StringsWatcher, error) { 2721 return unit.WatchApplicationConfigSettingsHash() 2722 } 2723 result, err := u.watchHashes(args, getWatcher) 2724 if err != nil { 2725 return params.StringsWatchResults{}, errors.Trace(err) 2726 } 2727 return result, nil 2728 } 2729 2730 // WatchUnitAddressesHash returns a StringsWatcher that yields the 2731 // hashes of the addresses for the unit whenever the addresses 2732 // change. The uniter can use the hash to determine whether the actual 2733 // address values have changed since it last saw the config. 2734 func (u *UniterAPI) WatchUnitAddressesHash(args params.Entities) (params.StringsWatchResults, error) { 2735 getWatcher := func(unit *state.Unit) (state.StringsWatcher, error) { 2736 if !unit.ShouldBeAssigned() { 2737 return unit.WatchContainerAddressesHash(), nil 2738 } 2739 machineId, err := unit.AssignedMachineId() 2740 if err != nil { 2741 return nil, err 2742 } 2743 machine, err := u.st.Machine(machineId) 2744 if err != nil { 2745 return nil, err 2746 } 2747 return machine.WatchAddressesHash(), nil 2748 } 2749 result, err := u.watchHashes(args, getWatcher) 2750 if err != nil { 2751 return params.StringsWatchResults{}, errors.Trace(err) 2752 } 2753 return result, nil 2754 } 2755 2756 // Mask WatchConfigSettingsHash from the v8 API. The API reflection 2757 // code in rpc/rpcreflect/type.go:newMethod skips 2-argument methods, 2758 // so this removes the method as far as the RPC machinery is 2759 // concerned. 2760 2761 // WatchConfigSettingsHash isn't on the v8 API. 2762 func (u *UniterAPIV8) WatchConfigSettingsHash(_, _ struct{}) {} 2763 2764 // WatchTrustConfigSettingsHash isn't on the v8 API. 2765 func (u *UniterAPIV8) WatchTrustConfigSettingsHash(_, _ struct{}) {} 2766 2767 // WatchUnitAddressesHash isn't on the v8 API. 2768 func (u *UniterAPIV8) WatchUnitAddressesHash(_, _ struct{}) {} 2769 2770 func (u *UniterAPI) watchHashes(args params.Entities, getWatcher func(u *state.Unit) (state.StringsWatcher, error)) (params.StringsWatchResults, error) { 2771 result := params.StringsWatchResults{ 2772 Results: make([]params.StringsWatchResult, len(args.Entities)), 2773 } 2774 canAccess, err := u.accessUnit() 2775 if err != nil { 2776 return params.StringsWatchResults{}, err 2777 } 2778 for i, entity := range args.Entities { 2779 tag, err := names.ParseUnitTag(entity.Tag) 2780 if err != nil { 2781 result.Results[i].Error = common.ServerError(common.ErrPerm) 2782 continue 2783 } 2784 err = common.ErrPerm 2785 watcherId := "" 2786 var changes []string 2787 if canAccess(tag) { 2788 watcherId, changes, err = u.watchOneUnitHashes(tag, getWatcher) 2789 } 2790 result.Results[i].StringsWatcherId = watcherId 2791 result.Results[i].Changes = changes 2792 result.Results[i].Error = common.ServerError(err) 2793 } 2794 return result, nil 2795 } 2796 2797 func (u *UniterAPI) watchOneUnitHashes(tag names.UnitTag, getWatcher func(u *state.Unit) (state.StringsWatcher, error)) (string, []string, error) { 2798 unit, err := u.getUnit(tag) 2799 if err != nil { 2800 return "", nil, err 2801 } 2802 w, err := getWatcher(unit) 2803 if err != nil { 2804 return "", nil, errors.Trace(err) 2805 } 2806 // Consume the initial event. 2807 if changes, ok := <-w.Changes(); ok { 2808 return u.resources.Register(w), changes, nil 2809 } 2810 return "", nil, watcher.EnsureErr(w) 2811 }