github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/api/uniter/unit.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 "gopkg.in/juju/charm.v4" 12 13 "github.com/juju/juju/api/common" 14 "github.com/juju/juju/api/watcher" 15 "github.com/juju/juju/apiserver/params" 16 ) 17 18 // Unit represents a juju unit as seen by a uniter worker. 19 type Unit struct { 20 st *State 21 tag names.UnitTag 22 life params.Life 23 } 24 25 // Tag returns the unit's tag. 26 func (u *Unit) Tag() names.UnitTag { 27 return u.tag 28 } 29 30 // Name returns the name of the unit. 31 func (u *Unit) Name() string { 32 return u.tag.Id() 33 } 34 35 // String returns the unit as a string. 36 func (u *Unit) String() string { 37 return u.Name() 38 } 39 40 // Life returns the unit's lifecycle value. 41 func (u *Unit) Life() params.Life { 42 return u.life 43 } 44 45 // Refresh updates the cached local copy of the unit's data. 46 func (u *Unit) Refresh() error { 47 life, err := u.st.life(u.tag) 48 if err != nil { 49 return err 50 } 51 u.life = life 52 return nil 53 } 54 55 // SetStatus sets the status of the unit agent. 56 func (u *Unit) SetStatus(status params.Status, info string, data map[string]interface{}) error { 57 var result params.ErrorResults 58 args := params.SetStatus{ 59 Entities: []params.EntityStatus{ 60 {Tag: u.tag.String(), Status: status, Info: info, Data: data}, 61 }, 62 } 63 err := u.st.facade.FacadeCall("SetStatus", args, &result) 64 if err != nil { 65 return err 66 } 67 return result.OneError() 68 } 69 70 // AddMetrics adds the metrics for the unit. 71 func (u *Unit) AddMetrics(metrics []params.Metric) error { 72 var result params.ErrorResults 73 args := params.MetricsParams{ 74 Metrics: []params.MetricsParam{{ 75 Tag: u.tag.String(), 76 Metrics: metrics, 77 }}, 78 } 79 err := u.st.facade.FacadeCall("AddMetrics", args, &result) 80 if err != nil { 81 return errors.Annotate(err, "unable to add metric") 82 } 83 return result.OneError() 84 } 85 86 // EnsureDead sets the unit lifecycle to Dead if it is Alive or 87 // Dying. It does nothing otherwise. 88 func (u *Unit) EnsureDead() error { 89 var result params.ErrorResults 90 args := params.Entities{ 91 Entities: []params.Entity{{Tag: u.tag.String()}}, 92 } 93 err := u.st.facade.FacadeCall("EnsureDead", args, &result) 94 if err != nil { 95 return err 96 } 97 return result.OneError() 98 } 99 100 // Watch returns a watcher for observing changes to the unit. 101 func (u *Unit) Watch() (watcher.NotifyWatcher, error) { 102 return common.Watch(u.st.facade, u.tag) 103 } 104 105 // Service returns the service. 106 func (u *Unit) Service() (*Service, error) { 107 service := &Service{ 108 st: u.st, 109 tag: u.ServiceTag(), 110 } 111 // Call Refresh() immediately to get the up-to-date 112 // life and other needed locally cached fields. 113 err := service.Refresh() 114 if err != nil { 115 return nil, err 116 } 117 return service, nil 118 } 119 120 // ConfigSettings returns the complete set of service charm config settings 121 // available to the unit. Unset values will be replaced with the default 122 // value for the associated option, and may thus be nil when no default is 123 // specified. 124 func (u *Unit) ConfigSettings() (charm.Settings, error) { 125 var results params.ConfigSettingsResults 126 args := params.Entities{ 127 Entities: []params.Entity{{Tag: u.tag.String()}}, 128 } 129 err := u.st.facade.FacadeCall("ConfigSettings", args, &results) 130 if err != nil { 131 return nil, err 132 } 133 if len(results.Results) != 1 { 134 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 135 } 136 result := results.Results[0] 137 if result.Error != nil { 138 return nil, result.Error 139 } 140 return charm.Settings(result.Settings), nil 141 } 142 143 // ServiceName returns the service name. 144 func (u *Unit) ServiceName() string { 145 service, err := names.UnitService(u.Name()) 146 if err != nil { 147 panic(err) 148 } 149 return service 150 } 151 152 // ServiceTag returns the service tag. 153 func (u *Unit) ServiceTag() names.ServiceTag { 154 return names.NewServiceTag(u.ServiceName()) 155 } 156 157 // Destroy, when called on a Alive unit, advances its lifecycle as far as 158 // possible; it otherwise has no effect. In most situations, the unit's 159 // life is just set to Dying; but if a principal unit that is not assigned 160 // to a provisioned machine is Destroyed, it will be removed from state 161 // directly. 162 func (u *Unit) Destroy() error { 163 var result params.ErrorResults 164 args := params.Entities{ 165 Entities: []params.Entity{{Tag: u.tag.String()}}, 166 } 167 err := u.st.facade.FacadeCall("Destroy", args, &result) 168 if err != nil { 169 return err 170 } 171 return result.OneError() 172 } 173 174 // DestroyAllSubordinates destroys all subordinates of the unit. 175 func (u *Unit) DestroyAllSubordinates() error { 176 var result params.ErrorResults 177 args := params.Entities{ 178 Entities: []params.Entity{{Tag: u.tag.String()}}, 179 } 180 err := u.st.facade.FacadeCall("DestroyAllSubordinates", args, &result) 181 if err != nil { 182 return err 183 } 184 return result.OneError() 185 } 186 187 // Resolved returns the resolved mode for the unit. 188 // 189 // NOTE: This differs from state.Unit.Resolved() by returning an 190 // error as well, because it needs to make an API call 191 func (u *Unit) Resolved() (params.ResolvedMode, error) { 192 var results params.ResolvedModeResults 193 args := params.Entities{ 194 Entities: []params.Entity{{Tag: u.tag.String()}}, 195 } 196 err := u.st.facade.FacadeCall("Resolved", args, &results) 197 if err != nil { 198 return "", err 199 } 200 if len(results.Results) != 1 { 201 return "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 202 } 203 result := results.Results[0] 204 if result.Error != nil { 205 return "", result.Error 206 } 207 return result.Mode, nil 208 } 209 210 // AssignedMachine returns the unit's assigned machine tag or an error 211 // satisfying params.IsCodeNotAssigned when the unit has no assigned 212 // machine.. 213 func (u *Unit) AssignedMachine() (names.MachineTag, error) { 214 if u.st.BestAPIVersion() < 1 { 215 return names.MachineTag{}, errors.NotImplementedf("unit.AssignedMachine() (need V1+)") 216 } 217 var invalidTag names.MachineTag 218 var results params.StringResults 219 args := params.Entities{ 220 Entities: []params.Entity{{Tag: u.tag.String()}}, 221 } 222 err := u.st.facade.FacadeCall("AssignedMachine", args, &results) 223 if err != nil { 224 return invalidTag, err 225 } 226 if len(results.Results) != 1 { 227 return invalidTag, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 228 } 229 result := results.Results[0] 230 if result.Error != nil { 231 return invalidTag, result.Error 232 } 233 return names.ParseMachineTag(result.Result) 234 } 235 236 // IsPrincipal returns whether the unit is deployed in its own container, 237 // and can therefore have subordinate services deployed alongside it. 238 // 239 // NOTE: This differs from state.Unit.IsPrincipal() by returning an 240 // error as well, because it needs to make an API call. 241 func (u *Unit) IsPrincipal() (bool, error) { 242 var results params.StringBoolResults 243 args := params.Entities{ 244 Entities: []params.Entity{{Tag: u.tag.String()}}, 245 } 246 err := u.st.facade.FacadeCall("GetPrincipal", args, &results) 247 if err != nil { 248 return false, err 249 } 250 if len(results.Results) != 1 { 251 return false, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 252 } 253 result := results.Results[0] 254 if result.Error != nil { 255 return false, result.Error 256 } 257 // GetPrincipal returns false when the unit is subordinate. 258 return !result.Ok, nil 259 } 260 261 // HasSubordinates returns the tags of any subordinate units. 262 func (u *Unit) HasSubordinates() (bool, error) { 263 var results params.BoolResults 264 args := params.Entities{ 265 Entities: []params.Entity{{Tag: u.tag.String()}}, 266 } 267 err := u.st.facade.FacadeCall("HasSubordinates", args, &results) 268 if err != nil { 269 return false, err 270 } 271 if len(results.Results) != 1 { 272 return false, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 273 } 274 result := results.Results[0] 275 if result.Error != nil { 276 return false, result.Error 277 } 278 return result.Result, nil 279 } 280 281 // PublicAddress returns the public address of the unit and whether it 282 // is valid. 283 // 284 // NOTE: This differs from state.Unit.PublicAddres() by returning 285 // an error instead of a bool, because it needs to make an API call. 286 // 287 // TODO(dimitern): We might be able to drop this, once we have machine 288 // addresses implemented fully. See also LP bug 1221798. 289 func (u *Unit) PublicAddress() (string, error) { 290 var results params.StringResults 291 args := params.Entities{ 292 Entities: []params.Entity{{Tag: u.tag.String()}}, 293 } 294 err := u.st.facade.FacadeCall("PublicAddress", args, &results) 295 if err != nil { 296 return "", err 297 } 298 if len(results.Results) != 1 { 299 return "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 300 } 301 result := results.Results[0] 302 if result.Error != nil { 303 return "", result.Error 304 } 305 return result.Result, nil 306 } 307 308 // PrivateAddress returns the private address of the unit and whether 309 // it is valid. 310 // 311 // NOTE: This differs from state.Unit.PrivateAddress() by returning 312 // an error instead of a bool, because it needs to make an API call. 313 // 314 // TODO(dimitern): We might be able to drop this, once we have machine 315 // addresses implemented fully. See also LP bug 1221798. 316 func (u *Unit) PrivateAddress() (string, error) { 317 var results params.StringResults 318 args := params.Entities{ 319 Entities: []params.Entity{{Tag: u.tag.String()}}, 320 } 321 err := u.st.facade.FacadeCall("PrivateAddress", args, &results) 322 if err != nil { 323 return "", err 324 } 325 if len(results.Results) != 1 { 326 return "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 327 } 328 result := results.Results[0] 329 if result.Error != nil { 330 return "", result.Error 331 } 332 return result.Result, nil 333 } 334 335 // AvailabilityZone returns the availability zone of the unit. 336 func (u *Unit) AvailabilityZone() (string, error) { 337 var results params.StringResults 338 args := params.Entities{ 339 Entities: []params.Entity{{Tag: u.tag.String()}}, 340 } 341 if err := u.st.facade.FacadeCall("AvailabilityZone", args, &results); err != nil { 342 return "", errors.Trace(err) 343 } 344 if len(results.Results) != 1 { 345 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 346 } 347 result := results.Results[0] 348 if result.Error != nil { 349 return "", errors.Trace(result.Error) 350 } 351 return result.Result, nil 352 } 353 354 // OpenPorts sets the policy of the port range with protocol to be 355 // opened. 356 func (u *Unit) OpenPorts(protocol string, fromPort, toPort int) error { 357 var result params.ErrorResults 358 args := params.EntitiesPortRanges{ 359 Entities: []params.EntityPortRange{{ 360 Tag: u.tag.String(), 361 Protocol: protocol, 362 FromPort: fromPort, 363 ToPort: toPort, 364 }}, 365 } 366 err := u.st.facade.FacadeCall("OpenPorts", args, &result) 367 if err != nil { 368 return err 369 } 370 return result.OneError() 371 } 372 373 // ClosePorts sets the policy of the port range with protocol to be 374 // closed. 375 func (u *Unit) ClosePorts(protocol string, fromPort, toPort int) error { 376 var result params.ErrorResults 377 args := params.EntitiesPortRanges{ 378 Entities: []params.EntityPortRange{{ 379 Tag: u.tag.String(), 380 Protocol: protocol, 381 FromPort: fromPort, 382 ToPort: toPort, 383 }}, 384 } 385 err := u.st.facade.FacadeCall("ClosePorts", args, &result) 386 if err != nil { 387 return err 388 } 389 return result.OneError() 390 } 391 392 // OpenPort sets the policy of the port with protocol and number to be 393 // opened. 394 // 395 // TODO(dimitern): This is deprecated and is kept for 396 // backwards-compatibility. Use OpenPorts instead. 397 func (u *Unit) OpenPort(protocol string, number int) error { 398 var result params.ErrorResults 399 args := params.EntitiesPorts{ 400 Entities: []params.EntityPort{ 401 {Tag: u.tag.String(), Protocol: protocol, Port: number}, 402 }, 403 } 404 err := u.st.facade.FacadeCall("OpenPort", args, &result) 405 if err != nil { 406 return err 407 } 408 return result.OneError() 409 } 410 411 // ClosePort sets the policy of the port with protocol and number to 412 // be closed. 413 // 414 // TODO(dimitern): This is deprecated and is kept for 415 // backwards-compatibility. Use ClosePorts instead. 416 func (u *Unit) ClosePort(protocol string, number int) error { 417 var result params.ErrorResults 418 args := params.EntitiesPorts{ 419 Entities: []params.EntityPort{ 420 {Tag: u.tag.String(), Protocol: protocol, Port: number}, 421 }, 422 } 423 err := u.st.facade.FacadeCall("ClosePort", args, &result) 424 if err != nil { 425 return err 426 } 427 return result.OneError() 428 } 429 430 var ErrNoCharmURLSet = errors.New("unit has no charm url set") 431 432 // CharmURL returns the charm URL this unit is currently using. 433 // 434 // NOTE: This differs from state.Unit.CharmURL() by returning 435 // an error instead of a bool, because it needs to make an API call. 436 func (u *Unit) CharmURL() (*charm.URL, error) { 437 var results params.StringBoolResults 438 args := params.Entities{ 439 Entities: []params.Entity{{Tag: u.tag.String()}}, 440 } 441 err := u.st.facade.FacadeCall("CharmURL", args, &results) 442 if err != nil { 443 return nil, err 444 } 445 if len(results.Results) != 1 { 446 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 447 } 448 result := results.Results[0] 449 if result.Error != nil { 450 return nil, result.Error 451 } 452 if result.Result != "" { 453 curl, err := charm.ParseURL(result.Result) 454 if err != nil { 455 return nil, err 456 } 457 return curl, nil 458 } 459 return nil, ErrNoCharmURLSet 460 } 461 462 // SetCharmURL marks the unit as currently using the supplied charm URL. 463 // An error will be returned if the unit is dead, or the charm URL not known. 464 func (u *Unit) SetCharmURL(curl *charm.URL) error { 465 if curl == nil { 466 return fmt.Errorf("charm URL cannot be nil") 467 } 468 var result params.ErrorResults 469 args := params.EntitiesCharmURL{ 470 Entities: []params.EntityCharmURL{ 471 {Tag: u.tag.String(), CharmURL: curl.String()}, 472 }, 473 } 474 err := u.st.facade.FacadeCall("SetCharmURL", args, &result) 475 if err != nil { 476 return err 477 } 478 return result.OneError() 479 } 480 481 // ClearResolved removes any resolved setting on the unit. 482 func (u *Unit) ClearResolved() error { 483 var result params.ErrorResults 484 args := params.Entities{ 485 Entities: []params.Entity{{Tag: u.tag.String()}}, 486 } 487 err := u.st.facade.FacadeCall("ClearResolved", args, &result) 488 if err != nil { 489 return err 490 } 491 return result.OneError() 492 } 493 494 // WatchConfigSettings returns a watcher for observing changes to the 495 // unit's service configuration settings. The unit must have a charm URL 496 // set before this method is called, and the returned watcher will be 497 // valid only while the unit's charm URL is not changed. 498 func (u *Unit) WatchConfigSettings() (watcher.NotifyWatcher, error) { 499 var results params.NotifyWatchResults 500 args := params.Entities{ 501 Entities: []params.Entity{{Tag: u.tag.String()}}, 502 } 503 err := u.st.facade.FacadeCall("WatchConfigSettings", args, &results) 504 if err != nil { 505 return nil, err 506 } 507 if len(results.Results) != 1 { 508 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 509 } 510 result := results.Results[0] 511 if result.Error != nil { 512 return nil, result.Error 513 } 514 w := watcher.NewNotifyWatcher(u.st.facade.RawAPICaller(), result) 515 return w, nil 516 } 517 518 // WatchAddresses returns a watcher for observing changes to the 519 // unit's addresses. The unit must be assigned to a machine before 520 // this method is called, and the returned watcher will be valid only 521 // while the unit's assigned machine is not changed. 522 func (u *Unit) WatchAddresses() (watcher.NotifyWatcher, error) { 523 var results params.NotifyWatchResults 524 args := params.Entities{ 525 Entities: []params.Entity{{Tag: u.tag.String()}}, 526 } 527 err := u.st.facade.FacadeCall("WatchUnitAddresses", args, &results) 528 if err != nil { 529 return nil, err 530 } 531 if len(results.Results) != 1 { 532 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 533 } 534 result := results.Results[0] 535 if result.Error != nil { 536 return nil, result.Error 537 } 538 w := watcher.NewNotifyWatcher(u.st.facade.RawAPICaller(), result) 539 return w, nil 540 } 541 542 // WatchActionNotifications returns a StringsWatcher for observing the 543 // ids of Actions added to the Unit. The initial event will contain the 544 // ids of any Actions pending at the time the Watcher is made. 545 func (u *Unit) WatchActionNotifications() (watcher.StringsWatcher, error) { 546 var results params.StringsWatchResults 547 args := params.Entities{ 548 Entities: []params.Entity{{Tag: u.tag.String()}}, 549 } 550 err := u.st.facade.FacadeCall("WatchActionNotifications", args, &results) 551 if err != nil { 552 return nil, err 553 } 554 if len(results.Results) != 1 { 555 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 556 } 557 result := results.Results[0] 558 if result.Error != nil { 559 return nil, result.Error 560 } 561 w := watcher.NewStringsWatcher(u.st.facade.RawAPICaller(), result) 562 return w, nil 563 } 564 565 // RequestReboot sets the reboot flag for its machine agent 566 func (u *Unit) RequestReboot() error { 567 machineId, err := u.AssignedMachine() 568 if err != nil { 569 return err 570 } 571 var result params.ErrorResults 572 args := params.Entities{ 573 Entities: []params.Entity{{Tag: machineId.String()}}, 574 } 575 err = u.st.facade.FacadeCall("RequestReboot", args, &result) 576 if err != nil { 577 return err 578 } 579 return result.OneError() 580 } 581 582 // JoinedRelations returns the tags of the relations the unit has joined. 583 func (u *Unit) JoinedRelations() ([]names.RelationTag, error) { 584 var results params.StringsResults 585 args := params.Entities{ 586 Entities: []params.Entity{{Tag: u.tag.String()}}, 587 } 588 err := u.st.facade.FacadeCall("JoinedRelations", args, &results) 589 if err != nil { 590 return nil, err 591 } 592 if len(results.Results) != 1 { 593 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 594 } 595 result := results.Results[0] 596 if result.Error != nil { 597 return nil, result.Error 598 } 599 var relTags []names.RelationTag 600 for _, rel := range result.Result { 601 tag, err := names.ParseRelationTag(rel) 602 if err != nil { 603 return nil, err 604 } 605 relTags = append(relTags, tag) 606 } 607 return relTags, nil 608 } 609 610 // MeterStatus returns the meter status of the unit. 611 func (u *Unit) MeterStatus() (statusCode, statusInfo string, rErr error) { 612 var results params.MeterStatusResults 613 args := params.Entities{ 614 Entities: []params.Entity{{Tag: u.tag.String()}}, 615 } 616 err := u.st.facade.FacadeCall("GetMeterStatus", args, &results) 617 if err != nil { 618 return "", "", errors.Trace(err) 619 } 620 if len(results.Results) != 1 { 621 return "", "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 622 } 623 result := results.Results[0] 624 if result.Error != nil { 625 return "", "", errors.Trace(result.Error) 626 } 627 return result.Code, result.Info, nil 628 } 629 630 // WatchMeterStatus returns a watcher for observing changes to the 631 // unit's meter status. 632 func (u *Unit) WatchMeterStatus() (watcher.NotifyWatcher, error) { 633 var results params.NotifyWatchResults 634 args := params.Entities{ 635 Entities: []params.Entity{{Tag: u.tag.String()}}, 636 } 637 err := u.st.facade.FacadeCall("WatchMeterStatus", args, &results) 638 if err != nil { 639 return nil, err 640 } 641 if len(results.Results) != 1 { 642 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 643 } 644 result := results.Results[0] 645 if result.Error != nil { 646 return nil, result.Error 647 } 648 w := watcher.NewNotifyWatcher(u.st.facade.RawAPICaller(), result) 649 return w, nil 650 }