rubycfn 0.4.10 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/Gemfile.lock +48 -46
  4. data/README.md +46 -71
  5. data/bin/rubycfn +17 -73
  6. data/lib/cli_methods.rb +2 -2
  7. data/lib/rubycfn/version.rb +1 -1
  8. data/rubycfn.gemspec +1 -1
  9. data/templates/.env +2 -0
  10. data/templates/.env.acceptance +1 -0
  11. data/templates/.env.dependencies.rspec +6 -0
  12. data/templates/.env.development +1 -0
  13. data/templates/.env.production +1 -0
  14. data/templates/.env.rspec +1 -0
  15. data/templates/.env.test +1 -0
  16. data/templates/{.gitignore.erb → .gitignore} +7 -0
  17. data/templates/{.rubocop.yml.erb → .rubocop.yml} +17 -1
  18. data/templates/{Gemfile.erb → Gemfile} +0 -1
  19. data/templates/README.md +58 -0
  20. data/templates/{Rakefile.erb → Rakefile} +15 -8
  21. data/templates/config.yaml +68 -0
  22. data/templates/lib/aws_helper/aws_sdk.rb +30 -0
  23. data/templates/{compiler.rb.erb → lib/aws_helper/compiler.rb} +15 -9
  24. data/templates/lib/aws_helper/dependencies.rb +35 -0
  25. data/templates/{deploy.rb.erb → lib/aws_helper/deploy.rb} +5 -4
  26. data/templates/lib/aws_helper/helpers.rb +3 -0
  27. data/templates/{main_aws_helper.rb.erb → lib/aws_helper/main.rb} +0 -0
  28. data/templates/{upload_stack.rb.erb → lib/aws_helper/upload_stack.rb} +8 -6
  29. data/templates/lib/core/applications.rb +625 -0
  30. data/templates/lib/core/assume_role.rb +40 -0
  31. data/templates/lib/core/classes.rb +25 -0
  32. data/templates/{core_compile.rb.erb → lib/core/compile.rb} +1 -0
  33. data/templates/lib/core/dependencies.rb +29 -0
  34. data/templates/{core_deploy.rb.erb → lib/core/deploy.rb} +20 -10
  35. data/templates/lib/core/git.rb +15 -0
  36. data/templates/lib/core/init.rb +221 -0
  37. data/templates/{core_upload.rb.erb → lib/core/upload.rb} +0 -0
  38. data/templates/{main.rb.erb → lib/main.rb} +8 -6
  39. data/templates/lib/shared_concerns/global_variables.rb +56 -0
  40. data/templates/{helper_methods.rb.erb → lib/shared_concerns/helper_functions.rb} +0 -0
  41. data/templates/lib/shared_concerns/helper_methods.rb +3 -0
  42. data/templates/{shared_methods.rb.erb → lib/shared_concerns/shared_methods.rb} +11 -0
  43. data/templates/lib/stacks/acm_stack/certificate_manager.rb +79 -0
  44. data/templates/{new_stack.rb.erb → lib/stacks/acm_stack/main.rb} +3 -4
  45. data/templates/lib/stacks/ecs_stack/ecs_cluster.rb +344 -0
  46. data/templates/lib/stacks/ecs_stack/lifecycle_hook.rb +190 -0
  47. data/templates/lib/stacks/ecs_stack/load_balancer.rb +70 -0
  48. data/templates/{ecs_stack.rb.erb → lib/stacks/ecs_stack/main.rb} +3 -0
  49. data/templates/lib/stacks/ecs_stack/rollback.rb +77 -0
  50. data/templates/{project_stack.rb.erb → lib/stacks/parent_stack/main.rb} +2 -2
  51. data/templates/lib/stacks/parent_stack/parent.rb +18 -0
  52. data/templates/lib/stacks/vpc_stack/infra_vpc.rb +193 -0
  53. data/templates/{vpc_stack.rb.erb → lib/stacks/vpc_stack/main.rb} +1 -2
  54. data/templates/{parent_stack_spec.rb.erb → spec/lib/parent_spec.rb} +2 -5
  55. data/templates/{spec_helper.rb.erb → spec/spec_helper.rb} +2 -2
  56. metadata +61 -51
  57. data/format.vim +0 -3
  58. data/templates/.env.erb +0 -4
  59. data/templates/.env.production.erb +0 -6
  60. data/templates/.env.rspec.erb +0 -6
  61. data/templates/.env.test.erb +0 -6
  62. data/templates/.gitlab-ci.yml.erb +0 -75
  63. data/templates/aws_sdk.rb.erb +0 -18
  64. data/templates/core_diff.rb.erb +0 -59
  65. data/templates/dependencies.rb.erb +0 -23
  66. data/templates/ecs_stack_concern.rb.erb +0 -20
  67. data/templates/global_variables.rb.erb +0 -16
  68. data/templates/helpers.rb.erb +0 -7
  69. data/templates/new_concern.rb.erb +0 -10
  70. data/templates/project_concern.rb.erb +0 -26
  71. data/templates/subnets.rb.erb +0 -18
  72. data/templates/vpc_concerns.rb.erb +0 -87
  73. data/templates/vpc_spec.rb.erb +0 -39
