github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/api/uniter/relationunit.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  	"launchpad.net/juju-core/names"
    10  	"launchpad.net/juju-core/state/api/params"
    11  	"launchpad.net/juju-core/state/api/watcher"
    12  )
    13  
    14  // This module implements a subset of the interface provided by
    15  // state.RelationUnit, as needed by the uniter API.
    16  // Most of this is pretty much a verbatim copy of the code in
    17  // state/relationunit.go, except for a few API-specific changes.
    18  
    19  // RelationUnit holds information about a single unit in a relation,
    20  // and allows clients to conveniently access unit-specific
    21  // functionality.
    22  type RelationUnit struct {
    23  	st       *State
    24  	relation *Relation
    25  	unit     *Unit
    26  	endpoint Endpoint
    27  	scope    string
    28  }
    29  
    30  // Relation returns the relation associated with the unit.
    31  func (ru *RelationUnit) Relation() *Relation {
    32  	return ru.relation
    33  }
    34  
    35  // Endpoint returns the relation endpoint that defines the unit's
    36  // participation in the relation.
    37  func (ru *RelationUnit) Endpoint() Endpoint {
    38  	return ru.endpoint
    39  }
    40  
    41  // PrivateAddress returns the private address of the unit and whether
    42  // it is valid.
    43  //
    44  // NOTE: This differs from state.RelationUnit.PrivateAddress() by
    45  // returning an error instead of a bool, because it needs to make an
    46  // API call.
    47  func (ru *RelationUnit) PrivateAddress() (string, error) {
    48  	return ru.unit.PrivateAddress()
    49  }
    50  
    51  // EnterScope ensures that the unit has entered its scope in the relation.
    52  // When the unit has already entered its relation scope, EnterScope will report
    53  // success but make no changes to state.
    54  //
    55  // Otherwise, assuming both the relation and the unit are alive, it will enter
    56  // scope.
    57  //
    58  // If the unit is a principal and the relation has container scope, EnterScope
    59  // will also create the required subordinate unit, if it does not already exist;
    60  // this is because there's no point having a principal in scope if there is no
    61  // corresponding subordinate to join it.
    62  //
    63  // Once a unit has entered a scope, it stays in scope without further
    64  // intervention; the relation will not be able to become Dead until all units
    65  // have departed its scopes.
    66  //
    67  // NOTE: Unlike state.RelatioUnit.EnterScope(), this method does not take
    68  // settings, because uniter only uses this to supply the unit's private
    69  // address, but this is not done at the server-side by the API.
    70  func (ru *RelationUnit) EnterScope() error {
    71  	var result params.ErrorResults
    72  	args := params.RelationUnits{
    73  		RelationUnits: []params.RelationUnit{{
    74  			Relation: ru.relation.tag,
    75  			Unit:     ru.unit.tag,
    76  		}},
    77  	}
    78  	err := ru.st.caller.Call("Uniter", "", "EnterScope", args, &result)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	return result.OneError()
    83  }
    84  
    85  // LeaveScope signals that the unit has left its scope in the relation.
    86  // After the unit has left its relation scope, it is no longer a member
    87  // of the relation; if the relation is dying when its last member unit
    88  // leaves, it is removed immediately. It is not an error to leave a scope
    89  // that the unit is not, or never was, a member of.
    90  func (ru *RelationUnit) LeaveScope() error {
    91  	var result params.ErrorResults
    92  	args := params.RelationUnits{
    93  		RelationUnits: []params.RelationUnit{{
    94  			Relation: ru.relation.tag,
    95  			Unit:     ru.unit.tag,
    96  		}},
    97  	}
    98  	err := ru.st.caller.Call("Uniter", "", "LeaveScope", args, &result)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	return result.OneError()
   103  }
   104  
   105  // Settings returns a Settings which allows access to the unit's settings
   106  // within the relation.
   107  func (ru *RelationUnit) Settings() (*Settings, error) {
   108  	var results params.RelationSettingsResults
   109  	args := params.RelationUnits{
   110  		RelationUnits: []params.RelationUnit{{
   111  			Relation: ru.relation.tag,
   112  			Unit:     ru.unit.tag,
   113  		}},
   114  	}
   115  	err := ru.st.caller.Call("Uniter", "", "ReadSettings", args, &results)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	if len(results.Results) != 1 {
   120  		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
   121  	}
   122  	result := results.Results[0]
   123  	if result.Error != nil {
   124  		return nil, result.Error
   125  	}
   126  	return newSettings(ru.st, ru.relation.tag, ru.unit.tag, result.Settings), nil
   127  }
   128  
   129  // ReadSettings returns a map holding the settings of the unit with the
   130  // supplied name within this relation. An error will be returned if the
   131  // relation no longer exists, or if the unit's service is not part of the
   132  // relation, or the settings are invalid; but mere non-existence of the
   133  // unit is not grounds for an error, because the unit settings are
   134  // guaranteed to persist for the lifetime of the relation, regardless
   135  // of the lifetime of the unit.
   136  func (ru *RelationUnit) ReadSettings(uname string) (params.RelationSettings, error) {
   137  	tag := names.UnitTag(uname)
   138  	var results params.RelationSettingsResults
   139  	args := params.RelationUnitPairs{
   140  		RelationUnitPairs: []params.RelationUnitPair{{
   141  			Relation:   ru.relation.tag,
   142  			LocalUnit:  ru.unit.tag,
   143  			RemoteUnit: tag,
   144  		}},
   145  	}
   146  	err := ru.st.caller.Call("Uniter", "", "ReadRemoteSettings", args, &results)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	if len(results.Results) != 1 {
   151  		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
   152  	}
   153  	result := results.Results[0]
   154  	if result.Error != nil {
   155  		return nil, result.Error
   156  	}
   157  	return result.Settings, nil
   158  }
   159  
   160  // Watch returns a watcher that notifies of changes to counterpart
   161  // units in the relation.
   162  func (ru *RelationUnit) Watch() (watcher.RelationUnitsWatcher, error) {
   163  	var results params.RelationUnitsWatchResults
   164  	args := params.RelationUnits{
   165  		RelationUnits: []params.RelationUnit{{
   166  			Relation: ru.relation.tag,
   167  			Unit:     ru.unit.tag,
   168  		}},
   169  	}
   170  	err := ru.st.caller.Call("Uniter", "", "WatchRelationUnits", args, &results)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	if len(results.Results) != 1 {
   175  		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
   176  	}
   177  	result := results.Results[0]
   178  	if result.Error != nil {
   179  		return nil, result.Error
   180  	}
   181  	w := watcher.NewRelationUnitsWatcher(ru.st.caller, result)
   182  	return w, nil
   183  }