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 }