launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/api/uniter/uniter.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 "launchpad.net/errgo/errors" 8 "launchpad.net/juju-core/charm" 9 "launchpad.net/juju-core/names" 10 "launchpad.net/juju-core/state/api/base" 11 "launchpad.net/juju-core/state/api/common" 12 "launchpad.net/juju-core/state/api/params" 13 ) 14 15 const uniter = "Uniter" 16 17 // State provides access to the Uniter API facade. 18 type State struct { 19 *common.EnvironWatcher 20 21 caller base.Caller 22 // unitTag contains the authenticated unit's tag. 23 unitTag string 24 } 25 26 // NewState creates a new client-side Uniter facade. 27 func NewState(caller base.Caller, authTag string) *State { 28 return &State{ 29 EnvironWatcher: common.NewEnvironWatcher(uniter, caller), 30 caller: caller, 31 unitTag: authTag} 32 } 33 34 // life requests the lifecycle of the given entity from the server. 35 func (st *State) life(tag string) (params.Life, error) { 36 return common.Life(st.caller, uniter, tag) 37 } 38 39 // relation requests relation information from the server. 40 func (st *State) relation(relationTag, unitTag string) (params.RelationResult, error) { 41 nothing := params.RelationResult{} 42 var result params.RelationResults 43 args := params.RelationUnits{ 44 RelationUnits: []params.RelationUnit{ 45 {Relation: relationTag, Unit: unitTag}, 46 }, 47 } 48 err := st.caller.Call(uniter, "", "Relation", args, &result) 49 if err != nil { 50 return nothing, base.WrapError(err) 51 } 52 if len(result.Results) != 1 { 53 return nothing, errors.Newf("expected one result, got %d", len(result.Results)) 54 } 55 if err := result.Results[0].Error; err != nil { 56 return nothing, base.WrapError(err) 57 } 58 return result.Results[0], nil 59 } 60 61 // Unit provides access to methods of a state.Unit through the facade. 62 func (st *State) Unit(tag string) (*Unit, error) { 63 life, err := st.life(tag) 64 if err != nil { 65 return nil, base.WrapError(err) 66 } 67 return &Unit{ 68 tag: tag, 69 life: life, 70 st: st, 71 }, nil 72 } 73 74 // Service returns a service state by tag. 75 func (st *State) Service(tag string) (*Service, error) { 76 life, err := st.life(tag) 77 if err != nil { 78 return nil, base.WrapError(err) 79 } 80 return &Service{ 81 tag: tag, 82 life: life, 83 st: st, 84 }, nil 85 } 86 87 // ProviderType returns a provider type used by the current juju 88 // environment. 89 // 90 // TODO(dimitern): We might be able to drop this, once we have machine 91 // addresses implemented fully. See also LP bug 1221798. 92 func (st *State) ProviderType() (string, error) { 93 var result params.StringResult 94 err := st.caller.Call(uniter, "", "ProviderType", nil, &result) 95 if err != nil { 96 return "", base.WrapError(err) 97 } 98 if err := result.Error; err != nil { 99 return "", base.WrapError(err) 100 } 101 return result.Result, nil 102 } 103 104 // Charm returns the charm with the given URL. 105 func (st *State) Charm(curl *charm.URL) (*Charm, error) { 106 if curl == nil { 107 return nil, errors.Newf("charm url cannot be nil") 108 } 109 return &Charm{ 110 st: st, 111 url: curl.String(), 112 }, nil 113 } 114 115 // Relation returns the existing relation with the given tag. 116 func (st *State) Relation(tag string) (*Relation, error) { 117 result, err := st.relation(tag, st.unitTag) 118 if err != nil { 119 return nil, base.WrapError(err) 120 } 121 return &Relation{ 122 id: result.Id, 123 tag: tag, 124 life: result.Life, 125 st: st, 126 }, nil 127 } 128 129 // Relation returns the existing relation with the given tag. 130 func (st *State) RelationById(id int) (*Relation, error) { 131 var results params.RelationResults 132 args := params.RelationIds{ 133 RelationIds: []int{id}, 134 } 135 err := st.caller.Call(uniter, "", "RelationById", args, &results) 136 if err != nil { 137 return nil, base.WrapError(err) 138 } 139 if len(results.Results) != 1 { 140 return nil, errors.Newf("expected one result, got %d", len(results.Results)) 141 } 142 result := results.Results[0] 143 if err := result.Error; err != nil { 144 return nil, base.WrapError(err) 145 } 146 relationTag := names.RelationTag(result.Key) 147 return &Relation{ 148 id: result.Id, 149 tag: relationTag, 150 life: result.Life, 151 st: st, 152 }, nil 153 } 154 155 // Environment returns the environment entity. 156 func (st *State) Environment() (*Environment, error) { 157 var result params.EnvironmentResult 158 err := st.caller.Call("Uniter", "", "CurrentEnvironment", nil, &result) 159 if params.IsCodeNotImplemented(err) { 160 // Fall back to using the 1.16 API. 161 return st.environment1dot16() 162 } 163 if err != nil { 164 return nil, base.WrapError(err) 165 } 166 if err := result.Error; err != nil { 167 return nil, base.WrapError(err) 168 } 169 return &Environment{ 170 name: result.Name, 171 uuid: result.UUID, 172 }, nil 173 } 174 175 // environment1dot16 requests just the UUID of the current environment, when 176 // using an older API server that does not support CurrentEnvironment API call. 177 func (st *State) environment1dot16() (*Environment, error) { 178 var result params.StringResult 179 err := st.caller.Call("Uniter", "", "CurrentEnvironUUID", nil, &result) 180 if err != nil { 181 return nil, base.WrapError(err) 182 } 183 if err := result.Error; err != nil { 184 return nil, base.WrapError(err) 185 } 186 return &Environment{ 187 uuid: result.Result, 188 }, nil 189 } 190 191 // APIAddresses returns the list of addresses used to connect to the API. 192 func (st *State) APIAddresses() ([]string, error) { 193 var result params.StringsResult 194 err := st.caller.Call(uniter, "", "APIAddresses", nil, &result) 195 if err != nil { 196 return nil, base.WrapError(err) 197 } 198 if err := result.Error; err != nil { 199 return nil, base.WrapError(err) 200 } 201 return result.Result, nil 202 }