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