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