github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/provider/vsphere/environ_availzones.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build !gccgo
     5  
     6  package vsphere
     7  
     8  import (
     9  	"github.com/juju/errors"
    10  	"github.com/juju/govmomi/vim25/mo"
    11  
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/instance"
    14  	"github.com/juju/juju/provider/common"
    15  )
    16  
    17  type vmwareAvailZone struct {
    18  	r mo.ComputeResource
    19  }
    20  
    21  // Name implements common.AvailabilityZone
    22  func (z *vmwareAvailZone) Name() string {
    23  	return z.r.Name
    24  }
    25  
    26  // Available implements common.AvailabilityZone
    27  func (z *vmwareAvailZone) Available() bool {
    28  	return true
    29  }
    30  
    31  // AvailabilityZones returns all availability zones in the environment.
    32  func (env *environ) AvailabilityZones() ([]common.AvailabilityZone, error) {
    33  	zones, err := env.client.AvailabilityZones()
    34  	if err != nil {
    35  		return nil, errors.Trace(err)
    36  	}
    37  
    38  	var result []common.AvailabilityZone
    39  	for _, zone := range zones {
    40  		result = append(result, &vmwareAvailZone{*zone})
    41  	}
    42  	return result, nil
    43  }
    44  
    45  // InstanceAvailabilityZoneNames returns the names of the availability
    46  // zones for the specified instances. The error returned follows the same
    47  // rules as Environ.Instances.
    48  func (env *environ) InstanceAvailabilityZoneNames(ids []instance.Id) ([]string, error) {
    49  	instances, err := env.Instances(ids)
    50  	if err != nil && err != environs.ErrPartialInstances && err != environs.ErrNoInstances {
    51  		return nil, errors.Trace(err)
    52  	}
    53  
    54  	zones, err := env.client.AvailabilityZones()
    55  	if err != nil {
    56  		return nil, errors.Trace(err)
    57  	}
    58  	results := make([]string, 0, len(ids))
    59  	for _, inst := range instances {
    60  		for _, zone := range zones {
    61  			if eInst := inst.(*environInstance); eInst != nil && zone.ResourcePool.Value == eInst.base.ResourcePool.Value {
    62  				results = append(results, zone.Name)
    63  				break
    64  			}
    65  		}
    66  	}
    67  
    68  	return results, err
    69  }
    70  
    71  func (env *environ) availZone(name string) (*vmwareAvailZone, error) {
    72  	zones, err := env.client.AvailabilityZones()
    73  	if err != nil {
    74  		return nil, errors.Trace(err)
    75  	}
    76  	for _, z := range zones {
    77  		if z.Name == name {
    78  			return &vmwareAvailZone{*z}, nil
    79  		}
    80  	}
    81  	return nil, errors.NotFoundf("invalid availability zone %q", name)
    82  }
    83  
    84  //this variable is exported, because it has to be rewritten in external unit tests
    85  var AvailabilityZoneAllocations = common.AvailabilityZoneAllocations
    86  
    87  // parseAvailabilityZones returns the availability zones that should be
    88  // tried for the given instance spec. If a placement argument was
    89  // provided then only that one is returned. Otherwise the environment is
    90  // queried for available zones. In that case, the resulting list is
    91  // roughly ordered such that the environment's instances are spread
    92  // evenly across the region.
    93  func (env *environ) parseAvailabilityZones(args environs.StartInstanceParams) ([]string, error) {
    94  	if args.Placement != "" {
    95  		// args.Placement will always be a zone name or empty.
    96  		placement, err := env.parsePlacement(args.Placement)
    97  		if err != nil {
    98  			return nil, errors.Trace(err)
    99  		}
   100  		return []string{placement.Name()}, nil
   101  	}
   102  
   103  	// If no availability zone is specified, then automatically spread across
   104  	// the known zones for optimal spread across the instance distribution
   105  	// group.
   106  	var group []instance.Id
   107  	var err error
   108  	if args.DistributionGroup != nil {
   109  		group, err = args.DistributionGroup()
   110  		if err != nil {
   111  			return nil, errors.Trace(err)
   112  		}
   113  	}
   114  	zoneInstances, err := AvailabilityZoneAllocations(env, group)
   115  	if err != nil {
   116  		return nil, errors.Trace(err)
   117  	}
   118  	logger.Infof("found %d zones: %v", len(zoneInstances), zoneInstances)
   119  
   120  	var zoneNames []string
   121  	for _, z := range zoneInstances {
   122  		zoneNames = append(zoneNames, z.ZoneName)
   123  	}
   124  
   125  	if len(zoneNames) == 0 {
   126  		return nil, errors.NotFoundf("failed to determine availability zones")
   127  	}
   128  
   129  	return zoneNames, nil
   130  }