Skip to content

Commit

Permalink
Fix #195 and #196 - issues with creating VPCs in regions with < 3 ava…
Browse files Browse the repository at this point in the history
…ilability zones
  • Loading branch information
cplee committed Jul 31, 2018
1 parent 1cb009f commit 67eab52
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
6 changes: 6 additions & 0 deletions common/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ type ImageFinder interface {
FindLatestImageID(namePattern string) (string, error)
}

// AZCounter for counting availability zones in a region
type AZCounter interface {
CountAZs() (int, error)
}

// StackManager composite of all stack capabilities
type StackManager interface {
StackUpserter
Expand All @@ -48,4 +53,5 @@ type StackManager interface {
StackGetter
StackDeleter
ImageFinder
AZCounter
}
19 changes: 19 additions & 0 deletions provider/aws/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,25 @@ func (cfnMgr *cloudformationStackManager) GetStack(stackName string) (*common.St
return stack, nil
}

// CountAZs for current region
func (cfnMgr *cloudformationStackManager) CountAZs() (int, error) {
ec2Api := cfnMgr.ec2API
resp, err := ec2Api.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("state"),
Values: []*string{
aws.String("available"),
},
},
},
})
if err != nil {
return 0, err
}
return len(resp.AvailabilityZones), nil
}

// FindLatestImageID for a given
func (cfnMgr *cloudformationStackManager) FindLatestImageID(namePattern string) (string, error) {
ec2Api := cfnMgr.ec2API
Expand Down
4 changes: 4 additions & 0 deletions templates/assets/vpc-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Parameters:
ElbSubnetIds:
Description: ELB subnet ids
Type: CommaDelimitedList
AZCount:
Description: Number of availability zones to use
Type: String
Default: '3'
Resources:
WaitHandle:
Type: "AWS::CloudFormation::WaitConditionHandle"
Expand Down
24 changes: 18 additions & 6 deletions templates/assets/vpc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ Parameters:
Description: SSH Key to add to bastion
Type: String
Default: ''
AZCount:
Description: Number of availability zones to use
Type: String
Default: '3'
Conditions:
HasElbSubnetAZ1:
"Fn::Not":
Expand All @@ -111,10 +115,14 @@ Conditions:
- !Ref ElbSubnetAZ2CidrBlock
- ''
HasElbSubnetAZ3:
"Fn::Not":
"Fn::And":
- "Fn::Equals":
- !Ref ElbSubnetAZ3CidrBlock
- ''
- !Ref AZCount
- '3'
- "Fn::Not":
- "Fn::Equals":
- !Ref ElbSubnetAZ3CidrBlock
- ''
HasInstanceSubnetAZ1:
"Fn::Not":
- "Fn::Equals":
Expand All @@ -126,10 +134,14 @@ Conditions:
- !Ref InstanceSubnetAZ2CidrBlock
- ''
HasInstanceSubnetAZ3:
"Fn::Not":
"Fn::And":
- "Fn::Equals":
- !Ref InstanceSubnetAZ3CidrBlock
- ''
- !Ref AZCount
- '3'
- "Fn::Not":
- "Fn::Equals":
- !Ref InstanceSubnetAZ3CidrBlock
- ''
IsPublicElb:
"Fn::Not":
- "Fn::Equals":
Expand Down
13 changes: 11 additions & 2 deletions workflows/environment_upsert.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func NewEnvironmentUpserter(ctx *common.Context, environmentName string) Executo
return newPipelineExecutor(
workflow.environmentFinder(&ctx.Config, environmentName),
workflow.environmentRolesetUpserter(ctx.RolesetManager, ctx.RolesetManager, consulStackParams, ecsStackParams),
workflow.environmentVpcUpserter(ctx.Config.Namespace, ecsStackParams, elbStackParams, consulStackParams, ctx.StackManager, ctx.StackManager, ctx.StackManager),
workflow.environmentVpcUpserter(ctx.Config.Namespace, ecsStackParams, elbStackParams, consulStackParams, ctx.StackManager, ctx.StackManager, ctx.StackManager, ctx.StackManager),
workflow.environmentElbUpserter(ctx.Config.Namespace, ecsStackParams, elbStackParams, ctx.StackManager, ctx.StackManager, ctx.StackManager),
newConditionalExecutor(workflow.isConsulEnabled(), workflow.environmentConsulUpserter(ctx.Config.Namespace, consulStackParams, ecsStackParams, ctx.StackManager, ctx.StackManager, ctx.StackManager), nil),
workflow.environmentUpserter(ctx.Config.Namespace, ecsStackParams, ctx.StackManager, ctx.StackManager, ctx.StackManager),
Expand All @@ -48,7 +48,7 @@ func (workflow *environmentWorkflow) environmentFinder(config *common.Config, en
}
}

func (workflow *environmentWorkflow) environmentVpcUpserter(namespace string, ecsStackParams map[string]string, elbStackParams map[string]string, consulStackParams map[string]string, imageFinder common.ImageFinder, stackUpserter common.StackUpserter, stackWaiter common.StackWaiter) Executor {
func (workflow *environmentWorkflow) environmentVpcUpserter(namespace string, ecsStackParams map[string]string, elbStackParams map[string]string, consulStackParams map[string]string, imageFinder common.ImageFinder, stackUpserter common.StackUpserter, stackWaiter common.StackWaiter, azCounter common.AZCounter) Executor {
return func() error {
environment := workflow.environment
vpcStackParams := make(map[string]string)
Expand Down Expand Up @@ -89,6 +89,15 @@ func (workflow *environmentWorkflow) environmentVpcUpserter(namespace string, ec
vpcStackParams["InstanceSubnetIds"] = strings.Join(environment.VpcTarget.InstanceSubnetIds, ",")
}

azCount, err := azCounter.CountAZs()
if err != nil {
return err
}
if azCount < 2 {
return fmt.Errorf("Only found %v availability zones...need at least 2", azCount)
}
vpcStackParams["AZCount"] = strconv.Itoa(azCount)

log.Noticef("Upserting VPC environment '%s' ...", environment.Name)

tags := createTagMap(&EnvironmentTags{
Expand Down
16 changes: 12 additions & 4 deletions workflows/environment_upsert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package workflows

import (
"bytes"
"testing"

"github.com/stelligent/mu/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gopkg.in/yaml.v2"
"testing"
)

func TestEnvironmentFinder(t *testing.T) {
Expand Down Expand Up @@ -70,6 +71,10 @@ func (m *mockedStackManagerForUpsert) FindLatestImageID(pattern string) (string,
args := m.Called()
return args.String(0), args.Error(1)
}
func (m *mockedStackManagerForUpsert) CountAZs() (int, error) {
args := m.Called()
return args.Int(0), nil
}

func TestEnvironmentEcsUpserter(t *testing.T) {
assert := assert.New(t)
Expand Down Expand Up @@ -196,8 +201,9 @@ func TestEnvironmentVpcUpserter(t *testing.T) {
stackManager.On("AwaitFinalStatus", "mu-vpc-foo").Return(&common.Stack{Status: common.StackStatusCreateComplete})
stackManager.On("UpsertStack", "mu-vpc-foo", mock.AnythingOfType("map[string]string")).Return(nil)
stackManager.On("FindLatestImageID").Return("ami-00000", nil)
stackManager.On("CountAZs").Return(3)

err := workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager)()
err := workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager, stackManager)()
assert.Nil(err)
assert.Equal("mu-vpc-foo-VpcId", vpcInputParams["VpcId"])
assert.Equal("mu-vpc-foo-InstanceSubnetIds", vpcInputParams["InstanceSubnetIds"])
Expand All @@ -221,8 +227,9 @@ func TestEnvironmentVpcUpserter_NoBastion(t *testing.T) {
stackManager := new(mockedStackManagerForUpsert)
stackManager.On("AwaitFinalStatus", "mu-vpc-foo").Return(&common.Stack{Status: common.StackStatusCreateComplete})
stackManager.On("UpsertStack", "mu-vpc-foo", mock.AnythingOfType("map[string]string")).Return(nil)
stackManager.On("CountAZs").Return(3)

err := workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager)()
err := workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager, stackManager)()
assert.Nil(err)
assert.Equal("mu-vpc-foo-VpcId", vpcInputParams["VpcId"])
assert.Equal("mu-vpc-foo-InstanceSubnetIds", vpcInputParams["InstanceSubnetIds"])
Expand Down Expand Up @@ -254,11 +261,12 @@ environments:
stackManager := new(mockedStackManagerForUpsert)
stackManager.On("UpsertStack", "mu-target-dev", mock.AnythingOfType("map[string]string")).Return(nil)
stackManager.On("AwaitFinalStatus", "mu-target-dev").Return(&common.Stack{Status: common.StackStatusCreateComplete})
stackManager.On("CountAZs").Return(3)

workflow := new(environmentWorkflow)
workflow.environment = &config.Environments[0]

err = workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager)()
err = workflow.environmentVpcUpserter("mu", vpcInputParams, vpcInputParams, vpcInputParams, stackManager, stackManager, stackManager, stackManager)()
assert.Nil(err)
assert.Equal("mu-target-dev-VpcId", vpcInputParams["VpcId"])
assert.Equal("mu-target-dev-InstanceSubnetIds", vpcInputParams["InstanceSubnetIds"])
Expand Down

0 comments on commit 67eab52

Please sign in to comment.