github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/provider/common/state.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "errors" 8 "fmt" 9 10 "github.com/juju/juju/environs" 11 "github.com/juju/juju/environs/bootstrap" 12 "github.com/juju/juju/environs/config" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/mongo" 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/state/api" 17 ) 18 19 // getAddresses queries and returns the Addresses for the given instances, 20 // ignoring nil instances or ones without addresses. 21 func getAddresses(instances []instance.Instance) []string { 22 names := make([]string, 0) 23 for _, inst := range instances { 24 if inst == nil { 25 continue 26 } 27 addrs, err := inst.Addresses() 28 if err != nil { 29 logger.Debugf( 30 "failed to get addresses for %v: %v (ignoring)", 31 inst.Id(), err, 32 ) 33 continue 34 } 35 for _, addr := range addrs { 36 names = append(names, addr.Value) 37 } 38 } 39 return names 40 } 41 42 // composeAddresses suffixes each of a slice of hostnames with a given port 43 // number. 44 func composeAddresses(hostnames []string, port int) []string { 45 addresses := make([]string, len(hostnames)) 46 for index, hostname := range hostnames { 47 addresses[index] = fmt.Sprintf("%s:%d", hostname, port) 48 } 49 return addresses 50 } 51 52 // getStateInfo puts together the state.Info and api.Info for the given 53 // config, with the given state-server host names. 54 // The given config absolutely must have a CACert. 55 func getStateInfo(config *config.Config, hostnames []string) (*state.Info, *api.Info) { 56 cert, hasCert := config.CACert() 57 if !hasCert { 58 panic(errors.New("getStateInfo: config has no CACert")) 59 } 60 return &state.Info{ 61 Info: mongo.Info{ 62 Addrs: composeAddresses(hostnames, config.StatePort()), 63 CACert: cert, 64 }, 65 }, &api.Info{ 66 Addrs: composeAddresses(hostnames, config.APIPort()), 67 CACert: cert, 68 } 69 } 70 71 // StateInfo is a reusable implementation of Environ.StateInfo, available to 72 // providers that also use the other functionality from this file. 73 func StateInfo(env environs.Environ) (*state.Info, *api.Info, error) { 74 st, err := bootstrap.LoadState(env.Storage()) 75 if err != nil { 76 return nil, nil, err 77 } 78 config := env.Config() 79 if _, hasCert := config.CACert(); !hasCert { 80 return nil, nil, fmt.Errorf("no CA certificate in environment configuration") 81 } 82 // Wait for the addresses of at least one of the instances to become available. 83 logger.Debugf("waiting for addresses of state server instances %v", st.StateInstances) 84 var addresses []string 85 for a := LongAttempt.Start(); len(addresses) == 0 && a.Next(); { 86 insts, err := env.Instances(st.StateInstances) 87 if err != nil && err != environs.ErrPartialInstances { 88 logger.Debugf("error getting state instances: %v", err.Error()) 89 return nil, nil, err 90 } 91 addresses = getAddresses(insts) 92 } 93 94 if len(addresses) == 0 { 95 return nil, nil, fmt.Errorf("timed out waiting for addresses from %v", st.StateInstances) 96 } 97 98 stateInfo, apiInfo := getStateInfo(config, addresses) 99 return stateInfo, apiInfo, nil 100 }