github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/address.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "net" 8 "reflect" 9 "strconv" 10 11 "github.com/juju/errors" 12 "gopkg.in/mgo.v2/bson" 13 "gopkg.in/mgo.v2/txn" 14 15 "github.com/juju/juju/network" 16 ) 17 18 // controllerAddresses returns the list of internal addresses of the state 19 // server machines. 20 func (st *State) controllerAddresses() ([]string, error) { 21 ssState := st 22 model, err := st.ControllerModel() 23 if err != nil { 24 return nil, errors.Trace(err) 25 } 26 if st.ModelTag() != model.ModelTag() { 27 // We are not using the controller model, so get one. 28 logger.Debugf("getting a controller state connection, current env: %s", st.ModelTag()) 29 ssState, err = st.ForModel(model.ModelTag()) 30 if err != nil { 31 return nil, errors.Trace(err) 32 } 33 defer ssState.Close() 34 logger.Debugf("ssState env: %s", ssState.ModelTag()) 35 } 36 37 type addressMachine struct { 38 Addresses []address 39 } 40 var allAddresses []addressMachine 41 // TODO(rog) 2013/10/14 index machines on jobs. 42 machines, closer := ssState.getCollection(machinesC) 43 defer closer() 44 err = machines.Find(bson.D{{"jobs", JobManageModel}}).All(&allAddresses) 45 if err != nil { 46 return nil, err 47 } 48 if len(allAddresses) == 0 { 49 return nil, errors.New("no controller machines found") 50 } 51 apiAddrs := make([]string, 0, len(allAddresses)) 52 for _, addrs := range allAddresses { 53 naddrs := networkAddresses(addrs.Addresses) 54 addr, ok := network.SelectControllerAddress(naddrs, false) 55 if ok { 56 apiAddrs = append(apiAddrs, addr.Value) 57 } 58 } 59 if len(apiAddrs) == 0 { 60 return nil, errors.New("no controller machines with addresses found") 61 } 62 return apiAddrs, nil 63 } 64 65 func appendPort(addrs []string, port int) []string { 66 newAddrs := make([]string, len(addrs)) 67 for i, addr := range addrs { 68 newAddrs[i] = net.JoinHostPort(addr, strconv.Itoa(port)) 69 } 70 return newAddrs 71 } 72 73 // Addresses returns the list of cloud-internal addresses that 74 // can be used to connect to the state. 75 func (st *State) Addresses() ([]string, error) { 76 addrs, err := st.controllerAddresses() 77 if err != nil { 78 return nil, errors.Trace(err) 79 } 80 config, err := st.ModelConfig() 81 if err != nil { 82 return nil, errors.Trace(err) 83 } 84 return appendPort(addrs, config.StatePort()), nil 85 } 86 87 // APIAddressesFromMachines returns the list of cloud-internal addresses that 88 // can be used to connect to the state API server. 89 // This method will be deprecated when API addresses are 90 // stored independently in their own document. 91 func (st *State) APIAddressesFromMachines() ([]string, error) { 92 addrs, err := st.controllerAddresses() 93 if err != nil { 94 return nil, errors.Trace(err) 95 } 96 config, err := st.ModelConfig() 97 if err != nil { 98 return nil, errors.Trace(err) 99 } 100 return appendPort(addrs, config.APIPort()), nil 101 } 102 103 const apiHostPortsKey = "apiHostPorts" 104 105 type apiHostPortsDoc struct { 106 APIHostPorts [][]hostPort `bson:"apihostports"` 107 } 108 109 // SetAPIHostPorts sets the addresses of the API server instances. 110 // Each server is represented by one element in the top level slice. 111 func (st *State) SetAPIHostPorts(netHostsPorts [][]network.HostPort) error { 112 doc := apiHostPortsDoc{ 113 APIHostPorts: fromNetworkHostsPorts(netHostsPorts), 114 } 115 buildTxn := func(attempt int) ([]txn.Op, error) { 116 existing, err := st.APIHostPorts() 117 if err != nil { 118 return nil, err 119 } 120 op := txn.Op{ 121 C: controllersC, 122 Id: apiHostPortsKey, 123 Assert: bson.D{{ 124 "apihostports", fromNetworkHostsPorts(existing), 125 }}, 126 } 127 if !hostsPortsEqual(netHostsPorts, existing) { 128 op.Update = bson.D{{ 129 "$set", bson.D{{"apihostports", doc.APIHostPorts}}, 130 }} 131 } 132 return []txn.Op{op}, nil 133 } 134 if err := st.run(buildTxn); err != nil { 135 return errors.Annotate(err, "cannot set API addresses") 136 } 137 logger.Debugf("setting API hostPorts: %v", netHostsPorts) 138 return nil 139 } 140 141 // APIHostPorts returns the API addresses as set by SetAPIHostPorts. 142 func (st *State) APIHostPorts() ([][]network.HostPort, error) { 143 var doc apiHostPortsDoc 144 controllers, closer := st.getCollection(controllersC) 145 defer closer() 146 err := controllers.Find(bson.D{{"_id", apiHostPortsKey}}).One(&doc) 147 if err != nil { 148 return nil, err 149 } 150 return networkHostsPorts(doc.APIHostPorts), nil 151 } 152 153 type DeployerConnectionValues struct { 154 StateAddresses []string 155 APIAddresses []string 156 } 157 158 // DeployerConnectionInfo returns the address information necessary for the deployer. 159 // The function does the expensive operations (getting stuff from mongo) just once. 160 func (st *State) DeployerConnectionInfo() (*DeployerConnectionValues, error) { 161 addrs, err := st.controllerAddresses() 162 if err != nil { 163 return nil, errors.Trace(err) 164 } 165 config, err := st.ModelConfig() 166 if err != nil { 167 return nil, errors.Trace(err) 168 } 169 return &DeployerConnectionValues{ 170 StateAddresses: appendPort(addrs, config.StatePort()), 171 APIAddresses: appendPort(addrs, config.APIPort()), 172 }, nil 173 } 174 175 // address represents the location of a machine, including metadata 176 // about what kind of location the address describes. 177 // 178 // TODO(dimitern) Make sure we integrate this with other networking 179 // stuff at some point. We want to use juju-specific network names 180 // that point to existing documents in the networks collection. 181 type address struct { 182 Value string `bson:"value"` 183 AddressType string `bson:"addresstype"` 184 Scope string `bson:"networkscope,omitempty"` 185 Origin string `bson:"origin,omitempty"` 186 SpaceName string `bson:"spacename,omitempty"` 187 } 188 189 // Origin specifies where an address comes from, whether it was reported by a 190 // provider or by a machine. 191 type Origin string 192 193 const ( 194 // Address origin unknown. 195 OriginUnknown Origin = "" 196 // Address comes from a provider. 197 OriginProvider Origin = "provider" 198 // Address comes from a machine. 199 OriginMachine Origin = "machine" 200 ) 201 202 // fromNetworkAddress is a convenience helper to create a state type 203 // out of the network type, here for Address with a given Origin. 204 func fromNetworkAddress(netAddr network.Address, origin Origin) address { 205 return address{ 206 Value: netAddr.Value, 207 AddressType: string(netAddr.Type), 208 Scope: string(netAddr.Scope), 209 Origin: string(origin), 210 SpaceName: string(netAddr.SpaceName), 211 } 212 } 213 214 // networkAddress is a convenience helper to return the state type 215 // as network type, here for Address. 216 func (addr *address) networkAddress() network.Address { 217 return network.Address{ 218 Value: addr.Value, 219 Type: network.AddressType(addr.AddressType), 220 Scope: network.Scope(addr.Scope), 221 SpaceName: network.SpaceName(addr.SpaceName), 222 } 223 } 224 225 // fromNetworkAddresses is a convenience helper to create a state type 226 // out of the network type, here for a slice of Address with a given origin. 227 func fromNetworkAddresses(netAddrs []network.Address, origin Origin) []address { 228 addrs := make([]address, len(netAddrs)) 229 for i, netAddr := range netAddrs { 230 addrs[i] = fromNetworkAddress(netAddr, origin) 231 } 232 return addrs 233 } 234 235 // networkAddresses is a convenience helper to return the state type 236 // as network type, here for a slice of Address. 237 func networkAddresses(addrs []address) []network.Address { 238 netAddrs := make([]network.Address, len(addrs)) 239 for i, addr := range addrs { 240 netAddrs[i] = addr.networkAddress() 241 } 242 return netAddrs 243 } 244 245 // hostPort associates an address with a port. See also network.HostPort, 246 // from/to which this is transformed. 247 // 248 // TODO(dimitern) Make sure we integrate this with other networking 249 // stuff at some point. We want to use juju-specific network names 250 // that point to existing documents in the networks collection. 251 type hostPort struct { 252 Value string `bson:"value"` 253 AddressType string `bson:"addresstype"` 254 Scope string `bson:"networkscope,omitempty"` 255 Port int `bson:"port"` 256 SpaceName string `bson:"spacename,omitempty"` 257 } 258 259 // fromNetworkHostPort is a convenience helper to create a state type 260 // out of the network type, here for HostPort. 261 func fromNetworkHostPort(netHostPort network.HostPort) hostPort { 262 return hostPort{ 263 Value: netHostPort.Value, 264 AddressType: string(netHostPort.Type), 265 Scope: string(netHostPort.Scope), 266 Port: netHostPort.Port, 267 SpaceName: string(netHostPort.SpaceName), 268 } 269 } 270 271 // networkHostPort is a convenience helper to return the state type 272 // as network type, here for HostPort. 273 func (hp *hostPort) networkHostPort() network.HostPort { 274 return network.HostPort{ 275 Address: network.Address{ 276 Value: hp.Value, 277 Type: network.AddressType(hp.AddressType), 278 Scope: network.Scope(hp.Scope), 279 SpaceName: network.SpaceName(hp.SpaceName), 280 }, 281 Port: hp.Port, 282 } 283 } 284 285 // fromNetworkHostsPorts is a helper to create a state type 286 // out of the network type, here for a nested slice of HostPort. 287 func fromNetworkHostsPorts(netHostsPorts [][]network.HostPort) [][]hostPort { 288 hsps := make([][]hostPort, len(netHostsPorts)) 289 for i, netHostPorts := range netHostsPorts { 290 hsps[i] = make([]hostPort, len(netHostPorts)) 291 for j, netHostPort := range netHostPorts { 292 hsps[i][j] = fromNetworkHostPort(netHostPort) 293 } 294 } 295 return hsps 296 } 297 298 // networkHostsPorts is a convenience helper to return the state type 299 // as network type, here for a nested slice of HostPort. 300 func networkHostsPorts(hsps [][]hostPort) [][]network.HostPort { 301 netHostsPorts := make([][]network.HostPort, len(hsps)) 302 for i, hps := range hsps { 303 netHostsPorts[i] = make([]network.HostPort, len(hps)) 304 for j, hp := range hps { 305 netHostsPorts[i][j] = hp.networkHostPort() 306 } 307 } 308 return netHostsPorts 309 } 310 311 // addressEqual checks that two slices of network addresses are equal. 312 func addressesEqual(a, b []network.Address) bool { 313 return reflect.DeepEqual(a, b) 314 } 315 316 // hostsPortsEqual checks that two arrays of network hostports are equal. 317 func hostsPortsEqual(a, b [][]network.HostPort) bool { 318 return reflect.DeepEqual(a, b) 319 }