launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/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  	"launchpad.net/errgo/errors"
     9  
    10  	"launchpad.net/juju-core/charm"
    11  	"launchpad.net/juju-core/names"
    12  	"launchpad.net/juju-core/state/api/base"
    13  	"launchpad.net/juju-core/state/api/params"
    14  	"launchpad.net/juju-core/state/api/watcher"
    15  )
    16  
    17  // Unit represents a juju unit as seen by a uniter worker.
    18  type Unit struct {
    19  	st   *State
    20  	tag  string
    21  	life params.Life
    22  }
    23  
    24  // Tag returns the unit's tag.
    25  func (u *Unit) Tag() string {
    26  	return u.tag
    27  }
    28  
    29  // Name returns the name of the unit.
    30  func (u *Unit) Name() string {
    31  	_, unitName, err := names.ParseTag(u.tag, names.UnitTagKind)
    32  	if err != nil {
    33  		panic(fmt.Sprintf("%q is not a valid unit tag", u.tag))
    34  	}
    35  	return unitName
    36  }
    37  
    38  // String returns the unit as a string.
    39  func (u *Unit) String() string {
    40  	return u.Name()
    41  }
    42  
    43  // Life returns the unit's lifecycle value.
    44  func (u *Unit) Life() params.Life {
    45  	return u.life
    46  }
    47  
    48  // Refresh updates the cached local copy of the unit's data.
    49  func (u *Unit) Refresh() error {
    50  	life, err := u.st.life(u.tag)
    51  	if err != nil {
    52  		return base.WrapError(err)
    53  	}
    54  	u.life = life
    55  	return nil
    56  }
    57  
    58  // SetStatus sets the status of the unit.
    59  func (u *Unit) SetStatus(status params.Status, info string, data params.StatusData) error {
    60  	var result params.ErrorResults
    61  	args := params.SetStatus{
    62  		Entities: []params.SetEntityStatus{
    63  			{Tag: u.tag, Status: status, Info: info, Data: data},
    64  		},
    65  	}
    66  	err := u.st.caller.Call("Uniter", "", "SetStatus", args, &result)
    67  	if err != nil {
    68  		return base.WrapError(err)
    69  	}
    70  	return result.OneError()
    71  }
    72  
    73  // EnsureDead sets the unit lifecycle to Dead if it is Alive or
    74  // Dying. It does nothing otherwise.
    75  func (u *Unit) EnsureDead() error {
    76  	var result params.ErrorResults
    77  	args := params.Entities{
    78  		Entities: []params.Entity{{Tag: u.tag}},
    79  	}
    80  	err := u.st.caller.Call("Uniter", "", "EnsureDead", args, &result)
    81  	if err != nil {
    82  		return base.WrapError(err)
    83  	}
    84  	return result.OneError()
    85  }
    86  
    87  // Watch returns a watcher for observing changes to the unit.
    88  func (u *Unit) Watch() (watcher.NotifyWatcher, error) {
    89  	var results params.NotifyWatchResults
    90  	args := params.Entities{
    91  		Entities: []params.Entity{{Tag: u.tag}},
    92  	}
    93  	err := u.st.caller.Call("Uniter", "", "Watch", args, &results)
    94  	if err != nil {
    95  		return nil, base.WrapError(err)
    96  	}
    97  	if len(results.Results) != 1 {
    98  		return nil, errors.Newf("expected one result, got %d", len(results.Results))
    99  	}
   100  	result := results.Results[0]
   101  	if result.Error != nil {
   102  		return nil, result.Error
   103  	}
   104  	w := watcher.NewNotifyWatcher(u.st.caller, result)
   105  	return w, nil
   106  }
   107  
   108  // Service returns the service.
   109  func (u *Unit) Service() (*Service, error) {
   110  	serviceTag := names.ServiceTag(u.ServiceName())
   111  	service := &Service{
   112  		st:  u.st,
   113  		tag: serviceTag,
   114  	}
   115  	// Call Refresh() immediately to get the up-to-date
   116  	// life and other needed locally cached fields.
   117  	err := service.Refresh()
   118  	if err != nil {
   119  		return nil, base.WrapError(err)
   120  	}
   121  	return service, nil
   122  }
   123  
   124  // ConfigSettings returns the complete set of service charm config settings
   125  // available to the unit. Unset values will be replaced with the default
   126  // value for the associated option, and may thus be nil when no default is
   127  // specified.
   128  func (u *Unit) ConfigSettings() (charm.Settings, error) {
   129  	var results params.ConfigSettingsResults
   130  	args := params.Entities{
   131  		Entities: []params.Entity{{Tag: u.tag}},
   132  	}
   133  	err := u.st.caller.Call("Uniter", "", "ConfigSettings", args, &results)
   134  	if err != nil {
   135  		return nil, base.WrapError(err)
   136  	}
   137  	if len(results.Results) != 1 {
   138  		return nil, errors.Newf("expected one result, got %d", len(results.Results))
   139  	}
   140  	result := results.Results[0]
   141  	if result.Error != nil {
   142  		return nil, result.Error
   143  	}
   144  	return charm.Settings(result.Settings), nil
   145  }
   146  
   147  // ServiceName returns the service name.
   148  func (u *Unit) ServiceName() string {
   149  	return names.UnitService(u.Name())
   150  }
   151  
   152  // ServiceTag returns the service tag.
   153  func (u *Unit) ServiceTag() string {
   154  	return names.ServiceTag(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}},
   166  	}
   167  	err := u.st.caller.Call("Uniter", "", "Destroy", args, &result)
   168  	if err != nil {
   169  		return base.WrapError(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}},
   179  	}
   180  	err := u.st.caller.Call("Uniter", "", "DestroyAllSubordinates", args, &result)
   181  	if err != nil {
   182  		return base.WrapError(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}},
   195  	}
   196  	err := u.st.caller.Call("Uniter", "", "Resolved", args, &results)
   197  	if err != nil {
   198  		return "", base.WrapError(err)
   199  	}
   200  	if len(results.Results) != 1 {
   201  		return "", errors.Newf("expected one 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  // IsPrincipal returns whether the unit is deployed in its own container,
   211  // and can therefore have subordinate services deployed alongside it.
   212  //
   213  // NOTE: This differs from state.Unit.IsPrincipal() by returning an
   214  // error as well, because it needs to make an API call.
   215  func (u *Unit) IsPrincipal() (bool, error) {
   216  	var results params.StringBoolResults
   217  	args := params.Entities{
   218  		Entities: []params.Entity{{Tag: u.tag}},
   219  	}
   220  	err := u.st.caller.Call("Uniter", "", "GetPrincipal", args, &results)
   221  	if err != nil {
   222  		return false, base.WrapError(err)
   223  	}
   224  	if len(results.Results) != 1 {
   225  		return false, errors.Newf("expected one result, got %d", len(results.Results))
   226  	}
   227  	result := results.Results[0]
   228  	if result.Error != nil {
   229  		return false, result.Error
   230  	}
   231  	// GetPrincipal returns false when the unit is subordinate.
   232  	return !result.Ok, nil
   233  }
   234  
   235  // HasSubordinates returns the tags of any subordinate units.
   236  func (u *Unit) HasSubordinates() (bool, error) {
   237  	var results params.BoolResults
   238  	args := params.Entities{
   239  		Entities: []params.Entity{{Tag: u.tag}},
   240  	}
   241  	err := u.st.caller.Call("Uniter", "", "HasSubordinates", args, &results)
   242  	if err != nil {
   243  		return false, base.WrapError(err)
   244  	}
   245  	if len(results.Results) != 1 {
   246  		return false, errors.Newf("expected one result, got %d", len(results.Results))
   247  	}
   248  	result := results.Results[0]
   249  	if result.Error != nil {
   250  		return false, result.Error
   251  	}
   252  	return result.Result, nil
   253  }
   254  
   255  // PublicAddress returns the public address of the unit and whether it
   256  // is valid.
   257  //
   258  // NOTE: This differs from state.Unit.PublicAddres() by returning
   259  // an error instead of a bool, because it needs to make an API call.
   260  //
   261  // TODO(dimitern): We might be able to drop this, once we have machine
   262  // addresses implemented fully. See also LP bug 1221798.
   263  func (u *Unit) PublicAddress() (string, error) {
   264  	var results params.StringResults
   265  	args := params.Entities{
   266  		Entities: []params.Entity{{Tag: u.tag}},
   267  	}
   268  	err := u.st.caller.Call("Uniter", "", "PublicAddress", args, &results)
   269  	if err != nil {
   270  		return "", base.WrapError(err)
   271  	}
   272  	if len(results.Results) != 1 {
   273  		return "", errors.Newf("expected one result, got %d", len(results.Results))
   274  	}
   275  	result := results.Results[0]
   276  	if result.Error != nil {
   277  		return "", result.Error
   278  	}
   279  	return result.Result, nil
   280  }
   281  
   282  // SetPublicAddress sets the public address of the unit.
   283  //
   284  // TODO(dimitern): We might be able to drop this, once we have machine
   285  // addresses implemented fully. See also LP bug 1221798.
   286  func (u *Unit) SetPublicAddress(address string) error {
   287  	var result params.ErrorResults
   288  	args := params.SetEntityAddresses{
   289  		Entities: []params.SetEntityAddress{
   290  			{Tag: u.tag, Address: address},
   291  		},
   292  	}
   293  	err := u.st.caller.Call("Uniter", "", "SetPublicAddress", args, &result)
   294  	if err != nil {
   295  		return base.WrapError(err)
   296  	}
   297  	return result.OneError()
   298  }
   299  
   300  // PrivateAddress returns the private address of the unit and whether
   301  // it is valid.
   302  //
   303  // NOTE: This differs from state.Unit.PrivateAddress() by returning
   304  // an error instead of a bool, because it needs to make an API call.
   305  //
   306  // TODO(dimitern): We might be able to drop this, once we have machine
   307  // addresses implemented fully. See also LP bug 1221798.
   308  func (u *Unit) PrivateAddress() (string, error) {
   309  	var results params.StringResults
   310  	args := params.Entities{
   311  		Entities: []params.Entity{{Tag: u.tag}},
   312  	}
   313  	err := u.st.caller.Call("Uniter", "", "PrivateAddress", args, &results)
   314  	if err != nil {
   315  		return "", base.WrapError(err)
   316  	}
   317  	if len(results.Results) != 1 {
   318  		return "", errors.Newf("expected one result, got %d", len(results.Results))
   319  	}
   320  	result := results.Results[0]
   321  	if result.Error != nil {
   322  		return "", result.Error
   323  	}
   324  	return result.Result, nil
   325  }
   326  
   327  // SetPrivateAddress sets the private address of the unit.
   328  //
   329  // TODO(dimitern): We might be able to drop this, once we have machine
   330  // addresses implemented fully. See also LP bug 1221798.
   331  func (u *Unit) SetPrivateAddress(address string) error {
   332  	var result params.ErrorResults
   333  	args := params.SetEntityAddresses{
   334  		Entities: []params.SetEntityAddress{
   335  			{Tag: u.tag, Address: address},
   336  		},
   337  	}
   338  	err := u.st.caller.Call("Uniter", "", "SetPrivateAddress", args, &result)
   339  	if err != nil {
   340  		return base.WrapError(err)
   341  	}
   342  	return result.OneError()
   343  }
   344  
   345  // OpenPort sets the policy of the port with protocol and number to be
   346  // opened.
   347  //
   348  // TODO: We should really be opening and closing ports on machines,
   349  // rather than units.
   350  func (u *Unit) OpenPort(protocol string, number int) error {
   351  	var result params.ErrorResults
   352  	args := params.EntitiesPorts{
   353  		Entities: []params.EntityPort{
   354  			{Tag: u.tag, Protocol: protocol, Port: number},
   355  		},
   356  	}
   357  	err := u.st.caller.Call("Uniter", "", "OpenPort", args, &result)
   358  	if err != nil {
   359  		return base.WrapError(err)
   360  	}
   361  	return result.OneError()
   362  }
   363  
   364  // ClosePort sets the policy of the port with protocol and number to
   365  // be closed.
   366  //
   367  // TODO: We should really be opening and closing ports on machines,
   368  // rather than units.
   369  func (u *Unit) ClosePort(protocol string, number int) error {
   370  	var result params.ErrorResults
   371  	args := params.EntitiesPorts{
   372  		Entities: []params.EntityPort{
   373  			{Tag: u.tag, Protocol: protocol, Port: number},
   374  		},
   375  	}
   376  	err := u.st.caller.Call("Uniter", "", "ClosePort", args, &result)
   377  	if err != nil {
   378  		return base.WrapError(err)
   379  	}
   380  	return result.OneError()
   381  }
   382  
   383  var ErrNoCharmURLSet = errors.New("unit has no charm url set")
   384  
   385  // CharmURL returns the charm URL this unit is currently using.
   386  //
   387  // NOTE: This differs from state.Unit.CharmURL() by returning
   388  // an error instead of a bool, because it needs to make an API call.
   389  func (u *Unit) CharmURL() (*charm.URL, error) {
   390  	var results params.StringBoolResults
   391  	args := params.Entities{
   392  		Entities: []params.Entity{{Tag: u.tag}},
   393  	}
   394  	err := u.st.caller.Call("Uniter", "", "CharmURL", args, &results)
   395  	if err != nil {
   396  		return nil, base.WrapError(err)
   397  	}
   398  	if len(results.Results) != 1 {
   399  		return nil, errors.Newf("expected one result, got %d", len(results.Results))
   400  	}
   401  	result := results.Results[0]
   402  	if result.Error != nil {
   403  		return nil, result.Error
   404  	}
   405  	if result.Result != "" {
   406  		curl, err := charm.ParseURL(result.Result)
   407  		if err != nil {
   408  			return nil, base.WrapError(err)
   409  		}
   410  		return curl, nil
   411  	}
   412  	return nil, ErrNoCharmURLSet
   413  }
   414  
   415  // SetCharmURL marks the unit as currently using the supplied charm URL.
   416  // An error will be returned if the unit is dead, or the charm URL not known.
   417  func (u *Unit) SetCharmURL(curl *charm.URL) error {
   418  	if curl == nil {
   419  		return errors.Newf("charm URL cannot be nil")
   420  	}
   421  	var result params.ErrorResults
   422  	args := params.EntitiesCharmURL{
   423  		Entities: []params.EntityCharmURL{
   424  			{Tag: u.tag, CharmURL: curl.String()},
   425  		},
   426  	}
   427  	err := u.st.caller.Call("Uniter", "", "SetCharmURL", args, &result)
   428  	if err != nil {
   429  		return base.WrapError(err)
   430  	}
   431  	return result.OneError()
   432  }
   433  
   434  // ClearResolved removes any resolved setting on the unit.
   435  func (u *Unit) ClearResolved() error {
   436  	var result params.ErrorResults
   437  	args := params.Entities{
   438  		Entities: []params.Entity{{Tag: u.tag}},
   439  	}
   440  	err := u.st.caller.Call("Uniter", "", "ClearResolved", args, &result)
   441  	if err != nil {
   442  		return base.WrapError(err)
   443  	}
   444  	return result.OneError()
   445  }
   446  
   447  // WatchConfigSettings returns a watcher for observing changes to the
   448  // unit's service configuration settings. The unit must have a charm URL
   449  // set before this method is called, and the returned watcher will be
   450  // valid only while the unit's charm URL is not changed.
   451  func (u *Unit) WatchConfigSettings() (watcher.NotifyWatcher, error) {
   452  	var results params.NotifyWatchResults
   453  	args := params.Entities{
   454  		Entities: []params.Entity{{Tag: u.tag}},
   455  	}
   456  	err := u.st.caller.Call("Uniter", "", "WatchConfigSettings", args, &results)
   457  	if err != nil {
   458  		return nil, base.WrapError(err)
   459  	}
   460  	if len(results.Results) != 1 {
   461  		return nil, errors.Newf("expected one result, got %d", len(results.Results))
   462  	}
   463  	result := results.Results[0]
   464  	if result.Error != nil {
   465  		return nil, result.Error
   466  	}
   467  	w := watcher.NewNotifyWatcher(u.st.caller, result)
   468  	return w, nil
   469  }