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