github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/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 "time" 8 9 "github.com/juju/charm/v12" 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 13 "github.com/juju/juju/api/common" 14 apiwatcher "github.com/juju/juju/api/watcher" 15 apiservererrors "github.com/juju/juju/apiserver/errors" 16 "github.com/juju/juju/core/life" 17 "github.com/juju/juju/core/model" 18 "github.com/juju/juju/core/network" 19 "github.com/juju/juju/core/secrets" 20 "github.com/juju/juju/core/status" 21 "github.com/juju/juju/core/watcher" 22 "github.com/juju/juju/rpc/params" 23 ) 24 25 // Unit represents a juju unit as seen by a uniter worker. 26 type Unit struct { 27 st *State 28 tag names.UnitTag 29 life life.Value 30 resolvedMode params.ResolvedMode 31 providerID string 32 } 33 34 // Tag returns the unit's tag. 35 func (u *Unit) Tag() names.UnitTag { 36 return u.tag 37 } 38 39 // ProviderID returns the provider Id of the unit. 40 func (u *Unit) ProviderID() string { 41 return u.providerID 42 } 43 44 // Name returns the name of the unit. 45 func (u *Unit) Name() string { 46 return u.tag.Id() 47 } 48 49 // String returns the unit as a string. 50 func (u *Unit) String() string { 51 return u.Name() 52 } 53 54 // Life returns the unit's lifecycle value. 55 func (u *Unit) Life() life.Value { 56 return u.life 57 } 58 59 // Resolved returns the unit's resolved mode value. 60 func (u *Unit) Resolved() params.ResolvedMode { 61 return u.resolvedMode 62 } 63 64 // Refresh updates the cached local copy of the unit's data. 65 func (u *Unit) Refresh() error { 66 var results params.UnitRefreshResults 67 args := params.Entities{ 68 Entities: []params.Entity{ 69 {Tag: u.tag.String()}, 70 }, 71 } 72 err := u.st.facade.FacadeCall("Refresh", args, &results) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 if len(results.Results) != 1 { 77 return errors.Errorf("expected 1 result, got %d", len(results.Results)) 78 } 79 result := results.Results[0] 80 if result.Error != nil { 81 // We should be able to use apiserver.common.RestoreError here, 82 // but because of poor design, it causes import errors. 83 if params.IsCodeNotFound(result.Error) { 84 return errors.NewNotFound(result.Error, "") 85 } 86 return errors.Trace(result.Error) 87 } 88 89 u.life = result.Life 90 u.resolvedMode = result.Resolved 91 u.providerID = result.ProviderID 92 return nil 93 } 94 95 // SetUnitStatus sets the status of the unit. 96 func (u *Unit) SetUnitStatus(unitStatus status.Status, info string, data map[string]interface{}) error { 97 var result params.ErrorResults 98 args := params.SetStatus{ 99 Entities: []params.EntityStatusArgs{ 100 {Tag: u.tag.String(), Status: unitStatus.String(), Info: info, Data: data}, 101 }, 102 } 103 err := u.st.facade.FacadeCall("SetUnitStatus", args, &result) 104 if err != nil { 105 return errors.Trace(err) 106 } 107 return result.OneError() 108 } 109 110 // UnitStatus gets the status details of the unit. 111 func (u *Unit) UnitStatus() (params.StatusResult, error) { 112 var results params.StatusResults 113 args := params.Entities{ 114 Entities: []params.Entity{ 115 {Tag: u.tag.String()}, 116 }, 117 } 118 err := u.st.facade.FacadeCall("UnitStatus", args, &results) 119 if err != nil { 120 return params.StatusResult{}, errors.Trace(err) 121 } 122 if len(results.Results) != 1 { 123 return params.StatusResult{}, errors.Errorf("expected 1 result, got %d", len(results.Results)) 124 } 125 result := results.Results[0] 126 if result.Error != nil { 127 return params.StatusResult{}, result.Error 128 } 129 return result, nil 130 } 131 132 // SetAgentStatus sets the status of the unit agent. 133 func (u *Unit) SetAgentStatus(agentStatus status.Status, info string, data map[string]interface{}) error { 134 var result params.ErrorResults 135 args := params.SetStatus{ 136 Entities: []params.EntityStatusArgs{ 137 {Tag: u.tag.String(), Status: agentStatus.String(), Info: info, Data: data}, 138 }, 139 } 140 err := u.st.facade.FacadeCall("SetAgentStatus", args, &result) 141 if err != nil { 142 return err 143 } 144 return result.OneError() 145 } 146 147 // AddMetrics adds the metrics for the unit. 148 func (u *Unit) AddMetrics(metrics []params.Metric) error { 149 var result params.ErrorResults 150 args := params.MetricsParams{ 151 Metrics: []params.MetricsParam{{ 152 Tag: u.tag.String(), 153 Metrics: metrics, 154 }}, 155 } 156 err := u.st.facade.FacadeCall("AddMetrics", args, &result) 157 if err != nil { 158 return errors.Annotate(err, "unable to add metric") 159 } 160 return result.OneError() 161 } 162 163 // AddMetricBatches makes an api call to the uniter requesting it to store metrics batches in state. 164 func (u *Unit) AddMetricBatches(batches []params.MetricBatch) (map[string]error, error) { 165 p := params.MetricBatchParams{ 166 Batches: make([]params.MetricBatchParam, len(batches)), 167 } 168 169 batchResults := make(map[string]error, len(batches)) 170 171 for i, batch := range batches { 172 p.Batches[i].Tag = u.tag.String() 173 p.Batches[i].Batch = batch 174 175 batchResults[batch.UUID] = nil 176 } 177 results := new(params.ErrorResults) 178 err := u.st.facade.FacadeCall("AddMetricBatches", p, results) 179 if err != nil { 180 return nil, errors.Annotate(err, "failed to send metric batches") 181 } 182 for i, result := range results.Results { 183 batchResults[batches[i].UUID] = result.Error 184 } 185 return batchResults, nil 186 } 187 188 // EnsureDead sets the unit lifecycle to Dead if it is Alive or 189 // Dying. It does nothing otherwise. 190 func (u *Unit) EnsureDead() error { 191 var result params.ErrorResults 192 args := params.Entities{ 193 Entities: []params.Entity{{Tag: u.tag.String()}}, 194 } 195 err := u.st.facade.FacadeCall("EnsureDead", args, &result) 196 if err != nil { 197 return err 198 } 199 return result.OneError() 200 } 201 202 // Watch returns a watcher for observing changes to the unit. 203 func (u *Unit) Watch() (watcher.NotifyWatcher, error) { 204 return common.Watch(u.st.facade, "Watch", u.tag) 205 } 206 207 // WatchRelations returns a StringsWatcher that notifies of changes to 208 // the lifecycles of relations involving u. 209 func (u *Unit) WatchRelations() (watcher.StringsWatcher, error) { 210 var results params.StringsWatchResults 211 args := params.Entities{ 212 Entities: []params.Entity{{Tag: u.tag.String()}}, 213 } 214 err := u.st.facade.FacadeCall("WatchUnitRelations", args, &results) 215 if err != nil { 216 return nil, err 217 } 218 if len(results.Results) != 1 { 219 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 220 } 221 result := results.Results[0] 222 if result.Error != nil { 223 return nil, result.Error 224 } 225 w := apiwatcher.NewStringsWatcher(u.st.facade.RawAPICaller(), result) 226 return w, nil 227 } 228 229 // Application returns the unit's application. 230 func (u *Unit) Application() (*Application, error) { 231 application := &Application{ 232 st: u.st, 233 tag: u.ApplicationTag(), 234 } 235 // Call Refresh() immediately to get the up-to-date 236 // life and other needed locally cached fields. 237 err := application.Refresh() 238 if err != nil { 239 return nil, err 240 } 241 return application, nil 242 } 243 244 // ConfigSettings returns the complete set of application charm config settings 245 // available to the unit. Unset values will be replaced with the default 246 // value for the associated option, and may thus be nil when no default is 247 // specified. 248 func (u *Unit) ConfigSettings() (charm.Settings, error) { 249 var results params.ConfigSettingsResults 250 args := params.Entities{ 251 Entities: []params.Entity{{Tag: u.tag.String()}}, 252 } 253 err := u.st.facade.FacadeCall("ConfigSettings", args, &results) 254 if err != nil { 255 return nil, err 256 } 257 if len(results.Results) != 1 { 258 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 259 } 260 result := results.Results[0] 261 if result.Error != nil { 262 return nil, result.Error 263 } 264 return charm.Settings(result.Settings), nil 265 } 266 267 // ApplicationName returns the application name. 268 func (u *Unit) ApplicationName() string { 269 application, err := names.UnitApplication(u.Name()) 270 if err != nil { 271 panic(err) 272 } 273 return application 274 } 275 276 // ApplicationTag returns the application tag. 277 func (u *Unit) ApplicationTag() names.ApplicationTag { 278 return names.NewApplicationTag(u.ApplicationName()) 279 } 280 281 // Destroy, when called on a Alive unit, advances its lifecycle as far as 282 // possible; it otherwise has no effect. In most situations, the unit's 283 // life is just set to Dying; but if a principal unit that is not assigned 284 // to a provisioned machine is Destroyed, it will be removed from state 285 // directly. 286 func (u *Unit) Destroy() error { 287 var result params.ErrorResults 288 args := params.Entities{ 289 Entities: []params.Entity{{Tag: u.tag.String()}}, 290 } 291 err := u.st.facade.FacadeCall("Destroy", args, &result) 292 if err != nil { 293 return err 294 } 295 return result.OneError() 296 } 297 298 // DestroyAllSubordinates destroys all subordinates of the unit. 299 func (u *Unit) DestroyAllSubordinates() error { 300 var result params.ErrorResults 301 args := params.Entities{ 302 Entities: []params.Entity{{Tag: u.tag.String()}}, 303 } 304 err := u.st.facade.FacadeCall("DestroyAllSubordinates", args, &result) 305 if err != nil { 306 return err 307 } 308 return result.OneError() 309 } 310 311 // AssignedMachine returns the unit's assigned machine tag or an error 312 // satisfying params.IsCodeNotAssigned when the unit has no assigned 313 // machine.. 314 func (u *Unit) AssignedMachine() (names.MachineTag, error) { 315 var invalidTag names.MachineTag 316 var results params.StringResults 317 args := params.Entities{ 318 Entities: []params.Entity{{Tag: u.tag.String()}}, 319 } 320 err := u.st.facade.FacadeCall("AssignedMachine", args, &results) 321 if err != nil { 322 return invalidTag, err 323 } 324 if len(results.Results) != 1 { 325 return invalidTag, errors.Errorf("expected 1 result, got %d", len(results.Results)) 326 } 327 result := results.Results[0] 328 if result.Error != nil { 329 return invalidTag, result.Error 330 } 331 return names.ParseMachineTag(result.Result) 332 } 333 334 // PrincipalName returns the principal unit name and true for subordinates. 335 // For principal units the function returns "" and false. 336 // 337 // NOTE: This differs from state.Unit.PrincipalName() by returning an 338 // error as well, because it needs to make an API call. 339 func (u *Unit) PrincipalName() (string, bool, error) { 340 var results params.StringBoolResults 341 args := params.Entities{ 342 Entities: []params.Entity{{Tag: u.tag.String()}}, 343 } 344 err := u.st.facade.FacadeCall("GetPrincipal", args, &results) 345 if err != nil { 346 return "", false, err 347 } 348 if len(results.Results) != 1 { 349 return "", false, errors.Errorf("expected 1 result, got %d", len(results.Results)) 350 } 351 result := results.Results[0] 352 if result.Error != nil { 353 return "", false, result.Error 354 } 355 var unitName string 356 if result.Ok { 357 unitTag, err := names.ParseUnitTag(result.Result) 358 if err != nil { 359 return "", false, err 360 } 361 unitName = unitTag.Id() 362 } 363 return unitName, result.Ok, nil 364 } 365 366 // HasSubordinates returns the tags of any subordinate units. 367 func (u *Unit) HasSubordinates() (bool, error) { 368 var results params.BoolResults 369 args := params.Entities{ 370 Entities: []params.Entity{{Tag: u.tag.String()}}, 371 } 372 err := u.st.facade.FacadeCall("HasSubordinates", args, &results) 373 if err != nil { 374 return false, err 375 } 376 if len(results.Results) != 1 { 377 return false, errors.Errorf("expected 1 result, got %d", len(results.Results)) 378 } 379 result := results.Results[0] 380 if result.Error != nil { 381 return false, result.Error 382 } 383 return result.Result, nil 384 } 385 386 // PublicAddress returns the public address of the unit and whether it 387 // is valid. 388 // 389 // NOTE: This differs from state.Unit.PublicAddres() by returning 390 // an error instead of a bool, because it needs to make an API call. 391 // 392 // TODO(dimitern): We might be able to drop this, once we have machine 393 // addresses implemented fully. See also LP bug 1221798. 394 func (u *Unit) PublicAddress() (string, error) { 395 var results params.StringResults 396 args := params.Entities{ 397 Entities: []params.Entity{{Tag: u.tag.String()}}, 398 } 399 err := u.st.facade.FacadeCall("PublicAddress", args, &results) 400 if err != nil { 401 return "", err 402 } 403 if len(results.Results) != 1 { 404 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 405 } 406 result := results.Results[0] 407 if result.Error != nil { 408 return "", result.Error 409 } 410 return result.Result, nil 411 } 412 413 // PrivateAddress returns the private address of the unit and whether 414 // it is valid. 415 // 416 // NOTE: This differs from state.Unit.PrivateAddress() by returning 417 // an error instead of a bool, because it needs to make an API call. 418 // 419 // TODO(dimitern): We might be able to drop this, once we have machine 420 // addresses implemented fully. See also LP bug 1221798. 421 func (u *Unit) PrivateAddress() (string, error) { 422 var results params.StringResults 423 args := params.Entities{ 424 Entities: []params.Entity{{Tag: u.tag.String()}}, 425 } 426 err := u.st.facade.FacadeCall("PrivateAddress", args, &results) 427 if err != nil { 428 return "", err 429 } 430 if len(results.Results) != 1 { 431 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 432 } 433 result := results.Results[0] 434 if result.Error != nil { 435 return "", result.Error 436 } 437 return result.Result, nil 438 } 439 440 // AvailabilityZone returns the availability zone of the unit. 441 func (u *Unit) AvailabilityZone() (string, error) { 442 var results params.StringResults 443 args := params.Entities{ 444 Entities: []params.Entity{{Tag: u.tag.String()}}, 445 } 446 if err := u.st.facade.FacadeCall("AvailabilityZone", args, &results); err != nil { 447 return "", errors.Trace(err) 448 } 449 if len(results.Results) != 1 { 450 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 451 } 452 result := results.Results[0] 453 if result.Error != nil { 454 return "", errors.Trace(result.Error) 455 } 456 return result.Result, nil 457 } 458 459 var ErrNoCharmURLSet = errors.New("unit has no charm url set") 460 461 // CharmURL returns the charm URL this unit is currently using. 462 func (u *Unit) CharmURL() (string, error) { 463 var results params.StringBoolResults 464 args := params.Entities{ 465 Entities: []params.Entity{{Tag: u.tag.String()}}, 466 } 467 err := u.st.facade.FacadeCall("CharmURL", args, &results) 468 if err != nil { 469 return "", err 470 } 471 if len(results.Results) != 1 { 472 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 473 } 474 result := results.Results[0] 475 if result.Error != nil { 476 return "", result.Error 477 } 478 if result.Result != "" { 479 return result.Result, nil 480 } 481 return "", ErrNoCharmURLSet 482 } 483 484 // SetCharmURL marks the unit as currently using the supplied charm URL. 485 // An error will be returned if the unit is dead, or the charm URL not known. 486 func (u *Unit) SetCharmURL(curl string) error { 487 if curl == "" { 488 return errors.Errorf("charm URL cannot be nil") 489 } 490 var result params.ErrorResults 491 args := params.EntitiesCharmURL{ 492 Entities: []params.EntityCharmURL{ 493 {Tag: u.tag.String(), CharmURL: curl}, 494 }, 495 } 496 err := u.st.facade.FacadeCall("SetCharmURL", args, &result) 497 if err != nil { 498 return err 499 } 500 return result.OneError() 501 } 502 503 // ClearResolved removes any resolved setting on the unit. 504 func (u *Unit) ClearResolved() error { 505 var result params.ErrorResults 506 args := params.Entities{ 507 Entities: []params.Entity{{Tag: u.tag.String()}}, 508 } 509 err := u.st.facade.FacadeCall("ClearResolved", args, &result) 510 if err != nil { 511 return err 512 } 513 return result.OneError() 514 } 515 516 // WatchConfigSettingsHash returns a watcher for observing changes to 517 // the unit's charm configuration settings (with a hash of the 518 // settings content so we can determine whether it has changed since 519 // it was last seen by the uniter). The unit must have a charm URL set 520 // before this method is called, and the returned watcher will be 521 // valid only while the unit's charm URL is not changed. 522 func (u *Unit) WatchConfigSettingsHash() (watcher.StringsWatcher, error) { 523 return getHashWatcher(u, "WatchConfigSettingsHash") 524 } 525 526 // WatchTrustConfigSettingsHash returns a watcher for observing changes to 527 // the unit's application configuration settings (with a hash of the 528 // settings content so we can determine whether it has changed since 529 // it was last seen by the uniter). 530 func (u *Unit) WatchTrustConfigSettingsHash() (watcher.StringsWatcher, error) { 531 return getHashWatcher(u, "WatchTrustConfigSettingsHash") 532 } 533 534 func getHashWatcher(u *Unit, methodName string) (watcher.StringsWatcher, error) { 535 var results params.StringsWatchResults 536 args := params.Entities{ 537 Entities: []params.Entity{{Tag: u.tag.String()}}, 538 } 539 err := u.st.facade.FacadeCall(methodName, args, &results) 540 if err != nil { 541 return nil, err 542 } 543 if len(results.Results) != 1 { 544 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 545 } 546 result := results.Results[0] 547 if result.Error != nil { 548 return nil, result.Error 549 } 550 w := apiwatcher.NewStringsWatcher(u.st.facade.RawAPICaller(), result) 551 return w, nil 552 } 553 554 // WatchAddressesHash returns a watcher for observing changes to the 555 // hash of the unit's addresses. 556 // For IAAS models, the unit must be assigned to a machine before 557 // this method is called, and the returned watcher will be valid 558 // only while the unit's assigned machine is not changed. 559 // For CAAS models, the watcher observes changes to the address 560 // of the pod associated with the unit. 561 func (u *Unit) WatchAddressesHash() (watcher.StringsWatcher, error) { 562 return getHashWatcher(u, "WatchUnitAddressesHash") 563 } 564 565 // WatchActionNotifications returns a StringsWatcher for observing the 566 // ids of Actions added to the Unit. The initial event will contain the 567 // ids of any Actions pending at the time the Watcher is made. 568 func (u *Unit) WatchActionNotifications() (watcher.StringsWatcher, error) { 569 var results params.StringsWatchResults 570 args := params.Entities{ 571 Entities: []params.Entity{{Tag: u.tag.String()}}, 572 } 573 err := u.st.facade.FacadeCall("WatchActionNotifications", args, &results) 574 if err != nil { 575 return nil, err 576 } 577 if len(results.Results) != 1 { 578 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 579 } 580 result := results.Results[0] 581 if result.Error != nil { 582 return nil, result.Error 583 } 584 w := apiwatcher.NewStringsWatcher(u.st.facade.RawAPICaller(), result) 585 return w, nil 586 } 587 588 // WatchUpgradeSeriesNotifications returns a NotifyWatcher for observing the 589 // state of a series upgrade. 590 func (u *Unit) WatchUpgradeSeriesNotifications() (watcher.NotifyWatcher, error) { 591 return u.st.WatchUpgradeSeriesNotifications() 592 } 593 594 // LogActionMessage logs a progress message for the specified action. 595 func (u *Unit) LogActionMessage(tag names.ActionTag, message string) error { 596 var result params.ErrorResults 597 args := params.ActionMessageParams{ 598 Messages: []params.EntityString{{Tag: tag.String(), Value: message}}, 599 } 600 err := u.st.facade.FacadeCall("LogActionsMessages", args, &result) 601 if err != nil { 602 return err 603 } 604 return result.OneError() 605 } 606 607 // UpgradeSeriesStatus returns the upgrade series status of a unit from remote state 608 func (u *Unit) UpgradeSeriesStatus() (model.UpgradeSeriesStatus, string, error) { 609 return u.st.UpgradeSeriesUnitStatus() 610 } 611 612 // SetUpgradeSeriesStatus sets the upgrade series status of the unit in the remote state 613 func (u *Unit) SetUpgradeSeriesStatus(status model.UpgradeSeriesStatus, reason string) error { 614 return u.st.SetUpgradeSeriesUnitStatus(status, reason) 615 } 616 617 // RequestReboot sets the reboot flag for its machine agent 618 func (u *Unit) RequestReboot() error { 619 machineId, err := u.AssignedMachine() 620 if err != nil { 621 return err 622 } 623 var result params.ErrorResults 624 args := params.Entities{ 625 Entities: []params.Entity{{Tag: machineId.String()}}, 626 } 627 err = u.st.facade.FacadeCall("RequestReboot", args, &result) 628 if err != nil { 629 return err 630 } 631 return result.OneError() 632 } 633 634 // RelationStatus holds information about a relation's scope and status. 635 type RelationStatus struct { 636 // Tag is the relation tag. 637 Tag names.RelationTag 638 639 // Suspended is true if the relation is suspended. 640 Suspended bool 641 642 // InScope is true if the relation unit is in scope. 643 InScope bool 644 } 645 646 // RelationsStatus returns the tags of the relations the unit has joined 647 // and entered scope, or the relation is suspended. 648 func (u *Unit) RelationsStatus() ([]RelationStatus, error) { 649 args := params.Entities{ 650 Entities: []params.Entity{{Tag: u.tag.String()}}, 651 } 652 var results params.RelationUnitStatusResults 653 err := u.st.facade.FacadeCall("RelationsStatus", args, &results) 654 if err != nil { 655 return nil, err 656 } 657 if len(results.Results) != 1 { 658 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 659 } 660 result := results.Results[0] 661 if result.Error != nil { 662 return nil, result.Error 663 } 664 var statusResult []RelationStatus 665 for _, result := range result.RelationResults { 666 tag, err := names.ParseRelationTag(result.RelationTag) 667 if err != nil { 668 return nil, err 669 } 670 statusResult = append(statusResult, RelationStatus{ 671 Tag: tag, 672 InScope: result.InScope, 673 Suspended: result.Suspended, 674 }) 675 } 676 return statusResult, nil 677 } 678 679 // MeterStatus returns the meter status of the unit. 680 func (u *Unit) MeterStatus() (statusCode, statusInfo string, rErr error) { 681 var results params.MeterStatusResults 682 args := params.Entities{ 683 Entities: []params.Entity{{Tag: u.tag.String()}}, 684 } 685 err := u.st.facade.FacadeCall("GetMeterStatus", args, &results) 686 if err != nil { 687 return "", "", errors.Trace(err) 688 } 689 if len(results.Results) != 1 { 690 return "", "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 691 } 692 result := results.Results[0] 693 if result.Error != nil { 694 return "", "", errors.Trace(result.Error) 695 } 696 return result.Code, result.Info, nil 697 } 698 699 // WatchMeterStatus returns a watcher for observing changes to the 700 // unit's meter status. 701 func (u *Unit) WatchMeterStatus() (watcher.NotifyWatcher, error) { 702 var results params.NotifyWatchResults 703 args := params.Entities{ 704 Entities: []params.Entity{{Tag: u.tag.String()}}, 705 } 706 err := u.st.facade.FacadeCall("WatchMeterStatus", args, &results) 707 if err != nil { 708 return nil, err 709 } 710 if len(results.Results) != 1 { 711 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 712 } 713 result := results.Results[0] 714 if result.Error != nil { 715 return nil, result.Error 716 } 717 w := apiwatcher.NewNotifyWatcher(u.st.facade.RawAPICaller(), result) 718 return w, nil 719 } 720 721 // WatchStorage returns a watcher for observing changes to the 722 // unit's storage attachments. 723 func (u *Unit) WatchStorage() (watcher.StringsWatcher, error) { 724 return u.st.WatchUnitStorageAttachments(u.tag) 725 } 726 727 // WatchInstanceData returns a watcher for observing changes to the 728 // instanceData of the unit's machine. Primarily used for watching 729 // LXDProfile changes. 730 func (u *Unit) WatchInstanceData() (watcher.NotifyWatcher, error) { 731 var results params.NotifyWatchResults 732 args := params.Entities{ 733 Entities: []params.Entity{{Tag: u.tag.String()}}, 734 } 735 err := u.st.facade.FacadeCall("WatchInstanceData", args, &results) 736 if err != nil { 737 return nil, err 738 } 739 if len(results.Results) != 1 { 740 return nil, errors.Errorf("expected 1 result, got %d", len(results.Results)) 741 } 742 result := results.Results[0] 743 if result.Error != nil { 744 return nil, result.Error 745 } 746 w := apiwatcher.NewNotifyWatcher(u.st.facade.RawAPICaller(), result) 747 return w, nil 748 } 749 750 // LXDProfileName returns the name of the lxd profile applied to the unit's 751 // machine for the current charm version. 752 func (u *Unit) LXDProfileName() (string, error) { 753 var results params.StringResults 754 args := params.Entities{ 755 Entities: []params.Entity{{Tag: u.tag.String()}}, 756 } 757 err := u.st.facade.FacadeCall("LXDProfileName", args, &results) 758 if err != nil { 759 return "", err 760 } 761 if len(results.Results) != 1 { 762 return "", errors.Errorf("expected 1 result, got %d", len(results.Results)) 763 } 764 result := results.Results[0] 765 if result.Error != nil { 766 return "", result.Error 767 } 768 return result.Result, nil 769 } 770 771 // CanApplyLXDProfile returns true if an lxd profile can be applied to 772 // this unit, e.g. this is an lxd machine or container and not maunal 773 func (u *Unit) CanApplyLXDProfile() (bool, error) { 774 var results params.BoolResults 775 args := params.Entities{ 776 Entities: []params.Entity{{Tag: u.tag.String()}}, 777 } 778 err := u.st.facade.FacadeCall("CanApplyLXDProfile", args, &results) 779 if err != nil { 780 return false, err 781 } 782 if len(results.Results) != 1 { 783 return false, errors.Errorf("expected 1 result, got %d", len(results.Results)) 784 } 785 result := results.Results[0] 786 if result.Error != nil { 787 return false, result.Error 788 } 789 return result.Result, nil 790 } 791 792 // NetworkInfo returns network interfaces/addresses for specified bindings. 793 func (u *Unit) NetworkInfo(bindings []string, relationId *int) (map[string]params.NetworkInfoResult, error) { 794 var results params.NetworkInfoResults 795 args := params.NetworkInfoParams{ 796 Unit: u.tag.String(), 797 Endpoints: bindings, 798 RelationId: relationId, 799 } 800 801 err := u.st.facade.FacadeCall("NetworkInfo", args, &results) 802 if err != nil { 803 return nil, errors.Trace(err) 804 } 805 806 return results.Results, nil 807 } 808 809 // State returns the state persisted by the charm running in this unit 810 // and the state internal to the uniter for this unit. 811 func (u *Unit) State() (params.UnitStateResult, error) { 812 return u.st.State() 813 } 814 815 // SetState sets the state persisted by the charm running in this unit 816 // and the state internal to the uniter for this unit. 817 func (u *Unit) SetState(unitState params.SetUnitStateArg) error { 818 return u.st.SetState(unitState) 819 } 820 821 // CommitHookChanges batches together all required API calls for applying 822 // a set of changes after a hook successfully completes and executes them in a 823 // single transaction. 824 func (u *Unit) CommitHookChanges(req params.CommitHookChangesArgs) error { 825 var results params.ErrorResults 826 err := u.st.facade.FacadeCall("CommitHookChanges", req, &results) 827 if err != nil { 828 return err 829 } 830 return apiservererrors.RestoreError(results.OneError()) 831 } 832 833 // CommitHookParamsBuilder is a helper type for populating the set of 834 // parameters used to perform a CommitHookChanges API call. 835 type CommitHookParamsBuilder struct { 836 arg params.CommitHookChangesArg 837 } 838 839 // NewCommitHookParamsBuilder returns a new builder for assembling the 840 // parameters for a CommitHookChanges API call. 841 func NewCommitHookParamsBuilder(unitTag names.UnitTag) *CommitHookParamsBuilder { 842 return &CommitHookParamsBuilder{ 843 arg: params.CommitHookChangesArg{ 844 Tag: unitTag.String(), 845 }, 846 } 847 } 848 849 // OpenPortRange records a request to open a particular port range. 850 func (b *CommitHookParamsBuilder) OpenPortRange(endpoint string, portRange network.PortRange) { 851 b.arg.OpenPorts = append(b.arg.OpenPorts, params.EntityPortRange{ 852 // The Tag is optional as the call uses the Tag from the 853 // CommitHookChangesArg; it is included here for consistency. 854 Tag: b.arg.Tag, 855 Endpoint: endpoint, 856 Protocol: portRange.Protocol, 857 FromPort: portRange.FromPort, 858 ToPort: portRange.ToPort, 859 }) 860 } 861 862 // ClosePortRange records a request to close a particular port range. 863 func (b *CommitHookParamsBuilder) ClosePortRange(endpoint string, portRange network.PortRange) { 864 b.arg.ClosePorts = append(b.arg.ClosePorts, params.EntityPortRange{ 865 // The Tag is optional as the call uses the Tag from the 866 // CommitHookChangesArg; it is included here for consistency. 867 Tag: b.arg.Tag, 868 Endpoint: endpoint, 869 Protocol: portRange.Protocol, 870 FromPort: portRange.FromPort, 871 ToPort: portRange.ToPort, 872 }) 873 } 874 875 // UpdateRelationUnitSettings records a request to update the unit/application 876 // settings for a relation. 877 func (b *CommitHookParamsBuilder) UpdateRelationUnitSettings(relName string, unitSettings, appSettings params.Settings) { 878 b.arg.RelationUnitSettings = append(b.arg.RelationUnitSettings, params.RelationUnitSettings{ 879 Relation: relName, 880 Unit: b.arg.Tag, 881 Settings: unitSettings, 882 ApplicationSettings: appSettings, 883 }) 884 } 885 886 // UpdateNetworkInfo records a request to update the network information 887 // settings for each joined relation. 888 func (b *CommitHookParamsBuilder) UpdateNetworkInfo() { 889 b.arg.UpdateNetworkInfo = true 890 } 891 892 // UpdateCharmState records a request to update the server-persisted charm state. 893 func (b *CommitHookParamsBuilder) UpdateCharmState(state map[string]string) { 894 b.arg.SetUnitState = ¶ms.SetUnitStateArg{ 895 // The Tag is optional as the call uses the Tag from the 896 // CommitHookChangesArg; it is included here for consistency. 897 Tag: b.arg.Tag, 898 CharmState: &state, 899 } 900 } 901 902 // AddStorage records a request for adding storage. 903 func (b *CommitHookParamsBuilder) AddStorage(constraints map[string][]params.StorageConstraints) { 904 storageReqs := make([]params.StorageAddParams, 0, len(constraints)) 905 for storage, cons := range constraints { 906 for _, one := range cons { 907 storageReqs = append(storageReqs, params.StorageAddParams{ 908 UnitTag: b.arg.Tag, 909 StorageName: storage, 910 Constraints: one, 911 }) 912 } 913 } 914 915 b.arg.AddStorage = storageReqs 916 } 917 918 // SetPodSpec records a request to update the PodSpec for an application. 919 func (b *CommitHookParamsBuilder) SetPodSpec(appTag names.ApplicationTag, spec *string) { 920 b.arg.SetPodSpec = ¶ms.PodSpec{ 921 Tag: appTag.String(), 922 Spec: spec, 923 } 924 } 925 926 // SetRawK8sSpec records a request to update the PodSpec for an application. 927 func (b *CommitHookParamsBuilder) SetRawK8sSpec(appTag names.ApplicationTag, spec *string) { 928 b.arg.SetRawK8sSpec = ¶ms.PodSpec{ 929 Tag: appTag.String(), 930 Spec: spec, 931 } 932 } 933 934 // SecretUpsertArg holds parameters for creating or updating a secret. 935 type SecretUpsertArg struct { 936 URI *secrets.URI 937 RotatePolicy *secrets.RotatePolicy 938 ExpireTime *time.Time 939 Description *string 940 Label *string 941 Value secrets.SecretValue 942 ValueRef *secrets.ValueRef 943 } 944 945 // SecretCreateArg holds parameters for creating a secret. 946 type SecretCreateArg struct { 947 SecretUpsertArg 948 OwnerTag names.Tag 949 } 950 951 // SecretUpdateArg holds parameters for updating a secret. 952 type SecretUpdateArg struct { 953 SecretUpsertArg 954 CurrentRevision int 955 } 956 957 // SecretDeleteArg holds parameters for deleting a secret. 958 type SecretDeleteArg struct { 959 URI *secrets.URI 960 Revision *int 961 } 962 963 // AddSecretCreates records requests to create secrets. 964 func (b *CommitHookParamsBuilder) AddSecretCreates(creates []SecretCreateArg) { 965 if len(creates) == 0 { 966 return 967 } 968 b.arg.SecretCreates = make([]params.CreateSecretArg, len(creates)) 969 for i, c := range creates { 970 971 var data secrets.SecretData 972 if c.Value != nil { 973 data = c.Value.EncodedValues() 974 } 975 if len(data) == 0 { 976 data = nil 977 } 978 979 uriStr := c.URI.String() 980 var valueRef *params.SecretValueRef 981 if c.ValueRef != nil { 982 valueRef = ¶ms.SecretValueRef{ 983 BackendID: c.ValueRef.BackendID, 984 RevisionID: c.ValueRef.RevisionID, 985 } 986 } 987 988 b.arg.SecretCreates[i] = params.CreateSecretArg{ 989 UpsertSecretArg: params.UpsertSecretArg{ 990 RotatePolicy: c.RotatePolicy, 991 ExpireTime: c.ExpireTime, 992 Description: c.Description, 993 Label: c.Label, 994 Content: params.SecretContentParams{ 995 Data: data, 996 ValueRef: valueRef, 997 }, 998 }, 999 URI: &uriStr, 1000 OwnerTag: c.OwnerTag.String(), 1001 } 1002 } 1003 } 1004 1005 // AddSecretUpdates records requests to update secrets. 1006 func (b *CommitHookParamsBuilder) AddSecretUpdates(updates []SecretUpsertArg) { 1007 if len(updates) == 0 { 1008 return 1009 } 1010 b.arg.SecretUpdates = make([]params.UpdateSecretArg, len(updates)) 1011 for i, u := range updates { 1012 1013 var data secrets.SecretData 1014 if u.Value != nil { 1015 data = u.Value.EncodedValues() 1016 } 1017 if len(data) == 0 { 1018 data = nil 1019 } 1020 1021 var valueRef *params.SecretValueRef 1022 if u.ValueRef != nil { 1023 valueRef = ¶ms.SecretValueRef{ 1024 BackendID: u.ValueRef.BackendID, 1025 RevisionID: u.ValueRef.RevisionID, 1026 } 1027 } 1028 1029 b.arg.SecretUpdates[i] = params.UpdateSecretArg{ 1030 UpsertSecretArg: params.UpsertSecretArg{ 1031 RotatePolicy: u.RotatePolicy, 1032 ExpireTime: u.ExpireTime, 1033 Description: u.Description, 1034 Label: u.Label, 1035 Content: params.SecretContentParams{ 1036 Data: data, 1037 ValueRef: valueRef, 1038 }, 1039 }, 1040 URI: u.URI.String(), 1041 } 1042 } 1043 } 1044 1045 // AddTrackLatest records the URIs for which the latest revision should be tracked. 1046 func (b *CommitHookParamsBuilder) AddTrackLatest(trackLatest []string) { 1047 if len(trackLatest) == 0 { 1048 return 1049 } 1050 b.arg.TrackLatest = make([]string, len(trackLatest)) 1051 copy(b.arg.TrackLatest, trackLatest) 1052 } 1053 1054 // SecretGrantRevokeArgs holds parameters for updating a secret's access. 1055 type SecretGrantRevokeArgs struct { 1056 URI *secrets.URI 1057 ApplicationName *string 1058 UnitName *string 1059 RelationKey *string 1060 Role secrets.SecretRole 1061 } 1062 1063 // Equal returns true if the two SecretGrantRevokeArgs are equal. 1064 func (arg SecretGrantRevokeArgs) Equal(other SecretGrantRevokeArgs) bool { 1065 return arg.URI.ID == other.URI.ID && 1066 arg.Role == other.Role && 1067 ((arg.ApplicationName == nil && other.ApplicationName == nil) || 1068 (arg.ApplicationName != nil && other.ApplicationName != nil && *arg.ApplicationName == *other.ApplicationName)) && 1069 ((arg.UnitName == nil && other.UnitName == nil) || 1070 (arg.UnitName != nil && other.UnitName != nil && *arg.UnitName == *other.UnitName)) && 1071 ((arg.RelationKey == nil && other.RelationKey == nil) || 1072 (arg.RelationKey != nil && other.RelationKey != nil && *arg.RelationKey == *other.RelationKey)) 1073 } 1074 1075 // AddSecretGrants records requests to grant secret access. 1076 func (b *CommitHookParamsBuilder) AddSecretGrants(grants []SecretGrantRevokeArgs) { 1077 if len(grants) == 0 { 1078 return 1079 } 1080 b.arg.SecretGrants = make([]params.GrantRevokeSecretArg, len(grants)) 1081 for i, g := range grants { 1082 b.arg.SecretGrants[i] = g.ToParams() 1083 } 1084 } 1085 1086 // AddSecretRevokes records requests to revoke secret access. 1087 func (b *CommitHookParamsBuilder) AddSecretRevokes(revokes []SecretGrantRevokeArgs) { 1088 if len(revokes) == 0 { 1089 return 1090 } 1091 b.arg.SecretRevokes = make([]params.GrantRevokeSecretArg, len(revokes)) 1092 for i, g := range revokes { 1093 b.arg.SecretRevokes[i] = g.ToParams() 1094 } 1095 } 1096 1097 // ToParams converts a SecretGrantRevokeArgs to a params.GrantRevokeSecretArg. 1098 func (arg SecretGrantRevokeArgs) ToParams() params.GrantRevokeSecretArg { 1099 var subjectTag, scopeTag string 1100 if arg.ApplicationName != nil { 1101 subjectTag = names.NewApplicationTag(*arg.ApplicationName).String() 1102 } 1103 if arg.UnitName != nil { 1104 subjectTag = names.NewUnitTag(*arg.UnitName).String() 1105 } 1106 if arg.RelationKey != nil { 1107 scopeTag = names.NewRelationTag(*arg.RelationKey).String() 1108 } else { 1109 scopeTag = subjectTag 1110 } 1111 return params.GrantRevokeSecretArg{ 1112 URI: arg.URI.String(), 1113 ScopeTag: scopeTag, 1114 SubjectTags: []string{subjectTag}, 1115 Role: string(arg.Role), 1116 } 1117 } 1118 1119 // AddSecretDeletes records requests to delete secrets. 1120 func (b *CommitHookParamsBuilder) AddSecretDeletes(deletes []SecretDeleteArg) { 1121 if len(deletes) == 0 { 1122 return 1123 } 1124 b.arg.SecretDeletes = make([]params.DeleteSecretArg, len(deletes)) 1125 for i, d := range deletes { 1126 var revs []int 1127 if d.Revision != nil { 1128 revs = []int{*d.Revision} 1129 } 1130 b.arg.SecretDeletes[i] = params.DeleteSecretArg{ 1131 URI: d.URI.String(), 1132 Revisions: revs, 1133 } 1134 } 1135 } 1136 1137 // Build assembles the recorded change requests into a CommitHookChangesArgs 1138 // instance that can be passed as an argument to the CommitHookChanges API 1139 // call. 1140 func (b *CommitHookParamsBuilder) Build() (params.CommitHookChangesArgs, int) { 1141 return params.CommitHookChangesArgs{ 1142 Args: []params.CommitHookChangesArg{ 1143 b.arg, 1144 }, 1145 }, b.changeCount() 1146 } 1147 1148 // changeCount returns the number of changes recorded by this builder instance. 1149 func (b *CommitHookParamsBuilder) changeCount() int { 1150 var count int 1151 if b.arg.UpdateNetworkInfo { 1152 count++ 1153 } 1154 if b.arg.SetUnitState != nil { 1155 count++ 1156 } 1157 if b.arg.SetPodSpec != nil { 1158 count++ 1159 } 1160 if b.arg.SetRawK8sSpec != nil { 1161 count++ 1162 } 1163 1164 count += len(b.arg.RelationUnitSettings) 1165 count += len(b.arg.OpenPorts) 1166 count += len(b.arg.ClosePorts) 1167 count += len(b.arg.AddStorage) 1168 count += len(b.arg.SecretCreates) 1169 count += len(b.arg.SecretUpdates) 1170 count += len(b.arg.SecretDeletes) 1171 count += len(b.arg.SecretGrants) 1172 count += len(b.arg.SecretRevokes) 1173 return count 1174 }