From 390bbb7b801e310ce32a8ce5534fb09a4a40e3c6 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Mon, 1 Aug 2016 16:46:16 -0400 Subject: [PATCH 1/5] use new resource names for nat/routes to allow resource switch --- api/dist/kernel.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index adc188c26a..379d18bacc 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -538,7 +538,7 @@ "VpcId": { "Ref": "Vpc" } } }, - "NatGateway0": { + "Nat0": { "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { @@ -546,7 +546,7 @@ "SubnetId": { "Ref": "Subnet0" } } }, - "NatGateway1": { + "Nat1": { "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { @@ -554,7 +554,7 @@ "SubnetId": { "Ref": "Subnet1" } } }, - "NatGateway2": { + "Nat2": { "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { @@ -696,7 +696,7 @@ }, "RoutesPrivate0": { "Condition": "Private", - "DependsOn": [ "NatGateway0" ], + "DependsOn": [ "Nat0" ], "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Fn::If": [ "BlankExistingVpc", @@ -707,7 +707,7 @@ }, "RoutesPrivate1": { "Condition": "Private", - "DependsOn": [ "NatGateway1" ], + "DependsOn": [ "Nat1" ], "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Fn::If": [ "BlankExistingVpc", @@ -718,7 +718,7 @@ }, "RoutesPrivate2": { "Condition": "Private", - "DependsOn": [ "NatGateway2" ], + "DependsOn": [ "Nat2" ], "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Fn::If": [ "BlankExistingVpc", @@ -727,33 +727,33 @@ ] } } }, - "RoutePrivateDefault0": { + "RouteDefaultPrivate0": { "Condition": "Private", - "DependsOn": [ "NatGateway0", "RoutesPrivate0" ], + "DependsOn": [ "Nat0", "RoutesPrivate0" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { "Ref": "NatGateway0" }, + "NatGatewayId": { "Ref": "Nat0" }, "RouteTableId": { "Ref": "RoutesPrivate0" } } }, - "RoutePrivateDefault1": { + "RouteDefaultPrivate1": { "Condition": "Private", - "DependsOn": [ "NatGateway1", "RoutesPrivate1" ], + "DependsOn": [ "Nat1", "RoutesPrivate1" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { "Ref": "NatGateway1" }, + "NatGatewayId": { "Ref": "Nat1" }, "RouteTableId": { "Ref": "RoutesPrivate1" } } }, - "RoutePrivateDefault2": { + "RouteDefaultPrivate2": { "Condition": "Private", - "DependsOn": [ "NatGateway2", "RoutesPrivate2" ], + "DependsOn": [ "Nat2", "RoutesPrivate2" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { "Ref": "NatGateway2" }, + "NatGatewayId": { "Ref": "Nat2" }, "RouteTableId": { "Ref": "RoutesPrivate2" } } }, From 30e1dcbfa3d60a1cd31c5ed91a56a5e44cdf4f57 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Mon, 1 Aug 2016 17:09:28 -0400 Subject: [PATCH 2/5] change name of eip resource to replace --- api/dist/kernel.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index 379d18bacc..5dccc60953 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -542,7 +542,7 @@ "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { - "AllocationId": { "Fn::GetAtt": [ "NatIp0", "AllocationId" ] }, + "AllocationId": { "Fn::GetAtt": [ "NatAddress0", "AllocationId" ] }, "SubnetId": { "Ref": "Subnet0" } } }, @@ -550,7 +550,7 @@ "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { - "AllocationId": { "Fn::GetAtt": [ "NatIp1", "AllocationId" ] }, + "AllocationId": { "Fn::GetAtt": [ "NatAddress1", "AllocationId" ] }, "SubnetId": { "Ref": "Subnet1" } } }, @@ -558,25 +558,25 @@ "Condition": "Private", "Type": "AWS::EC2::NatGateway", "Properties": { - "AllocationId": { "Fn::GetAtt": [ "NatIp2", "AllocationId" ] }, + "AllocationId": { "Fn::GetAtt": [ "NatAddress2", "AllocationId" ] }, "SubnetId": { "Ref": "Subnet2" } } }, - "NatIp0": { + "NatAddress0": { "Condition": "Private", "Type": "AWS::EC2::EIP", "Properties": { "Domain": "vpc" } }, - "NatIp1": { + "NatAddress1": { "Condition": "Private", "Type": "AWS::EC2::EIP", "Properties": { "Domain": "vpc" } }, - "NatIp2": { + "NatAddress2": { "Condition": "Private", "Type": "AWS::EC2::EIP", "Properties": { From b4a15b40bc3bac569c92f1d8fd42a360c006713c Mon Sep 17 00:00:00 2001 From: David Dollar Date: Mon, 1 Aug 2016 17:41:52 -0400 Subject: [PATCH 3/5] rename route resources to switch type --- api/dist/kernel.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index 5dccc60953..b0b6dd0193 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -694,7 +694,7 @@ "RouteTableId": { "Ref": "Routes" } } }, - "RoutesPrivate0": { + "RouteTablePrivate0": { "Condition": "Private", "DependsOn": [ "Nat0" ], "Type": "AWS::EC2::RouteTable", @@ -705,7 +705,7 @@ ] } } }, - "RoutesPrivate1": { + "RouteTablePrivate1": { "Condition": "Private", "DependsOn": [ "Nat1" ], "Type": "AWS::EC2::RouteTable", @@ -716,7 +716,7 @@ ] } } }, - "RoutesPrivate2": { + "RouteTablePrivate2": { "Condition": "Private", "DependsOn": [ "Nat2" ], "Type": "AWS::EC2::RouteTable", @@ -729,32 +729,32 @@ }, "RouteDefaultPrivate0": { "Condition": "Private", - "DependsOn": [ "Nat0", "RoutesPrivate0" ], + "DependsOn": [ "Nat0", "RouteTablePrivate0" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "Nat0" }, - "RouteTableId": { "Ref": "RoutesPrivate0" } + "RouteTableId": { "Ref": "RouteTablePrivate0" } } }, "RouteDefaultPrivate1": { "Condition": "Private", - "DependsOn": [ "Nat1", "RoutesPrivate1" ], + "DependsOn": [ "Nat1", "RouteTablePrivate1" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "Nat1" }, - "RouteTableId": { "Ref": "RoutesPrivate1" } + "RouteTableId": { "Ref": "RouteTablePrivate1" } } }, "RouteDefaultPrivate2": { "Condition": "Private", - "DependsOn": [ "Nat2", "RoutesPrivate2" ], + "DependsOn": [ "Nat2", "RouteTablePrivate2" ], "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "Nat2" }, - "RouteTableId": { "Ref": "RoutesPrivate2" } + "RouteTableId": { "Ref": "RouteTablePrivate2" } } }, "Subnet0Routes": { @@ -786,29 +786,29 @@ }, "SubnetPrivate0Routes": { "Condition": "Private", - "DependsOn": [ "SubnetPrivate0", "RoutesPrivate0" ], + "DependsOn": [ "SubnetPrivate0", "RouteTablePrivate0" ], "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "SubnetPrivate0" }, - "RouteTableId": { "Ref": "RoutesPrivate0" } + "RouteTableId": { "Ref": "RouteTablePrivate0" } } }, "SubnetPrivate1Routes": { "Condition": "Private", - "DependsOn": [ "SubnetPrivate1", "RoutesPrivate1" ], + "DependsOn": [ "SubnetPrivate1", "RouteTablePrivate1" ], "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "SubnetPrivate1" }, - "RouteTableId": { "Ref": "RoutesPrivate1" } + "RouteTableId": { "Ref": "RouteTablePrivate1" } } }, "SubnetPrivate2Routes": { "Condition": "Private", - "DependsOn": [ "SubnetPrivate2", "RoutesPrivate2" ], + "DependsOn": [ "SubnetPrivate2", "RouteTablePrivate2" ], "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "SubnetPrivate2" }, - "RouteTableId": { "Ref": "RoutesPrivate2" } + "RouteTableId": { "Ref": "RouteTablePrivate2" } } }, "SecurityGroup": { From f79f5484de68ea1070346e7813fc43f14d624fac Mon Sep 17 00:00:00 2001 From: David Dollar Date: Mon, 1 Aug 2016 18:11:09 -0400 Subject: [PATCH 4/5] bring back delete handlers for ec2route and ec2natgateway --- api/cmd/formation/handler/ec2.go | 96 ++++++++++++++++++++++++++ api/cmd/formation/handler/formation.go | 4 ++ 2 files changed, 100 insertions(+) diff --git a/api/cmd/formation/handler/ec2.go b/api/cmd/formation/handler/ec2.go index df4eec47dd..bb4b2060e3 100644 --- a/api/cmd/formation/handler/ec2.go +++ b/api/cmd/formation/handler/ec2.go @@ -5,8 +5,10 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" ) @@ -31,6 +33,40 @@ func HandleEC2AvailabilityZones(req Request) (string, map[string]string, error) return "", nil, fmt.Errorf("unknown RequestType: %s", req.RequestType) } +func HandleEC2NatGateway(req Request) (string, map[string]string, error) { + defer recoverFailure(req) + + switch req.RequestType { + case "Create": + return "invalid", nil, fmt.Errorf("Custom::EC2NatGateway is no longer available") + case "Update": + return "invalid", nil, fmt.Errorf("Custom::EC2NatGateway is no longer available") + case "Delete": + fmt.Println("DELETING NATGATEWAY") + fmt.Printf("req %+v\n", req) + return EC2NatGatewayDelete(req) + } + + return "", nil, fmt.Errorf("unknown RequestType: %s", req.RequestType) +} + +func HandleEC2Route(req Request) (string, map[string]string, error) { + defer recoverFailure(req) + + switch req.RequestType { + case "Create": + return "invalid", nil, fmt.Errorf("Custom::EC2Route is no longer available") + case "Update": + return "invalid", nil, fmt.Errorf("Custom::EC2Route is no longer available") + case "Delete": + fmt.Println("DELETING ROUTE") + fmt.Printf("req %+v\n", req) + return EC2RouteDelete(req) + } + + return "", nil, fmt.Errorf("unknown RequestType: %s", req.RequestType) +} + var regexMatchAvailabilityZones = regexp.MustCompile(`following availability zones: ([^.]+)`) func EC2AvailabilityZonesCreate(req Request) (string, map[string]string, error) { @@ -72,3 +108,63 @@ func EC2AvailabilityZonesDelete(req Request) (string, map[string]string, error) // nop return req.PhysicalResourceId, nil, nil } + +// TODO: delete +func EC2NatGatewayDelete(req Request) (string, map[string]string, error) { + _, err := EC2(req).DeleteNatGateway(&ec2.DeleteNatGatewayInput{ + NatGatewayId: aws.String(req.PhysicalResourceId), + }) + + // block for 2 minutes until it's deleted + // Fixes subsequent CF error on deleting Elastic IP: + // API: ec2:disassociateAddress You do not have permission to access the specified resource. + for i := 0; i < 12; i++ { + resp, derr := EC2(req).DescribeNatGateways(&ec2.DescribeNatGatewaysInput{ + NatGatewayIds: []*string{aws.String(req.PhysicalResourceId)}, + }) + + if derr != nil { + fmt.Printf("EC2NatGatewayDelete error: %s\n", derr) + + // if nat gateway not found, break + if ae, ok := derr.(awserr.Error); ok { + if ae.Code() == "InvalidParameterException" { + break + } + } + } + + // if NAT gateway is deleted, break + if len(resp.NatGateways) == 1 { + n := resp.NatGateways[0] + + if *n.State == "deleted" { + break + } + } + + // sleep and retry + time.Sleep(10 * time.Second) + } + + // return original DeleteNatGateway success / failure + return req.PhysicalResourceId, nil, err +} + +// TODO: delete +func EC2RouteDelete(req Request) (string, map[string]string, error) { + parts := strings.SplitN(req.PhysicalResourceId, "/", 2) + + _, err := EC2(req).DeleteRoute(&ec2.DeleteRouteInput{ + DestinationCidrBlock: aws.String(parts[1]), + RouteTableId: aws.String(parts[0]), + }) + + if ae, ok := err.(awserr.Error); ok { + if ae.Code() == "InvalidRoute.NotFound" { + return req.PhysicalResourceId, nil, nil + } + } + + return req.PhysicalResourceId, nil, err +} diff --git a/api/cmd/formation/handler/formation.go b/api/cmd/formation/handler/formation.go index be62294101..07a2c0855e 100644 --- a/api/cmd/formation/handler/formation.go +++ b/api/cmd/formation/handler/formation.go @@ -166,6 +166,10 @@ func HandleRequest(freq Request) error { switch freq.ResourceType { case "Custom::EC2AvailabilityZones": physical, outputs, err = HandleEC2AvailabilityZones(freq) + case "Custom::EC2NatGateway": + physical, outputs, err = HandleEC2NatGateway(freq) + case "Custom::EC2Route": + physical, outputs, err = HandleEC2Route(freq) case "Custom::ECRRepository": physical, outputs, err = HandleECRRepository(freq) case "Custom::ECSService": From 6c941278cc16150579062a6f5bdc98766be72f7f Mon Sep 17 00:00:00 2001 From: David Dollar Date: Mon, 1 Aug 2016 18:13:19 -0400 Subject: [PATCH 5/5] comments for hound --- api/cmd/formation/handler/ec2.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/cmd/formation/handler/ec2.go b/api/cmd/formation/handler/ec2.go index bb4b2060e3..0238f6e777 100644 --- a/api/cmd/formation/handler/ec2.go +++ b/api/cmd/formation/handler/ec2.go @@ -33,6 +33,7 @@ func HandleEC2AvailabilityZones(req Request) (string, map[string]string, error) return "", nil, fmt.Errorf("unknown RequestType: %s", req.RequestType) } +// HandleEC2NatGateway handles the lifecycle of a Custom::EC2NatGateway func HandleEC2NatGateway(req Request) (string, map[string]string, error) { defer recoverFailure(req) @@ -50,6 +51,7 @@ func HandleEC2NatGateway(req Request) (string, map[string]string, error) { return "", nil, fmt.Errorf("unknown RequestType: %s", req.RequestType) } +// HandleEC2Route handles the lifecycle of a Custom::EC2Route func HandleEC2Route(req Request) (string, map[string]string, error) { defer recoverFailure(req) @@ -109,6 +111,7 @@ func EC2AvailabilityZonesDelete(req Request) (string, map[string]string, error) return req.PhysicalResourceId, nil, nil } +// EC2NatGatewayDelete deletes a Custom::EC2route // TODO: delete func EC2NatGatewayDelete(req Request) (string, map[string]string, error) { _, err := EC2(req).DeleteNatGateway(&ec2.DeleteNatGatewayInput{ @@ -151,6 +154,7 @@ func EC2NatGatewayDelete(req Request) (string, map[string]string, error) { return req.PhysicalResourceId, nil, err } +// EC2RouteDelete deletes a Custom::EC2route // TODO: delete func EC2RouteDelete(req Request) (string, map[string]string, error) { parts := strings.SplitN(req.PhysicalResourceId, "/", 2)