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