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  }