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