github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/environs/utils.go (about) 1 package environs 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 "github.com/juju/utils" 10 11 "github.com/juju/juju/api" 12 "github.com/juju/juju/environs/storage" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/network" 15 "github.com/juju/juju/state" 16 ) 17 18 // LegacyStorage creates an Environ from the config in state and returns 19 // its provider storage interface if it supports one. If the environment 20 // does not support provider storage, then it will return an error 21 // satisfying errors.IsNotSupported. 22 func LegacyStorage(st *state.State) (storage.Storage, error) { 23 envConfig, err := st.EnvironConfig() 24 if err != nil { 25 return nil, fmt.Errorf("cannot get environment config: %v", err) 26 } 27 env, err := New(envConfig) 28 if err != nil { 29 return nil, fmt.Errorf("cannot access environment: %v", err) 30 } 31 if env, ok := env.(EnvironStorage); ok { 32 return env.Storage(), nil 33 } 34 errmsg := fmt.Sprintf("%s provider does not support provider storage", envConfig.Type()) 35 return nil, errors.NewNotSupported(nil, errmsg) 36 } 37 38 // AddressesRefreshAttempt is the attempt strategy used when 39 // refreshing instance addresses. 40 var AddressesRefreshAttempt = utils.AttemptStrategy{ 41 Total: 3 * time.Minute, 42 Delay: 1 * time.Second, 43 } 44 45 // getAddresses queries and returns the Addresses for the given instances, 46 // ignoring nil instances or ones without addresses. 47 func getAddresses(instances []instance.Instance) []network.Address { 48 var allAddrs []network.Address 49 for _, inst := range instances { 50 if inst == nil { 51 continue 52 } 53 addrs, err := inst.Addresses() 54 if err != nil { 55 logger.Debugf( 56 "failed to get addresses for %v: %v (ignoring)", 57 inst.Id(), err, 58 ) 59 continue 60 } 61 allAddrs = append(allAddrs, addrs...) 62 } 63 return allAddrs 64 } 65 66 // waitAnyInstanceAddresses waits for at least one of the instances 67 // to have addresses, and returns them. 68 func waitAnyInstanceAddresses( 69 env Environ, 70 instanceIds []instance.Id, 71 ) ([]network.Address, error) { 72 var addrs []network.Address 73 for a := AddressesRefreshAttempt.Start(); len(addrs) == 0 && a.Next(); { 74 instances, err := env.Instances(instanceIds) 75 if err != nil && err != ErrPartialInstances { 76 logger.Debugf("error getting state instances: %v", err) 77 return nil, err 78 } 79 addrs = getAddresses(instances) 80 } 81 if len(addrs) == 0 { 82 return nil, errors.NotFoundf("addresses for %v", instanceIds) 83 } 84 return addrs, nil 85 } 86 87 // APIInfo returns an api.Info for the environment. The result is populated 88 // with addresses and CA certificate, but no tag or password. 89 func APIInfo(env Environ) (*api.Info, error) { 90 instanceIds, err := env.StateServerInstances() 91 if err != nil { 92 return nil, err 93 } 94 logger.Debugf("StateServerInstances returned: %v", instanceIds) 95 addrs, err := waitAnyInstanceAddresses(env, instanceIds) 96 if err != nil { 97 return nil, err 98 } 99 config := env.Config() 100 cert, hasCert := config.CACert() 101 if !hasCert { 102 return nil, errors.New("config has no CACert") 103 } 104 apiPort := config.APIPort() 105 apiAddrs := network.HostPortsToStrings( 106 network.AddressesWithPort(addrs, apiPort), 107 ) 108 uuid, uuidSet := config.UUID() 109 if !uuidSet { 110 return nil, errors.New("config has no UUID") 111 } 112 envTag := names.NewEnvironTag(uuid) 113 apiInfo := &api.Info{Addrs: apiAddrs, CACert: cert, EnvironTag: envTag} 114 return apiInfo, nil 115 }