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  }