github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/environs/utils.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package environs 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/api" 14 "github.com/juju/juju/instance" 15 "github.com/juju/juju/network" 16 ) 17 18 // AddressesRefreshAttempt is the attempt strategy used when 19 // refreshing instance addresses. 20 var AddressesRefreshAttempt = utils.AttemptStrategy{ 21 Total: 3 * time.Minute, 22 Delay: 1 * time.Second, 23 } 24 25 // getAddresses queries and returns the Addresses for the given instances, 26 // ignoring nil instances or ones without addresses. 27 func getAddresses(instances []instance.Instance) []network.Address { 28 var allAddrs []network.Address 29 for _, inst := range instances { 30 if inst == nil { 31 continue 32 } 33 addrs, err := inst.Addresses() 34 if err != nil { 35 logger.Debugf( 36 "failed to get addresses for %v: %v (ignoring)", 37 inst.Id(), err, 38 ) 39 continue 40 } 41 allAddrs = append(allAddrs, addrs...) 42 } 43 return allAddrs 44 } 45 46 // waitAnyInstanceAddresses waits for at least one of the instances 47 // to have addresses, and returns them. 48 func waitAnyInstanceAddresses( 49 env Environ, 50 instanceIds []instance.Id, 51 ) ([]network.Address, error) { 52 var addrs []network.Address 53 for a := AddressesRefreshAttempt.Start(); len(addrs) == 0 && a.Next(); { 54 instances, err := env.Instances(instanceIds) 55 if err != nil && err != ErrPartialInstances { 56 logger.Debugf("error getting state instances: %v", err) 57 return nil, err 58 } 59 addrs = getAddresses(instances) 60 } 61 if len(addrs) == 0 { 62 return nil, errors.NotFoundf("addresses for %v", instanceIds) 63 } 64 return addrs, nil 65 } 66 67 // APIInfo returns an api.Info for the environment. The result is populated 68 // with addresses and CA certificate, but no tag or password. 69 func APIInfo(controllerUUID, modelUUID, caCert string, apiPort int, env Environ) (*api.Info, error) { 70 instanceIds, err := env.ControllerInstances(controllerUUID) 71 if err != nil { 72 return nil, err 73 } 74 logger.Debugf("ControllerInstances returned: %v", instanceIds) 75 addrs, err := waitAnyInstanceAddresses(env, instanceIds) 76 if err != nil { 77 return nil, err 78 } 79 apiAddrs := network.HostPortsToStrings( 80 network.AddressesWithPort(addrs, apiPort), 81 ) 82 modelTag := names.NewModelTag(modelUUID) 83 apiInfo := &api.Info{Addrs: apiAddrs, CACert: caCert, ModelTag: modelTag} 84 return apiInfo, nil 85 } 86 87 // CheckProviderAPI returns an error if a simple API call 88 // to check a basic response from the specified environ fails. 89 func CheckProviderAPI(env Environ) error { 90 // We will make a simple API call to the provider 91 // to ensure the underlying substrate is ok. 92 _, err := env.AllInstances() 93 switch err { 94 case nil, ErrPartialInstances, ErrNoInstances: 95 return nil 96 } 97 return errors.Annotate(err, "cannot make API call to provider") 98 }