/
environ_availzones.go
126 lines (110 loc) · 3.76 KB
/
environ_availzones.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package gce
import (
"github.com/juju/errors"
"github.com/juju/juju/environs"
"github.com/juju/juju/instance"
"github.com/juju/juju/provider/common"
"github.com/juju/juju/provider/gce/google"
)
// AvailabilityZones returns all availability zones in the environment.
func (env *environ) AvailabilityZones() ([]common.AvailabilityZone, error) {
zones, err := env.gce.AvailabilityZones(env.ecfg.region())
if err != nil {
return nil, errors.Trace(err)
}
var result []common.AvailabilityZone
for _, zone := range zones {
if zone.Deprecated() {
continue
}
// We make a copy since the loop var keeps the same pointer.
zoneCopy := zone
result = append(result, &zoneCopy)
}
return result, nil
}
// InstanceAvailabilityZoneNames returns the names of the availability
// zones for the specified instances. The error returned follows the same
// rules as Environ.Instances.
func (env *environ) InstanceAvailabilityZoneNames(ids []instance.Id) ([]string, error) {
instances, err := env.Instances(ids)
if err != nil && err != environs.ErrPartialInstances && err != environs.ErrNoInstances {
return nil, errors.Trace(err)
}
// We let the two environs errors pass on through. However, we do
// not use errors.Trace in that case since callers may not call
// errors.Cause.
results := make([]string, len(ids))
for i, inst := range instances {
if eInst := inst.(*environInstance); eInst != nil {
results[i] = eInst.base.ZoneName
}
}
return results, err
}
func (env *environ) availZone(name string) (*google.AvailabilityZone, error) {
zones, err := env.gce.AvailabilityZones(env.ecfg.region())
if err != nil {
return nil, errors.Trace(err)
}
for _, z := range zones {
if z.Name() == name {
return &z, nil
}
}
return nil, errors.NotFoundf("invalid availability zone %q", name)
}
func (env *environ) availZoneUp(name string) (*google.AvailabilityZone, error) {
zone, err := env.availZone(name)
if err != nil {
return nil, errors.Trace(err)
}
if !zone.Available() {
return nil, errors.Errorf("availability zone %q is %s", zone.Name(), zone.Status())
}
return zone, nil
}
var availabilityZoneAllocations = common.AvailabilityZoneAllocations
// parseAvailabilityZones returns the availability zones that should be
// tried for the given instance spec. If a placement argument was
// provided then only that one is returned. Otherwise the environment is
// queried for available zones. In that case, the resulting list is
// roughly ordered such that the environment's instances are spread
// evenly across the region.
func (env *environ) parseAvailabilityZones(args environs.StartInstanceParams) ([]string, error) {
if args.Placement != "" {
// args.Placement will always be a zone name or empty.
placement, err := env.parsePlacement(args.Placement)
if err != nil {
return nil, errors.Trace(err)
}
// TODO(ericsnow) Fail if placement.Zone is not in the env's configured region?
return []string{placement.Zone.Name()}, nil
}
// If no availability zone is specified, then automatically spread across
// the known zones for optimal spread across the instance distribution
// group.
var group []instance.Id
var err error
if args.DistributionGroup != nil {
group, err = args.DistributionGroup()
if err != nil {
return nil, errors.Trace(err)
}
}
zoneInstances, err := availabilityZoneAllocations(env, group)
if err != nil {
return nil, errors.Trace(err)
}
logger.Infof("found %d zones: %v", len(zoneInstances), zoneInstances)
var zoneNames []string
for _, z := range zoneInstances {
zoneNames = append(zoneNames, z.ZoneName)
}
if len(zoneNames) == 0 {
return nil, errors.NotFoundf("failed to determine availability zones")
}
return zoneNames, nil
}