github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/uniter/uniter_base.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // The uniter package implements the API interface used by the uniter 5 // worker. This file contains code common to all API versions. 6 package uniter 7 8 import ( 9 "fmt" 10 "net/url" 11 "path" 12 13 "github.com/juju/errors" 14 "github.com/juju/names" 15 "gopkg.in/juju/charm.v5" 16 17 "github.com/juju/juju/apiserver/common" 18 leadershipapiserver "github.com/juju/juju/apiserver/leadership" 19 "github.com/juju/juju/apiserver/meterstatus" 20 "github.com/juju/juju/apiserver/params" 21 "github.com/juju/juju/leadership" 22 "github.com/juju/juju/network" 23 "github.com/juju/juju/state" 24 "github.com/juju/juju/state/multiwatcher" 25 "github.com/juju/juju/state/watcher" 26 ) 27 28 // uniterBaseAPI implements common methods used by all API versions, 29 // and it's intended for embedding. 30 type uniterBaseAPI struct { 31 *common.LifeGetter 32 *StatusAPI 33 *common.DeadEnsurer 34 *common.AgentEntityWatcher 35 *common.APIAddresser 36 *common.EnvironWatcher 37 *common.RebootRequester 38 *leadershipapiserver.LeadershipSettingsAccessor 39 40 st *state.State 41 auth common.Authorizer 42 resources *common.Resources 43 accessUnit common.GetAuthFunc 44 accessService common.GetAuthFunc 45 unit *state.Unit 46 } 47 48 // newUniterBaseAPI creates a new instance of the uniter base API. 49 func newUniterBaseAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*uniterBaseAPI, error) { 50 if !authorizer.AuthUnitAgent() { 51 return nil, common.ErrPerm 52 } 53 var unit *state.Unit 54 var err error 55 switch tag := authorizer.GetAuthTag().(type) { 56 case names.UnitTag: 57 unit, err = st.Unit(tag.Id()) 58 if err != nil { 59 return nil, errors.Trace(err) 60 } 61 default: 62 return nil, errors.Errorf("expected names.UnitTag, got %T", tag) 63 } 64 accessUnit := func() (common.AuthFunc, error) { 65 return authorizer.AuthOwner, nil 66 } 67 accessService := func() (common.AuthFunc, error) { 68 switch tag := authorizer.GetAuthTag().(type) { 69 case names.UnitTag: 70 entity, err := st.Unit(tag.Id()) 71 if err != nil { 72 return nil, errors.Trace(err) 73 } 74 serviceName := entity.ServiceName() 75 serviceTag := names.NewServiceTag(serviceName) 76 return func(tag names.Tag) bool { 77 return tag == serviceTag 78 }, nil 79 default: 80 return nil, errors.Errorf("expected names.UnitTag, got %T", tag) 81 } 82 } 83 accessMachine := func() (common.AuthFunc, error) { 84 machineId, err := unit.AssignedMachineId() 85 if err != nil { 86 return nil, errors.Trace(err) 87 } 88 machine, err := st.Machine(machineId) 89 if err != nil { 90 return nil, errors.Trace(err) 91 } 92 return func(tag names.Tag) bool { 93 return tag == machine.Tag() 94 }, nil 95 } 96 97 accessUnitOrService := common.AuthEither(accessUnit, accessService) 98 return &uniterBaseAPI{ 99 LifeGetter: common.NewLifeGetter(st, accessUnitOrService), 100 DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), 101 AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), 102 APIAddresser: common.NewAPIAddresser(st, resources), 103 EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), 104 RebootRequester: common.NewRebootRequester(st, accessMachine), 105 LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), 106 107 // TODO(fwereade): so *every* unit should be allowed to get/set its 108 // own status *and* its service's? This is not a pleasing arrangement. 109 StatusAPI: NewStatusAPI(st, accessUnitOrService), 110 111 st: st, 112 auth: authorizer, 113 resources: resources, 114 accessUnit: accessUnit, 115 accessService: accessService, 116 unit: unit, 117 }, nil 118 } 119 120 // PublicAddress returns the public address for each given unit, if set. 121 func (u *uniterBaseAPI) PublicAddress(args params.Entities) (params.StringResults, error) { 122 result := params.StringResults{ 123 Results: make([]params.StringResult, len(args.Entities)), 124 } 125 canAccess, err := u.accessUnit() 126 if err != nil { 127 return params.StringResults{}, err 128 } 129 for i, entity := range args.Entities { 130 tag, err := names.ParseUnitTag(entity.Tag) 131 if err != nil { 132 result.Results[i].Error = common.ServerError(common.ErrPerm) 133 continue 134 } 135 err = common.ErrPerm 136 if canAccess(tag) { 137 var unit *state.Unit 138 unit, err = u.getUnit(tag) 139 if err == nil { 140 address, ok := unit.PublicAddress() 141 if ok { 142 result.Results[i].Result = address 143 } else { 144 err = common.NoAddressSetError(tag, "public") 145 } 146 } 147 } 148 result.Results[i].Error = common.ServerError(err) 149 } 150 return result, nil 151 } 152 153 // PrivateAddress returns the private address for each given unit, if set. 154 func (u *uniterBaseAPI) PrivateAddress(args params.Entities) (params.StringResults, error) { 155 result := params.StringResults{ 156 Results: make([]params.StringResult, len(args.Entities)), 157 } 158 canAccess, err := u.accessUnit() 159 if err != nil { 160 return params.StringResults{}, err 161 } 162 for i, entity := range args.Entities { 163 tag, err := names.ParseUnitTag(entity.Tag) 164 if err != nil { 165 result.Results[i].Error = common.ServerError(common.ErrPerm) 166 continue 167 } 168 err = common.ErrPerm 169 if canAccess(tag) { 170 var unit *state.Unit 171 unit, err = u.getUnit(tag) 172 if err == nil { 173 address, ok := unit.PrivateAddress() 174 if ok { 175 result.Results[i].Result = address 176 } else { 177 err = common.NoAddressSetError(tag, "private") 178 } 179 } 180 } 181 result.Results[i].Error = common.ServerError(err) 182 } 183 return result, nil 184 } 185 186 // TODO(ericsnow) Factor out the common code amongst the many methods here. 187 188 var getZone = func(st *state.State, tag names.Tag) (string, error) { 189 unit, err := st.Unit(tag.Id()) 190 if err != nil { 191 return "", errors.Trace(err) 192 } 193 zone, err := unit.AvailabilityZone() 194 return zone, errors.Trace(err) 195 } 196 197 // AvailabilityZone returns the availability zone for each given unit, if applicable. 198 func (u *uniterBaseAPI) AvailabilityZone(args params.Entities) (params.StringResults, error) { 199 var results params.StringResults 200 201 canAccess, err := u.accessUnit() 202 if err != nil { 203 return results, errors.Trace(err) 204 } 205 206 // Prep the results. 207 results = params.StringResults{ 208 Results: make([]params.StringResult, len(args.Entities)), 209 } 210 211 // Collect the zones. No zone will be collected for any entity where 212 // the tag is invalid or not authorized. Instead the corresponding 213 // result will be updated with the error. 214 for i, entity := range args.Entities { 215 tag, err := names.ParseUnitTag(entity.Tag) 216 if err != nil { 217 results.Results[i].Error = common.ServerError(common.ErrPerm) 218 continue 219 } 220 err = common.ErrPerm 221 if canAccess(tag) { 222 var zone string 223 zone, err = getZone(u.st, tag) 224 if err == nil { 225 results.Results[i].Result = zone 226 } 227 } 228 results.Results[i].Error = common.ServerError(err) 229 } 230 231 return results, nil 232 } 233 234 // Resolved returns the current resolved setting for each given unit. 235 func (u *uniterBaseAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) { 236 result := params.ResolvedModeResults{ 237 Results: make([]params.ResolvedModeResult, len(args.Entities)), 238 } 239 canAccess, err := u.accessUnit() 240 if err != nil { 241 return params.ResolvedModeResults{}, err 242 } 243 for i, entity := range args.Entities { 244 tag, err := names.ParseUnitTag(entity.Tag) 245 if err != nil { 246 result.Results[i].Error = common.ServerError(common.ErrPerm) 247 continue 248 } 249 err = common.ErrPerm 250 if canAccess(tag) { 251 var unit *state.Unit 252 unit, err = u.getUnit(tag) 253 if err == nil { 254 result.Results[i].Mode = params.ResolvedMode(unit.Resolved()) 255 } 256 } 257 result.Results[i].Error = common.ServerError(err) 258 } 259 return result, nil 260 } 261 262 // ClearResolved removes any resolved setting from each given unit. 263 func (u *uniterBaseAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) { 264 result := params.ErrorResults{ 265 Results: make([]params.ErrorResult, len(args.Entities)), 266 } 267 canAccess, err := u.accessUnit() 268 if err != nil { 269 return params.ErrorResults{}, err 270 } 271 for i, entity := range args.Entities { 272 tag, err := names.ParseUnitTag(entity.Tag) 273 if err != nil { 274 result.Results[i].Error = common.ServerError(common.ErrPerm) 275 continue 276 } 277 err = common.ErrPerm 278 if canAccess(tag) { 279 var unit *state.Unit 280 unit, err = u.getUnit(tag) 281 if err == nil { 282 err = unit.ClearResolved() 283 } 284 } 285 result.Results[i].Error = common.ServerError(err) 286 } 287 return result, nil 288 } 289 290 // GetPrincipal returns the result of calling PrincipalName() and 291 // converting it to a tag, on each given unit. 292 func (u *uniterBaseAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) { 293 result := params.StringBoolResults{ 294 Results: make([]params.StringBoolResult, len(args.Entities)), 295 } 296 canAccess, err := u.accessUnit() 297 if err != nil { 298 return params.StringBoolResults{}, err 299 } 300 for i, entity := range args.Entities { 301 tag, err := names.ParseUnitTag(entity.Tag) 302 if err != nil { 303 result.Results[i].Error = common.ServerError(common.ErrPerm) 304 continue 305 } 306 err = common.ErrPerm 307 if canAccess(tag) { 308 var unit *state.Unit 309 unit, err = u.getUnit(tag) 310 if err == nil { 311 principal, ok := unit.PrincipalName() 312 if principal != "" { 313 result.Results[i].Result = names.NewUnitTag(principal).String() 314 } 315 result.Results[i].Ok = ok 316 } 317 } 318 result.Results[i].Error = common.ServerError(err) 319 } 320 return result, nil 321 } 322 323 // Destroy advances all given Alive units' lifecycles as far as 324 // possible. See state/Unit.Destroy(). 325 func (u *uniterBaseAPI) Destroy(args params.Entities) (params.ErrorResults, error) { 326 result := params.ErrorResults{ 327 Results: make([]params.ErrorResult, len(args.Entities)), 328 } 329 canAccess, err := u.accessUnit() 330 if err != nil { 331 return params.ErrorResults{}, err 332 } 333 for i, entity := range args.Entities { 334 tag, err := names.ParseUnitTag(entity.Tag) 335 if err != nil { 336 result.Results[i].Error = common.ServerError(common.ErrPerm) 337 continue 338 } 339 err = common.ErrPerm 340 if canAccess(tag) { 341 var unit *state.Unit 342 unit, err = u.getUnit(tag) 343 if err == nil { 344 err = unit.Destroy() 345 } 346 } 347 result.Results[i].Error = common.ServerError(err) 348 } 349 return result, nil 350 } 351 352 // DestroyAllSubordinates destroys all subordinates of each given unit. 353 func (u *uniterBaseAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) { 354 result := params.ErrorResults{ 355 Results: make([]params.ErrorResult, len(args.Entities)), 356 } 357 canAccess, err := u.accessUnit() 358 if err != nil { 359 return params.ErrorResults{}, err 360 } 361 for i, entity := range args.Entities { 362 tag, err := names.ParseUnitTag(entity.Tag) 363 if err != nil { 364 result.Results[i].Error = common.ServerError(common.ErrPerm) 365 continue 366 } 367 err = common.ErrPerm 368 if canAccess(tag) { 369 var unit *state.Unit 370 unit, err = u.getUnit(tag) 371 if err == nil { 372 err = u.destroySubordinates(unit) 373 } 374 } 375 result.Results[i].Error = common.ServerError(err) 376 } 377 return result, nil 378 } 379 380 // HasSubordinates returns the whether each given unit has any subordinates. 381 func (u *uniterBaseAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) { 382 result := params.BoolResults{ 383 Results: make([]params.BoolResult, len(args.Entities)), 384 } 385 canAccess, err := u.accessUnit() 386 if err != nil { 387 return params.BoolResults{}, err 388 } 389 for i, entity := range args.Entities { 390 tag, err := names.ParseUnitTag(entity.Tag) 391 if err != nil { 392 result.Results[i].Error = common.ServerError(common.ErrPerm) 393 continue 394 } 395 err = common.ErrPerm 396 if canAccess(tag) { 397 var unit *state.Unit 398 unit, err = u.getUnit(tag) 399 if err == nil { 400 subordinates := unit.SubordinateNames() 401 result.Results[i].Result = len(subordinates) > 0 402 } 403 } 404 result.Results[i].Error = common.ServerError(err) 405 } 406 return result, nil 407 } 408 409 // CharmURL returns the charm URL for all given units or services. 410 func (u *uniterBaseAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) { 411 result := params.StringBoolResults{ 412 Results: make([]params.StringBoolResult, len(args.Entities)), 413 } 414 accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) 415 canAccess, err := accessUnitOrService() 416 if err != nil { 417 return params.StringBoolResults{}, err 418 } 419 for i, entity := range args.Entities { 420 tag, err := names.ParseTag(entity.Tag) 421 if err != nil { 422 result.Results[i].Error = common.ServerError(common.ErrPerm) 423 continue 424 } 425 err = common.ErrPerm 426 if canAccess(tag) { 427 var unitOrService state.Entity 428 unitOrService, err = u.st.FindEntity(tag) 429 if err == nil { 430 charmURLer := unitOrService.(interface { 431 CharmURL() (*charm.URL, bool) 432 }) 433 curl, ok := charmURLer.CharmURL() 434 if curl != nil { 435 result.Results[i].Result = curl.String() 436 result.Results[i].Ok = ok 437 } 438 } 439 } 440 result.Results[i].Error = common.ServerError(err) 441 } 442 return result, nil 443 } 444 445 // SetCharmURL sets the charm URL for each given unit. An error will 446 // be returned if a unit is dead, or the charm URL is not know. 447 func (u *uniterBaseAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) { 448 result := params.ErrorResults{ 449 Results: make([]params.ErrorResult, len(args.Entities)), 450 } 451 canAccess, err := u.accessUnit() 452 if err != nil { 453 return params.ErrorResults{}, err 454 } 455 for i, entity := range args.Entities { 456 tag, err := names.ParseUnitTag(entity.Tag) 457 if err != nil { 458 result.Results[i].Error = common.ServerError(common.ErrPerm) 459 continue 460 } 461 err = common.ErrPerm 462 if canAccess(tag) { 463 var unit *state.Unit 464 unit, err = u.getUnit(tag) 465 if err == nil { 466 var curl *charm.URL 467 curl, err = charm.ParseURL(entity.CharmURL) 468 if err == nil { 469 err = unit.SetCharmURL(curl) 470 } 471 } 472 } 473 result.Results[i].Error = common.ServerError(err) 474 } 475 return result, nil 476 } 477 478 // OpenPorts sets the policy of the port range with protocol to be 479 // opened, for all given units. 480 func (u *uniterBaseAPI) OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 481 result := params.ErrorResults{ 482 Results: make([]params.ErrorResult, len(args.Entities)), 483 } 484 canAccess, err := u.accessUnit() 485 if err != nil { 486 return params.ErrorResults{}, err 487 } 488 for i, entity := range args.Entities { 489 tag, err := names.ParseUnitTag(entity.Tag) 490 if err != nil { 491 result.Results[i].Error = common.ServerError(common.ErrPerm) 492 continue 493 } 494 err = common.ErrPerm 495 if canAccess(tag) { 496 var unit *state.Unit 497 unit, err = u.getUnit(tag) 498 if err == nil { 499 err = unit.OpenPorts(entity.Protocol, entity.FromPort, entity.ToPort) 500 } 501 } 502 result.Results[i].Error = common.ServerError(err) 503 } 504 return result, nil 505 } 506 507 // ClosePorts sets the policy of the port range with protocol to be 508 // closed, for all given units. 509 func (u *uniterBaseAPI) ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 510 result := params.ErrorResults{ 511 Results: make([]params.ErrorResult, len(args.Entities)), 512 } 513 canAccess, err := u.accessUnit() 514 if err != nil { 515 return params.ErrorResults{}, err 516 } 517 for i, entity := range args.Entities { 518 tag, err := names.ParseUnitTag(entity.Tag) 519 if err != nil { 520 result.Results[i].Error = common.ServerError(common.ErrPerm) 521 continue 522 } 523 err = common.ErrPerm 524 if canAccess(tag) { 525 var unit *state.Unit 526 unit, err = u.getUnit(tag) 527 if err == nil { 528 err = unit.ClosePorts(entity.Protocol, entity.FromPort, entity.ToPort) 529 } 530 } 531 result.Results[i].Error = common.ServerError(err) 532 } 533 return result, nil 534 } 535 536 // OpenPort sets the policy of the port with protocol an number to be 537 // opened, for all given units. 538 // 539 // TODO(dimitern): This is deprecated and is kept for 540 // backwards-compatibility. Use OpenPorts instead. 541 func (u *uniterBaseAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) { 542 rangesArgs := params.EntitiesPortRanges{ 543 Entities: make([]params.EntityPortRange, len(args.Entities)), 544 } 545 for i, entity := range args.Entities { 546 rangesArgs.Entities[i] = params.EntityPortRange{ 547 Tag: entity.Tag, 548 Protocol: entity.Protocol, 549 FromPort: entity.Port, 550 ToPort: entity.Port, 551 } 552 } 553 return u.OpenPorts(rangesArgs) 554 } 555 556 // ClosePort sets the policy of the port with protocol and number to 557 // be closed, for all given units. 558 // 559 // TODO(dimitern): This is deprecated and is kept for 560 // backwards-compatibility. Use ClosePorts instead. 561 func (u *uniterBaseAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) { 562 rangesArgs := params.EntitiesPortRanges{ 563 Entities: make([]params.EntityPortRange, len(args.Entities)), 564 } 565 for i, entity := range args.Entities { 566 rangesArgs.Entities[i] = params.EntityPortRange{ 567 Tag: entity.Tag, 568 Protocol: entity.Protocol, 569 FromPort: entity.Port, 570 ToPort: entity.Port, 571 } 572 } 573 return u.ClosePorts(rangesArgs) 574 } 575 576 // WatchConfigSettings returns a NotifyWatcher for observing changes 577 // to each unit's service configuration settings. See also 578 // state/watcher.go:Unit.WatchConfigSettings(). 579 func (u *uniterBaseAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 580 result := params.NotifyWatchResults{ 581 Results: make([]params.NotifyWatchResult, len(args.Entities)), 582 } 583 canAccess, err := u.accessUnit() 584 if err != nil { 585 return params.NotifyWatchResults{}, err 586 } 587 for i, entity := range args.Entities { 588 tag, err := names.ParseUnitTag(entity.Tag) 589 if err != nil { 590 result.Results[i].Error = common.ServerError(common.ErrPerm) 591 continue 592 } 593 err = common.ErrPerm 594 watcherId := "" 595 if canAccess(tag) { 596 watcherId, err = u.watchOneUnitConfigSettings(tag) 597 } 598 result.Results[i].NotifyWatcherId = watcherId 599 result.Results[i].Error = common.ServerError(err) 600 } 601 return result, nil 602 } 603 604 // WatchMeterStatus returns a NotifyWatcher for observing changes 605 // to each unit's meter status. 606 func (u *uniterBaseAPI) WatchMeterStatus(args params.Entities) (params.NotifyWatchResults, error) { 607 result := params.NotifyWatchResults{ 608 Results: make([]params.NotifyWatchResult, len(args.Entities)), 609 } 610 canAccess, err := u.accessUnit() 611 if err != nil { 612 return params.NotifyWatchResults{}, err 613 } 614 for i, entity := range args.Entities { 615 tag, err := names.ParseUnitTag(entity.Tag) 616 if err != nil { 617 result.Results[i].Error = common.ServerError(common.ErrPerm) 618 continue 619 } 620 err = common.ErrPerm 621 watcherId := "" 622 if canAccess(tag) { 623 watcherId, err = u.watchOneUnitMeterStatus(tag) 624 } 625 result.Results[i].NotifyWatcherId = watcherId 626 result.Results[i].Error = common.ServerError(err) 627 } 628 return result, nil 629 } 630 631 // WatchActionNotifications returns a StringsWatcher for observing 632 // incoming action calls to a unit. See also state/watcher.go 633 // Unit.WatchActionNotifications(). This method is called from 634 // api/uniter/uniter.go WatchActionNotifications(). 635 func (u *uniterBaseAPI) WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) { 636 nothing := params.StringsWatchResults{} 637 638 result := params.StringsWatchResults{ 639 Results: make([]params.StringsWatchResult, len(args.Entities)), 640 } 641 canAccess, err := u.accessUnit() 642 if err != nil { 643 return nothing, err 644 } 645 for i, entity := range args.Entities { 646 tag, err := names.ParseUnitTag(entity.Tag) 647 if err != nil { 648 return nothing, err 649 } 650 err = common.ErrPerm 651 if canAccess(tag) { 652 result.Results[i], err = u.watchOneUnitActionNotifications(tag) 653 } 654 result.Results[i].Error = common.ServerError(err) 655 } 656 return result, nil 657 } 658 659 // ConfigSettings returns the complete set of service charm config 660 // settings available to each given unit. 661 func (u *uniterBaseAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) { 662 result := params.ConfigSettingsResults{ 663 Results: make([]params.ConfigSettingsResult, len(args.Entities)), 664 } 665 canAccess, err := u.accessUnit() 666 if err != nil { 667 return params.ConfigSettingsResults{}, err 668 } 669 for i, entity := range args.Entities { 670 tag, err := names.ParseUnitTag(entity.Tag) 671 if err != nil { 672 result.Results[i].Error = common.ServerError(common.ErrPerm) 673 continue 674 } 675 err = common.ErrPerm 676 if canAccess(tag) { 677 var unit *state.Unit 678 unit, err = u.getUnit(tag) 679 if err == nil { 680 var settings charm.Settings 681 settings, err = unit.ConfigSettings() 682 if err == nil { 683 result.Results[i].Settings = params.ConfigSettings(settings) 684 } 685 } 686 } 687 result.Results[i].Error = common.ServerError(err) 688 } 689 return result, nil 690 } 691 692 // WatchServiceRelations returns a StringsWatcher, for each given 693 // service, that notifies of changes to the lifecycles of relations 694 // involving that service. 695 func (u *uniterBaseAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) { 696 result := params.StringsWatchResults{ 697 Results: make([]params.StringsWatchResult, len(args.Entities)), 698 } 699 canAccess, err := u.accessService() 700 if err != nil { 701 return params.StringsWatchResults{}, err 702 } 703 for i, entity := range args.Entities { 704 tag, err := names.ParseServiceTag(entity.Tag) 705 if err != nil { 706 result.Results[i].Error = common.ServerError(common.ErrPerm) 707 continue 708 } 709 err = common.ErrPerm 710 if canAccess(tag) { 711 result.Results[i], err = u.watchOneServiceRelations(tag) 712 } 713 result.Results[i].Error = common.ServerError(err) 714 } 715 return result, nil 716 } 717 718 // CharmArchiveSha256 returns the SHA256 digest of the charm archive 719 // (bundle) data for each charm url in the given parameters. 720 func (u *uniterBaseAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) { 721 result := params.StringResults{ 722 Results: make([]params.StringResult, len(args.URLs)), 723 } 724 for i, arg := range args.URLs { 725 curl, err := charm.ParseURL(arg.URL) 726 if err != nil { 727 err = common.ErrPerm 728 } else { 729 var sch *state.Charm 730 sch, err = u.st.Charm(curl) 731 if errors.IsNotFound(err) { 732 err = common.ErrPerm 733 } 734 if err == nil { 735 result.Results[i].Result = sch.BundleSha256() 736 } 737 } 738 result.Results[i].Error = common.ServerError(err) 739 } 740 return result, nil 741 } 742 743 // CharmArchiveURLs returns the URLS for the charm archive 744 // (bundle) data for each charm url in the given parameters. 745 func (u *uniterBaseAPI) CharmArchiveURLs(args params.CharmURLs) (params.StringsResults, error) { 746 apiHostPorts, err := u.st.APIHostPorts() 747 if err != nil { 748 return params.StringsResults{}, err 749 } 750 envUUID := u.st.EnvironUUID() 751 result := params.StringsResults{ 752 Results: make([]params.StringsResult, len(args.URLs)), 753 } 754 for i, curl := range args.URLs { 755 if _, err := charm.ParseURL(curl.URL); err != nil { 756 result.Results[i].Error = common.ServerError(common.ErrPerm) 757 continue 758 } 759 urlPath := "/" 760 if envUUID != "" { 761 urlPath = path.Join(urlPath, "environment", envUUID) 762 } 763 urlPath = path.Join(urlPath, "charms") 764 archiveURLs := make([]string, len(apiHostPorts)) 765 for j, server := range apiHostPorts { 766 archiveURL := &url.URL{ 767 Scheme: "https", 768 Host: network.SelectInternalHostPort(server, false), 769 Path: urlPath, 770 } 771 q := archiveURL.Query() 772 q.Set("url", curl.URL) 773 q.Set("file", "*") 774 archiveURL.RawQuery = q.Encode() 775 archiveURLs[j] = archiveURL.String() 776 } 777 result.Results[i].Result = archiveURLs 778 } 779 return result, nil 780 } 781 782 // Relation returns information about all given relation/unit pairs, 783 // including their id, key and the local endpoint. 784 func (u *uniterBaseAPI) Relation(args params.RelationUnits) (params.RelationResults, error) { 785 result := params.RelationResults{ 786 Results: make([]params.RelationResult, len(args.RelationUnits)), 787 } 788 canAccess, err := u.accessUnit() 789 if err != nil { 790 return params.RelationResults{}, err 791 } 792 for i, rel := range args.RelationUnits { 793 relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit) 794 if err == nil { 795 result.Results[i] = relParams 796 } 797 result.Results[i].Error = common.ServerError(err) 798 } 799 return result, nil 800 } 801 802 // Actions returns the Actions by Tags passed and ensures that the Unit asking 803 // for them is the same Unit that has the Actions. 804 func (u *uniterBaseAPI) Actions(args params.Entities) (params.ActionsQueryResults, error) { 805 nothing := params.ActionsQueryResults{} 806 807 actionFn, err := u.authAndActionFromTagFn() 808 if err != nil { 809 return nothing, err 810 } 811 812 results := params.ActionsQueryResults{ 813 Results: make([]params.ActionsQueryResult, len(args.Entities)), 814 } 815 816 for i, arg := range args.Entities { 817 action, err := actionFn(arg.Tag) 818 if err != nil { 819 results.Results[i].Error = common.ServerError(err) 820 continue 821 } 822 if action.Status() != state.ActionPending { 823 results.Results[i].Error = common.ServerError(common.ErrActionNotAvailable) 824 continue 825 } 826 results.Results[i].Action.Action = ¶ms.Action{ 827 Name: action.Name(), 828 Parameters: action.Parameters(), 829 } 830 } 831 832 return results, nil 833 } 834 835 // BeginActions marks the actions represented by the passed in Tags as running. 836 func (u *uniterBaseAPI) BeginActions(args params.Entities) (params.ErrorResults, error) { 837 nothing := params.ErrorResults{} 838 839 actionFn, err := u.authAndActionFromTagFn() 840 if err != nil { 841 return nothing, err 842 } 843 844 results := params.ErrorResults{Results: make([]params.ErrorResult, len(args.Entities))} 845 846 for i, arg := range args.Entities { 847 action, err := actionFn(arg.Tag) 848 if err != nil { 849 results.Results[i].Error = common.ServerError(err) 850 continue 851 } 852 853 _, err = action.Begin() 854 if err != nil { 855 results.Results[i].Error = common.ServerError(err) 856 continue 857 } 858 } 859 860 return results, nil 861 } 862 863 // FinishActions saves the result of a completed Action 864 func (u *uniterBaseAPI) FinishActions(args params.ActionExecutionResults) (params.ErrorResults, error) { 865 nothing := params.ErrorResults{} 866 867 actionFn, err := u.authAndActionFromTagFn() 868 if err != nil { 869 return nothing, err 870 } 871 872 results := params.ErrorResults{Results: make([]params.ErrorResult, len(args.Results))} 873 874 for i, arg := range args.Results { 875 action, err := actionFn(arg.ActionTag) 876 if err != nil { 877 results.Results[i].Error = common.ServerError(err) 878 continue 879 } 880 actionResults, err := paramsActionExecutionResultsToStateActionResults(arg) 881 if err != nil { 882 results.Results[i].Error = common.ServerError(err) 883 continue 884 } 885 886 _, err = action.Finish(actionResults) 887 if err != nil { 888 results.Results[i].Error = common.ServerError(err) 889 continue 890 } 891 } 892 893 return results, nil 894 } 895 896 // paramsActionExecutionResultsToStateActionResults does exactly what 897 // the name implies. 898 func paramsActionExecutionResultsToStateActionResults(arg params.ActionExecutionResult) (state.ActionResults, error) { 899 var status state.ActionStatus 900 switch arg.Status { 901 case params.ActionCancelled: 902 status = state.ActionCancelled 903 case params.ActionCompleted: 904 status = state.ActionCompleted 905 case params.ActionFailed: 906 status = state.ActionFailed 907 case params.ActionPending: 908 status = state.ActionPending 909 default: 910 return state.ActionResults{}, errors.Errorf("unrecognized action status '%s'", arg.Status) 911 } 912 return state.ActionResults{ 913 Status: status, 914 Results: arg.Results, 915 Message: arg.Message, 916 }, nil 917 } 918 919 // RelationById returns information about all given relations, 920 // specified by their ids, including their key and the local 921 // endpoint. 922 func (u *uniterBaseAPI) RelationById(args params.RelationIds) (params.RelationResults, error) { 923 result := params.RelationResults{ 924 Results: make([]params.RelationResult, len(args.RelationIds)), 925 } 926 for i, relId := range args.RelationIds { 927 relParams, err := u.getOneRelationById(relId) 928 if err == nil { 929 result.Results[i] = relParams 930 } 931 result.Results[i].Error = common.ServerError(err) 932 } 933 return result, nil 934 } 935 936 // JoinedRelations returns the tags of all relations for which each supplied unit 937 // has entered scope. It should be called RelationsInScope, but it's not convenient 938 // to make that change until we have versioned APIs. 939 func (u *uniterBaseAPI) JoinedRelations(args params.Entities) (params.StringsResults, error) { 940 result := params.StringsResults{ 941 Results: make([]params.StringsResult, len(args.Entities)), 942 } 943 if len(args.Entities) == 0 { 944 return result, nil 945 } 946 canRead, err := u.accessUnit() 947 if err != nil { 948 return params.StringsResults{}, err 949 } 950 for i, entity := range args.Entities { 951 tag, err := names.ParseUnitTag(entity.Tag) 952 if err != nil { 953 result.Results[i].Error = common.ServerError(common.ErrPerm) 954 continue 955 } 956 err = common.ErrPerm 957 if canRead(tag) { 958 var unit *state.Unit 959 unit, err = u.getUnit(tag) 960 if err == nil { 961 result.Results[i].Result, err = relationsInScopeTags(unit) 962 } 963 } 964 result.Results[i].Error = common.ServerError(err) 965 } 966 return result, nil 967 } 968 969 // CurrentEnvironUUID returns the UUID for the current juju environment. 970 func (u *uniterBaseAPI) CurrentEnvironUUID() (params.StringResult, error) { 971 result := params.StringResult{} 972 env, err := u.st.Environment() 973 if err == nil { 974 result.Result = env.UUID() 975 } 976 return result, err 977 } 978 979 // CurrentEnvironment returns the name and UUID for the current juju environment. 980 func (u *uniterBaseAPI) CurrentEnvironment() (params.EnvironmentResult, error) { 981 result := params.EnvironmentResult{} 982 env, err := u.st.Environment() 983 if err == nil { 984 result.Name = env.Name() 985 result.UUID = env.UUID() 986 } 987 return result, err 988 } 989 990 // ProviderType returns the provider type used by the current juju 991 // environment. 992 // 993 // TODO(dimitern): Refactor the uniter to call this instead of calling 994 // EnvironConfig() just to get the provider type. Once we have machine 995 // addresses, this might be completely unnecessary though. 996 func (u *uniterBaseAPI) ProviderType() (params.StringResult, error) { 997 result := params.StringResult{} 998 cfg, err := u.st.EnvironConfig() 999 if err == nil { 1000 result.Result = cfg.Type() 1001 } 1002 return result, err 1003 } 1004 1005 // EnterScope ensures each unit has entered its scope in the relation, 1006 // for all of the given relation/unit pairs. See also 1007 // state.RelationUnit.EnterScope(). 1008 func (u *uniterBaseAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) { 1009 result := params.ErrorResults{ 1010 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1011 } 1012 canAccess, err := u.accessUnit() 1013 if err != nil { 1014 return params.ErrorResults{}, err 1015 } 1016 for i, arg := range args.RelationUnits { 1017 tag, err := names.ParseUnitTag(arg.Unit) 1018 if err != nil { 1019 result.Results[i].Error = common.ServerError(common.ErrPerm) 1020 continue 1021 } 1022 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, tag) 1023 if err == nil { 1024 // Construct the settings, passing the unit's 1025 // private address (we already know it). 1026 privateAddress, _ := relUnit.PrivateAddress() 1027 settings := map[string]interface{}{ 1028 "private-address": privateAddress, 1029 } 1030 err = relUnit.EnterScope(settings) 1031 } 1032 result.Results[i].Error = common.ServerError(err) 1033 } 1034 return result, nil 1035 } 1036 1037 // LeaveScope signals each unit has left its scope in the relation, 1038 // for all of the given relation/unit pairs. See also 1039 // state.RelationUnit.LeaveScope(). 1040 func (u *uniterBaseAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) { 1041 result := params.ErrorResults{ 1042 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1043 } 1044 canAccess, err := u.accessUnit() 1045 if err != nil { 1046 return params.ErrorResults{}, err 1047 } 1048 for i, arg := range args.RelationUnits { 1049 unit, err := names.ParseUnitTag(arg.Unit) 1050 if err != nil { 1051 result.Results[i].Error = common.ServerError(common.ErrPerm) 1052 continue 1053 } 1054 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1055 if err == nil { 1056 err = relUnit.LeaveScope() 1057 } 1058 result.Results[i].Error = common.ServerError(err) 1059 } 1060 return result, nil 1061 } 1062 1063 // ReadSettings returns the local settings of each given set of 1064 // relation/unit. 1065 func (u *uniterBaseAPI) ReadSettings(args params.RelationUnits) (params.SettingsResults, error) { 1066 result := params.SettingsResults{ 1067 Results: make([]params.SettingsResult, len(args.RelationUnits)), 1068 } 1069 canAccess, err := u.accessUnit() 1070 if err != nil { 1071 return params.SettingsResults{}, err 1072 } 1073 for i, arg := range args.RelationUnits { 1074 unit, err := names.ParseUnitTag(arg.Unit) 1075 if err != nil { 1076 result.Results[i].Error = common.ServerError(common.ErrPerm) 1077 continue 1078 } 1079 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1080 if err == nil { 1081 var settings *state.Settings 1082 settings, err = relUnit.Settings() 1083 if err == nil { 1084 result.Results[i].Settings, err = convertRelationSettings(settings.Map()) 1085 } 1086 } 1087 result.Results[i].Error = common.ServerError(err) 1088 } 1089 return result, nil 1090 } 1091 1092 // ReadRemoteSettings returns the remote settings of each given set of 1093 // relation/local unit/remote unit. 1094 func (u *uniterBaseAPI) ReadRemoteSettings(args params.RelationUnitPairs) (params.SettingsResults, error) { 1095 result := params.SettingsResults{ 1096 Results: make([]params.SettingsResult, len(args.RelationUnitPairs)), 1097 } 1098 canAccess, err := u.accessUnit() 1099 if err != nil { 1100 return params.SettingsResults{}, err 1101 } 1102 for i, arg := range args.RelationUnitPairs { 1103 unit, err := names.ParseUnitTag(arg.LocalUnit) 1104 if err != nil { 1105 result.Results[i].Error = common.ServerError(common.ErrPerm) 1106 continue 1107 } 1108 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1109 if err == nil { 1110 // TODO(dfc) rework this logic 1111 remoteUnit := "" 1112 remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit) 1113 if err == nil { 1114 var settings map[string]interface{} 1115 settings, err = relUnit.ReadSettings(remoteUnit) 1116 if err == nil { 1117 result.Results[i].Settings, err = convertRelationSettings(settings) 1118 } 1119 } 1120 } 1121 result.Results[i].Error = common.ServerError(err) 1122 } 1123 return result, nil 1124 } 1125 1126 // UpdateSettings persists all changes made to the local settings of 1127 // all given pairs of relation and unit. Keys with empty values are 1128 // considered a signal to delete these values. 1129 func (u *uniterBaseAPI) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) { 1130 result := params.ErrorResults{ 1131 Results: make([]params.ErrorResult, len(args.RelationUnits)), 1132 } 1133 canAccess, err := u.accessUnit() 1134 if err != nil { 1135 return params.ErrorResults{}, err 1136 } 1137 for i, arg := range args.RelationUnits { 1138 unit, err := names.ParseUnitTag(arg.Unit) 1139 if err != nil { 1140 result.Results[i].Error = common.ServerError(common.ErrPerm) 1141 continue 1142 } 1143 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1144 if err == nil { 1145 var settings *state.Settings 1146 settings, err = relUnit.Settings() 1147 if err == nil { 1148 for k, v := range arg.Settings { 1149 if v == "" { 1150 settings.Delete(k) 1151 } else { 1152 settings.Set(k, v) 1153 } 1154 } 1155 _, err = settings.Write() 1156 } 1157 } 1158 result.Results[i].Error = common.ServerError(err) 1159 } 1160 return result, nil 1161 } 1162 1163 // WatchRelationUnits returns a RelationUnitsWatcher for observing 1164 // changes to every unit in the supplied relation that is visible to 1165 // the supplied unit. See also state/watcher.go:RelationUnit.Watch(). 1166 func (u *uniterBaseAPI) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) { 1167 result := params.RelationUnitsWatchResults{ 1168 Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)), 1169 } 1170 canAccess, err := u.accessUnit() 1171 if err != nil { 1172 return params.RelationUnitsWatchResults{}, err 1173 } 1174 for i, arg := range args.RelationUnits { 1175 unit, err := names.ParseUnitTag(arg.Unit) 1176 if err != nil { 1177 result.Results[i].Error = common.ServerError(common.ErrPerm) 1178 continue 1179 } 1180 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit) 1181 if err == nil { 1182 result.Results[i], err = u.watchOneRelationUnit(relUnit) 1183 } 1184 result.Results[i].Error = common.ServerError(err) 1185 } 1186 return result, nil 1187 } 1188 1189 // WatchAddresses returns a NotifyWatcher for observing changes 1190 // to each unit's addresses. 1191 func (u *uniterBaseAPI) WatchUnitAddresses(args params.Entities) (params.NotifyWatchResults, error) { 1192 result := params.NotifyWatchResults{ 1193 Results: make([]params.NotifyWatchResult, len(args.Entities)), 1194 } 1195 canAccess, err := u.accessUnit() 1196 if err != nil { 1197 return params.NotifyWatchResults{}, err 1198 } 1199 for i, entity := range args.Entities { 1200 unit, err := names.ParseUnitTag(entity.Tag) 1201 if err != nil { 1202 result.Results[i].Error = common.ServerError(common.ErrPerm) 1203 continue 1204 } 1205 err = common.ErrPerm 1206 watcherId := "" 1207 if canAccess(unit) { 1208 watcherId, err = u.watchOneUnitAddresses(unit) 1209 } 1210 result.Results[i].NotifyWatcherId = watcherId 1211 result.Results[i].Error = common.ServerError(err) 1212 } 1213 return result, nil 1214 } 1215 1216 // GetMeterStatus returns meter status information for each unit. 1217 func (u *uniterBaseAPI) GetMeterStatus(args params.Entities) (params.MeterStatusResults, error) { 1218 result := params.MeterStatusResults{ 1219 Results: make([]params.MeterStatusResult, len(args.Entities)), 1220 } 1221 canAccess, err := u.accessUnit() 1222 if err != nil { 1223 return params.MeterStatusResults{}, common.ErrPerm 1224 } 1225 for i, entity := range args.Entities { 1226 unitTag, err := names.ParseUnitTag(entity.Tag) 1227 if err != nil { 1228 result.Results[i].Error = common.ServerError(common.ErrPerm) 1229 continue 1230 } 1231 err = common.ErrPerm 1232 var status state.MeterStatus 1233 if canAccess(unitTag) { 1234 var unit *state.Unit 1235 unit, err = u.getUnit(unitTag) 1236 if err == nil { 1237 status, err = meterstatus.MeterStatusWrapper(unit.GetMeterStatus) 1238 } 1239 result.Results[i].Code = status.Code.String() 1240 result.Results[i].Info = status.Info 1241 } 1242 result.Results[i].Error = common.ServerError(err) 1243 } 1244 return result, nil 1245 } 1246 1247 func (u *uniterBaseAPI) getUnit(tag names.UnitTag) (*state.Unit, error) { 1248 return u.st.Unit(tag.Id()) 1249 } 1250 1251 func (u *uniterBaseAPI) getService(tag names.ServiceTag) (*state.Service, error) { 1252 return u.st.Service(tag.Id()) 1253 } 1254 1255 func (u *uniterBaseAPI) getRelationUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.RelationUnit, error) { 1256 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 1257 if err != nil { 1258 return nil, err 1259 } 1260 return rel.Unit(unit) 1261 } 1262 1263 func (u *uniterBaseAPI) getOneRelationById(relId int) (params.RelationResult, error) { 1264 nothing := params.RelationResult{} 1265 rel, err := u.st.Relation(relId) 1266 if errors.IsNotFound(err) { 1267 return nothing, common.ErrPerm 1268 } else if err != nil { 1269 return nothing, err 1270 } 1271 tag := u.auth.GetAuthTag() 1272 switch tag.(type) { 1273 case names.UnitTag: 1274 // do nothing 1275 default: 1276 panic("authenticated entity is not a unit") 1277 } 1278 unit, err := u.st.FindEntity(tag) 1279 if err != nil { 1280 return nothing, err 1281 } 1282 // Use the currently authenticated unit to get the endpoint. 1283 result, err := u.prepareRelationResult(rel, unit.(*state.Unit)) 1284 if err != nil { 1285 // An error from prepareRelationResult means the authenticated 1286 // unit's service is not part of the requested 1287 // relation. That's why it's appropriate to return ErrPerm 1288 // here. 1289 return nothing, common.ErrPerm 1290 } 1291 return result, nil 1292 } 1293 1294 func (u *uniterBaseAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.Relation, *state.Unit, error) { 1295 tag, err := names.ParseRelationTag(relTag) 1296 if err != nil { 1297 return nil, nil, common.ErrPerm 1298 } 1299 rel, err := u.st.KeyRelation(tag.Id()) 1300 if errors.IsNotFound(err) { 1301 return nil, nil, common.ErrPerm 1302 } else if err != nil { 1303 return nil, nil, err 1304 } 1305 if !canAccess(unitTag) { 1306 return nil, nil, common.ErrPerm 1307 } 1308 unit, err := u.getUnit(unitTag) 1309 return rel, unit, err 1310 } 1311 1312 func (u *uniterBaseAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) { 1313 nothing := params.RelationResult{} 1314 ep, err := rel.Endpoint(unit.ServiceName()) 1315 if err != nil { 1316 // An error here means the unit's service is not part of the 1317 // relation. 1318 return nothing, err 1319 } 1320 return params.RelationResult{ 1321 Id: rel.Id(), 1322 Key: rel.String(), 1323 Life: params.Life(rel.Life().String()), 1324 Endpoint: multiwatcher.Endpoint{ 1325 ServiceName: ep.ServiceName, 1326 Relation: ep.Relation, 1327 }, 1328 }, nil 1329 } 1330 1331 func (u *uniterBaseAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) { 1332 nothing := params.RelationResult{} 1333 tag, err := names.ParseUnitTag(unitTag) 1334 if err != nil { 1335 return nothing, common.ErrPerm 1336 } 1337 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, tag) 1338 if err != nil { 1339 return nothing, err 1340 } 1341 return u.prepareRelationResult(rel, unit) 1342 } 1343 1344 func (u *uniterBaseAPI) destroySubordinates(principal *state.Unit) error { 1345 subordinates := principal.SubordinateNames() 1346 for _, subName := range subordinates { 1347 unit, err := u.getUnit(names.NewUnitTag(subName)) 1348 if err != nil { 1349 return err 1350 } 1351 if err = unit.Destroy(); err != nil { 1352 return err 1353 } 1354 } 1355 return nil 1356 } 1357 1358 func (u *uniterBaseAPI) watchOneServiceRelations(tag names.ServiceTag) (params.StringsWatchResult, error) { 1359 nothing := params.StringsWatchResult{} 1360 service, err := u.getService(tag) 1361 if err != nil { 1362 return nothing, err 1363 } 1364 watch := service.WatchRelations() 1365 // Consume the initial event and forward it to the result. 1366 if changes, ok := <-watch.Changes(); ok { 1367 return params.StringsWatchResult{ 1368 StringsWatcherId: u.resources.Register(watch), 1369 Changes: changes, 1370 }, nil 1371 } 1372 return nothing, watcher.EnsureErr(watch) 1373 } 1374 1375 func (u *uniterBaseAPI) watchOneUnitConfigSettings(tag names.UnitTag) (string, error) { 1376 unit, err := u.getUnit(tag) 1377 if err != nil { 1378 return "", err 1379 } 1380 watch, err := unit.WatchConfigSettings() 1381 if err != nil { 1382 return "", err 1383 } 1384 // Consume the initial event. Technically, API 1385 // calls to Watch 'transmit' the initial event 1386 // in the Watch response. But NotifyWatchers 1387 // have no state to transmit. 1388 if _, ok := <-watch.Changes(); ok { 1389 return u.resources.Register(watch), nil 1390 } 1391 return "", watcher.EnsureErr(watch) 1392 } 1393 1394 func (u *uniterBaseAPI) watchOneUnitActionNotifications(tag names.UnitTag) (params.StringsWatchResult, error) { 1395 nothing := params.StringsWatchResult{} 1396 unit, err := u.getUnit(tag) 1397 if err != nil { 1398 return nothing, err 1399 } 1400 watch := unit.WatchActionNotifications() 1401 1402 if changes, ok := <-watch.Changes(); ok { 1403 return params.StringsWatchResult{ 1404 StringsWatcherId: u.resources.Register(watch), 1405 Changes: changes, 1406 }, nil 1407 } 1408 return nothing, watcher.EnsureErr(watch) 1409 } 1410 1411 func (u *uniterBaseAPI) watchOneUnitAddresses(tag names.UnitTag) (string, error) { 1412 unit, err := u.getUnit(tag) 1413 if err != nil { 1414 return "", err 1415 } 1416 machineId, err := unit.AssignedMachineId() 1417 if err != nil { 1418 return "", err 1419 } 1420 machine, err := u.st.Machine(machineId) 1421 if err != nil { 1422 return "", err 1423 } 1424 watch := machine.WatchAddresses() 1425 // Consume the initial event. Technically, API 1426 // calls to Watch 'transmit' the initial event 1427 // in the Watch response. But NotifyWatchers 1428 // have no state to transmit. 1429 if _, ok := <-watch.Changes(); ok { 1430 return u.resources.Register(watch), nil 1431 } 1432 return "", watcher.EnsureErr(watch) 1433 } 1434 1435 func (u *uniterBaseAPI) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) { 1436 watch := relUnit.Watch() 1437 // Consume the initial event and forward it to the result. 1438 if changes, ok := <-watch.Changes(); ok { 1439 return params.RelationUnitsWatchResult{ 1440 RelationUnitsWatcherId: u.resources.Register(watch), 1441 Changes: changes, 1442 }, nil 1443 } 1444 return params.RelationUnitsWatchResult{}, watcher.EnsureErr(watch) 1445 } 1446 1447 func (u *uniterBaseAPI) watchOneUnitMeterStatus(tag names.UnitTag) (string, error) { 1448 unit, err := u.getUnit(tag) 1449 if err != nil { 1450 return "", err 1451 } 1452 watch := unit.WatchMeterStatus() 1453 if _, ok := <-watch.Changes(); ok { 1454 return u.resources.Register(watch), nil 1455 } 1456 return "", watcher.EnsureErr(watch) 1457 } 1458 1459 func (u *uniterBaseAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) { 1460 // Make sure the unit is indeed remote. 1461 if remoteUnitTag == u.auth.GetAuthTag().String() { 1462 return "", common.ErrPerm 1463 } 1464 // Check remoteUnit is indeed related. Note that we don't want to actually get 1465 // the *Unit, because it might have been removed; but its relation settings will 1466 // persist until the relation itself has been removed (and must remain accessible 1467 // because the local unit's view of reality may be time-shifted). 1468 tag, err := names.ParseUnitTag(remoteUnitTag) 1469 if err != nil { 1470 return "", common.ErrPerm 1471 } 1472 remoteUnitName := tag.Id() 1473 remoteServiceName, err := names.UnitService(remoteUnitName) 1474 if err != nil { 1475 return "", common.ErrPerm 1476 } 1477 rel := relUnit.Relation() 1478 _, err = rel.RelatedEndpoints(remoteServiceName) 1479 if err != nil { 1480 return "", common.ErrPerm 1481 } 1482 return remoteUnitName, nil 1483 } 1484 1485 // authAndActionFromTagFn first authenticates the request, and then returns 1486 // a function with which to authenticate and retrieve each action in the 1487 // request. 1488 func (u *uniterBaseAPI) authAndActionFromTagFn() (func(string) (*state.Action, error), error) { 1489 canAccess, err := u.accessUnit() 1490 if err != nil { 1491 return nil, err 1492 } 1493 unit, ok := u.auth.GetAuthTag().(names.UnitTag) 1494 if !ok { 1495 return nil, fmt.Errorf("calling entity is not a unit") 1496 } 1497 1498 return func(tag string) (*state.Action, error) { 1499 actionTag, err := names.ParseActionTag(tag) 1500 if err != nil { 1501 return nil, err 1502 } 1503 action, err := u.st.ActionByTag(actionTag) 1504 if err != nil { 1505 return nil, err 1506 } 1507 receiverTag, err := names.ActionReceiverTag(action.Receiver()) 1508 if err != nil { 1509 return nil, err 1510 } 1511 if unit != receiverTag { 1512 return nil, common.ErrPerm 1513 } 1514 1515 if !canAccess(receiverTag) { 1516 return nil, common.ErrPerm 1517 } 1518 return action, nil 1519 }, nil 1520 } 1521 1522 func convertRelationSettings(settings map[string]interface{}) (params.Settings, error) { 1523 result := make(params.Settings) 1524 for k, v := range settings { 1525 // All relation settings should be strings. 1526 sval, ok := v.(string) 1527 if !ok { 1528 return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v) 1529 } 1530 result[k] = sval 1531 } 1532 return result, nil 1533 } 1534 1535 func relationsInScopeTags(unit *state.Unit) ([]string, error) { 1536 relations, err := unit.RelationsInScope() 1537 if err != nil { 1538 return nil, err 1539 } 1540 tags := make([]string, len(relations)) 1541 for i, relation := range relations { 1542 tags[i] = relation.Tag().String() 1543 } 1544 return tags, nil 1545 } 1546 1547 func leadershipSettingsAccessorFactory( 1548 st *state.State, 1549 resources *common.Resources, 1550 auth common.Authorizer, 1551 ) *leadershipapiserver.LeadershipSettingsAccessor { 1552 registerWatcher := func(serviceId string) (string, error) { 1553 service, err := st.Service(serviceId) 1554 if err != nil { 1555 return "", err 1556 } 1557 w := service.WatchLeaderSettings() 1558 if _, ok := <-w.Changes(); ok { 1559 return resources.Register(w), nil 1560 } 1561 return "", watcher.EnsureErr(w) 1562 } 1563 getSettings := func(serviceId string) (map[string]string, error) { 1564 service, err := st.Service(serviceId) 1565 if err != nil { 1566 return nil, err 1567 } 1568 return service.LeaderSettings() 1569 } 1570 writeSettings := func(token leadership.Token, serviceId string, settings map[string]string) error { 1571 service, err := st.Service(serviceId) 1572 if err != nil { 1573 return err 1574 } 1575 return service.UpdateLeaderSettings(token, settings) 1576 } 1577 return leadershipapiserver.NewLeadershipSettingsAccessor( 1578 auth, 1579 registerWatcher, 1580 getSettings, 1581 st.LeadershipChecker().LeadershipCheck, 1582 writeSettings, 1583 ) 1584 }