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