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