launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/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 errgo "launchpad.net/errgo/errors" 10 "launchpad.net/juju-core/charm" 11 "launchpad.net/juju-core/errors" 12 "launchpad.net/juju-core/names" 13 "launchpad.net/juju-core/state" 14 "launchpad.net/juju-core/state/api/params" 15 "launchpad.net/juju-core/state/apiserver/common" 16 "launchpad.net/juju-core/state/watcher" 17 ) 18 19 var mask = errgo.Mask 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), 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 entity, err := u.st.FindEntity(tag) 77 if err != nil { 78 return nil, mask(err, errors.IsNotFoundError) 79 } 80 return entity.(*state.Unit), nil 81 } 82 83 func (u *UniterAPI) getService(tag string) (*state.Service, error) { 84 entity, err := u.st.FindEntity(tag) 85 if err != nil { 86 return nil, mask(err, errors.IsNotFoundError) 87 } 88 return entity.(*state.Service), nil 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{}, mask(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 // SetPublicAddress sets the public address of each of the given units. 120 func (u *UniterAPI) SetPublicAddress(args params.SetEntityAddresses) (params.ErrorResults, error) { 121 result := params.ErrorResults{ 122 Results: make([]params.ErrorResult, len(args.Entities)), 123 } 124 canAccess, err := u.accessUnit() 125 if err != nil { 126 return params.ErrorResults{}, mask(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 err = unit.SetPublicAddress(entity.Address) 135 } 136 } 137 result.Results[i].Error = common.ServerError(err) 138 } 139 return result, nil 140 } 141 142 // PrivateAddress returns the private address for each given unit, if set. 143 func (u *UniterAPI) PrivateAddress(args params.Entities) (params.StringResults, error) { 144 result := params.StringResults{ 145 Results: make([]params.StringResult, len(args.Entities)), 146 } 147 canAccess, err := u.accessUnit() 148 if err != nil { 149 return params.StringResults{}, mask(err) 150 } 151 for i, entity := range args.Entities { 152 err := common.ErrPerm 153 if canAccess(entity.Tag) { 154 var unit *state.Unit 155 unit, err = u.getUnit(entity.Tag) 156 if err == nil { 157 address, ok := unit.PrivateAddress() 158 if ok { 159 result.Results[i].Result = address 160 } else { 161 err = common.NoAddressSetError(entity.Tag, "private") 162 } 163 } 164 } 165 result.Results[i].Error = common.ServerError(err) 166 } 167 return result, nil 168 } 169 170 // SetPrivateAddress sets the private address of each of the given units. 171 func (u *UniterAPI) SetPrivateAddress(args params.SetEntityAddresses) (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{}, mask(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.SetPrivateAddress(entity.Address) 186 } 187 } 188 result.Results[i].Error = common.ServerError(err) 189 } 190 return result, nil 191 } 192 193 // Resolved returns the current resolved setting for each given unit. 194 func (u *UniterAPI) Resolved(args params.Entities) (params.ResolvedModeResults, error) { 195 result := params.ResolvedModeResults{ 196 Results: make([]params.ResolvedModeResult, len(args.Entities)), 197 } 198 canAccess, err := u.accessUnit() 199 if err != nil { 200 return params.ResolvedModeResults{}, mask(err) 201 } 202 for i, entity := range args.Entities { 203 err := common.ErrPerm 204 if canAccess(entity.Tag) { 205 var unit *state.Unit 206 unit, err = u.getUnit(entity.Tag) 207 if err == nil { 208 result.Results[i].Mode = params.ResolvedMode(unit.Resolved()) 209 } 210 } 211 result.Results[i].Error = common.ServerError(err) 212 } 213 return result, nil 214 } 215 216 // ClearResolved removes any resolved setting from each given unit. 217 func (u *UniterAPI) ClearResolved(args params.Entities) (params.ErrorResults, error) { 218 result := params.ErrorResults{ 219 Results: make([]params.ErrorResult, len(args.Entities)), 220 } 221 canAccess, err := u.accessUnit() 222 if err != nil { 223 return params.ErrorResults{}, mask(err) 224 } 225 for i, entity := range args.Entities { 226 err := common.ErrPerm 227 if canAccess(entity.Tag) { 228 var unit *state.Unit 229 unit, err = u.getUnit(entity.Tag) 230 if err == nil { 231 err = unit.ClearResolved() 232 } 233 } 234 result.Results[i].Error = common.ServerError(err) 235 } 236 return result, nil 237 } 238 239 // GetPrincipal returns the result of calling PrincipalName() and 240 // converting it to a tag, on each given unit. 241 func (u *UniterAPI) GetPrincipal(args params.Entities) (params.StringBoolResults, error) { 242 result := params.StringBoolResults{ 243 Results: make([]params.StringBoolResult, len(args.Entities)), 244 } 245 canAccess, err := u.accessUnit() 246 if err != nil { 247 return params.StringBoolResults{}, mask(err) 248 } 249 for i, entity := range args.Entities { 250 err := common.ErrPerm 251 if canAccess(entity.Tag) { 252 var unit *state.Unit 253 unit, err = u.getUnit(entity.Tag) 254 if err == nil { 255 principal, ok := unit.PrincipalName() 256 if principal != "" { 257 result.Results[i].Result = names.UnitTag(principal) 258 } 259 result.Results[i].Ok = ok 260 } 261 } 262 result.Results[i].Error = common.ServerError(err) 263 } 264 return result, nil 265 } 266 267 // Destroy advances all given Alive units' lifecycles as far as 268 // possible. See state/Unit.Destroy(). 269 func (u *UniterAPI) Destroy(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{}, mask(err) 276 } 277 for i, entity := range args.Entities { 278 err := common.ErrPerm 279 if canAccess(entity.Tag) { 280 var unit *state.Unit 281 unit, err = u.getUnit(entity.Tag) 282 if err == nil { 283 err = unit.Destroy() 284 } 285 } 286 result.Results[i].Error = common.ServerError(err) 287 } 288 return result, nil 289 } 290 291 func (u *UniterAPI) destroySubordinates(principal *state.Unit) error { 292 subordinates := principal.SubordinateNames() 293 for _, subName := range subordinates { 294 unit, err := u.getUnit(names.UnitTag(subName)) 295 if err != nil { 296 return mask(err) 297 } 298 if err = unit.Destroy(); err != nil { 299 return mask(err) 300 } 301 } 302 return nil 303 } 304 305 // DestroyAllSubordinates destroys all subordinates of each given unit. 306 func (u *UniterAPI) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) { 307 result := params.ErrorResults{ 308 Results: make([]params.ErrorResult, len(args.Entities)), 309 } 310 canAccess, err := u.accessUnit() 311 if err != nil { 312 return params.ErrorResults{}, mask(err) 313 } 314 for i, entity := range args.Entities { 315 err := common.ErrPerm 316 if canAccess(entity.Tag) { 317 var unit *state.Unit 318 unit, err = u.getUnit(entity.Tag) 319 if err == nil { 320 err = u.destroySubordinates(unit) 321 } 322 } 323 result.Results[i].Error = common.ServerError(err) 324 } 325 return result, nil 326 } 327 328 // HasSubordinates returns the whether each given unit has any subordinates. 329 func (u *UniterAPI) HasSubordinates(args params.Entities) (params.BoolResults, error) { 330 result := params.BoolResults{ 331 Results: make([]params.BoolResult, len(args.Entities)), 332 } 333 canAccess, err := u.accessUnit() 334 if err != nil { 335 return params.BoolResults{}, mask(err) 336 } 337 for i, entity := range args.Entities { 338 err := common.ErrPerm 339 if canAccess(entity.Tag) { 340 var unit *state.Unit 341 unit, err = u.getUnit(entity.Tag) 342 if err == nil { 343 subordinates := unit.SubordinateNames() 344 result.Results[i].Result = len(subordinates) > 0 345 } 346 } 347 result.Results[i].Error = common.ServerError(err) 348 } 349 return result, nil 350 } 351 352 // CharmURL returns the charm URL for all given units or services. 353 func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) { 354 result := params.StringBoolResults{ 355 Results: make([]params.StringBoolResult, len(args.Entities)), 356 } 357 accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) 358 canAccess, err := accessUnitOrService() 359 if err != nil { 360 return params.StringBoolResults{}, mask(err) 361 } 362 for i, entity := range args.Entities { 363 err := common.ErrPerm 364 if canAccess(entity.Tag) { 365 var unitOrService state.Entity 366 unitOrService, err = u.st.FindEntity(entity.Tag) 367 if err == nil { 368 charmURLer := unitOrService.(interface { 369 CharmURL() (*charm.URL, bool) 370 }) 371 curl, ok := charmURLer.CharmURL() 372 if curl != nil { 373 result.Results[i].Result = curl.String() 374 result.Results[i].Ok = ok 375 } 376 } 377 } 378 result.Results[i].Error = common.ServerError(err) 379 } 380 return result, nil 381 } 382 383 // SetCharmURL sets the charm URL for each given unit. An error will 384 // be returned if a unit is dead, or the charm URL is not know. 385 func (u *UniterAPI) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) { 386 result := params.ErrorResults{ 387 Results: make([]params.ErrorResult, len(args.Entities)), 388 } 389 canAccess, err := u.accessUnit() 390 if err != nil { 391 return params.ErrorResults{}, mask(err) 392 } 393 for i, entity := range args.Entities { 394 err := common.ErrPerm 395 if canAccess(entity.Tag) { 396 var unit *state.Unit 397 unit, err = u.getUnit(entity.Tag) 398 if err == nil { 399 var curl *charm.URL 400 curl, err = charm.ParseURL(entity.CharmURL) 401 if err == nil { 402 err = unit.SetCharmURL(curl) 403 } 404 } 405 } 406 result.Results[i].Error = common.ServerError(err) 407 } 408 return result, nil 409 } 410 411 // OpenPort sets the policy of the port with protocol an number to be 412 // opened, for all given units. 413 func (u *UniterAPI) OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) { 414 result := params.ErrorResults{ 415 Results: make([]params.ErrorResult, len(args.Entities)), 416 } 417 canAccess, err := u.accessUnit() 418 if err != nil { 419 return params.ErrorResults{}, mask(err) 420 } 421 for i, entity := range args.Entities { 422 err := common.ErrPerm 423 if canAccess(entity.Tag) { 424 var unit *state.Unit 425 unit, err = u.getUnit(entity.Tag) 426 if err == nil { 427 err = unit.OpenPort(entity.Protocol, entity.Port) 428 } 429 } 430 result.Results[i].Error = common.ServerError(err) 431 } 432 return result, nil 433 } 434 435 // ClosePort sets the policy of the port with protocol and number to 436 // be closed, for all given units. 437 func (u *UniterAPI) ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) { 438 result := params.ErrorResults{ 439 Results: make([]params.ErrorResult, len(args.Entities)), 440 } 441 canAccess, err := u.accessUnit() 442 if err != nil { 443 return params.ErrorResults{}, mask(err) 444 } 445 for i, entity := range args.Entities { 446 err := common.ErrPerm 447 if canAccess(entity.Tag) { 448 var unit *state.Unit 449 unit, err = u.getUnit(entity.Tag) 450 if err == nil { 451 err = unit.ClosePort(entity.Protocol, entity.Port) 452 } 453 } 454 result.Results[i].Error = common.ServerError(err) 455 } 456 return result, nil 457 } 458 459 func (u *UniterAPI) watchOneUnitConfigSettings(tag string) (string, error) { 460 unit, err := u.getUnit(tag) 461 if err != nil { 462 return "", mask(err, errors.IsNotFoundError) 463 } 464 watch, err := unit.WatchConfigSettings() 465 if err != nil { 466 return "", mask(err) 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 } 472 473 if _, ok := <-watch.Changes(); ok { 474 return u.resources.Register(watch), nil 475 } 476 return "", watcher.MustErr(watch) 477 } 478 479 // WatchConfigSettings returns a NotifyWatcher for observing changes 480 // to each unit's service configuration settings. See also 481 // state/watcher.go:Unit.WatchConfigSettings(). 482 func (u *UniterAPI) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 483 result := params.NotifyWatchResults{ 484 Results: make([]params.NotifyWatchResult, len(args.Entities)), 485 } 486 canAccess, err := u.accessUnit() 487 if err != nil { 488 return params.NotifyWatchResults{}, mask(err) 489 } 490 for i, entity := range args.Entities { 491 err := common.ErrPerm 492 watcherId := "" 493 if canAccess(entity.Tag) { 494 watcherId, err = u.watchOneUnitConfigSettings(entity.Tag) 495 } 496 result.Results[i].NotifyWatcherId = watcherId 497 result.Results[i].Error = common.ServerError(err) 498 } 499 return result, nil 500 } 501 502 // ConfigSettings returns the complete set of service charm config 503 // settings available to each given unit. 504 func (u *UniterAPI) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) { 505 result := params.ConfigSettingsResults{ 506 Results: make([]params.ConfigSettingsResult, len(args.Entities)), 507 } 508 canAccess, err := u.accessUnit() 509 if err != nil { 510 return params.ConfigSettingsResults{}, mask(err) 511 } 512 for i, entity := range args.Entities { 513 err := common.ErrPerm 514 if canAccess(entity.Tag) { 515 var unit *state.Unit 516 unit, err = u.getUnit(entity.Tag) 517 if err == nil { 518 var settings charm.Settings 519 settings, err = unit.ConfigSettings() 520 if err == nil { 521 result.Results[i].Settings = params.ConfigSettings(settings) 522 } 523 } 524 } 525 result.Results[i].Error = common.ServerError(err) 526 } 527 return result, nil 528 } 529 530 func (u *UniterAPI) watchOneServiceRelations(tag string) (params.StringsWatchResult, error) { 531 nothing := params.StringsWatchResult{} 532 service, err := u.getService(tag) 533 if err != nil { 534 return nothing, mask(err) 535 } 536 watch := service.WatchRelations() 537 // Consume the initial event and forward it to the result. 538 if changes, ok := <-watch.Changes(); ok { 539 return params.StringsWatchResult{ 540 StringsWatcherId: u.resources.Register(watch), 541 Changes: changes, 542 }, nil 543 } 544 return nothing, watcher.MustErr(watch) 545 } 546 547 // WatchServiceRelations returns a StringsWatcher, for each given 548 // service, that notifies of changes to the lifecycles of relations 549 // involving that service. 550 func (u *UniterAPI) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) { 551 result := params.StringsWatchResults{ 552 Results: make([]params.StringsWatchResult, len(args.Entities)), 553 } 554 canAccess, err := u.accessService() 555 if err != nil { 556 return params.StringsWatchResults{}, mask(err) 557 } 558 for i, entity := range args.Entities { 559 err := common.ErrPerm 560 if canAccess(entity.Tag) { 561 result.Results[i], err = u.watchOneServiceRelations(entity.Tag) 562 } 563 result.Results[i].Error = common.ServerError(err) 564 } 565 return result, nil 566 } 567 568 // CharmArchiveURL returns the URL, corresponding to the charm archive 569 // (bundle) in the provider storage for each given charm URL, along 570 // with the DisableSSLHostnameVerification flag. 571 func (u *UniterAPI) CharmArchiveURL(args params.CharmURLs) (params.CharmArchiveURLResults, error) { 572 result := params.CharmArchiveURLResults{ 573 Results: make([]params.CharmArchiveURLResult, len(args.URLs)), 574 } 575 // Get the SSL hostname verification environment setting. 576 envConfig, err := u.st.EnvironConfig() 577 if err != nil { 578 return result, mask(err) 579 } 580 581 // SSLHostnameVerification defaults to true, so we need to 582 // invert that, for backwards-compatibility (older versions 583 // will have DisableSSLHostnameVerification: false by default). 584 disableSSLHostnameVerification := !envConfig.SSLHostnameVerification() 585 for i, arg := range args.URLs { 586 curl, err := charm.ParseURL(arg.URL) 587 if err != nil { 588 err = common.ErrPerm 589 } else { 590 var sch *state.Charm 591 sch, err = u.st.Charm(curl) 592 if errors.IsNotFoundError(err) { 593 err = common.ErrPerm 594 } 595 if err == nil { 596 result.Results[i].Result = sch.BundleURL().String() 597 result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification 598 } 599 } 600 result.Results[i].Error = common.ServerError(err) 601 } 602 return result, nil 603 } 604 605 // CharmArchiveSha256 returns the SHA256 digest of the charm archive 606 // (bundle) data for each charm url in the given parameters. 607 func (u *UniterAPI) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) { 608 result := params.StringResults{ 609 Results: make([]params.StringResult, len(args.URLs)), 610 } 611 for i, arg := range args.URLs { 612 curl, err := charm.ParseURL(arg.URL) 613 if err != nil { 614 err = common.ErrPerm 615 } else { 616 var sch *state.Charm 617 sch, err = u.st.Charm(curl) 618 if errors.IsNotFoundError(err) { 619 err = common.ErrPerm 620 } 621 if err == nil { 622 result.Results[i].Result = sch.BundleSha256() 623 } 624 } 625 result.Results[i].Error = common.ServerError(err) 626 } 627 return result, nil 628 } 629 630 func (u *UniterAPI) getRelationAndUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.Relation, *state.Unit, error) { 631 _, key, err := names.ParseTag(relTag, names.RelationTagKind) 632 if err != nil { 633 return nil, nil, common.ErrPerm 634 } 635 rel, err := u.st.KeyRelation(key) 636 if errors.IsNotFoundError(err) { 637 return nil, nil, common.ErrPerm 638 } else if err != nil { 639 return nil, nil, mask(err) 640 } 641 if !canAccess(unitTag) { 642 return nil, nil, common.ErrPerm 643 } 644 unit, err := u.getUnit(unitTag) 645 return rel, unit, err 646 } 647 648 func (u *UniterAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) { 649 nothing := params.RelationResult{} 650 ep, err := rel.Endpoint(unit.ServiceName()) 651 if err != nil { 652 // An error here means the unit's service is not part of the 653 // relation. 654 return nothing, mask(err) 655 } 656 return params.RelationResult{ 657 Id: rel.Id(), 658 Key: rel.String(), 659 Life: params.Life(rel.Life().String()), 660 Endpoint: params.Endpoint{ 661 ServiceName: ep.ServiceName, 662 Relation: ep.Relation, 663 }, 664 }, nil 665 } 666 667 func (u *UniterAPI) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) { 668 nothing := params.RelationResult{} 669 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 670 if err != nil { 671 return nothing, mask(err, errgo.Any) 672 } 673 return u.prepareRelationResult(rel, unit) 674 } 675 676 func (u *UniterAPI) getOneRelationById(relId int) (params.RelationResult, error) { 677 nothing := params.RelationResult{} 678 rel, err := u.st.Relation(relId) 679 if errors.IsNotFoundError(err) { 680 return nothing, common.ErrPerm 681 } else if err != nil { 682 // Use the currently authenticated unit to get the endpoint. 683 return nothing, mask(err, errgo.Any) 684 } 685 686 unit, ok := u.auth.GetAuthEntity().(*state.Unit) 687 if !ok { 688 panic("authenticated entity is not a unit") 689 } 690 result, err := u.prepareRelationResult(rel, unit) 691 if err != nil { 692 // An error from prepareRelationResult means the authenticated 693 // unit's service is not part of the requested 694 // relation. That's why it's appropriate to return ErrPerm 695 // here. 696 return nothing, common.ErrPerm 697 } 698 return result, nil 699 } 700 701 func (u *UniterAPI) getRelationUnit(canAccess common.AuthFunc, relTag, unitTag string) (*state.RelationUnit, error) { 702 rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag) 703 if err != nil { 704 return nil, mask(err, errgo.Any) 705 } 706 return rel.Unit(unit) 707 } 708 709 // Relation returns information about all given relation/unit pairs, 710 // including their id, key and the local endpoint. 711 func (u *UniterAPI) Relation(args params.RelationUnits) (params.RelationResults, error) { 712 result := params.RelationResults{ 713 Results: make([]params.RelationResult, len(args.RelationUnits)), 714 } 715 canAccess, err := u.accessUnit() 716 if err != nil { 717 return params.RelationResults{}, mask(err) 718 } 719 for i, rel := range args.RelationUnits { 720 relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit) 721 if err == nil { 722 result.Results[i] = relParams 723 } 724 result.Results[i].Error = common.ServerError(err) 725 } 726 return result, nil 727 } 728 729 // RelationById returns information about all given relations, 730 // specified by their ids, including their key and the local 731 // endpoint. 732 func (u *UniterAPI) RelationById(args params.RelationIds) (params.RelationResults, error) { 733 result := params.RelationResults{ 734 Results: make([]params.RelationResult, len(args.RelationIds)), 735 } 736 for i, relId := range args.RelationIds { 737 relParams, err := u.getOneRelationById(relId) 738 if err == nil { 739 result.Results[i] = relParams 740 } 741 result.Results[i].Error = common.ServerError(err) 742 } 743 return result, nil 744 } 745 746 // CurrentEnvironUUID returns the UUID for the current juju environment. 747 func (u *UniterAPI) CurrentEnvironUUID() (params.StringResult, error) { 748 result := params.StringResult{} 749 env, err := u.st.Environment() 750 if err == nil { 751 result.Result = env.UUID() 752 } 753 return result, err 754 } 755 756 // CurrentEnvironment returns the name and UUID for the current juju environment. 757 func (u *UniterAPI) CurrentEnvironment() (params.EnvironmentResult, error) { 758 result := params.EnvironmentResult{} 759 env, err := u.st.Environment() 760 if err == nil { 761 result.Name = env.Name() 762 result.UUID = env.UUID() 763 } 764 return result, err 765 } 766 767 // ProviderType returns the provider type used by the current juju 768 // environment. 769 // 770 // TODO(dimitern): Refactor the uniter to call this instead of calling 771 // EnvironConfig() just to get the provider type. Once we have machine 772 // addresses, this might be completely unnecessary though. 773 func (u *UniterAPI) ProviderType() (params.StringResult, error) { 774 result := params.StringResult{} 775 cfg, err := u.st.EnvironConfig() 776 if err == nil { 777 result.Result = cfg.Type() 778 } 779 return result, err 780 } 781 782 // EnterScope ensures each unit has entered its scope in the relation, 783 // for all of the given relation/unit pairs. See also 784 // state.RelationUnit.EnterScope(). 785 func (u *UniterAPI) EnterScope(args params.RelationUnits) (params.ErrorResults, error) { 786 result := params.ErrorResults{ 787 Results: make([]params.ErrorResult, len(args.RelationUnits)), 788 } 789 canAccess, err := u.accessUnit() 790 if err != nil { 791 return params.ErrorResults{}, mask(err) 792 } 793 for i, arg := range args.RelationUnits { 794 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 795 if err == nil { 796 // Construct the settings, passing the unit's 797 // private address (we already know it). 798 privateAddress, _ := relUnit.PrivateAddress() 799 settings := map[string]interface{}{ 800 "private-address": privateAddress, 801 } 802 err = relUnit.EnterScope(settings) 803 } 804 result.Results[i].Error = common.ServerError(err) 805 } 806 return result, nil 807 } 808 809 // LeaveScope signals each unit has left its scope in the relation, 810 // for all of the given relation/unit pairs. See also 811 // state.RelationUnit.LeaveScope(). 812 func (u *UniterAPI) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) { 813 result := params.ErrorResults{ 814 Results: make([]params.ErrorResult, len(args.RelationUnits)), 815 } 816 canAccess, err := u.accessUnit() 817 if err != nil { 818 return params.ErrorResults{}, mask(err) 819 } 820 for i, arg := range args.RelationUnits { 821 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 822 if err == nil { 823 err = relUnit.LeaveScope() 824 } 825 result.Results[i].Error = common.ServerError(err) 826 } 827 return result, nil 828 } 829 830 func convertRelationSettings(settings map[string]interface{}) (params.RelationSettings, error) { 831 result := make(params.RelationSettings) 832 for k, v := range settings { 833 // All relation settings should be strings. 834 sval, ok := v.(string) 835 if !ok { 836 return nil, errgo.Newf("unexpected relation setting %q: expected string, got %T", k, v) 837 } 838 result[k] = sval 839 } 840 return result, nil 841 } 842 843 // ReadSettings returns the local settings of each given set of 844 // relation/unit. 845 func (u *UniterAPI) ReadSettings(args params.RelationUnits) (params.RelationSettingsResults, error) { 846 result := params.RelationSettingsResults{ 847 Results: make([]params.RelationSettingsResult, len(args.RelationUnits)), 848 } 849 canAccess, err := u.accessUnit() 850 if err != nil { 851 return params.RelationSettingsResults{}, mask(err) 852 } 853 for i, arg := range args.RelationUnits { 854 relUnit, err := u.getRelationUnit(canAccess, arg.Relation, arg.Unit) 855 if err == nil { 856 var settings *state.Settings 857 settings, err = relUnit.Settings() 858 if err == nil { 859 result.Results[i].Settings, err = convertRelationSettings(settings.Map()) 860 } 861 } 862 result.Results[i].Error = common.ServerError(err) 863 } 864 return result, nil 865 } 866 867 func (u *UniterAPI) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) { 868 // Make sure the unit is indeed remote. 869 if remoteUnitTag == u.auth.GetAuthTag() { 870 return "", common.ErrPerm 871 } 872 remoteUnit, err := u.getUnit(remoteUnitTag) 873 if err != nil { 874 return "", common.ErrPerm 875 } 876 // Check remoteUnit is indeed related. 877 rel := relUnit.Relation() 878 _, err = rel.RelatedEndpoints(remoteUnit.ServiceName()) 879 if err != nil { 880 return "", common.ErrPerm 881 } 882 return remoteUnit.Name(), 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{}, mask(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{}, mask(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{}, mask(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, mask(err, errgo.Any) 987 } 988 989 return params.StringResult{ 990 Result: service.GetOwnerTag(), 991 }, nil 992 }