github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "net/url" 11 "path" 12 13 "github.com/juju/errors" 14 "github.com/juju/loggo" 15 "github.com/juju/names" 16 "gopkg.in/juju/charm.v6-unstable" 17 18 "github.com/juju/juju/apiserver/common" 19 leadershipapiserver "github.com/juju/juju/apiserver/leadership" 20 "github.com/juju/juju/apiserver/meterstatus" 21 "github.com/juju/juju/apiserver/params" 22 "github.com/juju/juju/core/leadership" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/state/multiwatcher" 26 "github.com/juju/juju/state/watcher" 27 ) 28 29 var logger = loggo.GetLogger("juju.apiserver.uniter") 30 31 func init() { 32 common.RegisterStandardFacade("Uniter", 3, NewUniterAPIV3) 33 } 34 35 // UniterAPIV3 implements the API version 3, used by the uniter worker. 36 type UniterAPIV3 struct { 37 *common.LifeGetter 38 *StatusAPI 39 *common.DeadEnsurer 40 *common.AgentEntityWatcher 41 *common.APIAddresser 42 *common.ModelWatcher 43 *common.RebootRequester 44 *leadershipapiserver.LeadershipSettingsAccessor 45 meterstatus.MeterStatus 46 47 st *state.State 48 auth common.Authorizer 49 resources *common.Resources 50 accessUnit common.GetAuthFunc 51 accessService common.GetAuthFunc 52 unit *state.Unit 53 accessMachine common.GetAuthFunc 54 StorageAPI 55 } 56 57 // NewUniterAPIV3 creates a new instance of the Uniter API, version 3. 58 func NewUniterAPIV3(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*UniterAPIV3, error) { 59 if !authorizer.AuthUnitAgent() { 60 return nil, common.ErrPerm 61 } 62 var unit *state.Unit 63 var err error 64 switch tag := authorizer.GetAuthTag().(type) { 65 case names.UnitTag: 66 unit, err = st.Unit(tag.Id()) 67 if err != nil { 68 return nil, errors.Trace(err) 69 } 70 default: 71 return nil, errors.Errorf("expected names.UnitTag, got %T", tag) 72 } 73 accessUnit := func() (common.AuthFunc, error) { 74 return authorizer.AuthOwner, nil 75 } 76 accessService := func() (common.AuthFunc, error) { 77 switch tag := authorizer.GetAuthTag().(type) { 78 case names.UnitTag: 79 entity, err := st.Unit(tag.Id()) 80 if err != nil { 81 return nil, errors.Trace(err) 82 } 83 serviceName := entity.ServiceName() 84 serviceTag := names.NewServiceTag(serviceName) 85 return func(tag names.Tag) bool { 86 return tag == serviceTag 87 }, nil 88 default: 89 return nil, errors.Errorf("expected names.UnitTag, got %T", tag) 90 } 91 } 92 accessMachine := func() (common.AuthFunc, error) { 93 switch tag := authorizer.GetAuthTag().(type) { 94 case names.UnitTag: 95 entity, err := st.Unit(tag.Id()) 96 if err != nil { 97 return nil, errors.Trace(err) 98 } 99 machineId, err := entity.AssignedMachineId() 100 if err != nil { 101 return nil, errors.Trace(err) 102 } 103 machineTag := names.NewMachineTag(machineId) 104 return func(tag names.Tag) bool { 105 return tag == machineTag 106 }, nil 107 default: 108 return nil, errors.Errorf("expected names.UnitTag, got %T", tag) 109 } 110 } 111 storageAPI, err := newStorageAPI(getStorageState(st), resources, accessUnit) 112 if err != nil { 113 return nil, err 114 } 115 msAPI, err := meterstatus.NewMeterStatusAPI(st, resources, authorizer) 116 if err != nil { 117 return nil, errors.Annotate(err, "could not create meter status API handler") 118 } 119 accessUnitOrService := common.AuthEither(accessUnit, accessService) 120 return &UniterAPIV3{ 121 LifeGetter: common.NewLifeGetter(st, accessUnitOrService), 122 DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), 123 AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), 124 APIAddresser: common.NewAPIAddresser(st, resources), 125 ModelWatcher: common.NewModelWatcher(st, resources, authorizer), 126 RebootRequester: common.NewRebootRequester(st, accessMachine), 127 LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), 128 MeterStatus: msAPI, 129 // TODO(fwereade): so *every* unit should be allowed to get/set its 130 // own status *and* its service's? This is not a pleasing arrangement. 131 StatusAPI: NewStatusAPI(st, accessUnitOrService), 132 133 st: st, 134 auth: authorizer, 135 resources: resources, 136 accessUnit: accessUnit, 137 accessService: accessService, 138 accessMachine: accessMachine, 139 unit: unit, 140 StorageAPI: *storageAPI, 141 }, nil 142 } 143 144 // AllMachinePorts returns all opened port ranges for each given 145 // machine (on all networks). 146 func (u *UniterAPIV3) AllMachinePorts(args params.Entities) (params.MachinePortsResults, error) { 147 result := params.MachinePortsResults{ 148 Results: make([]params.MachinePortsResult, len(args.Entities)), 149 } 150 canAccess, err := u.accessMachine() 151 if err != nil { 152 return params.MachinePortsResults{}, err 153 } 154 for i, entity := range args.Entities { 155 result.Results[i] = u.getOneMachinePorts(canAccess, entity.Tag) 156 } 157 return result, nil 158 } 159 160 // ServiceOwner returns the owner user for each given service tag. 161 func (u *UniterAPIV3) ServiceOwner(args params.Entities) (params.StringResults, error) { 162 result := params.StringResults{ 163 Results: make([]params.StringResult, len(args.Entities)), 164 } 165 canAccess, err := u.accessService() 166 if err != nil { 167 return params.StringResults{}, err 168 } 169 for i, entity := range args.Entities { 170 tag, err := names.ParseServiceTag(entity.Tag) 171 if err != nil { 172 result.Results[i].Error = common.ServerError(common.ErrPerm) 173 continue 174 } 175 if !canAccess(tag) { 176 result.Results[i].Error = common.ServerError(common.ErrPerm) 177 continue 178 } 179 service, err := u.getService(tag) 180 if err != nil { 181 result.Results[i].Error = common.ServerError(err) 182 continue 183 } 184 result.Results[i].Result = service.GetOwnerTag() 185 } 186 return result, nil 187 } 188 189 // AssignedMachine returns the machine tag for each given unit tag, or 190 // an error satisfying params.IsCodeNotAssigned when a unit has no 191 // assigned machine. 192 func (u *UniterAPIV3) AssignedMachine(args params.Entities) (params.StringResults, error) { 193 result := params.StringResults{ 194 Results: make([]params.StringResult, len(args.Entities)), 195 } 196 canAccess, err := u.accessUnit() 197 if err != nil { 198 return params.StringResults{}, err 199 } 200 for i, entity := range args.Entities { 201 tag, err := names.ParseUnitTag(entity.Tag) 202 if err != nil { 203 result.Results[i].Error = common.ServerError(common.ErrPerm) 204 continue 205 } 206 if !canAccess(tag) { 207 result.Results[i].Error = common.ServerError(common.ErrPerm) 208 continue 209 } 210 unit, err := u.getUnit(tag) 211 if err != nil { 212 result.Results[i].Error = common.ServerError(err) 213 continue 214 } 215 machineId, err := unit.AssignedMachineId() 216 if err != nil { 217 result.Results[i].Error = common.ServerError(err) 218 } else { 219 result.Results[i].Result = names.NewMachineTag(machineId).String() 220 } 221 } 222 return result, nil 223 } 224 225 func (u *UniterAPIV3) getMachine(tag names.MachineTag) (*state.Machine, error) { 226 return u.st.Machine(tag.Id()) 227 } 228 229 func (u *UniterAPIV3) getOneMachinePorts(canAccess common.AuthFunc, machineTag string) params.MachinePortsResult { 230 tag, err := names.ParseMachineTag(machineTag) 231 if err != nil { 232 return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)} 233 } 234 if !canAccess(tag) { 235 return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)} 236 } 237 machine, err := u.getMachine(tag) 238 if err != nil { 239 return params.MachinePortsResult{Error: common.ServerError(err)} 240 } 241 allPorts, err := machine.AllPorts() 242 if err != nil { 243 return params.MachinePortsResult{Error: common.ServerError(err)} 244 } 245 var resultPorts []params.MachinePortRange 246 for _, ports := range allPorts { 247 // AllPortRanges gives a map, but apis require a stable order 248 // for results, so sort the port ranges. 249 portRangesToUnits := ports.AllPortRanges() 250 portRanges := make([]network.PortRange, 0, len(portRangesToUnits)) 251 for portRange := range portRangesToUnits { 252 portRanges = append(portRanges, portRange) 253 } 254 network.SortPortRanges(portRanges) 255 for _, portRange := range portRanges { 256 unitName := portRangesToUnits[portRange] 257 resultPorts = append(resultPorts, params.MachinePortRange{ 258 UnitTag: names.NewUnitTag(unitName).String(), 259 PortRange: params.FromNetworkPortRange(portRange), 260 }) 261 } 262 } 263 return params.MachinePortsResult{ 264 Ports: resultPorts, 265 } 266 } 267 268 // PublicAddress returns the public address for each given unit, if set. 269 func (u *UniterAPIV3) PublicAddress(args params.Entities) (params.StringResults, error) { 270 result := params.StringResults{ 271 Results: make([]params.StringResult, len(args.Entities)), 272 } 273 canAccess, err := u.accessUnit() 274 if err != nil { 275 return params.StringResults{}, err 276 } 277 for i, entity := range args.Entities { 278 tag, err := names.ParseUnitTag(entity.Tag) 279 if err != nil { 280 result.Results[i].Error = common.ServerError(common.ErrPerm) 281 continue 282 } 283 err = common.ErrPerm 284 if canAccess(tag) { 285 var unit *state.Unit 286 unit, err = u.getUnit(tag) 287 if err == nil { 288 var address network.Address 289 address, err = unit.PublicAddress() 290 if err == nil { 291 result.Results[i].Result = address.Value 292 } else if network.IsNoAddress(err) { 293 err = common.NoAddressSetError(tag, "public") 294 } 295 } 296 } 297 result.Results[i].Error = common.ServerError(err) 298 } 299 return result, nil 300 } 301 302 // PrivateAddress returns the private address for each given unit, if set. 303 func (u *UniterAPIV3) PrivateAddress(args params.Entities) (params.StringResults, error) { 304 result := params.StringResults{ 305 Results: make([]params.StringResult, len(args.Entities)), 306 } 307 canAccess, err := u.accessUnit() 308 if err != nil { 309 return params.StringResults{}, err 310 } 311 for i, entity := range args.Entities { 312 tag, err := names.ParseUnitTag(entity.Tag) 313 if err != nil { 314 result.Results[i].Error = common.ServerError(common.ErrPerm) 315 continue 316 } 317 err = common.ErrPerm 318 if canAccess(tag) { 319 var unit *state.Unit 320 unit, err = u.getUnit(tag) 321 if err == nil { 322 var address network.Address 323 address, err = unit.PrivateAddress() 324 if err == nil { 325 result.Results[i].Result = address.Value 326 } else if network.IsNoAddress(err) { 327 err = common.NoAddressSetError(tag, "private") 328 } 329 } 330 } 331 result.Results[i].Error = common.ServerError(err) 332 } 333 return result, nil 334 } 335 336 // TODO(ericsnow) Factor out the common code amongst the many methods here. 337 338 var getZone = func(st *state.State, tag names.Tag) (string, error) { 339 unit, err := st.Unit(tag.Id()) 340 if err != nil { 341 return "", errors.Trace(err) 342 } 343 zone, err := unit.AvailabilityZone() 344 return zone, errors.Trace(err) 345 } 346 347 // AvailabilityZone returns the availability zone for each given unit, if applicable. 348 func (u *UniterAPIV3) AvailabilityZone(args params.Entities) (params.StringResults, error) { 349 var results params.StringResults 350 351 canAccess, err := u.accessUnit() 352 if err != nil { 353 return results, errors.Trace(err) 354 } 355 356 // Prep the results. 357 results = params.StringResults{ 358 Results: make([]params.StringResult, len(args.Entities)), 359 } 360 361 // Collect the zones. No zone will be collected for any entity where 362 // the tag is invalid or not authorized. Instead the corresponding 363 // result will be updated with the error. 364 for i, entity := range args.Entities { 365 tag, err := names.ParseUnitTag(entity.Tag) 366 if err != nil { 367 results.Results[i].Error = common.ServerError(common.ErrPerm) 368 continue 369 } 370 err = common.ErrPerm 371 if canAccess(tag) { 372 var zone string 373 zone, err = getZone(u.st, tag) 374 if err == nil { 375 results.Results[i].Result = zone 376 } 377 } 378 results.Results[i].Error = common.ServerError(err) 379 } 380 381 return results, nil 382 } 383 384 // Resolved returns the current resolved setting for each given unit. 385 func (u *UniterAPIV3) Resolved(args params.Entities) (params.ResolvedModeResults, error) { 386 result := params.ResolvedModeResults{ 387 Results: make([]params.ResolvedModeResult, len(args.Entities)), 388 } 389 canAccess, err := u.accessUnit() 390 if err != nil { 391 return params.ResolvedModeResults{}, err 392 } 393 for i, entity := range args.Entities { 394 tag, err := names.ParseUnitTag(entity.Tag) 395 if err != nil { 396 result.Results[i].Error = common.ServerError(common.ErrPerm) 397 continue 398 } 399 err = common.ErrPerm 400 if canAccess(tag) { 401 var unit *state.Unit 402 unit, err = u.getUnit(tag) 403 if err == nil { 404 result.Results[i].Mode = params.ResolvedMode(unit.Resolved()) 405 } 406 } 407 result.Results[i].Error = common.ServerError(err) 408 } 409 return result, nil 410 } 411 412 // ClearResolved removes any resolved setting from each given unit. 413 func (u *UniterAPIV3) ClearResolved(args params.Entities) (params.ErrorResults, error) { 414 result := params.ErrorResults{ 415 Results: make([]params.ErrorResult, len(args.Entities)), 416 } 417 canAccess, err := u.accessUnit() 418 if err != nil { 419 return params.ErrorResults{}, err 420 } 421 for i, entity := range args.Entities { 422 tag, err := names.ParseUnitTag(entity.Tag) 423 if err != nil { 424 result.Results[i].Error = common.ServerError(common.ErrPerm) 425 continue 426 } 427 err = common.ErrPerm 428 if canAccess(tag) { 429 var unit *state.Unit 430 unit, err = u.getUnit(tag) 431 if err == nil { 432 err = unit.ClearResolved() 433 } 434 } 435 result.Results[i].Error = common.ServerError(err) 436 } 437 return result, nil 438 } 439 440 // GetPrincipal returns the result of calling PrincipalName() and 441 // converting it to a tag, on each given unit. 442 func (u *UniterAPIV3) GetPrincipal(args params.Entities) (params.StringBoolResults, error) { 443 result := params.StringBoolResults{ 444 Results: make([]params.StringBoolResult, len(args.Entities)), 445 } 446 canAccess, err := u.accessUnit() 447 if err != nil { 448 return params.StringBoolResults{}, err 449 } 450 for i, entity := range args.Entities { 451 tag, err := names.ParseUnitTag(entity.Tag) 452 if err != nil { 453 result.Results[i].Error = common.ServerError(common.ErrPerm) 454 continue 455 } 456 err = common.ErrPerm 457 if canAccess(tag) { 458 var unit *state.Unit 459 unit, err = u.getUnit(tag) 460 if err == nil { 461 principal, ok := unit.PrincipalName() 462 if principal != "" { 463 result.Results[i].Result = names.NewUnitTag(principal).String() 464 } 465 result.Results[i].Ok = ok 466 } 467 } 468 result.Results[i].Error = common.ServerError(err) 469 } 470 return result, nil 471 } 472 473 // Destroy advances all given Alive units' lifecycles as far as 474 // possible. See state/Unit.Destroy(). 475 func (u *UniterAPIV3) Destroy(args params.Entities) (params.ErrorResults, error) { 476 result := params.ErrorResults{ 477 Results: make([]params.ErrorResult, len(args.Entities)), 478 } 479 canAccess, err := u.accessUnit() 480 if err != nil { 481 return params.ErrorResults{}, err 482 } 483 for i, entity := range args.Entities { 484 tag, err := names.ParseUnitTag(entity.Tag) 485 if err != nil { 486 result.Results[i].Error = common.ServerError(common.ErrPerm) 487 continue 488 } 489 err = common.ErrPerm 490 if canAccess(tag) { 491 var unit *state.Unit 492 unit, err = u.getUnit(tag) 493 if err == nil { 494 err = unit.Destroy() 495 } 496 } 497 result.Results[i].Error = common.ServerError(err) 498 } 499 return result, nil 500 } 501 502 // DestroyAllSubordinates destroys all subordinates of each given unit. 503 func (u *UniterAPIV3) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) { 504 result := params.ErrorResults{ 505 Results: make([]params.ErrorResult, len(args.Entities)), 506 } 507 canAccess, err := u.accessUnit() 508 if err != nil { 509 return params.ErrorResults{}, err 510 } 511 for i, entity := range args.Entities { 512 tag, err := names.ParseUnitTag(entity.Tag) 513 if err != nil { 514 result.Results[i].Error = common.ServerError(common.ErrPerm) 515 continue 516 } 517 err = common.ErrPerm 518 if canAccess(tag) { 519 var unit *state.Unit 520 unit, err = u.getUnit(tag) 521 if err == nil { 522 err = u.destroySubordinates(unit) 523 } 524 } 525 result.Results[i].Error = common.ServerError(err) 526 } 527 return result, nil 528 } 529 530 // HasSubordinates returns the whether each given unit has any subordinates. 531 func (u *UniterAPIV3) HasSubordinates(args params.Entities) (params.BoolResults, error) { 532 result := params.BoolResults{ 533 Results: make([]params.BoolResult, len(args.Entities)), 534 } 535 canAccess, err := u.accessUnit() 536 if err != nil { 537 return params.BoolResults{}, err 538 } 539 for i, entity := range args.Entities { 540 tag, err := names.ParseUnitTag(entity.Tag) 541 if err != nil { 542 result.Results[i].Error = common.ServerError(common.ErrPerm) 543 continue 544 } 545 err = common.ErrPerm 546 if canAccess(tag) { 547 var unit *state.Unit 548 unit, err = u.getUnit(tag) 549 if err == nil { 550 subordinates := unit.SubordinateNames() 551 result.Results[i].Result = len(subordinates) > 0 552 } 553 } 554 result.Results[i].Error = common.ServerError(err) 555 } 556 return result, nil 557 } 558 559 // CharmModifiedVersion returns the most CharmModifiedVersion for all given 560 // units or services. 561 func (u *UniterAPIV3) CharmModifiedVersion(args params.Entities) (params.IntResults, error) { 562 results := params.IntResults{ 563 Results: make([]params.IntResult, len(args.Entities)), 564 } 565 566 accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) 567 canAccess, err := accessUnitOrService() 568 if err != nil { 569 return results, err 570 } 571 for i, entity := range args.Entities { 572 ver, err := u.charmModifiedVersion(entity.Tag, canAccess) 573 if err != nil { 574 results.Results[i].Error = common.ServerError(err) 575 continue 576 } 577 results.Results[i].Result = ver 578 } 579 return results, nil 580 } 581 582 func (u *UniterAPIV3) charmModifiedVersion(tagStr string, canAccess func(names.Tag) bool) (int, error) { 583 tag, err := names.ParseTag(tagStr) 584 if err != nil { 585 return -1, common.ErrPerm 586 } 587 if !canAccess(tag) { 588 return -1, common.ErrPerm 589 } 590 unitOrService, err := u.st.FindEntity(tag) 591 if err != nil { 592 return -1, err 593 } 594 var service *state.Service 595 switch entity := unitOrService.(type) { 596 case *state.Service: 597 service = entity 598 case *state.Unit: 599 service, err = entity.Service() 600 if err != nil { 601 return -1, err 602 } 603 default: 604 return -1, errors.BadRequestf("type %t does not have a CharmModifiedVersion", entity) 605 } 606 return service.CharmModifiedVersion(), nil 607 } 608 609 // CharmURL returns the charm URL for all given units or services. 610 func (u *UniterAPIV3) CharmURL(args params.Entities) (params.StringBoolResults, error) { 611 result := params.StringBoolResults{ 612 Results: make([]params.StringBoolResult, len(args.Entities)), 613 } 614 accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) 615 canAccess, err := accessUnitOrService() 616 if err != nil { 617 return params.StringBoolResults{}, err 618 } 619 for i, entity := range args.Entities { 620 tag, err := names.ParseTag(entity.Tag) 621 if err != nil { 622 result.Results[i].Error = common.ServerError(common.ErrPerm) 623 continue 624 } 625 err = common.ErrPerm 626 if canAccess(tag) { 627 var unitOrService state.Entity 628 unitOrService, err = u.st.FindEntity(tag) 629 if err == nil { 630 charmURLer := unitOrService.(interface { 631 CharmURL() (*charm.URL, bool) 632 }) 633 curl, ok := charmURLer.CharmURL() 634 if curl != nil { 635 result.Results[i].Result = curl.String() 636 result.Results[i].Ok = ok 637 } 638 } 639 } 640 result.Results[i].Error = common.ServerError(err) 641 } 642 return result, nil 643 } 644 645 // SetCharmURL sets the charm URL for each given unit. An error will 646 // be returned if a unit is dead, or the charm URL is not know. 647 func (u *UniterAPIV3) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) { 648 result := params.ErrorResults{ 649 Results: make([]params.ErrorResult, len(args.Entities)), 650 } 651 canAccess, err := u.accessUnit() 652 if err != nil { 653 return params.ErrorResults{}, err 654 } 655 for i, entity := range args.Entities { 656 tag, err := names.ParseUnitTag(entity.Tag) 657 if err != nil { 658 result.Results[i].Error = common.ServerError(common.ErrPerm) 659 continue 660 } 661 err = common.ErrPerm 662 if canAccess(tag) { 663 var unit *state.Unit 664 unit, err = u.getUnit(tag) 665 if err == nil { 666 var curl *charm.URL 667 curl, err = charm.ParseURL(entity.CharmURL) 668 if err == nil { 669 err = unit.SetCharmURL(curl) 670 } 671 } 672 } 673 result.Results[i].Error = common.ServerError(err) 674 } 675 return result, nil 676 } 677 678 // OpenPorts sets the policy of the port range with protocol to be 679 // opened, for all given units. 680 func (u *UniterAPIV3) OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 681 result := params.ErrorResults{ 682 Results: make([]params.ErrorResult, len(args.Entities)), 683 } 684 canAccess, err := u.accessUnit() 685 if err != nil { 686 return params.ErrorResults{}, err 687 } 688 for i, entity := range args.Entities { 689 tag, err := names.ParseUnitTag(entity.Tag) 690 if err != nil { 691 result.Results[i].Error = common.ServerError(common.ErrPerm) 692 continue 693 } 694 err = common.ErrPerm 695 if canAccess(tag) { 696 var unit *state.Unit 697 unit, err = u.getUnit(tag) 698 if err == nil { 699 err = unit.OpenPorts(entity.Protocol, entity.FromPort, entity.ToPort) 700 } 701 } 702 result.Results[i].Error = common.ServerError(err) 703 } 704 return result, nil 705 } 706 707 // ClosePorts sets the policy of the port range with protocol to be 708 // closed, for all given units. 709 func (u *UniterAPIV3) ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) { 710 result := params.ErrorResults{ 711 Results: make([]params.ErrorResult, len(args.Entities)), 712 } 713 canAccess, err := u.accessUnit() 714 if err != nil { 715 return params.ErrorResults{}, err 716 } 717 for i, entity := range args.Entities { 718 tag, err := names.ParseUnitTag(entity.Tag) 719 if err != nil { 720 result.Results[i].Error = common.ServerError(common.ErrPerm) 721 continue 722 } 723 err = common.ErrPerm 724 if canAccess(tag) { 725 var unit *state.Unit 726 unit, err = u.getUnit(tag) 727 if err == nil { 728 err = unit.ClosePorts(entity.Protocol, entity.FromPort, entity.ToPort) 729 } 730 } 731 result.Results[i].Error = common.ServerError(err) 732 } 733 return result, nil 734 } 735 736 // WatchConfigSettings returns a NotifyWatcher for observing changes 737 // to each unit's service configuration settings. See also 738 // state/watcher.go:Unit.WatchConfigSettings(). 739 func (u *UniterAPIV3) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) { 740 result := params.NotifyWatchResults{ 741 Results: make([]params.NotifyWatchResult, len(args.Entities)), 742 } 743 canAccess, err := u.accessUnit() 744 if err != nil { 745 return params.NotifyWatchResults{}, err 746 } 747 for i, entity := range args.Entities { 748 tag, err := names.ParseUnitTag(entity.Tag) 749 if err != nil { 750 result.Results[i].Error = common.ServerError(common.ErrPerm) 751 continue 752 } 753 err = common.ErrPerm 754 watcherId := "" 755 if canAccess(tag) { 756 watcherId, err = u.watchOneUnitConfigSettings(tag) 757 } 758 result.Results[i].NotifyWatcherId = watcherId 759 result.Results[i].Error = common.ServerError(err) 760 } 761 return result, nil 762 } 763 764 // WatchActionNotifications returns a StringsWatcher for observing 765 // incoming action calls to a unit. See also state/watcher.go 766 // Unit.WatchActionNotifications(). This method is called from 767 // api/uniter/uniter.go WatchActionNotifications(). 768 func (u *UniterAPIV3) WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) { 769 tagToActionReceiver := common.TagToActionReceiverFn(u.st.FindEntity) 770 watchOne := common.WatchOneActionReceiverNotifications(tagToActionReceiver, u.resources.Register) 771 canAccess, err := u.accessUnit() 772 if err != nil { 773 return params.StringsWatchResults{}, err 774 } 775 return common.WatchActionNotifications(args, canAccess, watchOne), nil 776 } 777 778 // ConfigSettings returns the complete set of service charm config 779 // settings available to each given unit. 780 func (u *UniterAPIV3) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) { 781 result := params.ConfigSettingsResults{ 782 Results: make([]params.ConfigSettingsResult, len(args.Entities)), 783 } 784 canAccess, err := u.accessUnit() 785 if err != nil { 786 return params.ConfigSettingsResults{}, err 787 } 788 for i, entity := range args.Entities { 789 tag, err := names.ParseUnitTag(entity.Tag) 790 if err != nil { 791 result.Results[i].Error = common.ServerError(common.ErrPerm) 792 continue 793 } 794 err = common.ErrPerm 795 if canAccess(tag) { 796 var unit *state.Unit 797 unit, err = u.getUnit(tag) 798 if err == nil { 799 var settings charm.Settings 800 settings, err = unit.ConfigSettings() 801 if err == nil { 802 result.Results[i].Settings = params.ConfigSettings(settings) 803 } 804 } 805 } 806 result.Results[i].Error = common.ServerError(err) 807 } 808 return result, nil 809 } 810 811 // WatchServiceRelations returns a StringsWatcher, for each given 812 // service, that notifies of changes to the lifecycles of relations 813 // involving that service. 814 func (u *UniterAPIV3) WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) { 815 result := params.StringsWatchResults{ 816 Results: make([]params.StringsWatchResult, len(args.Entities)), 817 } 818 canAccess, err := u.accessService() 819 if err != nil { 820 return params.StringsWatchResults{}, err 821 } 822 for i, entity := range args.Entities { 823 tag, err := names.ParseServiceTag(entity.Tag) 824 if err != nil { 825 result.Results[i].Error = common.ServerError(common.ErrPerm) 826 continue 827 } 828 err = common.ErrPerm 829 if canAccess(tag) { 830 result.Results[i], err = u.watchOneServiceRelations(tag) 831 } 832 result.Results[i].Error = common.ServerError(err) 833 } 834 return result, nil 835 } 836 837 // CharmArchiveSha256 returns the SHA256 digest of the charm archive 838 // (bundle) data for each charm url in the given parameters. 839 func (u *UniterAPIV3) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) { 840 result := params.StringResults{ 841 Results: make([]params.StringResult, len(args.URLs)), 842 } 843 for i, arg := range args.URLs { 844 curl, err := charm.ParseURL(arg.URL) 845 if err != nil { 846 err = common.ErrPerm 847 } else { 848 var sch *state.Charm 849 sch, err = u.st.Charm(curl) 850 if errors.IsNotFound(err) { 851 err = common.ErrPerm 852 } 853 if err == nil { 854 result.Results[i].Result = sch.BundleSha256() 855 } 856 } 857 result.Results[i].Error = common.ServerError(err) 858 } 859 return result, nil 860 } 861 862 // CharmArchiveURLs returns the URLS for the charm archive 863 // (bundle) data for each charm url in the given parameters. 864 func (u *UniterAPIV3) CharmArchiveURLs(args params.CharmURLs) (params.StringsResults, error) { 865 apiHostPorts, err := u.st.APIHostPorts() 866 if err != nil { 867 return params.StringsResults{}, err 868 } 869 modelUUID := u.st.ModelUUID() 870 result := params.StringsResults{ 871 Results: make([]params.StringsResult, len(args.URLs)), 872 } 873 for i, curl := range args.URLs { 874 if _, err := charm.ParseURL(curl.URL); err != nil { 875 result.Results[i].Error = common.ServerError(common.ErrPerm) 876 continue 877 } 878 urlPath := "/" 879 if modelUUID != "" { 880 urlPath = path.Join(urlPath, "model", modelUUID) 881 } 882 urlPath = path.Join(urlPath, "charms") 883 archiveURLs := make([]string, len(apiHostPorts)) 884 for j, server := range apiHostPorts { 885 archiveURL := &url.URL{ 886 Scheme: "https", 887 Host: network.SelectInternalHostPort(server, false), 888 Path: urlPath, 889 } 890 q := archiveURL.Query() 891 q.Set("url", curl.URL) 892 q.Set("file", "*") 893 archiveURL.RawQuery = q.Encode() 894 archiveURLs[j] = archiveURL.String() 895 } 896 result.Results[i].Result = archiveURLs 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.ServiceTag) (*state.Service, error) { 1247 return u.st.Service(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.ServiceName()) 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 ServiceName: ep.ServiceName, 1321 Relation: 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.ServiceTag) (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.UnitService(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 *common.Resources, 1479 auth common.Authorizer, 1480 ) *leadershipapiserver.LeadershipSettingsAccessor { 1481 registerWatcher := func(serviceId string) (string, error) { 1482 service, err := st.Service(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.Service(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.Service(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.Service() 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 && !network.IsNoAddress(err) { 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 service %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 err != nil { 1658 return nil, errors.Annotatef(err, "cannot get subnet for address %q", addr) 1659 } 1660 if subnet == nil { 1661 logger.Debugf("skipping %s: not linked to a known subnet", addr) 1662 continue 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 }