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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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  }