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