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 }