github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/uniter/uniter.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 5 // used by the uniter worker. 6 package uniter 7 8 import ( 9 "fmt" 10 11 "launchpad.net/juju-core/charm" 12 "launchpad.net/juju-core/errors" 13 "launchpad.net/juju-core/names" 14 "launchpad.net/juju-core/state" 15 "launchpad.net/juju-core/state/api/params" 16 "launchpad.net/juju-core/state/apiserver/common" 17 "launchpad.net/juju-core/state/watcher" 18 ) 19 20 // UniterAPI implements the API used by the uniter worker. 21 type UniterAPI struct { 22 *common.LifeGetter 23 *common.StatusSetter 24 *common.DeadEnsurer 25 *common.AgentEntityWatcher 26 *common.APIAddresser 27 *common.EnvironWatcher 28 29 st *state.State 30 auth common.Authorizer 31 resources *common.Resources 32 accessUnit common.GetAuthFunc 33 accessService common.GetAuthFunc 34 } 35 36 // NewUniterAPI creates a new instance of the Uniter API. 37 func NewUniterAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*UniterAPI, error) { 38 if !authorizer.AuthUnitAgent() { 39 return nil, common.ErrPerm 40 } 41 accessUnit := func() (common.AuthFunc, error) { 42 return authorizer.AuthOwner, nil 43 } 44 accessService := func() (common.AuthFunc, error) { 45 unit, ok := authorizer.GetAuthEntity().(*state.Unit) 46 if !ok { 47 panic("authenticated entity is not a unit") 48 } 49 return func(tag string) bool { 50 return tag == names.ServiceTag(unit.ServiceName()) 51 }, nil 52 } 53 accessUnitOrService := common.AuthEither(accessUnit, accessService) 54 // Uniter can always watch for environ changes. 55 getCanWatch := common.AuthAlways(true) 56 // Uniter can not get the secrets. 57 getCanReadSecrets := common.AuthAlways(false) 58 return &UniterAPI{ 59 LifeGetter: common.NewLifeGetter(st, accessUnitOrService), 60 StatusSetter: common.NewStatusSetter(st, accessUnit), 61 DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), 62 AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), 63 APIAddresser: common.NewAPIAddresser(st), 64 EnvironWatcher: common.NewEnvironWatcher(st, resources, getCanWatch, getCanReadSecrets), 65 66 st: st, 67 auth: authorizer, 68 resources: resources, 69 accessUnit: accessUnit, 70 accessService: accessService, 71 }, nil 72 } 73 74 func (u *UniterAPI) getUnit(tag string) (*state.Unit, error) { 75 _, name, err := names.ParseTag(tag, names.UnitTagKind) 76 if err != nil { 77 return nil, err 78 } 79 return u.st.Unit(name) 80 } 81 82 func (u *UniterAPI) getService(tag string) (*state.Service, error) { 83 _, name, err := names.ParseTag(tag, names.ServiceTagKind) 84 if err != nil { 85 return nil, err 86 } 87 return u.st.Service(name) 88 } 89 90 // PublicAddress returns the public address for each given unit, if set. 91 func (u *UniterAPI) PublicAddress(args params.Entities) (params.StringResults, error) { 92 result := params.StringResults{ 93 Results: make([]params.StringResult, len(args.Entities)), 94 } 95 canAccess, err := u.accessUnit() 96 if err != nil { 97 return params.StringResults{}, err 98 } 99 for i, entity := range args.Entities { 100 err := common.ErrPerm 101 if canAccess(entity.Tag) { 102 var unit *state.Unit 103 unit, err = u.getUnit(entity.Tag) 104 if err == nil { 105 address, ok := unit.PublicAddress() 106 if ok { 107 result.Results[i].Result = address 108 } else { 109 err = common.NoAddressSetError(entity.Tag, "public") 110 } 111 } 112 } 113 result.Results[i].Error = common.ServerError(err) 114 } 115 return result, nil 116 } 117 118 // SetPublicAddress sets the public address of each of the given units. 119 func (u *UniterAPI) SetPublicAddress(args params.SetEntityAddresses) (params.ErrorResults, error) { 120 result := params.ErrorResults{ 121 Results: make([]params.ErrorResult, len(args.Entities)), 122 } 123 canAccess, err := u.accessUnit() 124 if err != nil { 125 return params.ErrorResults{}, err 126 } 127 for i, entity := range args.Entities { 128 err := common.ErrPerm 129 if canAccess(entity.Tag) { 130 var unit *state.Unit 131 unit, err = u.getUnit(entity.Tag) 132 if err == nil { 133 err = unit.SetPublicAddress(entity.Address) 134 } 135 } 136 result.Results[i].Error = common.ServerError(err) 137 } 138 return result, nil 139 } 140 141 // PrivateAddress returns the private address for each given unit, if set. 142 func (u *UniterAPI) PrivateAddress(args params.Entities) (params.StringResults, error) { 143 result := params.StringResults{ 144 Results: make([]params.StringResult, len(args.Entities)), 145 } 146 canAccess, err := u.accessUnit() 147 if err != nil { 148 return params.StringResults{}, err 149 } 150 for i, entity := range args.Entities { 151 err := common.ErrPerm 152 if canAccess(entity.Tag) { 153 var unit *state.Unit 154 unit, err = u.getUnit(entity.Tag) 155 if err == nil { 156 address, ok := unit.PrivateAddress() 157 if ok { 158 result.Results[i].Result = address 159 } else { 160 err = common.NoAddressSetError(entity.Tag, "private") 161 } 162 } 163 } 164 result.Results[i].Error = common.ServerError(err) 165 } 166 return result, nil 167 } 168 169 // SetPrivateAddress sets the private address of each of the given units. 170 func (u *UniterAPI) SetPrivateAddress(args params.SetEntityAddresses) (params.ErrorResults, error) { 171 result := params.ErrorResults{ 172 Results: make([]params.ErrorResult, len(args.Entities)), 173 } 174 canAccess, err := u.accessUnit() 175 if err != nil { 176 return params.ErrorResults{}, err 177 } 178 for i, entity := range args.Entities { 179 err := common.ErrPerm 180 if canAccess(entity.Tag) { 181 var unit *state.Unit 182 unit, err = u.getUnit(entity.Tag) 183 if err == nil { 184 err = unit.SetPrivateAddress(entity.Address) 185 } 186 } 187 result.Results[i].Error = common.ServerError(err) 188 } 189 return result, nil 190 } 191 192 // Resolved returns the current resolved setting for each given unit. 193 func (u *UniterAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) { 194 result := params.ResolvedModeResults{ 195 Results: make([]params.ResolvedModeResult, len(args.Entities)), 196 } 197 canAccess, err := u.accessUnit() 198 if err != nil { 199 return params.ResolvedModeResults{}, err 200 } 201 for i, entity := range args.Entities { 202 err := common.ErrPerm 203 if canAccess(entity.Tag) { 204 var unit *state.Unit 205 unit, err = u.getUnit(entity.Tag) 206 if err == nil { 207 result.Results[i].Mode = params.ResolvedMode(unit.Resolved()) 208 } 209 } 210 result.Results[i].Error = common.ServerError(err) 211 } 212 return result, nil 213 } 214 215 // ClearResolved removes any resolved setting from each given unit. 216 func (u *UniterAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) { 217 result := params.ErrorResults{ 218 Results: make([]params.ErrorResult, len(args.Entities)), 219 } 220 canAccess, err := u.accessUnit() 221 if err != nil { 222 return params.ErrorResults{}, err 223 } 224 for i, entity := range args.Entities { 225 err := common.ErrPerm 226 if canAccess(entity.Tag) { 227 var unit *state.Unit 228 unit, err = u.getUnit(entity.Tag) 229 if err == nil { 230 err = unit.ClearResolved() 231 } 232 } 233 result.Results[i].Error = common.ServerError(err) 234 } 235 return result, nil 236 } 237 238 // GetPrincipal returns the result of calling PrincipalName() and 239 // converting it to a tag, on each given unit. 240 func (u *UniterAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) { 241 result := params.StringBoolResults{ 242 Results: make([]params.StringBoolResult, len(args.Entities)), 243 } 244 canAccess, err := u.accessUnit() 245 if err != nil { 246 return params.StringBoolResults{}, err 247 } 248 for i, entity := range args.Entities { 249 err := common.ErrPerm 250 if canAccess(entity.Tag) { 251 var unit *state.Unit 252 unit, err = u.getUnit(entity.Tag) 253 if err == nil { 254 principal, ok := unit.PrincipalName() 255 if principal != "" { 256 result.Results[i].Result = names.UnitTag(principal) 257 } 258 result.Results[i].Ok = ok 259 } 260 } 261 result.Results[i].Error = common.ServerError(err) 262 } 263 return result, nil 264 } 265 266 // Destroy advances all given Alive units' lifecycles as far as 267 // possible. See state/Unit.Destroy(). 268 func (u *UniterAPI) Destroy(args params.Entities) (params.ErrorResults, error) { 269 result := params.ErrorResults{ 270 Results: make([]params.ErrorResult, len(args.Entities)), 271 } 272 canAccess, err := u.accessUnit() 273 if err != nil { 274 return params.ErrorResults{}, err 275 } 276 for i, entity := range args.Entities { 277 err := common.ErrPerm 278 if canAccess(entity.Tag) { 279 var unit *state.Unit 280 unit, err = u.getUnit(entity.Tag) 281 if err == nil { 282 err = unit.Destroy() 283 } 284 } 285 result.Results[i].Error = common.ServerError(err) 286 } 287 return result, nil 288 } 289 290 func (u *UniterAPI) destroySubordinates(principal *state.Unit) error { 291 subordinates := principal.SubordinateNames() 292 for _, subName := range subordinates { 293 unit, err := u.getUnit(names.UnitTag(subName)) 294 if err != nil { 295 return err 296 } 297 if err = unit.Destroy(); err != nil { 298 return err 299 } 300 } 301 return nil 302 } 303 304 // DestroyAllSubordinates destroys all subordinates of each given unit. 305 func (u *UniterAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) { 306 result := params.ErrorResults{ 307 Results: make([]params.ErrorResult, len(args.Entities)), 308 } 309 canAccess, err := u.accessUnit() 310 if err != nil { 311 return params.ErrorResults{}, err 312 } 313 for i, entity := range args.Entities { 314 err := common.ErrPerm 315 if canAccess(entity.Tag) { 316 var unit *state.Unit 317 unit, err = u.getUnit(entity.Tag) 318 if err == nil { 319 err = u.destroySubordinates(unit) 320 } 321 } 322 result.Results[i].Error = common.ServerError(err) 323 } 324 return result, nil 325 } 326 327 // HasSubordinates returns the whether each given unit has any subordinates. 328 func (u *UniterAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) { 329 result := params.BoolResults{ 330 Results: make([]params.BoolResult, len(args.Entities)), 331 } 332 canAccess, err := u.accessUnit() 333 if err != nil { 334 return params.BoolResults{}, err 335 } 336 for i, entity := range args.Entities { 337 err := common.ErrPerm 338 if canAccess(entity.Tag) { 339 var unit *state.Unit 340 unit, err = u.getUnit(entity.Tag) 341 if err == nil { 342 subordinates := unit.SubordinateNames() 343 result.Results[i].Result = len(subordinates) > 0 344 } 345 } 346 result.Results[i].Error = common.ServerError(err) 347 } 348 return result, nil 349 } 350 351 // CharmURL returns the charm URL for all given units or services. 352 func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) { 353 result := params.StringBoolResults{ 354 Results: make([]params.StringBoolResult, len(args.Entities)), 355 } 356 accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) 357 canAccess, err := accessUnitOrService() 358 if err != nil { 359 return params.StringBoolResults{}, err 360 } 361 for i, entity := range args.Entities { 362 err := common.ErrPerm 363 if canAccess(entity.Tag) { 364 var unitOrService state.Entity 365 unitOrService, err = u.st.FindEntity(entity.Tag) 366 if err == nil { 367 charmURLer := unitOrService.(interface { 368 CharmURL() (*charm.URL, bool) 369 }) 370 curl, ok := charmURLer.CharmURL() 371 if curl != nil { 372 result.Results[i].Result = curl.String() 373 result.Results[i].Ok = ok 374 } 375 } 376 } 377 result.Results[i].Error = common.ServerError(err) 378 } 379 return result, nil 380 } 381 382 // SetCharmURL sets the charm URL for each given unit. An error will 383 // be returned if a unit is dead, or the charm URL is not know. 384 func (u *UniterAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) { 385 result := params.ErrorResults{ 386 Results: make([]params.ErrorResult, len(args.Entities)), 387 } 388 canAccess, err := u.accessUnit() 389 if err != nil { 390 return params.ErrorResults{}, err 391 } 392 for i, entity := range args.Entities { 393 err := common.ErrPerm 394 if canAccess(entity.Tag) { 395 var unit *state.Unit 396 unit, err = u.getUnit(entity.Tag) 397 if err == nil { 398 var curl *charm.URL 399 curl, err = charm.ParseURL(entity.CharmURL) 400 if err == nil { 401 err = unit.SetCharmURL(curl) 402 } 403 } 404 } 405 result.Results[i].Error = common.ServerError(err) 406 } 407 return result, nil 408 } 409 410 // OpenPort sets the policy of the port with protocol an number to be 411 // opened, for all given units. 412 func (u *UniterAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) { 413 result := params.ErrorResults{ 414 Results: make([]params.ErrorResult, len(args.Entities)), 415 } 416 canAccess, err := u.accessUnit() 417 if err != nil { 418 return params.ErrorResults{}, err 419 } 420 for i, entity := range args.Entities { 421 err := common.ErrPerm 422 if canAccess(entity.Tag) { 423 var unit *state.Unit 424 unit, err = u.getUnit(entity.Tag) 425 if err == nil { 426 err = unit.OpenPort(entity.Protocol, entity.Port) 427 } 428 } 429 result.Results[i].Error = common.ServerError(err) 430 } 431 return result, nil 432 } 433 434 // ClosePort sets the policy of the port with protocol and number to 435 // be closed, for all given units. 436 func (u *UniterAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) { 437 result := params.ErrorResults{ 438 Results: make([]params.ErrorResult, len(args.Entities)), 439 } 440 canAccess, err := u.accessUnit() 441 if err != nil { 442 return params.ErrorResults{}, err 443 } 444 for i, entity := range args.Entities { 445 err := common.ErrPerm 446 if canAccess(entity.Tag) { 447 var unit *state.Unit 448 unit, err = u.getUnit(entity.Tag) 449 if err == nil { 450 err = unit.ClosePort(entity.Protocol, entity.Port) 451 } 452 } 453 result.Results[i].Error = common.ServerError(err) 454 } 455 return result, nil 456 } 457 458 func (u *UniterAPI) watchOneUnitConfigSettings(tag string) (string, error) { 459 unit, err := u.getUnit(tag) 460 if err != nil { 461 return "", err 462 } 463 watch, err := unit.WatchConfigSettings() 464 if err != nil { 465 return "", err 466 } 467 // Consume the initial event. Technically, API 468 // calls to Watch 'transmit' the initial event 469 // in the Watch response. But NotifyWatchers 470 // have no state to transmit. 471 if _, ok := <-watch.Changes(); ok { 472 return u.resources.Register(watch), nil 473 } 474 return "", watcher.MustErr(watch) 475 } 476 477 // WatchConfigSettings returns a NotifyWatcher for observing changes 478 // to each unit's service configuration settings. See also 479 // state/watcher.go:Unit.WatchConfigSettings(). 480 func (u *UniterAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 481 result := params.NotifyWatchResults{ 482 Results: make([]params.NotifyWatchResult, len(args.Entities)), 483 } 484 canAccess, err := u.accessUnit() 485 if err != nil { 486 return params.NotifyWatchResults{}, err 487 } 488 for i, entity := range args.Entities { 489 err := common.ErrPerm 490 watcherId := "" 491 if canAccess(entity.Tag) { 492 watcherId, err = u.watchOneUnitConfigSettings(entity.Tag) 493 } 494 result.Results[i].NotifyWatcherId = watcherId 495 result.Results[i].Error = common.ServerError(err) 496 } 497 return result, nil 498 } 499 500 // ConfigSettings returns the complete set of service charm config 501 // settings available to each given unit. 502 func (u *UniterAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) { 503 result := params.ConfigSettingsResults{ 504 Results: make([]params.ConfigSettingsResult, len(args.Entities)), 505 } 506 canAccess, err := u.accessUnit() 507 if err != nil { 508 return params.ConfigSettingsResults{}, err 509 } 510 for i, entity := range args.Entities { 511 err := common.ErrPerm 512 if canAccess(entity.Tag) { 513 var unit *state.Unit 514 unit, err = u.getUnit(entity.Tag) 515 if err == nil { 516 var settings charm.Settings 517 settings, err = unit.ConfigSettings() 518 if err == nil { 519 result.Results[i].Settings = params.ConfigSettings(settings) 520 } 521 } 522 } 523 result.Results[i].Error = common.ServerError(err) 524 } 525 return result, nil 526 } 527 528 func (u *UniterAPI) watchOneServiceRelations(tag string) (params.StringsWatchResult, error) { 529 nothing := params.StringsWatchResult{} 530 service, err := u.getService(tag) 531 if err != nil { 532 return nothing, err 533 } 534 watch := service.WatchRelations() 535 // Consume the initial event and forward it to the result. 536 if changes, ok := <-watch.Changes(); ok { 537 return params.StringsWatchResult{ 538 StringsWatcherId: u.resources.Register(watch), 539 Changes: changes, 540 }, nil 541 } 542 return nothing, watcher.MustErr(watch) 543 } 544 545 // WatchServiceRelations returns a StringsWatcher, for each given 546 // service, that notifies of changes to the lifecycles of relations 547 // involving that service. 548 func (u *UniterAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) { 549 result := params.StringsWatchResults{ 550 Results: make([]params.StringsWatchResult, len(args.Entities)), 551 } 552 canAccess, err := u.accessService() 553 if err != nil { 554 return params.StringsWatchResults{}, err 555 } 556 for i, entity := range args.Entities { 557 err := common.ErrPerm 558 if canAccess(entity.Tag) { 559 result.Results[i], err = u.watchOneServiceRelations(entity.Tag) 560 } 561 result.Results[i].Error = common.ServerError(err) 562 } 563 return result, nil 564 } 565 566 // CharmArchiveURL returns the URL, corresponding to the charm archive 567 // (bundle) in the provider storage for each given charm URL, along 568 // with the DisableSSLHostnameVerification flag. 569 func (u *UniterAPI) CharmArchiveURL(args params.CharmURLs) (params.CharmArchiveURLResults, error) { 570 result := params.CharmArchiveURLResults{ 571 Results: make([]params.CharmArchiveURLResult, len(args.URLs)), 572 } 573 // Get the SSL hostname verification environment setting. 574 envConfig, err := u.st.EnvironConfig() 575 if err != nil { 576 return result, err 577 } 578 // SSLHostnameVerification defaults to true, so we need to 579 // invert that, for backwards-compatibility (older versions 580 // will have DisableSSLHostnameVerification: false by default). 581 disableSSLHostnameVerification := !envConfig.SSLHostnameVerification() 582 for i, arg := range args.URLs { 583 curl, err := charm.ParseURL(arg.URL) 584 if err != nil { 585 err = common.ErrPerm 586 } else { 587 var sch *state.Charm 588 sch, err = u.st.Charm(curl) 589 if errors.IsNotFoundError(err) { 590 err = common.ErrPerm 591 } 592 if err == nil { 593 result.Results[i].Result = sch.BundleURL().String() 594 result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification 595 } 596 } 597 result.Results[i].Error = common.ServerError(err) 598 } 599 return result, nil 600 } 601 602 // CharmArchiveSha256 returns the SHA256 digest of the charm archive 603 // (bundle) data for each charm url in the given parameters. 604 func (u *UniterAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) { 605 result := params.StringResults{ 606 Results: make([]params.StringResult, len(args.URLs)), 607 } 608 for i, arg := range args.URLs { 609 curl, err := charm.ParseURL(arg.URL) 610 if err != nil { 611 err = common.ErrPerm 612 } else { 613 var sch *state.Charm 614 sch, err = u.st.Charm(curl) 615 if errors.IsNotFoundError(err) { 616 err = common.ErrPerm 617 } 618 if err == nil { 619 result.Results[i].Result = sch.BundleSha256() 620 } 621 } 622 result.Results[i].Error = common.ServerError(err) 623 } 624 return result, nil 625 } 626 627 func (u *UniterAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.Relation, *state.Unit, error) { 628 _, key, err := names.ParseTag(relTag, names.RelationTagKind) 629 if err != nil { 630 return nil, nil, common.ErrPerm 631 } 632 rel, err := u.st.KeyRelation(key) 633 if errors.IsNotFoundError(err) { 634 return nil, nil, common.ErrPerm 635 } else if err != nil { 636 return nil, nil, err 637 } 638 if !canAccess(unitTag) { 639 return nil, nil, common.ErrPerm 640 } 641 unit, err := u.getUnit(unitTag) 642 return rel, unit, err 643 } 644 645 func (u *UniterAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) { 646 nothing := params.RelationResult{} 647 ep, err := rel.Endpoint(unit.ServiceName()) 648 if err != nil { 649 // An error here means the unit's service is not part of the 650 // relation. 651 return nothing, err 652 } 653 return params.RelationResult{ 654 Id: rel.Id(), 655 Key: rel.String(), 656 Life: params.Life(rel.Life().String()), 657 Endpoint: params.Endpoint{ 658 ServiceName: ep.ServiceName, 659 Relation: ep.Relation, 660 }, 661 }, nil 662 } 663 664 func (u *UniterAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) { 665 nothing := params.RelationResult{} 666 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 667 if err != nil { 668 return nothing, err 669 } 670 return u.prepareRelationResult(rel, unit) 671 } 672 673 func (u *UniterAPI) getOneRelationById(relId int) (params.RelationResult, error) { 674 nothing := params.RelationResult{} 675 rel, err := u.st.Relation(relId) 676 if errors.IsNotFoundError(err) { 677 return nothing, common.ErrPerm 678 } else if err != nil { 679 return nothing, err 680 } 681 // Use the currently authenticated unit to get the endpoint. 682 unit, ok := u.auth.GetAuthEntity().(*state.Unit) 683 if !ok { 684 panic("authenticated entity is not a unit") 685 } 686 result, err := u.prepareRelationResult(rel, unit) 687 if err != nil { 688 // An error from prepareRelationResult means the authenticated 689 // unit's service is not part of the requested 690 // relation. That's why it's appropriate to return ErrPerm 691 // here. 692 return nothing, common.ErrPerm 693 } 694 return result, nil 695 } 696 697 func (u *UniterAPI) getRelationUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.RelationUnit, error) { 698 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 699 if err != nil { 700 return nil, err 701 } 702 return rel.Unit(unit) 703 } 704 705 // Relation returns information about all given relation/unit pairs, 706 // including their id, key and the local endpoint. 707 func (u *UniterAPI) Relation(args params.RelationUnits) (params.RelationResults, error) { 708 result := params.RelationResults{ 709 Results: make([]params.RelationResult, len(args.RelationUnits)), 710 } 711 canAccess, err := u.accessUnit() 712 if err != nil { 713 return params.RelationResults{}, err 714 } 715 for i, rel := range args.RelationUnits { 716 relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit) 717 if err == nil { 718 result.Results[i] = relParams 719 } 720 result.Results[i].Error = common.ServerError(err) 721 } 722 return result, nil 723 } 724 725 // RelationById returns information about all given relations, 726 // specified by their ids, including their key and the local 727 // endpoint. 728 func (u *UniterAPI) RelationById(args params.RelationIds) (params.RelationResults, error) { 729 result := params.RelationResults{ 730 Results: make([]params.RelationResult, len(args.RelationIds)), 731 } 732 for i, relId := range args.RelationIds { 733 relParams, err := u.getOneRelationById(relId) 734 if err == nil { 735 result.Results[i] = relParams 736 } 737 result.Results[i].Error = common.ServerError(err) 738 } 739 return result, nil 740 } 741 742 // CurrentEnvironUUID returns the UUID for the current juju environment. 743 func (u *UniterAPI) CurrentEnvironUUID() (params.StringResult, error) { 744 result := params.StringResult{} 745 env, err := u.st.Environment() 746 if err == nil { 747 result.Result = env.UUID() 748 } 749 return result, err 750 } 751 752 // CurrentEnvironment returns the name and UUID for the current juju environment. 753 func (u *UniterAPI) CurrentEnvironment() (params.EnvironmentResult, error) { 754 result := params.EnvironmentResult{} 755 env, err := u.st.Environment() 756 if err == nil { 757 result.Name = env.Name() 758 result.UUID = env.UUID() 759 } 760 return result, err 761 } 762 763 // ProviderType returns the provider type used by the current juju 764 // environment. 765 // 766 // TODO(dimitern): Refactor the uniter to call this instead of calling 767 // EnvironConfig() just to get the provider type. Once we have machine 768 // addresses, this might be completely unnecessary though. 769 func (u *UniterAPI) ProviderType() (params.StringResult, error) { 770 result := params.StringResult{} 771 cfg, err := u.st.EnvironConfig() 772 if err == nil { 773 result.Result = cfg.Type() 774 } 775 return result, err 776 } 777 778 // EnterScope ensures each unit has entered its scope in the relation, 779 // for all of the given relation/unit pairs. See also 780 // state.RelationUnit.EnterScope(). 781 func (u *UniterAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) { 782 result := params.ErrorResults{ 783 Results: make([]params.ErrorResult, len(args.RelationUnits)), 784 } 785 canAccess, err := u.accessUnit() 786 if err != nil { 787 return params.ErrorResults{}, err 788 } 789 for i, arg := range args.RelationUnits { 790 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 791 if err == nil { 792 // Construct the settings, passing the unit's 793 // private address (we already know it). 794 privateAddress, _ := relUnit.PrivateAddress() 795 settings := map[string]interface{}{ 796 "private-address": privateAddress, 797 } 798 err = relUnit.EnterScope(settings) 799 } 800 result.Results[i].Error = common.ServerError(err) 801 } 802 return result, nil 803 } 804 805 // LeaveScope signals each unit has left its scope in the relation, 806 // for all of the given relation/unit pairs. See also 807 // state.RelationUnit.LeaveScope(). 808 func (u *UniterAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) { 809 result := params.ErrorResults{ 810 Results: make([]params.ErrorResult, len(args.RelationUnits)), 811 } 812 canAccess, err := u.accessUnit() 813 if err != nil { 814 return params.ErrorResults{}, err 815 } 816 for i, arg := range args.RelationUnits { 817 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 818 if err == nil { 819 err = relUnit.LeaveScope() 820 } 821 result.Results[i].Error = common.ServerError(err) 822 } 823 return result, nil 824 } 825 826 func convertRelationSettings(settings map[string]interface{}) (params.RelationSettings, error) { 827 result := make(params.RelationSettings) 828 for k, v := range settings { 829 // All relation settings should be strings. 830 sval, ok := v.(string) 831 if !ok { 832 return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v) 833 } 834 result[k] = sval 835 } 836 return result, nil 837 } 838 839 // ReadSettings returns the local settings of each given set of 840 // relation/unit. 841 func (u *UniterAPI) ReadSettings(args params.RelationUnits) (params.RelationSettingsResults, error) { 842 result := params.RelationSettingsResults{ 843 Results: make([]params.RelationSettingsResult, len(args.RelationUnits)), 844 } 845 canAccess, err := u.accessUnit() 846 if err != nil { 847 return params.RelationSettingsResults{}, err 848 } 849 for i, arg := range args.RelationUnits { 850 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 851 if err == nil { 852 var settings *state.Settings 853 settings, err = relUnit.Settings() 854 if err == nil { 855 result.Results[i].Settings, err = convertRelationSettings(settings.Map()) 856 } 857 } 858 result.Results[i].Error = common.ServerError(err) 859 } 860 return result, nil 861 } 862 863 func (u *UniterAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) { 864 // Make sure the unit is indeed remote. 865 if remoteUnitTag == u.auth.GetAuthTag() { 866 return "", common.ErrPerm 867 } 868 // Check remoteUnit is indeed related. Note that we don't want to actually get 869 // the *Unit, because it might have been removed; but its relation settings will 870 // persist until the relation itself has been removed (and must remain accessible 871 // because the local unit's view of reality may be time-shifted). 872 _, remoteUnitName, err := names.ParseTag(remoteUnitTag, names.UnitTagKind) 873 if err != nil { 874 return "", err 875 } 876 remoteServiceName := names.UnitService(remoteUnitName) 877 rel := relUnit.Relation() 878 _, err = rel.RelatedEndpoints(remoteServiceName) 879 if err != nil { 880 return "", common.ErrPerm 881 } 882 return remoteUnitName, nil 883 } 884 885 // ReadRemoteSettings returns the remote settings of each given set of 886 // relation/local unit/remote unit. 887 func (u *UniterAPI) ReadRemoteSettings(args params.RelationUnitPairs) (params.RelationSettingsResults, error) { 888 result := params.RelationSettingsResults{ 889 Results: make([]params.RelationSettingsResult, len(args.RelationUnitPairs)), 890 } 891 canAccess, err := u.accessUnit() 892 if err != nil { 893 return params.RelationSettingsResults{}, err 894 } 895 for i, arg := range args.RelationUnitPairs { 896 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.LocalUnit) 897 if err == nil { 898 remoteUnit := "" 899 remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit) 900 if err == nil { 901 var settings map[string]interface{} 902 settings, err = relUnit.ReadSettings(remoteUnit) 903 if err == nil { 904 result.Results[i].Settings, err = convertRelationSettings(settings) 905 } 906 } 907 } 908 result.Results[i].Error = common.ServerError(err) 909 } 910 return result, nil 911 } 912 913 // UpdateSettings persists all changes made to the local settings of 914 // all given pairs of relation and unit. Keys with empty values are 915 // considered a signal to delete these values. 916 func (u *UniterAPI) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) { 917 result := params.ErrorResults{ 918 Results: make([]params.ErrorResult, len(args.RelationUnits)), 919 } 920 canAccess, err := u.accessUnit() 921 if err != nil { 922 return params.ErrorResults{}, err 923 } 924 for i, arg := range args.RelationUnits { 925 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 926 if err == nil { 927 var settings *state.Settings 928 settings, err = relUnit.Settings() 929 if err == nil { 930 for k, v := range arg.Settings { 931 if v == "" { 932 settings.Delete(k) 933 } else { 934 settings.Set(k, v) 935 } 936 } 937 _, err = settings.Write() 938 } 939 } 940 result.Results[i].Error = common.ServerError(err) 941 } 942 return result, nil 943 } 944 945 func (u *UniterAPI) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) { 946 watch := relUnit.Watch() 947 // Consume the initial event and forward it to the result. 948 if changes, ok := <-watch.Changes(); ok { 949 return params.RelationUnitsWatchResult{ 950 RelationUnitsWatcherId: u.resources.Register(watch), 951 Changes: changes, 952 }, nil 953 } 954 return params.RelationUnitsWatchResult{}, watcher.MustErr(watch) 955 } 956 957 // WatchRelationUnits returns a RelationUnitsWatcher for observing 958 // changes to every unit in the supplied relation that is visible to 959 // the supplied unit. See also state/watcher.go:RelationUnit.Watch(). 960 func (u *UniterAPI) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) { 961 result := params.RelationUnitsWatchResults{ 962 Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)), 963 } 964 canAccess, err := u.accessUnit() 965 if err != nil { 966 return params.RelationUnitsWatchResults{}, err 967 } 968 for i, arg := range args.RelationUnits { 969 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 970 if err == nil { 971 result.Results[i], err = u.watchOneRelationUnit(relUnit) 972 } 973 result.Results[i].Error = common.ServerError(err) 974 } 975 return result, nil 976 } 977 978 // TODO(dimitern) bug #1270795 2014-01-20 979 // Add a doc comment here and use u.accessService() 980 // below in the body to check for permissions. 981 func (u *UniterAPI) GetOwnerTag(args params.Entities) (params.StringResult, error) { 982 983 nothing := params.StringResult{} 984 service, err := u.getService(args.Entities[0].Tag) 985 if err != nil { 986 return nothing, err 987 } 988 989 return params.StringResult{ 990 Result: service.GetOwnerTag(), 991 }, nil 992 }