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 }