@@ -0,0 +1,190 @@
1
+ module EcsStack
2
+ module LifecycleHook
3
+ extend ActiveSupport::Concern
4
+ ## Drains instances on termination
5
+ included do
6
+ unless infra_config["environments"][environment]["cluster_size"].nil? || infra_config["environments"][environment]["cluster_size"].to_i.zero?
7
+ resource :ecs_lifecycle_notification_topic,
8
+ depends_on: :lifecycle_handler_function,
9
+ type: "AWS::SNS::Topic" do |r|
10
+ r.property(:subscription) do
11
+ [
12
+ {
13
+ "Endpoint": :lifecycle_handler_function.ref(:arn),
14
+ "Protocol": "lambda"
15
+ }
16
+ ]
17
+ end
18
+ end
19
+
20
+ resource :instance_terminating_hook,
21
+ depends_on: :ecs_lifecycle_notification_topic,
22
+ type: "AWS::AutoScaling::LifecycleHook" do |r|
23
+ r.property(:auto_scaling_group_name) { :ecs_auto_scaling_group.ref }
24
+ r.property(:default_result) { "ABANDON" }
25
+ r.property(:heartbeat_timeout) { 900 }
26
+ r.property(:lifecycle_transition) { "autoscaling:EC2_INSTANCE_TERMINATING" }
27
+ r.property(:notification_target_arn) { :ecs_lifecycle_notification_topic.ref }
28
+ r.property(:role_arn) { :autoscaling_notification_role.ref(:arn) }
29
+ end
30
+
31
+ resource :autoscaling_notification_role,
32
+ type: "AWS::IAM::Role" do |r|
33
+ r.property(:assume_role_policy_document) do
34
+ {
35
+ "Version": "2012-10-17",
36
+ "Statement": [
37
+ {
38
+ "Effect": "Allow",
39
+ "Principal": {
40
+ "Service": [
41
+ "autoscaling.amazonaws.com"
42
+ ]
43
+ },
44
+ "Action": [
45
+ "sts:AssumeRole"
46
+ ]
47
+ }
48
+ ]
49
+ }
50
+ end
51
+ r.property(:managed_policy_arns) { ["arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole"] }
52
+ end
53
+
54
+ resource :lambda_execution_role,
55
+ type: "AWS::IAM::Role" do |r|
56
+ r.property(:policies) do
57
+ [
58
+ {
59
+ "PolicyName": "lambda-inline",
60
+ "PolicyDocument": {
61
+ "Version": "2012-10-17",
62
+ "Statement": [
63
+ {
64
+ "Effect": "Allow",
65
+ "Action": [
66
+ "autoscaling:CompleteLifecycleAction",
67
+ "logs:CreateLogGroup",
68
+ "logs:CreateLogStream",
69
+ "logs:PutLogEvents",
70
+ "ec2:DescribeInstances",
71
+ "ec2:DescribeInstanceAttribute",
72
+ "ec2:DescribeInstanceStatus",
73
+ "ec2:DescribeHosts",
74
+ "ecs:ListContainerInstances",
75
+ "ecs:SubmitContainerStateChange",
76
+ "ecs:SubmitTaskStateChange",
77
+ "ecs:DescribeContainerInstances",
78
+ "ecs:UpdateContainerInstancesState",
79
+ "ecs:ListTasks",
80
+ "ecs:DescribeTasks",
81
+ "sns:Publish",
82
+ "sns:ListSubscriptions"
83
+ ],
84
+ "Resource": "*"
85
+ }
86
+ ]
87
+ }
88
+ }
89
+ ]
90
+ end
91
+ r.property(:assume_role_policy_document) do
92
+ {
93
+ "Version": "2012-10-17",
94
+ "Statement": [
95
+ {
96
+ "Effect": "Allow",
97
+ "Principal": {
98
+ "Service": [
99
+ "lambda.amazonaws.com"
100
+ ]
101
+ },
102
+ "Action": [
103
+ "sts:AssumeRole"
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+ end
109
+ r.property(:managed_policy_arns) do
110
+ [
111
+ "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole"
112
+ ]
113
+ end
114
+ end
115
+
116
+ resource :lambda_invoke_permission,
117
+ type: "AWS::Lambda::Permission" do |r|
118
+ r.property(:function_name) { :lifecycle_handler_function.ref }
119
+ r.property(:action) { "lambda:InvokeFunction" }
120
+ r.property(:principal) { "sns.amazonaws.com" }
121
+ r.property(:source_arn) { :ecs_lifecycle_notification_topic.ref }
122
+ end
123
+
124
+ resource :lifecycle_handler_function,
125
+ type: "AWS::Lambda::Function" do |r|
126
+ r.property(:environment) do
127
+ {
128
+ "Variables": {
129
+ "CLUSTER": :ecs_cluster.ref
130
+ }
131
+ }
132
+ end
133
+ r.property(:code) do
134
+ {
135
+ "ZipFile": {
136
+ "Fn::Join": [
137
+ "\n",
138
+ [
139
+ "import boto3,json,os,time",
140
+ "ec2Client = boto3.client('ec2')",
141
+ "ecsClient = boto3.client('ecs')",
142
+ "autoscalingClient = boto3.client('autoscaling')",
143
+ "snsClient = boto3.client('sns')",
144
+ "lambdaClient = boto3.client('lambda')",
145
+ "def publishSNSMessage(snsMessage,snsTopicArn):",
146
+ " response = snsClient.publish(TopicArn=snsTopicArn,Message=json.dumps(snsMessage),Subject='reinvoking')",
147
+ "def setContainerInstanceStatusToDraining(ecsClusterName,containerInstanceArn):",
148
+ " response = ecsClient.update_container_instances_state(cluster=ecsClusterName,containerInstances=[containerInstanceArn],status='DRAINING')",
149
+ "def tasksRunning(ecsClusterName,ec2InstanceId):",
150
+ " ecsContainerInstances = ecsClient.describe_container_instances(cluster=ecsClusterName,containerInstances=ecsClient.list_container_instances(cluster=ecsClusterName)['containerInstanceArns'])['containerInstances']",
151
+ " for i in ecsContainerInstances:",
152
+ " if i['ec2InstanceId'] == ec2InstanceId:",
153
+ " if i['status'] == 'ACTIVE':",
154
+ " setContainerInstanceStatusToDraining(ecsClusterName,i['containerInstanceArn'])",
155
+ " return 1",
156
+ " if (i['runningTasksCount']>0) or (i['pendingTasksCount']>0):",
157
+ " return 1",
158
+ " return 0",
159
+ " return 2",
160
+ "def lambda_handler(event, context):",
161
+ " ecsClusterName=os.environ['CLUSTER']",
162
+ " snsTopicArn=event['Records'][0]['Sns']['TopicArn']",
163
+ " snsMessage=json.loads(event['Records'][0]['Sns']['Message'])",
164
+ " lifecycleHookName=snsMessage['LifecycleHookName']",
165
+ " lifecycleActionToken=snsMessage['LifecycleActionToken']",
166
+ " asgName=snsMessage['AutoScalingGroupName']",
167
+ " ec2InstanceId=snsMessage['EC2InstanceId']",
168
+ " checkTasks=tasksRunning(ecsClusterName,ec2InstanceId)",
169
+ " if checkTasks==0:",
170
+ " try:",
171
+ " response = autoscalingClient.complete_lifecycle_action(LifecycleHookName=lifecycleHookName,AutoScalingGroupName=asgName,LifecycleActionToken=lifecycleActionToken,LifecycleActionResult='CONTINUE')",
172
+ " except BaseException as e:",
173
+ " print(str(e))",
174
+ " elif checkTasks==1:",
175
+ " time.sleep(5)",
176
+ " publishSNSMessage(snsMessage,snsTopicArn)"
177
+ ]
178
+ ]
179
+ }
180
+ }
181
+ end
182
+ r.property(:handler) { "index.lambda_handler" }
183
+ r.property(:role) { :lambda_execution_role.ref(:arn) }
184
+ r.property(:runtime) { "python3.6" }
185
+ r.property(:timeout) { 10 }
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,70 @@
1
+ module EcsStack
2
+ module LoadBalancer
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ parameter :public_subnets,
6
+ description: "List of Public EC2 Subnets for the ALB"
7
+
8
+ unless infra_config["environments"][environment]["cluster_size"].nil? || infra_config["environments"][environment]["cluster_size"].to_i.zero?
9
+ resource :ecs_load_balancer,
10
+ type: "AWS::ElasticLoadBalancingV2::LoadBalancer" do |r|
11
+ r.property(:name) { environment }
12
+ r.property(:subnets) { :public_subnets.ref.fnsplit(",") }
13
+ r.property(:security_groups) do
14
+ [
15
+ :ecs_host_security_group.ref,
16
+ :load_balancer_security_group.ref # Not sure if necessary
17
+ ]
18
+ end
19
+ r.property(:tags) do
20
+ [
21
+ {
22
+ "Key": "Name",
23
+ "Value": "#{environment}_ecs_loadbalancer"
24
+ }
25
+ ]
26
+ end
27
+ end
28
+
29
+ resource :load_balancer_listener,
30
+ type: "AWS::ElasticLoadBalancingV2::Listener" do |r|
31
+ r.property(:load_balancer_arn) { :ecs_load_balancer.ref }
32
+ r.property(:port) { 80 }
33
+ r.property(:protocol) { "HTTP" }
34
+ r.property(:default_actions) do
35
+ [
36
+ {
37
+ "Type": "forward",
38
+ "TargetGroupArn": :default_target_group.ref
39
+ }
40
+ ]
41
+ end
42
+ end
43
+
44
+ resource :default_target_group,
45
+ type: "AWS::ElasticLoadBalancingV2::TargetGroup" do |r|
46
+ r.property(:name) { "#{environment}-default" }
47
+ r.property(:vpc_id) { :vpc.ref }
48
+ r.property(:port) { 80 }
49
+ r.property(:protocol) { "HTTP" }
50
+ end
51
+
52
+ output :ecs_load_balancer,
53
+ description: "ECS Application Load Balancer",
54
+ value: :ecs_load_balancer.ref
55
+
56
+ output :ecs_load_balancer_url,
57
+ description: "URL of the ECS ALB",
58
+ value: :ecs_load_balancer.ref("DNSName")
59
+
60
+ output :ecs_load_balancer_listener,
61
+ description: "ECS Port 80 listener",
62
+ value: :load_balancer_listener.ref
63
+
64
+ output :ecs_load_balancer_hosted_zone_id,
65
+ description: "Canonical Hosted Zone ID of the ALB",
66
+ value: :ecs_load_balancer.ref("CanonicalHostedZoneID")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -6,6 +6,9 @@ module EcsStack
6
6
  include Concerns::GlobalVariables
7
7
  include Concerns::SharedMethods
8
8
  include EcsStack::EcsCluster
9
+ include EcsStack::LifecycleHook
10
+ include EcsStack::LoadBalancer
11
+ include EcsStack::Rollback
9
12
 
10
13
  description generate_stack_description("EcsStack")
11
14
  end
@@ -0,0 +1,77 @@
1
+ module EcsStack
2
+ module Rollback
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ resource :application_deployment_failure_rollback_lambda,
6
+ type: "AWS::Lambda::Function" do |r|
7
+ r.property(:code) do
8
+ {
9
+ "S3Bucket": "xebia-${AWS::Region}".fnsub,
10
+ "S3Key": "ecs-rollback-0.0.6.zip"
11
+ }
12
+ end
13
+ r.property(:handler) { "index.lambda_handler" }
14
+ r.property(:role) { :application_deployment_failure_rollback_lambda_role.ref(:arn) }
15
+ r.property(:runtime) { "ruby2.5" }
16
+ r.property(:timeout) { 500 }
17
+ end
18
+
19
+ resource :application_deployment_failure_rollback_lambda_role,
20
+ type: "AWS::IAM::Role" do |r|
21
+ r.property(:assume_role_policy_document) do
22
+ {
23
+ "Version": "2012-10-17",
24
+ "Statement": [
25
+ {
26
+ "Effect": "Allow",
27
+ "Principal": {
28
+ "Service": [
29
+ "lambda.amazonaws.com"
30
+ ]
31
+ },
32
+ "Action": "sts:AssumeRole"
33
+ }
34
+ ]
35
+ }
36
+ end
37
+ r.property(:role_name) { "#{environment}-EcsApplicationFailureDetectionRole" }
38
+ end
39
+
40
+ resource :application_deployment_failure_rollback_lambda_policy,
41
+ type: "AWS::IAM::Policy" do |r|
42
+ r.property(:policy_document) do
43
+ {
44
+ "Version": "2012-10-17",
45
+ "Statement": [
46
+ {
47
+ "Effect": "Allow",
48
+ "Action": %w(logs:CreateLogGroup logs:CreateLogStream logs:PutLogEvents),
49
+ "Resource": [
50
+ "arn:aws:logs:*:*:*"
51
+ ]
52
+ },
53
+ {
54
+ "Effect": "Allow",
55
+ "Action": [
56
+ "ecs:*"
57
+ ],
58
+ "Resource": [
59
+ "*"
60
+ ]
61
+ }
62
+ ]
63
+ }
64
+ end
65
+ r.property(:policy_name) { "#{environment}-EcsApplicationFailureDetectionPolicy" }
66
+ r.property(:roles) do
67
+ [
68
+ :application_deployment_failure_rollback_lambda_role.ref
69
+ ]
70
+ end
71
+ end
72
+
73
+ output :application_deployment_failure_rollback_function_arn,
74
+ value: :application_deployment_failure_rollback_lambda.ref(:arn)
75
+ end
76
+ end
77
+ end
@@ -1,11 +1,11 @@
1
- module <%= name %>Stack
1
+ module InfraStack
2
2
  extend ActiveSupport::Concern
3
3
  include Rubycfn
4
4
 
5
5
  included do
6
6
  include Concerns::GlobalVariables
7
7
  include Concerns::SharedMethods
8
- include <%= name %>Stack::Parent
8
+ include InfraStack::Parent
9
9
 
10
10
  description generate_stack_description("ParentStack")
11
11
  end
@@ -0,0 +1,18 @@
1
+ require_relative "../../core/applications"
2
+
3
+ module InfraStack
4
+ module Parent
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ generate_bootstrap_parameters
8
+
9
+ resource :vpc_stack,
10
+ type: "AWS::CloudFormation::Stack" do |r|
11
+ r.property(:template_url) { "vpcstack" }
12
+ r.property(:tags) { default_tags }
13
+ end
14
+
15
+ create_applications
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,193 @@
1
+ module VpcStack
2
+ module InfraVpc
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ vpc_subnets = infra_config["subnets"]
6
+
7
+ variable :cidr_block,
8
+ default: "10.0.0.0/16",
9
+ value: infra_config["environments"][environment]["vpc_cidr"]
10
+
11
+ resource :infra_vpc,
12
+ type: "AWS::EC2::VPC" do |r|
13
+ r.property(:cidr_block) { cidr_block }
14
+ r.property(:enable_dns_support) { true }
15
+ r.property(:enable_dns_hostnames) { true }
16
+ r.property(:tags) do
17
+ [
18
+ {
19
+ "Key": "Name",
20
+ "Value": "infra_#{environment}_vpc"
21
+ },
22
+ {
23
+ "Key": "Environment",
24
+ "Value": environment.to_s
25
+ }
26
+ ]
27
+ end
28
+ end
29
+
30
+ resource :infra_internet_gateway,
31
+ type: "AWS::EC2::InternetGateway"
32
+
33
+ resource :infra_route,
34
+ type: "AWS::EC2::Route" do |r|
35
+ r.property(:destination_cidr_block) { "0.0.0.0/0" }
36
+ r.property(:gateway_id) { :infra_internet_gateway.ref }
37
+ r.property(:route_table_id) { :infra_route_table.ref }
38
+ end
39
+
40
+ resource :infra_route_table,
41
+ type: "AWS::EC2::RouteTable" do |r|
42
+ r.property(:vpc_id) { :infra_vpc.ref }
43
+ r.property(:tags) do
44
+ [
45
+ {
46
+ "Key": "Name",
47
+ "Value": "Infra #{environment} Public Route Table"
48
+ },
49
+ {
50
+ "Key": "Environment",
51
+ "Value": environment.to_s
52
+ }
53
+ ]
54
+ end
55
+ end
56
+
57
+ resource :infra_private_route_table,
58
+ amount: 3,
59
+ type: "AWS::EC2::RouteTable" do |r, index|
60
+ r.property(:vpc_id) { :infra_vpc.ref }
61
+ r.property(:tags) do
62
+ [
63
+ {
64
+ "Key": "Name",
65
+ "Value": "Infra #{environment} Private Route Table #{index.zero? && "" || index + 1}"
66
+ },
67
+ {
68
+ "Key": "Environment",
69
+ "Value": environment.to_s
70
+ }
71
+ ]
72
+ end
73
+ end
74
+
75
+ resource :infra_vpc_gateway_attachment,
76
+ type: "AWS::EC2::VPCGatewayAttachment" do |r|
77
+ r.property(:internet_gateway_id) { :infra_internet_gateway.ref }
78
+ r.property(:vpc_id) { :infra_vpc.ref }
79
+ end
80
+
81
+ vpc_subnets.each_with_index do |subnet, _subnet_count|
82
+ subnet.each do |subnet_name, arguments|
83
+ resource "infra_#{subnet_name}_subnet".cfnize,
84
+ type: "AWS::EC2::Subnet",
85
+ amount: 3 do |r, index|
86
+ subnet_cidr = [
87
+ :infra_vpc.ref(:cidr_block),
88
+ (3 * arguments["offset"]).to_s,
89
+ (Math.log(256) / Math.log(2)).floor.to_s
90
+ ].fncidr.fnselect(index + (3 * arguments["offset"]) - 3)
91
+
92
+ r.property(:availability_zone) do
93
+ {
94
+ "Fn::GetAZs": ""
95
+ }.fnselect(index)
96
+ end
97
+ r.property(:cidr_block) { subnet_cidr }
98
+ r.property(:map_public_ip_on_launch) { arguments["public"] }
99
+ r.property(:tags) do
100
+ [
101
+ {
102
+ "Key": "Name",
103
+ "Value": "#{environment}_#{subnet_name}_#{index + 1}".cfnize
104
+ },
105
+ {
106
+ "Key": "Team",
107
+ "Value": arguments["owner"]
108
+ },
109
+ {
110
+ "Key": "resource_type",
111
+ "Value": subnet_name.to_s.cfnize
112
+ }
113
+ ]
114
+ end
115
+ r.property(:vpc_id) { :infra_vpc.ref }
116
+
117
+ if arguments["output_cidr"]
118
+ cidr_output_name = "#{subnet_name}_subnet#{index.positive? ? (index + 1) : ""}_cidr".cfnize
119
+
120
+ output cidr_output_name,
121
+ value: subnet_cidr
122
+ end
123
+ end
124
+
125
+ if arguments["public"]
126
+ resource "infra_#{subnet_name}_subnet_route_table_association".cfnize,
127
+ amount: 3,
128
+ type: "AWS::EC2::SubnetRouteTableAssociation" do |r, index|
129
+ r.property(:route_table_id) { :infra_route_table.ref }
130
+ r.property(:subnet_id) { "infra_#{subnet_name}_subnet#{index.zero? && "" || index + 1}".cfnize.ref }
131
+ end
132
+ else
133
+ resource "infra_#{subnet_name}_subnet_route_table_association".cfnize,
134
+ amount: 3,
135
+ type: "AWS::EC2::SubnetRouteTableAssociation" do |r, index|
136
+ r.property(:route_table_id) { "infra_private_route_table#{index.zero? && "" || index + 1}".cfnize.ref }
137
+ r.property(:subnet_id) { "infra_#{subnet_name}_subnet#{index.zero? && "" || index + 1}".cfnize.ref }
138
+ end
139
+ end
140
+
141
+ # Generate outputs for these subnets
142
+ 3.times do |i|
143
+ output_name = "#{subnet_name}_subnet#{i.positive? ? (i + 1) : ""}_name".cfnize
144
+
145
+ output output_name,
146
+ value: "infra_#{subnet_name}_subnet#{i.positive? ? (i + 1) : ""}".cfnize.ref
147
+ end
148
+
149
+ # Deploy NAT Gateway in subnet marked with "deploy_nat": true
150
+ if arguments["deploy_nat"]
151
+ resource "infra_#{subnet_name}_elastic_ip".cfnize,
152
+ amount: 3,
153
+ type: "AWS::EC2::EIP" do |r, _|
154
+ r.property(:domain) { "vpc" }
155
+ end
156
+
157
+ resource "infra_#{subnet_name}_nat_gateway".cfnize,
158
+ amount: 3,
159
+ type: "AWS::EC2::NatGateway" do |r, index|
160
+ r.property(:allocation_id) { "infra_#{subnet_name}_elastic_ip#{index.zero? && "" || index + 1}".cfnize.ref(:allocation_id) }
161
+ r.property(:subnet_id) { "infra_#{subnet_name}_subnet#{index.zero? && "" || index + 1}".cfnize.ref }
162
+ end
163
+
164
+ resource :infra_nat_gateway_route,
165
+ depends_on: :infra_vpc_gateway_attachment,
166
+ amount: 3,
167
+ type: "AWS::EC2::Route" do |r, index|
168
+ r.depends_on [
169
+ "InfraEc2PublicNatGateway#{index.zero? && "" || index + 1}"
170
+ ]
171
+ r.property(:destination_cidr_block) { "0.0.0.0/0" }
172
+ r.property(:nat_gateway_id) { "infra_#{subnet_name}_nat_gateway#{index.zero? && "" || index + 1}".cfnize.ref }
173
+ r.property(:route_table_id) { "infra_private_route_table#{index.zero? && "" || index + 1}".cfnize.ref }
174
+ end
175
+
176
+ # Generate outputs for NAT gateway
177
+ 3.times do |i|
178
+ output_name = "nat_gateway_#{subnet_name}#{i.positive? ? (i + 1) : ""}"
179
+
180
+ output output_name,
181
+ value: "infra_#{subnet_name}_nat_gateway#{i.positive? ? (i + 1) : ""}".cfnize.ref
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ output :vpc_cidr,
188
+ value: :infra_vpc.ref(:cidr_block)
189
+ output :vpc_id,
190
+ value: :infra_vpc.ref
191
+ end
192
+ end
193
+ end