diff --git a/platform/api/aws/ec2.go b/platform/api/aws/ec2.go index 126de763e..fb0adc6cc 100644 --- a/platform/api/aws/ec2.go +++ b/platform/api/aws/ec2.go @@ -106,57 +106,66 @@ func (a *API) CreateInstances(name, keyname, userdata string, count uint64) ([]* return nil, fmt.Errorf("error resolving vpc: %v", err) } - subnetId, err := a.getSubnetID(vpcId) + subnetIds, err := a.getSubnetIDs(vpcId) if err != nil { - return nil, fmt.Errorf("error resolving subnet: %v", err) + return nil, fmt.Errorf("error resolving subnets: %v", err) } key := &keyname if keyname == "" { key = nil } - inst := ec2.RunInstancesInput{ - ImageId: &a.opts.AMI, - MinCount: &cnt, - MaxCount: &cnt, - KeyName: key, - InstanceType: &a.opts.InstanceType, - SecurityGroupIds: []*string{&sgId}, - SubnetId: &subnetId, - UserData: ud, - IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ - Name: &a.opts.IAMInstanceProfile, - }, - TagSpecifications: []*ec2.TagSpecification{ - &ec2.TagSpecification{ - ResourceType: aws.String(ec2.ResourceTypeInstance), - Tags: []*ec2.Tag{ - &ec2.Tag{ - Key: aws.String("Name"), - Value: aws.String(name), - }, - &ec2.Tag{ - Key: aws.String("CreatedBy"), - Value: aws.String("mantle"), + + var reservations *ec2.Reservation + + for _, subnetId := range subnetIds { + inst := ec2.RunInstancesInput{ + ImageId: &a.opts.AMI, + MinCount: &cnt, + MaxCount: &cnt, + KeyName: key, + InstanceType: &a.opts.InstanceType, + SecurityGroupIds: []*string{&sgId}, + SubnetId: &subnetId, + UserData: ud, + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Name: &a.opts.IAMInstanceProfile, + }, + TagSpecifications: []*ec2.TagSpecification{ + &ec2.TagSpecification{ + ResourceType: aws.String(ec2.ResourceTypeInstance), + Tags: []*ec2.Tag{ + &ec2.Tag{ + Key: aws.String("Name"), + Value: aws.String(name), + }, + &ec2.Tag{ + Key: aws.String("CreatedBy"), + Value: aws.String("mantle"), + }, }, }, }, - }, - } + } - var reservations *ec2.Reservation - err = util.RetryConditional(5, 5*time.Second, func(err error) bool { - // due to AWS' eventual consistency despite ensuring that the IAM Instance - // Profile has been created it may not be available to ec2 yet. - if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "iamInstanceProfile.name")) { - return true + err = util.RetryConditional(5, 5*time.Second, func(err error) bool { + // due to AWS' eventual consistency despite ensuring that the IAM Instance + // Profile has been created it may not be available to ec2 yet. + if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "iamInstanceProfile.name")) { + return true + } + return false + }, func() error { + var ierr error + reservations, ierr = a.ec2.RunInstances(&inst) + return ierr + }) + + if err == nil { + break } - return false - }, func() error { - var ierr error - reservations, ierr = a.ec2.RunInstances(&inst) - return ierr - }) + } + if err != nil { return nil, fmt.Errorf("error running instances: %v", err) } diff --git a/platform/api/aws/network.go b/platform/api/aws/network.go index 9ce1a66a4..df2746f6a 100644 --- a/platform/api/aws/network.go +++ b/platform/api/aws/network.go @@ -304,8 +304,8 @@ func (a *API) createSubnets(vpcId, routeTableId string) error { return nil } -// getSubnetID gets a subnet for the given VPC. -func (a *API) getSubnetID(vpc string) (string, error) { +// getSubnetIDs gets the subnets for the given VPC. +func (a *API) getSubnetIDs(vpc string) ([]string, error) { subIds, err := a.ec2.DescribeSubnets(&ec2.DescribeSubnetsInput{ Filters: []*ec2.Filter{ { @@ -315,14 +315,21 @@ func (a *API) getSubnetID(vpc string) (string, error) { }, }) if err != nil { - return "", fmt.Errorf("unable to get subnets for vpc %v: %v", vpc, err) + return nil, fmt.Errorf("unable to get subnets for vpc %v: %v", vpc, err) } + + var ids []string + for _, id := range subIds.Subnets { if id.SubnetId != nil { - return *id.SubnetId, nil + ids = append(ids, *id.SubnetId) } } - return "", fmt.Errorf("no subnets found for vpc %v", vpc) + if len(ids) == 0 { + return nil, fmt.Errorf("no subnets found for vpc %v", vpc) + } + + return ids, nil } // getVPCID gets a VPC for the given security group