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

     1  // Copyright 2011-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  	"math/rand"
     9  	"net"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/juju/errors"
    15  	"github.com/juju/retry"
    16  	"github.com/juju/utils"
    17  	"github.com/juju/utils/clock"
    18  	"gopkg.in/amz.v3/aws"
    19  	"gopkg.in/amz.v3/ec2"
    20  	"gopkg.in/juju/names.v2"
    21  
    22  	"github.com/juju/juju/cloudconfig/instancecfg"
    23  	"github.com/juju/juju/cloudconfig/providerinit"
    24  	"github.com/juju/juju/constraints"
    25  	"github.com/juju/juju/environs"
    26  	"github.com/juju/juju/environs/config"
    27  	"github.com/juju/juju/environs/instances"
    28  	"github.com/juju/juju/environs/simplestreams"
    29  	"github.com/juju/juju/environs/tags"
    30  	"github.com/juju/juju/instance"
    31  	"github.com/juju/juju/network"
    32  	"github.com/juju/juju/provider/common"
    33  	"github.com/juju/juju/provider/ec2/internal/ec2instancetypes"
    34  	"github.com/juju/juju/tools"
    35  )
    36  
    37  const (
    38  	invalidParameterValue = "InvalidParameterValue"
    39  
    40  	// tagName is the AWS-specific tag key that populates resources'
    41  	// name columns in the console.
    42  	tagName = "Name"
    43  )
    44  
    45  var (
    46  	// Use shortAttempt to poll for short-term events or for retrying API calls.
    47  	// TODO(katco): 2016-08-09: lp:1611427
    48  	shortAttempt = utils.AttemptStrategy{
    49  		Total: 5 * time.Second,
    50  		Delay: 200 * time.Millisecond,
    51  	}
    52  
    53  	// aliveInstanceStates are the states which we filter by when listing
    54  	// instances in an environment.
    55  	aliveInstanceStates = []string{"pending", "running"}
    56  )
    57  
    58  type environ struct {
    59  	name  string
    60  	cloud environs.CloudSpec
    61  	ec2   *ec2.EC2
    62  
    63  	// ecfgMutex protects the *Unlocked fields below.
    64  	ecfgMutex    sync.Mutex
    65  	ecfgUnlocked *environConfig
    66  
    67  	availabilityZonesMutex sync.Mutex
    68  	availabilityZones      []common.AvailabilityZone
    69  
    70  	defaultVPCMutex   sync.Mutex
    71  	defaultVPCChecked bool
    72  	defaultVPC        *ec2.VPC
    73  }
    74  
    75  func (e *environ) Config() *config.Config {
    76  	return e.ecfg().Config
    77  }
    78  
    79  func (e *environ) SetConfig(cfg *config.Config) error {
    80  	ecfg, err := providerInstance.newConfig(cfg)
    81  	if err != nil {
    82  		return errors.Trace(err)
    83  	}
    84  	e.ecfgMutex.Lock()
    85  	e.ecfgUnlocked = ecfg
    86  	e.ecfgMutex.Unlock()
    87  	return nil
    88  }
    89  
    90  func (e *environ) ecfg() *environConfig {
    91  	e.ecfgMutex.Lock()
    92  	ecfg := e.ecfgUnlocked
    93  	e.ecfgMutex.Unlock()
    94  	return ecfg
    95  }
    96  
    97  func (e *environ) Name() string {
    98  	return e.name
    99  }
   100  
   101  // PrepareForBootstrap is part of the Environ interface.
   102  func (env *environ) PrepareForBootstrap(ctx environs.BootstrapContext) error {
   103  	if ctx.ShouldVerifyCredentials() {
   104  		if err := verifyCredentials(env); err != nil {
   105  			return err
   106  		}
   107  	}
   108  	ecfg := env.ecfg()
   109  	vpcID, forceVPCID := ecfg.vpcID(), ecfg.forceVPCID()
   110  	if err := validateBootstrapVPC(env.ec2, env.cloud.Region, vpcID, forceVPCID, ctx); err != nil {
   111  		return errors.Trace(err)
   112  	}
   113  	return nil
   114  }
   115  
   116  // Create is part of the Environ interface.
   117  func (env *environ) Create(args environs.CreateParams) error {
   118  	if err := verifyCredentials(env); err != nil {
   119  		return err
   120  	}
   121  	vpcID := env.ecfg().vpcID()
   122  	if err := validateModelVPC(env.ec2, env.name, vpcID); err != nil {
   123  		return errors.Trace(err)
   124  	}
   125  	// TODO(axw) 2016-08-04 #1609643
   126  	// Create global security group(s) here.
   127  	return nil
   128  }
   129  
   130  // Bootstrap is part of the Environ interface.
   131  func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) {
   132  	return common.Bootstrap(ctx, e, args)
   133  }
   134  
   135  // BootstrapMessage is part of the Environ interface.
   136  func (e *environ) BootstrapMessage() string {
   137  	return ""
   138  }
   139  
   140  // SupportsSpaces is specified on environs.Networking.
   141  func (e *environ) SupportsSpaces() (bool, error) {
   142  	return true, nil
   143  }
   144  
   145  // SupportsSpaceDiscovery is specified on environs.Networking.
   146  func (e *environ) SupportsSpaceDiscovery() (bool, error) {
   147  	return false, nil
   148  }
   149  
   150  var unsupportedConstraints = []string{
   151  	constraints.Tags,
   152  	// TODO(anastasiamac 2016-03-16) LP#1557874
   153  	// use virt-type in StartInstances
   154  	constraints.VirtType,
   155  }
   156  
   157  // ConstraintsValidator is defined on the Environs interface.
   158  func (e *environ) ConstraintsValidator() (constraints.Validator, error) {
   159  	validator := constraints.NewValidator()
   160  	validator.RegisterConflicts(
   161  		[]string{constraints.InstanceType},
   162  		[]string{constraints.Mem, constraints.Cores, constraints.CpuPower})
   163  	validator.RegisterUnsupported(unsupportedConstraints)
   164  	instanceTypes, err := e.supportedInstanceTypes()
   165  	if err != nil {
   166  		return nil, errors.Trace(err)
   167  	}
   168  	instTypeNames := make([]string, len(instanceTypes))
   169  	for i, itype := range instanceTypes {
   170  		instTypeNames[i] = itype.Name
   171  	}
   172  	validator.RegisterVocabulary(constraints.InstanceType, instTypeNames)
   173  	return validator, nil
   174  }
   175  
   176  func archMatches(arches []string, arch *string) bool {
   177  	if arch == nil {
   178  		return true
   179  	}
   180  	for _, a := range arches {
   181  		if a == *arch {
   182  			return true
   183  		}
   184  	}
   185  	return false
   186  }
   187  
   188  var ec2AvailabilityZones = (*ec2.EC2).AvailabilityZones
   189  
   190  type ec2AvailabilityZone struct {
   191  	ec2.AvailabilityZoneInfo
   192  }
   193  
   194  func (z *ec2AvailabilityZone) Name() string {
   195  	return z.AvailabilityZoneInfo.Name
   196  }
   197  
   198  func (z *ec2AvailabilityZone) Available() bool {
   199  	return z.AvailabilityZoneInfo.State == availableState
   200  }
   201  
   202  // AvailabilityZones returns a slice of availability zones
   203  // for the configured region.
   204  func (e *environ) AvailabilityZones() ([]common.AvailabilityZone, error) {
   205  	e.availabilityZonesMutex.Lock()
   206  	defer e.availabilityZonesMutex.Unlock()
   207  	if e.availabilityZones == nil {
   208  		filter := ec2.NewFilter()
   209  		filter.Add("region-name", e.cloud.Region)
   210  		resp, err := ec2AvailabilityZones(e.ec2, filter)
   211  		if err != nil {
   212  			return nil, err
   213  		}
   214  		logger.Debugf("availability zones: %+v", resp)
   215  		e.availabilityZones = make([]common.AvailabilityZone, len(resp.Zones))
   216  		for i, z := range resp.Zones {
   217  			e.availabilityZones[i] = &ec2AvailabilityZone{z}
   218  		}
   219  	}
   220  	return e.availabilityZones, nil
   221  }
   222  
   223  // InstanceAvailabilityZoneNames returns the availability zone names for each
   224  // of the specified instances.
   225  func (e *environ) InstanceAvailabilityZoneNames(ids []instance.Id) ([]string, error) {
   226  	instances, err := e.Instances(ids)
   227  	if err != nil && err != environs.ErrPartialInstances {
   228  		return nil, err
   229  	}
   230  	zones := make([]string, len(instances))
   231  	for i, inst := range instances {
   232  		if inst == nil {
   233  			continue
   234  		}
   235  		zones[i] = inst.(*ec2Instance).AvailZone
   236  	}
   237  	return zones, err
   238  }
   239  
   240  type ec2Placement struct {
   241  	availabilityZone ec2.AvailabilityZoneInfo
   242  }
   243  
   244  func (e *environ) parsePlacement(placement string) (*ec2Placement, error) {
   245  	pos := strings.IndexRune(placement, '=')
   246  	if pos == -1 {
   247  		return nil, fmt.Errorf("unknown placement directive: %v", placement)
   248  	}
   249  	switch key, value := placement[:pos], placement[pos+1:]; key {
   250  	case "zone":
   251  		availabilityZone := value
   252  		zones, err := e.AvailabilityZones()
   253  		if err != nil {
   254  			return nil, err
   255  		}
   256  		for _, z := range zones {
   257  			if z.Name() == availabilityZone {
   258  				return &ec2Placement{
   259  					z.(*ec2AvailabilityZone).AvailabilityZoneInfo,
   260  				}, nil
   261  			}
   262  		}
   263  		return nil, fmt.Errorf("invalid availability zone %q", availabilityZone)
   264  	}
   265  	return nil, fmt.Errorf("unknown placement directive: %v", placement)
   266  }
   267  
   268  // PrecheckInstance is defined on the state.Prechecker interface.
   269  func (e *environ) PrecheckInstance(series string, cons constraints.Value, placement string) error {
   270  	if placement != "" {
   271  		if _, err := e.parsePlacement(placement); err != nil {
   272  			return err
   273  		}
   274  	}
   275  	if !cons.HasInstanceType() {
   276  		return nil
   277  	}
   278  	// Constraint has an instance-type constraint so let's see if it is valid.
   279  	instanceTypes, err := e.supportedInstanceTypes()
   280  	if err != nil {
   281  		return errors.Trace(err)
   282  	}
   283  	for _, itype := range instanceTypes {
   284  		if itype.Name != *cons.InstanceType {
   285  			continue
   286  		}
   287  		if archMatches(itype.Arches, cons.Arch) {
   288  			return nil
   289  		}
   290  	}
   291  	if cons.Arch == nil {
   292  		return fmt.Errorf("invalid AWS instance type %q specified", *cons.InstanceType)
   293  	}
   294  	return fmt.Errorf("invalid AWS instance type %q and arch %q specified", *cons.InstanceType, *cons.Arch)
   295  }
   296  
   297  // MetadataLookupParams returns parameters which are used to query simplestreams metadata.
   298  func (e *environ) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
   299  	var endpoint string
   300  	if region == "" {
   301  		region = e.cloud.Region
   302  		endpoint = e.cloud.Endpoint
   303  	} else {
   304  		// TODO(axw) 2016-10-04 #1630089
   305  		// MetadataLookupParams needs to be updated so that providers
   306  		// are not expected to know how to map regions to endpoints.
   307  		ec2Region, ok := aws.Regions[region]
   308  		if !ok {
   309  			return nil, errors.Errorf("unknown region %q", region)
   310  		}
   311  		endpoint = ec2Region.EC2Endpoint
   312  	}
   313  	return &simplestreams.MetadataLookupParams{
   314  		Series:   config.PreferredSeries(e.ecfg()),
   315  		Region:   region,
   316  		Endpoint: endpoint,
   317  	}, nil
   318  }
   319  
   320  // Region is specified in the HasRegion interface.
   321  func (e *environ) Region() (simplestreams.CloudSpec, error) {
   322  	return simplestreams.CloudSpec{
   323  		Region:   e.cloud.Region,
   324  		Endpoint: e.cloud.Endpoint,
   325  	}, nil
   326  }
   327  
   328  const (
   329  	ebsStorage = "ebs"
   330  	ssdStorage = "ssd"
   331  )
   332  
   333  // DistributeInstances implements the state.InstanceDistributor policy.
   334  func (e *environ) DistributeInstances(candidates, distributionGroup []instance.Id) ([]instance.Id, error) {
   335  	return common.DistributeInstances(e, candidates, distributionGroup)
   336  }
   337  
   338  var availabilityZoneAllocations = common.AvailabilityZoneAllocations
   339  
   340  // MaintainInstance is specified in the InstanceBroker interface.
   341  func (*environ) MaintainInstance(args environs.StartInstanceParams) error {
   342  	return nil
   343  }
   344  
   345  // resourceName returns the string to use for a resource's Name tag,
   346  // to help users identify Juju-managed resources in the AWS console.
   347  func resourceName(tag names.Tag, envName string) string {
   348  	return fmt.Sprintf("juju-%s-%s", envName, tag)
   349  }
   350  
   351  // StartInstance is specified in the InstanceBroker interface.
   352  func (e *environ) StartInstance(args environs.StartInstanceParams) (_ *environs.StartInstanceResult, resultErr error) {
   353  	if args.ControllerUUID == "" {
   354  		return nil, errors.New("missing controller UUID")
   355  	}
   356  	var inst *ec2Instance
   357  	defer func() {
   358  		if resultErr == nil || inst == nil {
   359  			return
   360  		}
   361  		if err := e.StopInstances(inst.Id()); err != nil {
   362  			logger.Errorf("error stopping failed instance: %v", err)
   363  		}
   364  	}()
   365  
   366  	var availabilityZones []string
   367  	if args.Placement != "" {
   368  		placement, err := e.parsePlacement(args.Placement)
   369  		if err != nil {
   370  			return nil, err
   371  		}
   372  		if placement.availabilityZone.State != availableState {
   373  			return nil, errors.Errorf("availability zone %q is %s", placement.availabilityZone.Name, placement.availabilityZone.State)
   374  		}
   375  		availabilityZones = append(availabilityZones, placement.availabilityZone.Name)
   376  	}
   377  
   378  	// If no availability zone is specified, then automatically spread across
   379  	// the known zones for optimal spread across the instance distribution
   380  	// group.
   381  	var zoneInstances []common.AvailabilityZoneInstances
   382  	if len(availabilityZones) == 0 {
   383  		var err error
   384  		var group []instance.Id
   385  		if args.DistributionGroup != nil {
   386  			group, err = args.DistributionGroup()
   387  			if err != nil {
   388  				return nil, err
   389  			}
   390  		}
   391  		zoneInstances, err = availabilityZoneAllocations(e, group)
   392  		if err != nil {
   393  			return nil, err
   394  		}
   395  		for _, z := range zoneInstances {
   396  			availabilityZones = append(availabilityZones, z.ZoneName)
   397  		}
   398  		if len(availabilityZones) == 0 {
   399  			return nil, errors.New("failed to determine availability zones")
   400  		}
   401  	}
   402  
   403  	arches := args.Tools.Arches()
   404  
   405  	instanceTypes, err := e.supportedInstanceTypes()
   406  	if err != nil {
   407  		return nil, errors.Trace(err)
   408  	}
   409  
   410  	spec, err := findInstanceSpec(
   411  		args.InstanceConfig.Controller != nil,
   412  		args.ImageMetadata,
   413  		instanceTypes,
   414  		&instances.InstanceConstraint{
   415  			Region:      e.cloud.Region,
   416  			Series:      args.InstanceConfig.Series,
   417  			Arches:      arches,
   418  			Constraints: args.Constraints,
   419  			Storage:     []string{ssdStorage, ebsStorage},
   420  		},
   421  	)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  	tools, err := args.Tools.Match(tools.Filter{Arch: spec.Image.Arch})
   426  	if err != nil {
   427  		return nil, errors.Errorf("chosen architecture %v not present in %v", spec.Image.Arch, arches)
   428  	}
   429  
   430  	if spec.InstanceType.Deprecated {
   431  		logger.Infof("deprecated instance type specified: %s", spec.InstanceType.Name)
   432  	}
   433  
   434  	if err := args.InstanceConfig.SetTools(tools); err != nil {
   435  		return nil, errors.Trace(err)
   436  	}
   437  	if err := instancecfg.FinishInstanceConfig(args.InstanceConfig, e.Config()); err != nil {
   438  		return nil, err
   439  	}
   440  
   441  	userData, err := providerinit.ComposeUserData(args.InstanceConfig, nil, AmazonRenderer{})
   442  	if err != nil {
   443  		return nil, errors.Annotate(err, "cannot make user data")
   444  	}
   445  	logger.Debugf("ec2 user data; %d bytes", len(userData))
   446  	var apiPort int
   447  	if args.InstanceConfig.Controller != nil {
   448  		apiPort = args.InstanceConfig.Controller.Config.APIPort()
   449  	} else {
   450  		apiPort = args.InstanceConfig.APIInfo.Ports()[0]
   451  	}
   452  	groups, err := e.setUpGroups(args.ControllerUUID, args.InstanceConfig.MachineId, apiPort)
   453  	if err != nil {
   454  		return nil, errors.Annotate(err, "cannot set up groups")
   455  	}
   456  
   457  	blockDeviceMappings := getBlockDeviceMappings(
   458  		args.Constraints,
   459  		args.InstanceConfig.Series,
   460  		args.InstanceConfig.Controller != nil,
   461  	)
   462  	rootDiskSize := uint64(blockDeviceMappings[0].VolumeSize) * 1024
   463  
   464  	// If --constraints spaces=foo was passed, the provisioner will populate
   465  	// args.SubnetsToZones map. In AWS a subnet can span only one zone, so here
   466  	// we build the reverse map zonesToSubnets, which we will use to below in
   467  	// the RunInstance loop to provide an explicit subnet ID, rather than just
   468  	// AZ. This ensures instances in the same group (units of a service or all
   469  	// instances when adding a machine manually) will still be evenly
   470  	// distributed across AZs, but only within subnets of the space constraint.
   471  	//
   472  	// TODO(dimitern): This should be done in a provider-independant way.
   473  	if spaces := args.Constraints.IncludeSpaces(); len(spaces) > 1 {
   474  		logger.Infof("ignoring all but the first positive space from constraints: %v", spaces)
   475  	}
   476  
   477  	var instResp *ec2.RunInstancesResp
   478  	commonRunArgs := &ec2.RunInstances{
   479  		MinCount:            1,
   480  		MaxCount:            1,
   481  		UserData:            userData,
   482  		InstanceType:        spec.InstanceType.Name,
   483  		SecurityGroups:      groups,
   484  		BlockDeviceMappings: blockDeviceMappings,
   485  		ImageId:             spec.Image.Id,
   486  	}
   487  
   488  	haveVPCID := isVPCIDSet(e.ecfg().vpcID())
   489  
   490  	for _, zone := range availabilityZones {
   491  		runArgs := commonRunArgs
   492  		runArgs.AvailZone = zone
   493  
   494  		var subnetIDsForZone []string
   495  		var subnetErr error
   496  		if haveVPCID {
   497  			var allowedSubnetIDs []string
   498  			for subnetID, _ := range args.SubnetsToZones {
   499  				allowedSubnetIDs = append(allowedSubnetIDs, string(subnetID))
   500  			}
   501  			subnetIDsForZone, subnetErr = getVPCSubnetIDsForAvailabilityZone(e.ec2, e.ecfg().vpcID(), zone, allowedSubnetIDs)
   502  		} else if args.Constraints.HaveSpaces() {
   503  			subnetIDsForZone, subnetErr = findSubnetIDsForAvailabilityZone(zone, args.SubnetsToZones)
   504  		}
   505  
   506  		switch {
   507  		case subnetErr != nil && errors.IsNotFound(subnetErr):
   508  			logger.Infof("no matching subnets in zone %q; assuming zone is constrained and trying another", zone)
   509  			continue
   510  		case subnetErr != nil:
   511  			return nil, errors.Annotatef(subnetErr, "getting subnets for zone %q", zone)
   512  		case len(subnetIDsForZone) > 1:
   513  			// With multiple equally suitable subnets, picking one at random
   514  			// will allow for better instance spread within the same zone, and
   515  			// still work correctly if we happen to pick a constrained subnet
   516  			// (we'll just treat this the same way we treat constrained zones
   517  			// and retry).
   518  			runArgs.SubnetId = subnetIDsForZone[rand.Intn(len(subnetIDsForZone))]
   519  			logger.Infof(
   520  				"selected random subnet %q from all matching in zone %q: %v",
   521  				runArgs.SubnetId, zone, subnetIDsForZone,
   522  			)
   523  		case len(subnetIDsForZone) == 1:
   524  			runArgs.SubnetId = subnetIDsForZone[0]
   525  			logger.Infof("selected subnet %q in zone %q", runArgs.SubnetId, zone)
   526  		}
   527  
   528  		instResp, err = runInstances(e.ec2, runArgs)
   529  		if err == nil || !isZoneOrSubnetConstrainedError(err) {
   530  			break
   531  		}
   532  
   533  		logger.Infof("%q is constrained, trying another availability zone", zone)
   534  	}
   535  
   536  	if err != nil {
   537  		return nil, errors.Annotate(err, "cannot run instances")
   538  	}
   539  	if len(instResp.Instances) != 1 {
   540  		return nil, errors.Errorf("expected 1 started instance, got %d", len(instResp.Instances))
   541  	}
   542  
   543  	inst = &ec2Instance{
   544  		e:        e,
   545  		Instance: &instResp.Instances[0],
   546  	}
   547  	instAZ := inst.Instance.AvailZone
   548  	if haveVPCID {
   549  		instVPC := e.ecfg().vpcID()
   550  		instSubnet := inst.Instance.SubnetId
   551  		logger.Infof("started instance %q in AZ %q, subnet %q, VPC %q", inst.Id(), instAZ, instSubnet, instVPC)
   552  	} else {
   553  		logger.Infof("started instance %q in AZ %q", inst.Id(), instAZ)
   554  	}
   555  
   556  	// Tag instance, for accounting and identification.
   557  	instanceName := resourceName(
   558  		names.NewMachineTag(args.InstanceConfig.MachineId), e.Config().Name(),
   559  	)
   560  	args.InstanceConfig.Tags[tagName] = instanceName
   561  	if err := tagResources(e.ec2, args.InstanceConfig.Tags, string(inst.Id())); err != nil {
   562  		return nil, errors.Annotate(err, "tagging instance")
   563  	}
   564  
   565  	// Tag the machine's root EBS volume, if it has one.
   566  	if inst.Instance.RootDeviceType == "ebs" {
   567  		cfg := e.Config()
   568  		tags := tags.ResourceTags(
   569  			names.NewModelTag(cfg.UUID()),
   570  			names.NewControllerTag(args.ControllerUUID),
   571  			cfg,
   572  		)
   573  		tags[tagName] = instanceName + "-root"
   574  		if err := tagRootDisk(e.ec2, tags, inst.Instance); err != nil {
   575  			return nil, errors.Annotate(err, "tagging root disk")
   576  		}
   577  	}
   578  
   579  	hc := instance.HardwareCharacteristics{
   580  		Arch:     &spec.Image.Arch,
   581  		Mem:      &spec.InstanceType.Mem,
   582  		CpuCores: &spec.InstanceType.CpuCores,
   583  		CpuPower: spec.InstanceType.CpuPower,
   584  		RootDisk: &rootDiskSize,
   585  		// Tags currently not supported by EC2
   586  		AvailabilityZone: &inst.Instance.AvailZone,
   587  	}
   588  	return &environs.StartInstanceResult{
   589  		Instance: inst,
   590  		Hardware: &hc,
   591  	}, nil
   592  }
   593  
   594  // tagResources calls ec2.CreateTags, tagging each of the specified resources
   595  // with the given tags. tagResources will retry for a short period of time
   596  // if it receives a *.NotFound error response from EC2.
   597  func tagResources(e *ec2.EC2, tags map[string]string, resourceIds ...string) error {
   598  	if len(tags) == 0 {
   599  		return nil
   600  	}
   601  	ec2Tags := make([]ec2.Tag, 0, len(tags))
   602  	for k, v := range tags {
   603  		ec2Tags = append(ec2Tags, ec2.Tag{k, v})
   604  	}
   605  	var err error
   606  	for a := shortAttempt.Start(); a.Next(); {
   607  		_, err = e.CreateTags(resourceIds, ec2Tags)
   608  		if err == nil || !strings.HasSuffix(ec2ErrCode(err), ".NotFound") {
   609  			return err
   610  		}
   611  	}
   612  	return err
   613  }
   614  
   615  func tagRootDisk(e *ec2.EC2, tags map[string]string, inst *ec2.Instance) error {
   616  	if len(tags) == 0 {
   617  		return nil
   618  	}
   619  	findVolumeId := func(inst *ec2.Instance) string {
   620  		for _, m := range inst.BlockDeviceMappings {
   621  			if m.DeviceName != inst.RootDeviceName {
   622  				continue
   623  			}
   624  			return m.VolumeId
   625  		}
   626  		return ""
   627  	}
   628  	// Wait until the instance has an associated EBS volume in the
   629  	// block-device-mapping.
   630  	volumeId := findVolumeId(inst)
   631  	// TODO(katco): 2016-08-09: lp:1611427
   632  	waitRootDiskAttempt := utils.AttemptStrategy{
   633  		Total: 5 * time.Minute,
   634  		Delay: 5 * time.Second,
   635  	}
   636  	for a := waitRootDiskAttempt.Start(); volumeId == "" && a.Next(); {
   637  		resp, err := e.Instances([]string{inst.InstanceId}, nil)
   638  		if err = errors.Annotate(err, "cannot fetch instance information"); err != nil {
   639  			logger.Warningf("%v", err)
   640  			if a.HasNext() == false {
   641  				return err
   642  			}
   643  			logger.Infof("retrying fetch of instances")
   644  			continue
   645  		}
   646  		if len(resp.Reservations) > 0 && len(resp.Reservations[0].Instances) > 0 {
   647  			inst = &resp.Reservations[0].Instances[0]
   648  			volumeId = findVolumeId(inst)
   649  		}
   650  	}
   651  	if volumeId == "" {
   652  		return errors.New("timed out waiting for EBS volume to be associated")
   653  	}
   654  	return tagResources(e, tags, volumeId)
   655  }
   656  
   657  var runInstances = _runInstances
   658  
   659  // runInstances calls ec2.RunInstances for a fixed number of attempts until
   660  // RunInstances returns an error code that does not indicate an error that
   661  // may be caused by eventual consistency.
   662  func _runInstances(e *ec2.EC2, ri *ec2.RunInstances) (resp *ec2.RunInstancesResp, err error) {
   663  	for a := shortAttempt.Start(); a.Next(); {
   664  		resp, err = e.RunInstances(ri)
   665  		if err == nil || !isNotFoundError(err) {
   666  			break
   667  		}
   668  	}
   669  	return resp, err
   670  }
   671  
   672  func (e *environ) StopInstances(ids ...instance.Id) error {
   673  	return errors.Trace(e.terminateInstances(ids))
   674  }
   675  
   676  // groupInfoByName returns information on the security group
   677  // with the given name including rules and other details.
   678  func (e *environ) groupInfoByName(groupName string) (ec2.SecurityGroupInfo, error) {
   679  	resp, err := e.securityGroupsByNameOrID(groupName)
   680  	if err != nil {
   681  		return ec2.SecurityGroupInfo{}, err
   682  	}
   683  
   684  	if len(resp.Groups) != 1 {
   685  		return ec2.SecurityGroupInfo{}, errors.NewNotFound(fmt.Errorf(
   686  			"expected one security group named %q, got %v",
   687  			groupName, resp.Groups,
   688  		), "")
   689  	}
   690  	return resp.Groups[0], nil
   691  }
   692  
   693  // groupByName returns the security group with the given name.
   694  func (e *environ) groupByName(groupName string) (ec2.SecurityGroup, error) {
   695  	groupInfo, err := e.groupInfoByName(groupName)
   696  	return groupInfo.SecurityGroup, err
   697  }
   698  
   699  // isNotFoundError returns whether err is a typed NotFoundError or an EC2 error
   700  // code for "group not found", indicating no matching instances (as they are
   701  // filtered by group).
   702  func isNotFoundError(err error) bool {
   703  	return err != nil && (errors.IsNotFound(err) || ec2ErrCode(err) == "InvalidGroup.NotFound")
   704  }
   705  
   706  // Instances is part of the environs.Environ interface.
   707  func (e *environ) Instances(ids []instance.Id) ([]instance.Instance, error) {
   708  	if len(ids) == 0 {
   709  		return nil, nil
   710  	}
   711  	insts := make([]instance.Instance, len(ids))
   712  	// Make a series of requests to cope with eventual consistency.
   713  	// Each request will attempt to add more instances to the requested
   714  	// set.
   715  	var err error
   716  	for a := shortAttempt.Start(); a.Next(); {
   717  		var need []string
   718  		for i, inst := range insts {
   719  			if inst == nil {
   720  				need = append(need, string(ids[i]))
   721  			}
   722  		}
   723  		filter := ec2.NewFilter()
   724  		filter.Add("instance-state-name", aliveInstanceStates...)
   725  		filter.Add("instance-id", need...)
   726  		e.addModelFilter(filter)
   727  		err = e.gatherInstances(ids, insts, filter)
   728  		if err == nil || err != environs.ErrPartialInstances {
   729  			break
   730  		}
   731  	}
   732  	if err == environs.ErrPartialInstances {
   733  		for _, inst := range insts {
   734  			if inst != nil {
   735  				return insts, environs.ErrPartialInstances
   736  			}
   737  		}
   738  		return nil, environs.ErrNoInstances
   739  	}
   740  	if err != nil {
   741  		return nil, err
   742  	}
   743  	return insts, nil
   744  }
   745  
   746  // gatherInstances tries to get information on each instance
   747  // id whose corresponding insts slot is nil.
   748  //
   749  // This function returns environs.ErrPartialInstances if the
   750  // insts slice has not been completely filled.
   751  func (e *environ) gatherInstances(
   752  	ids []instance.Id,
   753  	insts []instance.Instance,
   754  	filter *ec2.Filter,
   755  ) error {
   756  	resp, err := e.ec2.Instances(nil, filter)
   757  	if err != nil {
   758  		return err
   759  	}
   760  	n := 0
   761  	// For each requested id, add it to the returned instances
   762  	// if we find it in the response.
   763  	for i, id := range ids {
   764  		if insts[i] != nil {
   765  			n++
   766  			continue
   767  		}
   768  		for j := range resp.Reservations {
   769  			r := &resp.Reservations[j]
   770  			for k := range r.Instances {
   771  				if r.Instances[k].InstanceId != string(id) {
   772  					continue
   773  				}
   774  				inst := r.Instances[k]
   775  				// TODO(wallyworld): lookup the details to fill in the instance type data
   776  				insts[i] = &ec2Instance{e: e, Instance: &inst}
   777  				n++
   778  			}
   779  		}
   780  	}
   781  	if n < len(ids) {
   782  		return environs.ErrPartialInstances
   783  	}
   784  	return nil
   785  }
   786  
   787  // NetworkInterfaces implements NetworkingEnviron.NetworkInterfaces.
   788  func (e *environ) NetworkInterfaces(instId instance.Id) ([]network.InterfaceInfo, error) {
   789  	var err error
   790  	var networkInterfacesResp *ec2.NetworkInterfacesResp
   791  	for a := shortAttempt.Start(); a.Next(); {
   792  		logger.Tracef("retrieving NICs for instance %q", instId)
   793  		filter := ec2.NewFilter()
   794  		filter.Add("attachment.instance-id", string(instId))
   795  		networkInterfacesResp, err = e.ec2.NetworkInterfaces(nil, filter)
   796  		logger.Tracef("instance %q NICs: %#v (err: %v)", instId, networkInterfacesResp, err)
   797  		if err != nil {
   798  			logger.Errorf("failed to get instance %q interfaces: %v (retrying)", instId, err)
   799  			continue
   800  		}
   801  		if len(networkInterfacesResp.Interfaces) == 0 {
   802  			logger.Tracef("instance %q has no NIC attachment yet, retrying...", instId)
   803  			continue
   804  		}
   805  		logger.Tracef("found instance %q NICS: %#v", instId, networkInterfacesResp.Interfaces)
   806  		break
   807  	}
   808  	if err != nil {
   809  		// either the instance doesn't exist or we couldn't get through to
   810  		// the ec2 api
   811  		return nil, errors.Annotatef(err, "cannot get instance %q network interfaces", instId)
   812  	}
   813  	ec2Interfaces := networkInterfacesResp.Interfaces
   814  	result := make([]network.InterfaceInfo, len(ec2Interfaces))
   815  	for i, iface := range ec2Interfaces {
   816  		resp, err := e.ec2.Subnets([]string{iface.SubnetId}, nil)
   817  		if err != nil {
   818  			return nil, errors.Annotatef(err, "failed to retrieve subnet %q info", iface.SubnetId)
   819  		}
   820  		if len(resp.Subnets) != 1 {
   821  			return nil, errors.Errorf("expected 1 subnet, got %d", len(resp.Subnets))
   822  		}
   823  		subnet := resp.Subnets[0]
   824  		cidr := subnet.CIDRBlock
   825  
   826  		result[i] = network.InterfaceInfo{
   827  			DeviceIndex:       iface.Attachment.DeviceIndex,
   828  			MACAddress:        iface.MACAddress,
   829  			CIDR:              cidr,
   830  			ProviderId:        network.Id(iface.Id),
   831  			ProviderSubnetId:  network.Id(iface.SubnetId),
   832  			AvailabilityZones: []string{subnet.AvailZone},
   833  			VLANTag:           0, // Not supported on EC2.
   834  			// Getting the interface name is not supported on EC2, so fake it.
   835  			InterfaceName: fmt.Sprintf("unsupported%d", iface.Attachment.DeviceIndex),
   836  			Disabled:      false,
   837  			NoAutoStart:   false,
   838  			ConfigType:    network.ConfigDHCP,
   839  			InterfaceType: network.EthernetInterface,
   840  			Address:       network.NewScopedAddress(iface.PrivateIPAddress, network.ScopeCloudLocal),
   841  		}
   842  	}
   843  	return result, nil
   844  }
   845  
   846  func makeSubnetInfo(cidr string, subnetId network.Id, availZones []string) (network.SubnetInfo, error) {
   847  	_, _, err := net.ParseCIDR(cidr)
   848  	if err != nil {
   849  		return network.SubnetInfo{}, errors.Annotatef(err, "skipping subnet %q, invalid CIDR", cidr)
   850  	}
   851  
   852  	info := network.SubnetInfo{
   853  		CIDR:              cidr,
   854  		ProviderId:        subnetId,
   855  		VLANTag:           0, // Not supported on EC2
   856  		AvailabilityZones: availZones,
   857  	}
   858  	logger.Tracef("found subnet with info %#v", info)
   859  	return info, nil
   860  
   861  }
   862  
   863  // Spaces is not implemented by the ec2 provider as we don't currently have
   864  // provider level spaces.
   865  func (e *environ) Spaces() ([]network.SpaceInfo, error) {
   866  	return nil, errors.NotSupportedf("Spaces")
   867  }
   868  
   869  // Subnets returns basic information about the specified subnets known
   870  // by the provider for the specified instance or list of ids. subnetIds can be
   871  // empty, in which case all known are returned. Implements
   872  // NetworkingEnviron.Subnets.
   873  func (e *environ) Subnets(instId instance.Id, subnetIds []network.Id) ([]network.SubnetInfo, error) {
   874  	var results []network.SubnetInfo
   875  	subIdSet := make(map[string]bool)
   876  	for _, subId := range subnetIds {
   877  		subIdSet[string(subId)] = false
   878  	}
   879  
   880  	if instId != instance.UnknownId {
   881  		interfaces, err := e.NetworkInterfaces(instId)
   882  		if err != nil {
   883  			return results, errors.Trace(err)
   884  		}
   885  		if len(subnetIds) == 0 {
   886  			for _, iface := range interfaces {
   887  				subIdSet[string(iface.ProviderSubnetId)] = false
   888  			}
   889  		}
   890  		for _, iface := range interfaces {
   891  			_, ok := subIdSet[string(iface.ProviderSubnetId)]
   892  			if !ok {
   893  				logger.Tracef("subnet %q not in %v, skipping", iface.ProviderSubnetId, subnetIds)
   894  				continue
   895  			}
   896  			subIdSet[string(iface.ProviderSubnetId)] = true
   897  			info, err := makeSubnetInfo(iface.CIDR, iface.ProviderSubnetId, iface.AvailabilityZones)
   898  			if err != nil {
   899  				// Error will already have been logged.
   900  				continue
   901  			}
   902  			results = append(results, info)
   903  		}
   904  	} else {
   905  		resp, err := e.ec2.Subnets(nil, nil)
   906  		if err != nil {
   907  			return nil, errors.Annotatef(err, "failed to retrieve subnets")
   908  		}
   909  		if len(subnetIds) == 0 {
   910  			for _, subnet := range resp.Subnets {
   911  				subIdSet[subnet.Id] = false
   912  			}
   913  		}
   914  
   915  		for _, subnet := range resp.Subnets {
   916  			_, ok := subIdSet[subnet.Id]
   917  			if !ok {
   918  				logger.Tracef("subnet %q not in %v, skipping", subnet.Id, subnetIds)
   919  				continue
   920  			}
   921  			subIdSet[subnet.Id] = true
   922  			cidr := subnet.CIDRBlock
   923  			info, err := makeSubnetInfo(cidr, network.Id(subnet.Id), []string{subnet.AvailZone})
   924  			if err != nil {
   925  				// Error will already have been logged.
   926  				continue
   927  			}
   928  			results = append(results, info)
   929  
   930  		}
   931  	}
   932  
   933  	notFound := []string{}
   934  	for subId, found := range subIdSet {
   935  		if !found {
   936  			notFound = append(notFound, subId)
   937  		}
   938  	}
   939  	if len(notFound) != 0 {
   940  		return nil, errors.Errorf("failed to find the following subnet ids: %v", notFound)
   941  	}
   942  
   943  	return results, nil
   944  }
   945  
   946  // AllInstances is part of the environs.InstanceBroker interface.
   947  func (e *environ) AllInstances() ([]instance.Instance, error) {
   948  	return e.AllInstancesByState("pending", "running")
   949  }
   950  
   951  // AllInstancesByState returns all instances in the environment
   952  // with one of the specified instance states.
   953  func (e *environ) AllInstancesByState(states ...string) ([]instance.Instance, error) {
   954  	// NOTE(axw) we use security group filtering here because instances
   955  	// start out untagged. If Juju were to abort after starting an instance,
   956  	// but before tagging it, it would be leaked. We only need to do this
   957  	// for AllInstances, as it is the result of AllInstances that is used
   958  	// in "harvesting" unknown instances by the provisioner.
   959  	//
   960  	// One possible alternative is to modify ec2.RunInstances to allow the
   961  	// caller to specify ClientToken, and then format it like
   962  	//     <controller-uuid>:<model-uuid>:<machine-id>
   963  	//     (with base64-encoding to keep the size under the 64-byte limit)
   964  	//
   965  	// It is possible to filter on "client-token", and specify wildcards;
   966  	// therefore we could use client-token filters everywhere in the ec2
   967  	// provider instead of tags or security groups. The only danger is if
   968  	// we need to make non-idempotent calls to RunInstances for the machine
   969  	// ID. I don't think this is needed, but I am not confident enough to
   970  	// change this fundamental right now.
   971  	//
   972  	// An EC2 API call is required to resolve the group name to an id, as
   973  	// VPC enabled accounts do not support name based filtering.
   974  	groupName := e.jujuGroupName()
   975  	group, err := e.groupByName(groupName)
   976  	if isNotFoundError(err) {
   977  		// If there's no group, then there cannot be any instances.
   978  		return nil, nil
   979  	} else if err != nil {
   980  		return nil, errors.Trace(err)
   981  	}
   982  	filter := ec2.NewFilter()
   983  	filter.Add("instance-state-name", states...)
   984  	filter.Add("instance.group-id", group.Id)
   985  	return e.allInstances(filter)
   986  }
   987  
   988  // ControllerInstances is part of the environs.Environ interface.
   989  func (e *environ) ControllerInstances(controllerUUID string) ([]instance.Id, error) {
   990  	filter := ec2.NewFilter()
   991  	filter.Add("instance-state-name", aliveInstanceStates...)
   992  	filter.Add(fmt.Sprintf("tag:%s", tags.JujuIsController), "true")
   993  	e.addControllerFilter(filter, controllerUUID)
   994  	ids, err := e.allInstanceIDs(filter)
   995  	if err != nil {
   996  		return nil, errors.Trace(err)
   997  	}
   998  	if len(ids) == 0 {
   999  		return nil, environs.ErrNotBootstrapped
  1000  	}
  1001  	return ids, nil
  1002  }
  1003  
  1004  // allControllerManagedInstances returns the IDs of all instances managed by
  1005  // this environment's controller.
  1006  //
  1007  // Note that this requires that all instances are tagged; we cannot filter on
  1008  // security groups, as we do not know the names of the models.
  1009  func (e *environ) allControllerManagedInstances(controllerUUID string) ([]instance.Id, error) {
  1010  	filter := ec2.NewFilter()
  1011  	filter.Add("instance-state-name", aliveInstanceStates...)
  1012  	e.addControllerFilter(filter, controllerUUID)
  1013  	return e.allInstanceIDs(filter)
  1014  }
  1015  
  1016  func (e *environ) allInstanceIDs(filter *ec2.Filter) ([]instance.Id, error) {
  1017  	insts, err := e.allInstances(filter)
  1018  	if err != nil {
  1019  		return nil, errors.Trace(err)
  1020  	}
  1021  	ids := make([]instance.Id, len(insts))
  1022  	for i, inst := range insts {
  1023  		ids[i] = inst.Id()
  1024  	}
  1025  	return ids, nil
  1026  }
  1027  
  1028  func (e *environ) allInstances(filter *ec2.Filter) ([]instance.Instance, error) {
  1029  	resp, err := e.ec2.Instances(nil, filter)
  1030  	if err != nil {
  1031  		return nil, errors.Annotate(err, "listing instances")
  1032  	}
  1033  	var insts []instance.Instance
  1034  	for _, r := range resp.Reservations {
  1035  		for i := range r.Instances {
  1036  			inst := r.Instances[i]
  1037  			// TODO(wallyworld): lookup the details to fill in the instance type data
  1038  			insts = append(insts, &ec2Instance{e: e, Instance: &inst})
  1039  		}
  1040  	}
  1041  	return insts, nil
  1042  }
  1043  
  1044  // Destroy is part of the environs.Environ interface.
  1045  func (e *environ) Destroy() error {
  1046  	if err := common.Destroy(e); err != nil {
  1047  		return errors.Trace(err)
  1048  	}
  1049  	if err := e.cleanEnvironmentSecurityGroups(); err != nil {
  1050  		return errors.Annotate(err, "cannot delete environment security groups")
  1051  	}
  1052  	return nil
  1053  }
  1054  
  1055  // DestroyController implements the Environ interface.
  1056  func (e *environ) DestroyController(controllerUUID string) error {
  1057  	// In case any hosted environment hasn't been cleaned up yet,
  1058  	// we also attempt to delete their resources when the controller
  1059  	// environment is destroyed.
  1060  	if err := e.destroyControllerManagedEnvirons(controllerUUID); err != nil {
  1061  		return errors.Annotate(err, "destroying managed environs")
  1062  	}
  1063  	return e.Destroy()
  1064  }
  1065  
  1066  // destroyControllerManagedEnvirons destroys all environments managed by this
  1067  // environment's controller.
  1068  func (e *environ) destroyControllerManagedEnvirons(controllerUUID string) error {
  1069  
  1070  	// Terminate all instances managed by the controller.
  1071  	instIds, err := e.allControllerManagedInstances(controllerUUID)
  1072  	if err != nil {
  1073  		return errors.Annotate(err, "listing instances")
  1074  	}
  1075  	if err := e.terminateInstances(instIds); err != nil {
  1076  		return errors.Annotate(err, "terminating instances")
  1077  	}
  1078  
  1079  	// Delete all volumes managed by the controller.
  1080  	volIds, err := e.allControllerManagedVolumes(controllerUUID)
  1081  	if err != nil {
  1082  		return errors.Annotate(err, "listing volumes")
  1083  	}
  1084  	errs := destroyVolumes(e.ec2, volIds)
  1085  	for i, err := range errs {
  1086  		if err == nil {
  1087  			continue
  1088  		}
  1089  		return errors.Annotatef(err, "destroying volume %q", volIds[i], err)
  1090  	}
  1091  
  1092  	// Delete security groups managed by the controller.
  1093  	groups, err := e.controllerSecurityGroups(controllerUUID)
  1094  	if err != nil {
  1095  		return errors.Trace(err)
  1096  	}
  1097  	for _, g := range groups {
  1098  		if err := deleteSecurityGroupInsistently(e.ec2, g, clock.WallClock); err != nil {
  1099  			return errors.Annotatef(
  1100  				err, "cannot delete security group %q (%q)",
  1101  				g.Name, g.Id,
  1102  			)
  1103  		}
  1104  	}
  1105  	return nil
  1106  }
  1107  
  1108  func (e *environ) allControllerManagedVolumes(controllerUUID string) ([]string, error) {
  1109  	filter := ec2.NewFilter()
  1110  	e.addControllerFilter(filter, controllerUUID)
  1111  	return listVolumes(e.ec2, filter)
  1112  }
  1113  
  1114  func portsToIPPerms(ports []network.PortRange) []ec2.IPPerm {
  1115  	ipPerms := make([]ec2.IPPerm, len(ports))
  1116  	for i, p := range ports {
  1117  		ipPerms[i] = ec2.IPPerm{
  1118  			Protocol:  p.Protocol,
  1119  			FromPort:  p.FromPort,
  1120  			ToPort:    p.ToPort,
  1121  			SourceIPs: []string{"0.0.0.0/0"},
  1122  		}
  1123  	}
  1124  	return ipPerms
  1125  }
  1126  
  1127  func (e *environ) openPortsInGroup(name string, ports []network.PortRange) error {
  1128  	if len(ports) == 0 {
  1129  		return nil
  1130  	}
  1131  	// Give permissions for anyone to access the given ports.
  1132  	g, err := e.groupByName(name)
  1133  	if err != nil {
  1134  		return err
  1135  	}
  1136  	ipPerms := portsToIPPerms(ports)
  1137  	_, err = e.ec2.AuthorizeSecurityGroup(g, ipPerms)
  1138  	if err != nil && ec2ErrCode(err) == "InvalidPermission.Duplicate" {
  1139  		if len(ports) == 1 {
  1140  			return nil
  1141  		}
  1142  		// If there's more than one port and we get a duplicate error,
  1143  		// then we go through authorizing each port individually,
  1144  		// otherwise the ports that were *not* duplicates will have
  1145  		// been ignored
  1146  		for i := range ipPerms {
  1147  			_, err := e.ec2.AuthorizeSecurityGroup(g, ipPerms[i:i+1])
  1148  			if err != nil && ec2ErrCode(err) != "InvalidPermission.Duplicate" {
  1149  				return fmt.Errorf("cannot open port %v: %v", ipPerms[i], err)
  1150  			}
  1151  		}
  1152  		return nil
  1153  	}
  1154  	if err != nil {
  1155  		return fmt.Errorf("cannot open ports: %v", err)
  1156  	}
  1157  	return nil
  1158  }
  1159  
  1160  func (e *environ) closePortsInGroup(name string, ports []network.PortRange) error {
  1161  	if len(ports) == 0 {
  1162  		return nil
  1163  	}
  1164  	// Revoke permissions for anyone to access the given ports.
  1165  	// Note that ec2 allows the revocation of permissions that aren't
  1166  	// granted, so this is naturally idempotent.
  1167  	g, err := e.groupByName(name)
  1168  	if err != nil {
  1169  		return err
  1170  	}
  1171  	_, err = e.ec2.RevokeSecurityGroup(g, portsToIPPerms(ports))
  1172  	if err != nil {
  1173  		return fmt.Errorf("cannot close ports: %v", err)
  1174  	}
  1175  	return nil
  1176  }
  1177  
  1178  func (e *environ) portsInGroup(name string) (ports []network.PortRange, err error) {
  1179  	group, err := e.groupInfoByName(name)
  1180  	if err != nil {
  1181  		return nil, err
  1182  	}
  1183  	for _, p := range group.IPPerms {
  1184  		if len(p.SourceIPs) != 1 {
  1185  			logger.Errorf("expected exactly one IP permission, found: %v", p)
  1186  			continue
  1187  		}
  1188  		ports = append(ports, network.PortRange{
  1189  			Protocol: p.Protocol,
  1190  			FromPort: p.FromPort,
  1191  			ToPort:   p.ToPort,
  1192  		})
  1193  	}
  1194  	network.SortPortRanges(ports)
  1195  	return ports, nil
  1196  }
  1197  
  1198  func (e *environ) OpenPorts(ports []network.PortRange) error {
  1199  	if e.Config().FirewallMode() != config.FwGlobal {
  1200  		return errors.Errorf("invalid firewall mode %q for opening ports on model", e.Config().FirewallMode())
  1201  	}
  1202  	if err := e.openPortsInGroup(e.globalGroupName(), ports); err != nil {
  1203  		return errors.Trace(err)
  1204  	}
  1205  	logger.Infof("opened ports in global group: %v", ports)
  1206  	return nil
  1207  }
  1208  
  1209  func (e *environ) ClosePorts(ports []network.PortRange) error {
  1210  	if e.Config().FirewallMode() != config.FwGlobal {
  1211  		return errors.Errorf("invalid firewall mode %q for closing ports on model", e.Config().FirewallMode())
  1212  	}
  1213  	if err := e.closePortsInGroup(e.globalGroupName(), ports); err != nil {
  1214  		return errors.Trace(err)
  1215  	}
  1216  	logger.Infof("closed ports in global group: %v", ports)
  1217  	return nil
  1218  }
  1219  
  1220  func (e *environ) Ports() ([]network.PortRange, error) {
  1221  	if e.Config().FirewallMode() != config.FwGlobal {
  1222  		return nil, errors.Errorf("invalid firewall mode %q for retrieving ports from model", e.Config().FirewallMode())
  1223  	}
  1224  	return e.portsInGroup(e.globalGroupName())
  1225  }
  1226  
  1227  func (*environ) Provider() environs.EnvironProvider {
  1228  	return &providerInstance
  1229  }
  1230  
  1231  func (e *environ) instanceSecurityGroups(instIDs []instance.Id, states ...string) ([]ec2.SecurityGroup, error) {
  1232  	strInstID := make([]string, len(instIDs))
  1233  	for i := range instIDs {
  1234  		strInstID[i] = string(instIDs[i])
  1235  	}
  1236  
  1237  	filter := ec2.NewFilter()
  1238  	if len(states) > 0 {
  1239  		filter.Add("instance-state-name", states...)
  1240  	}
  1241  
  1242  	resp, err := e.ec2.Instances(strInstID, filter)
  1243  	if err != nil {
  1244  		return nil, errors.Annotatef(err, "cannot retrieve instance information from aws to delete security groups")
  1245  	}
  1246  
  1247  	securityGroups := []ec2.SecurityGroup{}
  1248  	for _, res := range resp.Reservations {
  1249  		for _, inst := range res.Instances {
  1250  			logger.Debugf("instance %q has security groups %+v", inst.InstanceId, inst.SecurityGroups)
  1251  			securityGroups = append(securityGroups, inst.SecurityGroups...)
  1252  		}
  1253  	}
  1254  	return securityGroups, nil
  1255  }
  1256  
  1257  // controllerSecurityGroups returns the details of all security groups managed
  1258  // by the environment's controller.
  1259  func (e *environ) controllerSecurityGroups(controllerUUID string) ([]ec2.SecurityGroup, error) {
  1260  	filter := ec2.NewFilter()
  1261  	e.addControllerFilter(filter, controllerUUID)
  1262  	resp, err := e.ec2.SecurityGroups(nil, filter)
  1263  	if err != nil {
  1264  		return nil, errors.Annotate(err, "listing security groups")
  1265  	}
  1266  	groups := make([]ec2.SecurityGroup, len(resp.Groups))
  1267  	for i, info := range resp.Groups {
  1268  		groups[i] = ec2.SecurityGroup{Id: info.Id, Name: info.Name}
  1269  	}
  1270  	return groups, nil
  1271  }
  1272  
  1273  // cleanEnvironmentSecurityGroups attempts to delete all security groups owned
  1274  // by the environment.
  1275  func (e *environ) cleanEnvironmentSecurityGroups() error {
  1276  	jujuGroup := e.jujuGroupName()
  1277  	g, err := e.groupByName(jujuGroup)
  1278  	if isNotFoundError(err) {
  1279  		return nil
  1280  	}
  1281  	if err != nil {
  1282  		return errors.Annotatef(err, "cannot retrieve default security group: %q", jujuGroup)
  1283  	}
  1284  	if err := deleteSecurityGroupInsistently(e.ec2, g, clock.WallClock); err != nil {
  1285  		return errors.Annotate(err, "cannot delete default security group")
  1286  	}
  1287  	return nil
  1288  }
  1289  
  1290  func (e *environ) terminateInstances(ids []instance.Id) error {
  1291  	if len(ids) == 0 {
  1292  		return nil
  1293  	}
  1294  
  1295  	// TODO (anastasiamac 2016-04-11) Err if instances still have resources hanging around.
  1296  	// LP#1568654
  1297  	defer func() {
  1298  		e.deleteSecurityGroupsForInstances(ids)
  1299  	}()
  1300  
  1301  	// TODO (anastasiamac 2016-04-7) instance termination would benefit
  1302  	// from retry with exponential delay just like security groups
  1303  	// in defer. Bug#1567179.
  1304  	var err error
  1305  	for a := shortAttempt.Start(); a.Next(); {
  1306  		_, err = terminateInstancesById(e.ec2, ids...)
  1307  		if err == nil || ec2ErrCode(err) != "InvalidInstanceID.NotFound" {
  1308  			// This will return either success at terminating all instances (1st condition) or
  1309  			// encountered error as long as it's not NotFound (2nd condition).
  1310  			return err
  1311  		}
  1312  	}
  1313  
  1314  	// We will get here only if we got a NotFound error.
  1315  	// 1. If we attempted to terminate only one instance was, return now.
  1316  	if len(ids) == 1 {
  1317  		ids = nil
  1318  		return nil
  1319  	}
  1320  	// 2. If we attempted to terminate several instances and got a NotFound error,
  1321  	// it means that no instances were terminated.
  1322  	// So try each instance individually, ignoring a NotFound error this time.
  1323  	deletedIDs := []instance.Id{}
  1324  	for _, id := range ids {
  1325  		_, err = terminateInstancesById(e.ec2, id)
  1326  		if err == nil {
  1327  			deletedIDs = append(deletedIDs, id)
  1328  		}
  1329  		if err != nil && ec2ErrCode(err) != "InvalidInstanceID.NotFound" {
  1330  			ids = deletedIDs
  1331  			return err
  1332  		}
  1333  	}
  1334  	// We will get here if all of the instances are deleted successfully,
  1335  	// or are not found, which implies they were previously deleted.
  1336  	ids = deletedIDs
  1337  	return nil
  1338  }
  1339  
  1340  var terminateInstancesById = func(ec2inst *ec2.EC2, ids ...instance.Id) (*ec2.TerminateInstancesResp, error) {
  1341  	strs := make([]string, len(ids))
  1342  	for i, id := range ids {
  1343  		strs[i] = string(id)
  1344  	}
  1345  	return ec2inst.TerminateInstances(strs)
  1346  }
  1347  
  1348  func (e *environ) deleteSecurityGroupsForInstances(ids []instance.Id) {
  1349  	if len(ids) == 0 {
  1350  		logger.Debugf("no need to delete security groups: no intances were terminated successfully")
  1351  		return
  1352  	}
  1353  
  1354  	// We only want to attempt deleting security groups for the
  1355  	// instances that have been successfully terminated.
  1356  	securityGroups, err := e.instanceSecurityGroups(ids, "shutting-down", "terminated")
  1357  	if err != nil {
  1358  		logger.Errorf("cannot determine security groups to delete: %v", err)
  1359  		return
  1360  	}
  1361  
  1362  	// TODO(perrito666) we need to tag global security groups to be able
  1363  	// to tell them apart from future groups that are neither machine
  1364  	// nor environment group.
  1365  	// https://bugs.launchpad.net/juju-core/+bug/1534289
  1366  	jujuGroup := e.jujuGroupName()
  1367  
  1368  	for _, deletable := range securityGroups {
  1369  		if deletable.Name == jujuGroup {
  1370  			continue
  1371  		}
  1372  		if err := deleteSecurityGroupInsistently(e.ec2, deletable, clock.WallClock); err != nil {
  1373  			// In ideal world, we would err out here.
  1374  			// However:
  1375  			// 1. We do not know if all instances have been terminated.
  1376  			// If some instances erred out, they may still be using this security group.
  1377  			// In this case, our failure to delete security group is reasonable: it's still in use.
  1378  			// 2. Some security groups may be shared by multiple instances,
  1379  			// for example, global firewalling. We should not delete these.
  1380  			logger.Errorf("provider failure: %v", err)
  1381  		}
  1382  	}
  1383  }
  1384  
  1385  // SecurityGroupCleaner defines provider instance methods needed to delete
  1386  // a security group.
  1387  type SecurityGroupCleaner interface {
  1388  
  1389  	// DeleteSecurityGroup deletes security group on the provider.
  1390  	DeleteSecurityGroup(group ec2.SecurityGroup) (resp *ec2.SimpleResp, err error)
  1391  }
  1392  
  1393  var deleteSecurityGroupInsistently = func(inst SecurityGroupCleaner, group ec2.SecurityGroup, clock clock.Clock) error {
  1394  	err := retry.Call(retry.CallArgs{
  1395  		Attempts:    30,
  1396  		Delay:       time.Second,
  1397  		MaxDelay:    time.Minute, // because 2**29 seconds is beyond reasonable
  1398  		BackoffFunc: retry.DoubleDelay,
  1399  		Clock:       clock,
  1400  		Func: func() error {
  1401  			_, err := inst.DeleteSecurityGroup(group)
  1402  			if err == nil || isNotFoundError(err) {
  1403  				logger.Debugf("deleting security group %q", group.Name)
  1404  				return nil
  1405  			}
  1406  			return errors.Trace(err)
  1407  		},
  1408  		NotifyFunc: func(err error, attempt int) {
  1409  			logger.Debugf("deleting security group %q, attempt %d", group.Name, attempt)
  1410  		},
  1411  	})
  1412  	if err != nil {
  1413  		return errors.Annotatef(err, "cannot delete security group %q: consider deleting it manually", group.Name)
  1414  	}
  1415  	return nil
  1416  }
  1417  
  1418  func (e *environ) addModelFilter(f *ec2.Filter) {
  1419  	f.Add(fmt.Sprintf("tag:%s", tags.JujuModel), e.uuid())
  1420  }
  1421  
  1422  func (e *environ) addControllerFilter(f *ec2.Filter, controllerUUID string) {
  1423  	f.Add(fmt.Sprintf("tag:%s", tags.JujuController), controllerUUID)
  1424  }
  1425  
  1426  func (e *environ) uuid() string {
  1427  	return e.Config().UUID()
  1428  }
  1429  
  1430  func (e *environ) globalGroupName() string {
  1431  	return fmt.Sprintf("%s-global", e.jujuGroupName())
  1432  }
  1433  
  1434  func (e *environ) machineGroupName(machineId string) string {
  1435  	return fmt.Sprintf("%s-%s", e.jujuGroupName(), machineId)
  1436  }
  1437  
  1438  func (e *environ) jujuGroupName() string {
  1439  	return "juju-" + e.uuid()
  1440  }
  1441  
  1442  // setUpGroups creates the security groups for the new machine, and
  1443  // returns them.
  1444  //
  1445  // Instances are tagged with a group so they can be distinguished from
  1446  // other instances that might be running on the same EC2 account.  In
  1447  // addition, a specific machine security group is created for each
  1448  // machine, so that its firewall rules can be configured per machine.
  1449  func (e *environ) setUpGroups(controllerUUID, machineId string, apiPort int) ([]ec2.SecurityGroup, error) {
  1450  
  1451  	// Ensure there's a global group for Juju-related traffic.
  1452  	jujuGroup, err := e.ensureGroup(controllerUUID, e.jujuGroupName(),
  1453  		[]ec2.IPPerm{{
  1454  			Protocol:  "tcp",
  1455  			FromPort:  22,
  1456  			ToPort:    22,
  1457  			SourceIPs: []string{"0.0.0.0/0"},
  1458  		}, {
  1459  			Protocol:  "tcp",
  1460  			FromPort:  apiPort,
  1461  			ToPort:    apiPort,
  1462  			SourceIPs: []string{"0.0.0.0/0"},
  1463  		}, {
  1464  			Protocol: "tcp",
  1465  			FromPort: 0,
  1466  			ToPort:   65535,
  1467  		}, {
  1468  			Protocol: "udp",
  1469  			FromPort: 0,
  1470  			ToPort:   65535,
  1471  		}, {
  1472  			Protocol: "icmp",
  1473  			FromPort: -1,
  1474  			ToPort:   -1,
  1475  		}},
  1476  	)
  1477  	if err != nil {
  1478  		return nil, err
  1479  	}
  1480  
  1481  	var machineGroup ec2.SecurityGroup
  1482  	switch e.Config().FirewallMode() {
  1483  	case config.FwInstance:
  1484  		machineGroup, err = e.ensureGroup(controllerUUID, e.machineGroupName(machineId), nil)
  1485  	case config.FwGlobal:
  1486  		machineGroup, err = e.ensureGroup(controllerUUID, e.globalGroupName(), nil)
  1487  	}
  1488  	if err != nil {
  1489  		return nil, err
  1490  	}
  1491  	return []ec2.SecurityGroup{jujuGroup, machineGroup}, nil
  1492  }
  1493  
  1494  // zeroGroup holds the zero security group.
  1495  var zeroGroup ec2.SecurityGroup
  1496  
  1497  // securityGroupsByNameOrID calls ec2.SecurityGroups() either with the given
  1498  // groupName or with filter by vpc-id and group-name, depending on whether
  1499  // vpc-id is empty or not.
  1500  func (e *environ) securityGroupsByNameOrID(groupName string) (*ec2.SecurityGroupsResp, error) {
  1501  	if chosenVPCID := e.ecfg().vpcID(); isVPCIDSet(chosenVPCID) {
  1502  		// AWS VPC API requires both of these filters (and no
  1503  		// group names/ids set) for non-default EC2-VPC groups:
  1504  		filter := ec2.NewFilter()
  1505  		filter.Add("vpc-id", chosenVPCID)
  1506  		filter.Add("group-name", groupName)
  1507  		return e.ec2.SecurityGroups(nil, filter)
  1508  	}
  1509  
  1510  	// EC2-Classic or EC2-VPC with implicit default VPC need to use the
  1511  	// GroupName.X arguments instead of the filters.
  1512  	groups := ec2.SecurityGroupNames(groupName)
  1513  	return e.ec2.SecurityGroups(groups, nil)
  1514  }
  1515  
  1516  // ensureGroup returns the security group with name and perms.
  1517  // If a group with name does not exist, one will be created.
  1518  // If it exists, its permissions are set to perms.
  1519  // Any entries in perms without SourceIPs will be granted for
  1520  // the named group only.
  1521  func (e *environ) ensureGroup(controllerUUID, name string, perms []ec2.IPPerm) (g ec2.SecurityGroup, err error) {
  1522  	// Specify explicit VPC ID if needed (not for default VPC or EC2-classic).
  1523  	chosenVPCID := e.ecfg().vpcID()
  1524  	inVPCLogSuffix := fmt.Sprintf(" (in VPC %q)", chosenVPCID)
  1525  	if !isVPCIDSet(chosenVPCID) {
  1526  		chosenVPCID = ""
  1527  		inVPCLogSuffix = ""
  1528  	}
  1529  
  1530  	resp, err := e.ec2.CreateSecurityGroup(chosenVPCID, name, "juju group")
  1531  	if err != nil && ec2ErrCode(err) != "InvalidGroup.Duplicate" {
  1532  		err = errors.Annotatef(err, "creating security group %q%s", name, inVPCLogSuffix)
  1533  		return zeroGroup, err
  1534  	}
  1535  
  1536  	var have permSet
  1537  	if err == nil {
  1538  		g = resp.SecurityGroup
  1539  		// Tag the created group with the model and controller UUIDs.
  1540  		cfg := e.Config()
  1541  		tags := tags.ResourceTags(
  1542  			names.NewModelTag(cfg.UUID()),
  1543  			names.NewControllerTag(controllerUUID),
  1544  			cfg,
  1545  		)
  1546  		if err := tagResources(e.ec2, tags, g.Id); err != nil {
  1547  			return g, errors.Annotate(err, "tagging security group")
  1548  		}
  1549  		logger.Debugf("created security group %q with ID %q%s", name, g.Id, inVPCLogSuffix)
  1550  	} else {
  1551  		resp, err := e.securityGroupsByNameOrID(name)
  1552  		if err != nil {
  1553  			err = errors.Annotatef(err, "fetching security group %q%s", name, inVPCLogSuffix)
  1554  			return zeroGroup, err
  1555  		}
  1556  		if len(resp.Groups) == 0 {
  1557  			return zeroGroup, errors.NotFoundf("security group %q%s", name, inVPCLogSuffix)
  1558  		}
  1559  		info := resp.Groups[0]
  1560  		// It's possible that the old group has the wrong
  1561  		// description here, but if it does it's probably due
  1562  		// to something deliberately playing games with juju,
  1563  		// so we ignore it.
  1564  		g = info.SecurityGroup
  1565  		have = newPermSetForGroup(info.IPPerms, g)
  1566  	}
  1567  
  1568  	want := newPermSetForGroup(perms, g)
  1569  	revoke := make(permSet)
  1570  	for p := range have {
  1571  		if !want[p] {
  1572  			revoke[p] = true
  1573  		}
  1574  	}
  1575  	if len(revoke) > 0 {
  1576  		_, err := e.ec2.RevokeSecurityGroup(g, revoke.ipPerms())
  1577  		if err != nil {
  1578  			err = errors.Annotatef(err, "revoking security group %q%s", g.Id, inVPCLogSuffix)
  1579  			return zeroGroup, err
  1580  		}
  1581  	}
  1582  
  1583  	add := make(permSet)
  1584  	for p := range want {
  1585  		if !have[p] {
  1586  			add[p] = true
  1587  		}
  1588  	}
  1589  	if len(add) > 0 {
  1590  		_, err := e.ec2.AuthorizeSecurityGroup(g, add.ipPerms())
  1591  		if err != nil {
  1592  			err = errors.Annotatef(err, "authorizing security group %q%s", g.Id, inVPCLogSuffix)
  1593  			return zeroGroup, err
  1594  		}
  1595  	}
  1596  	return g, nil
  1597  }
  1598  
  1599  // permKey represents a permission for a group or an ip address range to access
  1600  // the given range of ports. Only one of groupId or ipAddr should be non-empty.
  1601  type permKey struct {
  1602  	protocol string
  1603  	fromPort int
  1604  	toPort   int
  1605  	groupId  string
  1606  	ipAddr   string
  1607  }
  1608  
  1609  type permSet map[permKey]bool
  1610  
  1611  // newPermSetForGroup returns a set of all the permissions in the
  1612  // given slice of IPPerms. It ignores the name and owner
  1613  // id in source groups, and any entry with no source ips will
  1614  // be granted for the given group only.
  1615  func newPermSetForGroup(ps []ec2.IPPerm, group ec2.SecurityGroup) permSet {
  1616  	m := make(permSet)
  1617  	for _, p := range ps {
  1618  		k := permKey{
  1619  			protocol: p.Protocol,
  1620  			fromPort: p.FromPort,
  1621  			toPort:   p.ToPort,
  1622  		}
  1623  		if len(p.SourceIPs) > 0 {
  1624  			for _, ip := range p.SourceIPs {
  1625  				k.ipAddr = ip
  1626  				m[k] = true
  1627  			}
  1628  		} else {
  1629  			k.groupId = group.Id
  1630  			m[k] = true
  1631  		}
  1632  	}
  1633  	return m
  1634  }
  1635  
  1636  // ipPerms returns m as a slice of permissions usable
  1637  // with the ec2 package.
  1638  func (m permSet) ipPerms() (ps []ec2.IPPerm) {
  1639  	// We could compact the permissions, but it
  1640  	// hardly seems worth it.
  1641  	for p := range m {
  1642  		ipp := ec2.IPPerm{
  1643  			Protocol: p.protocol,
  1644  			FromPort: p.fromPort,
  1645  			ToPort:   p.toPort,
  1646  		}
  1647  		if p.ipAddr != "" {
  1648  			ipp.SourceIPs = []string{p.ipAddr}
  1649  		} else {
  1650  			ipp.SourceGroups = []ec2.UserSecurityGroup{{Id: p.groupId}}
  1651  		}
  1652  		ps = append(ps, ipp)
  1653  	}
  1654  	return
  1655  }
  1656  
  1657  func isZoneOrSubnetConstrainedError(err error) bool {
  1658  	return isZoneConstrainedError(err) || isSubnetConstrainedError(err)
  1659  }
  1660  
  1661  // isZoneConstrainedError reports whether or not the error indicates
  1662  // RunInstances failed due to the specified availability zone being
  1663  // constrained for the instance type being provisioned, or is
  1664  // otherwise unusable for the specific request made.
  1665  func isZoneConstrainedError(err error) bool {
  1666  	switch err := err.(type) {
  1667  	case *ec2.Error:
  1668  		switch err.Code {
  1669  		case "Unsupported", "InsufficientInstanceCapacity":
  1670  			// A big hammer, but we've now seen several different error messages
  1671  			// for constrained zones, and who knows how many more there might
  1672  			// be. If the message contains "Availability Zone", it's a fair
  1673  			// bet that it's constrained or otherwise unusable.
  1674  			return strings.Contains(err.Message, "Availability Zone")
  1675  		case "InvalidInput":
  1676  			// If the region has a default VPC, then we will receive an error
  1677  			// if the AZ does not have a default subnet. Until we have proper
  1678  			// support for networks, we'll skip over these.
  1679  			return strings.HasPrefix(err.Message, "No default subnet for availability zone")
  1680  		case "VolumeTypeNotAvailableInZone":
  1681  			return true
  1682  		}
  1683  	}
  1684  	return false
  1685  }
  1686  
  1687  // isSubnetConstrainedError reports whether or not the error indicates
  1688  // RunInstances failed due to the specified VPC subnet ID being constrained for
  1689  // the instance type being provisioned, or is otherwise unusable for the
  1690  // specific request made.
  1691  func isSubnetConstrainedError(err error) bool {
  1692  	switch err := err.(type) {
  1693  	case *ec2.Error:
  1694  		switch err.Code {
  1695  		case "InsufficientFreeAddressesInSubnet", "InsufficientInstanceCapacity":
  1696  			// Subnet and/or VPC general limits reached.
  1697  			return true
  1698  		case "InvalidSubnetID.NotFound":
  1699  			// This shouldn't happen, as we validate the subnet IDs, but it can
  1700  			// happen if the user manually deleted the subnet outside of Juju.
  1701  			return true
  1702  		}
  1703  	}
  1704  	return false
  1705  }
  1706  
  1707  // If the err is of type *ec2.Error, ec2ErrCode returns
  1708  // its code, otherwise it returns the empty string.
  1709  func ec2ErrCode(err error) string {
  1710  	ec2err, _ := errors.Cause(err).(*ec2.Error)
  1711  	if ec2err == nil {
  1712  		return ""
  1713  	}
  1714  	return ec2err.Code
  1715  }
  1716  
  1717  func (e *environ) AllocateContainerAddresses(hostInstanceID instance.Id, containerTag names.MachineTag, preparedInfo []network.InterfaceInfo) ([]network.InterfaceInfo, error) {
  1718  	return nil, errors.NotSupportedf("container address allocation")
  1719  }
  1720  
  1721  func (e *environ) ReleaseContainerAddresses(interfaces []network.ProviderInterfaceInfo) error {
  1722  	return errors.NotSupportedf("container address allocation")
  1723  }
  1724  
  1725  func (e *environ) supportedInstanceTypes() ([]instances.InstanceType, error) {
  1726  	allInstanceTypes := ec2instancetypes.RegionInstanceTypes(e.cloud.Region)
  1727  	if isVPCIDSet(e.ecfg().vpcID()) {
  1728  		return allInstanceTypes, nil
  1729  	}
  1730  	hasDefaultVPC, err := e.hasDefaultVPC()
  1731  	if err != nil {
  1732  		return nil, errors.Trace(err)
  1733  	}
  1734  	if hasDefaultVPC {
  1735  		return allInstanceTypes, nil
  1736  	}
  1737  
  1738  	// The region has no default VPC, and the user has not specified
  1739  	// one to use. We filter out any instance types that are not
  1740  	// supported in EC2-Classic.
  1741  	supportedInstanceTypes := make([]instances.InstanceType, 0, len(allInstanceTypes))
  1742  	for _, instanceType := range allInstanceTypes {
  1743  		if !ec2instancetypes.SupportsClassic(instanceType.Name) {
  1744  			continue
  1745  		}
  1746  		supportedInstanceTypes = append(supportedInstanceTypes, instanceType)
  1747  	}
  1748  	return supportedInstanceTypes, nil
  1749  }
  1750  
  1751  func (e *environ) hasDefaultVPC() (bool, error) {
  1752  	e.defaultVPCMutex.Lock()
  1753  	defer e.defaultVPCMutex.Unlock()
  1754  	if !e.defaultVPCChecked {
  1755  		filter := ec2.NewFilter()
  1756  		filter.Add("isDefault", "true")
  1757  		resp, err := e.ec2.VPCs(nil, filter)
  1758  		if err != nil {
  1759  			return false, errors.Trace(err)
  1760  		}
  1761  		if len(resp.VPCs) > 0 {
  1762  			e.defaultVPC = &resp.VPCs[0]
  1763  		}
  1764  		e.defaultVPCChecked = true
  1765  	}
  1766  	return e.defaultVPC != nil, nil
  1767  }