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