github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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/core/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  // EnterScope ensures that the unit has entered its scope in the relation.
    44  // When the unit has already entered its relation scope, EnterScope will report
    45  // success but make no changes to state.
    46  //
    47  // Otherwise, assuming both the relation and the unit are alive, it will enter
    48  // scope.
    49  //
    50  // If the unit is a principal and the relation has container scope, EnterScope
    51  // will also create the required subordinate unit, if it does not already exist;
    52  // this is because there's no point having a principal in scope if there is no
    53  // corresponding subordinate to join it.
    54  //
    55  // Once a unit has entered a scope, it stays in scope without further
    56  // intervention; the relation will not be able to become Dead until all units
    57  // have departed its scopes.
    58  //
    59  // NOTE: Unlike state.RelatioUnit.EnterScope(), this method does not take
    60  // settings, because uniter only uses this to supply the unit's private
    61  // address, but this is not done at the server-side by the API.
    62  func (ru *RelationUnit) EnterScope() error {
    63  	var result params.ErrorResults
    64  	args := params.RelationUnits{
    65  		RelationUnits: []params.RelationUnit{{
    66  			Relation: ru.relation.tag.String(),
    67  			Unit:     ru.unit.tag.String(),
    68  		}},
    69  	}
    70  	err := ru.st.facade.FacadeCall("EnterScope", args, &result)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	return result.OneError()
    75  }
    76  
    77  // LeaveScope signals that the unit has left its scope in the relation.
    78  // After the unit has left its relation scope, it is no longer a member
    79  // of the relation; if the relation is dying when its last member unit
    80  // leaves, it is removed immediately. It is not an error to leave a scope
    81  // that the unit is not, or never was, a member of.
    82  func (ru *RelationUnit) LeaveScope() error {
    83  	var result params.ErrorResults
    84  	args := params.RelationUnits{
    85  		RelationUnits: []params.RelationUnit{{
    86  			Relation: ru.relation.tag.String(),
    87  			Unit:     ru.unit.tag.String(),
    88  		}},
    89  	}
    90  	err := ru.st.facade.FacadeCall("LeaveScope", args, &result)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	return result.OneError()
    95  }
    96  
    97  // Settings returns a Settings which allows access to the unit's settings
    98  // within the relation.
    99  func (ru *RelationUnit) Settings() (*Settings, error) {
   100  	var results params.SettingsResults
   101  	args := params.RelationUnits{
   102  		RelationUnits: []params.RelationUnit{{
   103  			Relation: ru.relation.tag.String(),
   104  			Unit:     ru.unit.tag.String(),
   105  		}},
   106  	}
   107  	err := ru.st.facade.FacadeCall("ReadSettings", args, &results)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	if len(results.Results) != 1 {
   112  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   113  	}
   114  	result := results.Results[0]
   115  	if result.Error != nil {
   116  		return nil, result.Error
   117  	}
   118  	return newSettings(ru.st, ru.relation.tag.String(), ru.unit.tag.String(), result.Settings), nil
   119  }
   120  
   121  // ReadSettings returns a map holding the settings of the unit with the
   122  // supplied name within this relation. An error will be returned if the
   123  // relation no longer exists, or if the unit's application is not part of the
   124  // relation, or the settings are invalid; but mere non-existence of the
   125  // unit is not grounds for an error, because the unit settings are
   126  // guaranteed to persist for the lifetime of the relation, regardless
   127  // of the lifetime of the unit.
   128  func (ru *RelationUnit) ReadSettings(uname string) (params.Settings, error) {
   129  	if !names.IsValidUnit(uname) {
   130  		return nil, errors.Errorf("%q is not a valid unit", uname)
   131  	}
   132  	tag := names.NewUnitTag(uname)
   133  	var results params.SettingsResults
   134  	args := params.RelationUnitPairs{
   135  		RelationUnitPairs: []params.RelationUnitPair{{
   136  			Relation:   ru.relation.tag.String(),
   137  			LocalUnit:  ru.unit.tag.String(),
   138  			RemoteUnit: tag.String(),
   139  		}},
   140  	}
   141  	err := ru.st.facade.FacadeCall("ReadRemoteSettings", args, &results)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	if len(results.Results) != 1 {
   146  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   147  	}
   148  	result := results.Results[0]
   149  	if result.Error != nil {
   150  		return nil, result.Error
   151  	}
   152  	return result.Settings, nil
   153  }
   154  
   155  // Watch returns a watcher that notifies of changes to counterpart
   156  // units in the relation.
   157  func (ru *RelationUnit) Watch() (watcher.RelationUnitsWatcher, error) {
   158  	return ru.st.WatchRelationUnits(ru.relation.tag, ru.unit.tag)
   159  }