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