github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/gce/environ_availzones.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package gce 5 6 import ( 7 "github.com/juju/errors" 8 9 "github.com/juju/juju/environs" 10 "github.com/juju/juju/instance" 11 "github.com/juju/juju/provider/common" 12 "github.com/juju/juju/provider/gce/google" 13 ) 14 15 // AvailabilityZones returns all availability zones in the environment. 16 func (env *environ) AvailabilityZones() ([]common.AvailabilityZone, error) { 17 zones, err := env.gce.AvailabilityZones(env.cloud.Region) 18 if err != nil { 19 return nil, errors.Trace(err) 20 } 21 22 var result []common.AvailabilityZone 23 for _, zone := range zones { 24 if zone.Deprecated() { 25 continue 26 } 27 // We make a copy since the loop var keeps the same pointer. 28 zoneCopy := zone 29 result = append(result, &zoneCopy) 30 } 31 return result, nil 32 } 33 34 // InstanceAvailabilityZoneNames returns the names of the availability 35 // zones for the specified instances. The error returned follows the same 36 // rules as Environ.Instances. 37 func (env *environ) InstanceAvailabilityZoneNames(ids []instance.Id) ([]string, error) { 38 instances, err := env.Instances(ids) 39 if err != nil && err != environs.ErrPartialInstances && err != environs.ErrNoInstances { 40 return nil, errors.Trace(err) 41 } 42 // We let the two environs errors pass on through. However, we do 43 // not use errors.Trace in that case since callers may not call 44 // errors.Cause. 45 46 results := make([]string, len(ids)) 47 for i, inst := range instances { 48 if eInst := inst.(*environInstance); eInst != nil { 49 results[i] = eInst.base.ZoneName 50 } 51 } 52 53 return results, err 54 } 55 56 func (env *environ) availZone(name string) (*google.AvailabilityZone, error) { 57 zones, err := env.gce.AvailabilityZones(env.cloud.Region) 58 if err != nil { 59 return nil, errors.Trace(err) 60 } 61 for _, z := range zones { 62 if z.Name() == name { 63 return &z, nil 64 } 65 } 66 return nil, errors.NotFoundf("invalid availability zone %q", name) 67 } 68 69 func (env *environ) availZoneUp(name string) (*google.AvailabilityZone, error) { 70 zone, err := env.availZone(name) 71 if err != nil { 72 return nil, errors.Trace(err) 73 } 74 if !zone.Available() { 75 return nil, errors.Errorf("availability zone %q is %s", zone.Name(), zone.Status()) 76 } 77 return zone, nil 78 } 79 80 var availabilityZoneAllocations = common.AvailabilityZoneAllocations 81 82 // parseAvailabilityZones returns the availability zones that should be 83 // tried for the given instance spec. If a placement argument was 84 // provided then only that one is returned. Otherwise the environment is 85 // queried for available zones. In that case, the resulting list is 86 // roughly ordered such that the environment's instances are spread 87 // evenly across the region. 88 func (env *environ) parseAvailabilityZones(args environs.StartInstanceParams) ([]string, error) { 89 if args.Placement != "" { 90 // args.Placement will always be a zone name or empty. 91 placement, err := env.parsePlacement(args.Placement) 92 if err != nil { 93 return nil, errors.Trace(err) 94 } 95 // TODO(ericsnow) Fail if placement.Zone is not in the env's configured region? 96 return []string{placement.Zone.Name()}, nil 97 } 98 99 // If no availability zone is specified, then automatically spread across 100 // the known zones for optimal spread across the instance distribution 101 // group. 102 var group []instance.Id 103 var err error 104 if args.DistributionGroup != nil { 105 group, err = args.DistributionGroup() 106 if err != nil { 107 return nil, errors.Trace(err) 108 } 109 } 110 zoneInstances, err := availabilityZoneAllocations(env, group) 111 if err != nil { 112 return nil, errors.Trace(err) 113 } 114 logger.Infof("found %d zones: %v", len(zoneInstances), zoneInstances) 115 116 var zoneNames []string 117 for _, z := range zoneInstances { 118 zoneNames = append(zoneNames, z.ZoneName) 119 } 120 121 if len(zoneNames) == 0 { 122 return nil, errors.NotFoundf("failed to determine availability zones") 123 } 124 125 return zoneNames, nil 126 }