shiprails 0.1.5 → 0.1.7
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.
- checksums.yaml +4 -4
- data/lib/shiprails/ship/install.rb +1 -1
- data/lib/shiprails/ship/setup.rb +469 -15
- data/lib/shiprails/version.rb +1 -1
- data/shiprails.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c32b0a8dd0dfb9748f6638795d209ff1851e018
|
4
|
+
data.tar.gz: 558a8c9922e386130f411b446cb469018b6785fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f477b73820f0046ff2c42952482c5b8b28def379a3df2e5dec8f44bd165d9df05bc78c57e67f747d141a12cff85c984a04f95c0fbf0c5be9a360477d59f0e1d1
|
7
|
+
data.tar.gz: 37b8bb889c1d0ffe99f34163400b73321e54d8623feb8a4d356cf3725acecf34d3952f7509958b0ceb67fd516fcc95081ce998f55abef1a2d4d915c8279ce12a
|
@@ -48,7 +48,7 @@ module Shiprails
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def ec2_ssh_private_key_path
|
51
|
-
@ec2_ssh_private_key_path ||= ask "Where is your AWS EC2 SSH private key?", default:
|
51
|
+
@ec2_ssh_private_key_path ||= ask "Where is your AWS EC2 SSH private key?", default: "#{project_name}.pem"
|
52
52
|
end
|
53
53
|
|
54
54
|
def environments
|
data/lib/shiprails/ship/setup.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require "active_support/all"
|
2
2
|
require "aws-sdk"
|
3
|
+
require "base64"
|
4
|
+
require "fileutils"
|
3
5
|
require "git"
|
6
|
+
require "netaddr"
|
4
7
|
require "thor/group"
|
5
8
|
|
6
9
|
module Shiprails
|
@@ -35,11 +38,349 @@ module Shiprails
|
|
35
38
|
say "Created CloudWatch Log groups.", :green
|
36
39
|
end
|
37
40
|
|
41
|
+
def create_vpcs
|
42
|
+
say "Creating VPCs..."
|
43
|
+
created_vpcs = []
|
44
|
+
configuration[:services].each do |service_name, service|
|
45
|
+
service[:regions].each do |region_name, region|
|
46
|
+
ec2 = Aws::EC2::Client.new region: region_name.to_s
|
47
|
+
region[:environments].each do |environment_name|
|
48
|
+
vpc_name = "#{project_name}_#{environment_name}"
|
49
|
+
unless created_vpcs.include? vpc_name
|
50
|
+
begin
|
51
|
+
vpcs = ec2.describe_vpcs.vpcs
|
52
|
+
vpc = vpcs.find{ |v| v.tags.find{|t| t.key == "Name" }.try(:value) == vpc_name }
|
53
|
+
unless vpc.nil?
|
54
|
+
say "Found #{vpc_name}."
|
55
|
+
next
|
56
|
+
end
|
57
|
+
say "Setting up #{vpc_name}."
|
58
|
+
vpc_cidr_block = "10.0.0.0/16"
|
59
|
+
vpc = ec2.create_vpc({
|
60
|
+
amazon_provided_ipv_6_cidr_block: true,
|
61
|
+
cidr_block: vpc_cidr_block,
|
62
|
+
}).vpc
|
63
|
+
vpc = Aws::EC2::Vpc.new client: ec2, id: vpc.vpc_id
|
64
|
+
vpc.modify_attribute({
|
65
|
+
enable_dns_support: { value: true }
|
66
|
+
})
|
67
|
+
vpc.create_tags({ tags: [{ key: 'Name', value: vpc_name }]})
|
68
|
+
availability_zones = ec2.describe_availability_zones({
|
69
|
+
filters: [{
|
70
|
+
name: "state",
|
71
|
+
values: ["available"]
|
72
|
+
}]
|
73
|
+
}).availability_zones
|
74
|
+
say "Creating #{availability_zones.length} availability zones."
|
75
|
+
bits = 16
|
76
|
+
while true
|
77
|
+
begin
|
78
|
+
NetAddr::CIDR.create(vpc_cidr_block).subnet(:Bits => bits, :NumSubnets => availability_zones.count)
|
79
|
+
rescue
|
80
|
+
bits += 1
|
81
|
+
retry if bits <= 32
|
82
|
+
end
|
83
|
+
break
|
84
|
+
end
|
85
|
+
cidr_blocks = NetAddr::CIDR.create(vpc_cidr_block).subnet(:Bits => bits, :NumSubnets => availability_zones.count)
|
86
|
+
availability_zones.each_with_index do |zone, idx|
|
87
|
+
ec2.create_subnet({
|
88
|
+
vpc_id: vpc.vpc_id,
|
89
|
+
cidr_block: cidr_blocks[idx],
|
90
|
+
ipv_6_cidr_block: "2001:db8:1234:1a#{idx.to_s.rjust(2, '0')}::/64",
|
91
|
+
availability_zone: zone.zone_name,
|
92
|
+
})
|
93
|
+
say "Created subnet for #{zone.zone_name} availability zone (#{vpc_name})."
|
94
|
+
end
|
95
|
+
ec2.create_route_table({
|
96
|
+
vpc_id: vpc.vpc_id,
|
97
|
+
})
|
98
|
+
say "Created route table for #{vpc_name}."
|
99
|
+
ig = ec2.create_internet_gateway.internet_gateway
|
100
|
+
ec2.attach_internet_gateway({
|
101
|
+
internet_gateway_id: ig.internet_gateway_id,
|
102
|
+
vpc_id: vpc.vpc_id,
|
103
|
+
})
|
104
|
+
say "Created internet gateway for #{vpc_name}."
|
105
|
+
# rescue Aws::IAM::Errors::EntityAlreadyExists => err
|
106
|
+
end
|
107
|
+
say "Created #{vpc_name} VPC."
|
108
|
+
created_vpcs << vpc_name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
say "Created VPCs.", :green
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_security_groups
|
117
|
+
say "Creating security groups..."
|
118
|
+
completed_vpcs = []
|
119
|
+
configuration[:services].each do |service_name, service|
|
120
|
+
service[:regions].each do |region_name, region|
|
121
|
+
ec2 = Aws::EC2::Client.new region: region_name.to_s
|
122
|
+
region[:environments].each do |environment_name|
|
123
|
+
vpc_name = "#{project_name}_#{environment_name}"
|
124
|
+
unless completed_vpcs.include? vpc_name
|
125
|
+
begin
|
126
|
+
vpcs = ec2.describe_vpcs.vpcs
|
127
|
+
vpc = vpcs.find{ |v| v.tags.find{|t| t.key == "Name" }.value == vpc_name }
|
128
|
+
ecs_security_group_id = ec2.create_security_group({
|
129
|
+
group_name: "ecs-#{vpc_name}",
|
130
|
+
description: "ECS cluster instances",
|
131
|
+
vpc_id: vpc.vpc_id
|
132
|
+
}).group_id
|
133
|
+
elb_security_group_id = ec2.create_security_group({
|
134
|
+
group_name: "elb-#{vpc_name}",
|
135
|
+
description: "ELB instances",
|
136
|
+
vpc_id: vpc.vpc_id
|
137
|
+
}).group_id
|
138
|
+
public_web_security_group_id = ec2.create_security_group({
|
139
|
+
group_name: "public-web-#{vpc_name}",
|
140
|
+
description: "Public web ingress",
|
141
|
+
vpc_id: vpc.vpc_id
|
142
|
+
}).group_id
|
143
|
+
datastores_security_group_id = ec2.create_security_group({
|
144
|
+
group_name: "datastores-#{vpc_name}",
|
145
|
+
description: "RDS, ElastiCache, etc. instances",
|
146
|
+
vpc_id: vpc.vpc_id
|
147
|
+
}).group_id
|
148
|
+
team_access_security_group_id = ec2.create_security_group({
|
149
|
+
group_name: "team-access-#{vpc_name}",
|
150
|
+
description: "Ingress for team members",
|
151
|
+
vpc_id: vpc.vpc_id
|
152
|
+
}).group_id
|
153
|
+
# allow ECS instances to receive traffic from ELBs
|
154
|
+
ec2.authorize_security_group_ingress({
|
155
|
+
group_id: ecs_security_group_id,
|
156
|
+
source_security_group_name: "elb-#{vpc_name}",
|
157
|
+
})
|
158
|
+
# allow public web group to receive traffic from the web
|
159
|
+
ec2.authorize_security_group_ingress({
|
160
|
+
group_id: public_web_security_group_id,
|
161
|
+
ip_permissions: [
|
162
|
+
{
|
163
|
+
prefix_list_ids: [],
|
164
|
+
from_port: "80",
|
165
|
+
ip_ranges: [{
|
166
|
+
cidr_ip: "0.0.0.0/0"
|
167
|
+
}],
|
168
|
+
to_port: "80",
|
169
|
+
ip_protocol: "tcp",
|
170
|
+
user_id_group_pairs: [],
|
171
|
+
ipv_6_ranges: [{
|
172
|
+
cidr_ipv_6: "::/0"
|
173
|
+
}]
|
174
|
+
},
|
175
|
+
{
|
176
|
+
prefix_list_ids: [],
|
177
|
+
from_port: "443",
|
178
|
+
ip_ranges: [{
|
179
|
+
cidr_ip: "0.0.0.0/0"
|
180
|
+
}],
|
181
|
+
to_port: "443",
|
182
|
+
ip_protocol: "-1",
|
183
|
+
user_id_group_pairs: [],
|
184
|
+
ipv_6_ranges: [{
|
185
|
+
cidr_ipv_6: "::/0"
|
186
|
+
}]
|
187
|
+
},
|
188
|
+
]
|
189
|
+
})
|
190
|
+
# allow datastore instances to receive traffic from ECS instances
|
191
|
+
current_ip_address = `curl http://ipecho.net/plain`
|
192
|
+
ec2.authorize_security_group_ingress({
|
193
|
+
group_id: team_access_security_group_id,
|
194
|
+
ip_permissions: [
|
195
|
+
{
|
196
|
+
prefix_list_ids: [],
|
197
|
+
from_port: "-1",
|
198
|
+
ip_ranges: [{
|
199
|
+
cidr_ip: "#{current_ip_address}/32"
|
200
|
+
}],
|
201
|
+
to_port: "-1",
|
202
|
+
ip_protocol: "-1",
|
203
|
+
user_id_group_pairs: [],
|
204
|
+
ipv_6_ranges: []
|
205
|
+
},
|
206
|
+
]
|
207
|
+
})
|
208
|
+
# allow ELBs to access ECS instances
|
209
|
+
ec2.authorize_security_group_egress({
|
210
|
+
group_id: elb_security_group_id,
|
211
|
+
source_security_group_name: "ecs-#{vpc_name}",
|
212
|
+
})
|
213
|
+
# allow ECS instances to access the public web
|
214
|
+
ec2.authorize_security_group_egress({
|
215
|
+
group_id: ecs_security_group_id,
|
216
|
+
ip_permissions: [
|
217
|
+
{
|
218
|
+
prefix_list_ids: [],
|
219
|
+
from_port: "80",
|
220
|
+
ip_ranges: [{
|
221
|
+
cidr_ip: "0.0.0.0/0"
|
222
|
+
}],
|
223
|
+
to_port: "80",
|
224
|
+
ip_protocol: "tcp",
|
225
|
+
user_id_group_pairs: [],
|
226
|
+
ipv_6_ranges: [{
|
227
|
+
cidr_ipv_6: "::/0"
|
228
|
+
}]
|
229
|
+
},
|
230
|
+
{
|
231
|
+
prefix_list_ids: [],
|
232
|
+
from_port: "443",
|
233
|
+
ip_ranges: [{
|
234
|
+
cidr_ip: "0.0.0.0/0"
|
235
|
+
}],
|
236
|
+
to_port: "443",
|
237
|
+
ip_protocol: "-1",
|
238
|
+
user_id_group_pairs: [],
|
239
|
+
ipv_6_ranges: [{
|
240
|
+
cidr_ipv_6: "::/0"
|
241
|
+
}]
|
242
|
+
},
|
243
|
+
]
|
244
|
+
})
|
245
|
+
rescue Aws::EC2::Errors::InvalidGroupDuplicate => err
|
246
|
+
say "Security groups for #{vpc_name} VPC already setup."
|
247
|
+
end
|
248
|
+
say "Created security groups for #{vpc_name} VPC."
|
249
|
+
completed_vpcs << vpc_name
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
say "Created security groups..", :green
|
255
|
+
end
|
256
|
+
|
257
|
+
def create_key_pairs
|
258
|
+
say "Creating EC2 key pairs..."
|
259
|
+
created_key_pairs = []
|
260
|
+
configuration[:services].each do |service_name, service|
|
261
|
+
service[:regions].each do |region_name, region|
|
262
|
+
region[:environments].each do |environment_name|
|
263
|
+
key_pair_name = "#{project_name}"
|
264
|
+
unless created_key_pairs.include? key_pair_name
|
265
|
+
begin
|
266
|
+
ec2 = Aws::EC2::Client.new(region: region_name.to_s)
|
267
|
+
key_pair = ec2.create_key_pair({
|
268
|
+
key_name: key_pair_name
|
269
|
+
})
|
270
|
+
File.open("#{project_name}.pem", 'w') { |file| file.write(key_pair.key_material) }
|
271
|
+
FileUtils.chmod 0600, "#{project_name}.pem"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
say "Created EC2 key pairs.", :green
|
278
|
+
end
|
279
|
+
|
280
|
+
def create_ecs_autoscale_role
|
281
|
+
say "Creating ECS AutoScaling IAM roles..."
|
282
|
+
iam = Aws::IAM::Client.new
|
283
|
+
created_roles = []
|
284
|
+
configuration[:services].each do |service_name, service|
|
285
|
+
service[:regions].each do |region_name, region|
|
286
|
+
region[:environments].each do |environment_name|
|
287
|
+
role_name = "#{project_name}_#{environment_name}-ecsAutoScaling"
|
288
|
+
unless created_roles.include? role_name
|
289
|
+
begin
|
290
|
+
role = iam.create_role({
|
291
|
+
assume_role_policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"application-autoscaling.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}",
|
292
|
+
path: "/",
|
293
|
+
role_name: role_name,
|
294
|
+
})
|
295
|
+
iam.attach_role_policy({
|
296
|
+
policy_arn: "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole",
|
297
|
+
role_name: role_name,
|
298
|
+
})
|
299
|
+
rescue Aws::IAM::Errors::EntityAlreadyExists => err
|
300
|
+
end
|
301
|
+
say "Created #{role_name} IAM role."
|
302
|
+
created_roles << role_name
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
say "Created ECS AutoScaling IAM roles.", :green
|
308
|
+
end
|
309
|
+
|
310
|
+
def create_ecs_instance_role
|
311
|
+
say "Creating ECS EC2 Instance IAM roles..."
|
312
|
+
iam = Aws::IAM::Client.new
|
313
|
+
created_roles = []
|
314
|
+
configuration[:services].each do |service_name, service|
|
315
|
+
service[:regions].each do |region_name, region|
|
316
|
+
region[:environments].each do |environment_name|
|
317
|
+
role_name = "#{project_name}_#{environment_name}-ecsInstanceRole"
|
318
|
+
unless created_roles.include? role_name
|
319
|
+
begin
|
320
|
+
role = iam.create_role({
|
321
|
+
assume_role_policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}",
|
322
|
+
path: "/",
|
323
|
+
role_name: role_name,
|
324
|
+
})
|
325
|
+
iam.attach_role_policy({
|
326
|
+
policy_arn: "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role",
|
327
|
+
role_name: role_name,
|
328
|
+
})
|
329
|
+
iam.put_role_policy({
|
330
|
+
policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"logs:CreateLogGroup\",\"logs:CreateLogStream\",\"logs:DescribeLogGroups\",\"logs:DescribeLogStreams\",\"logs:PutLogEvents\"],\"Effect\":\"Allow\",\"Resource\":\"arn:aws:logs:#{region_name.to_s}:#{aws_account_number}:log-group:#{project_name}_#{environment_name}\"}]}",
|
331
|
+
policy_name: "ecs-cloudwatch-logs",
|
332
|
+
role_name: role_name,
|
333
|
+
})
|
334
|
+
iam.put_role_policy({
|
335
|
+
policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"ecs:DescribeTasks\",\"ecs:ListContainerInstances\",\"ecs:ListTasks\",\"ecs:StartTask\",\"ecs:StopTask\"],\"Resource\":\"arn:aws:ecs:#{region_name.to_s}:#{aws_account_number}:cluster/#{project_name}_#{environment_name}\"}]}",
|
336
|
+
policy_name: "ecs-tasks",
|
337
|
+
role_name: role_name,
|
338
|
+
})
|
339
|
+
iam.put_role_policy({
|
340
|
+
policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1492034037000\",\"Effect\":\"Allow\",\"Action\":[\"s3:Get*\"],\"Resource\":[\"arn:aws:s3:::#{project_name}-config/#{environment_name}/*\"]}]}",
|
341
|
+
policy_name: "read-config-from-s3",
|
342
|
+
role_name: role_name,
|
343
|
+
})
|
344
|
+
rescue Aws::IAM::Errors::EntityAlreadyExists => err
|
345
|
+
end
|
346
|
+
say "Created #{role_name} IAM role."
|
347
|
+
created_roles << role_name
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
say "Created ECS EC2 Instance IAM roles.", :green
|
353
|
+
end
|
354
|
+
|
38
355
|
def create_ecs_task_role
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
356
|
+
say "Creating ECS Task IAM roles..."
|
357
|
+
iam = Aws::IAM::Client.new
|
358
|
+
created_roles = []
|
359
|
+
configuration[:services].each do |service_name, service|
|
360
|
+
service[:regions].each do |region_name, region|
|
361
|
+
region[:environments].each do |environment_name|
|
362
|
+
role_name = "#{project_name}_#{environment_name}-ecs-task"
|
363
|
+
unless created_roles.include? role_name
|
364
|
+
begin
|
365
|
+
role = iam.create_role({
|
366
|
+
assume_role_policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ecs-tasks.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}",
|
367
|
+
path: "/",
|
368
|
+
role_name: role_name,
|
369
|
+
})
|
370
|
+
iam.put_role_policy({
|
371
|
+
policy_document: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1492034037000\",\"Effect\":\"Allow\",\"Action\":[\"s3:Get*\"],\"Resource\":[\"arn:aws:s3:::#{project_name}-config/#{environment_name}/*\"]}]}",
|
372
|
+
policy_name: "read-config-from-s3",
|
373
|
+
role_name: role_name,
|
374
|
+
})
|
375
|
+
rescue Aws::IAM::Errors::EntityAlreadyExists => err
|
376
|
+
end
|
377
|
+
say "Created #{role_name} IAM role."
|
378
|
+
created_roles << role_name
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
say "Created ECS Task IAM roles.", :green
|
43
384
|
end
|
44
385
|
|
45
386
|
def create_ecs_tasks
|
@@ -60,10 +401,6 @@ module Shiprails
|
|
60
401
|
task_definition.delete :requires_attributes
|
61
402
|
say "Updating ECS task (#{task_name})."
|
62
403
|
rescue Aws::ECS::Errors::ClientException => e
|
63
|
-
#
|
64
|
-
# TODO: set task role
|
65
|
-
#
|
66
|
-
say "TODO: set task role", :blue
|
67
404
|
task_definition = {
|
68
405
|
container_definitions: [
|
69
406
|
{
|
@@ -97,7 +434,8 @@ module Shiprails
|
|
97
434
|
}
|
98
435
|
}
|
99
436
|
],
|
100
|
-
family: task_name
|
437
|
+
family: task_name,
|
438
|
+
task_role_arn: "arn:aws:iam::#{aws_account_number}:role/#{project_name}_#{environment_name}-ecs-task"
|
101
439
|
}
|
102
440
|
say "Creating new ECS task (#{task_name})!"
|
103
441
|
end
|
@@ -130,15 +468,123 @@ module Shiprails
|
|
130
468
|
end
|
131
469
|
|
132
470
|
def create_ec2_launch_configurations
|
133
|
-
say "
|
471
|
+
say "Creating EC2 LaunchConfigurations..."
|
472
|
+
autoscaling = Aws::AutoScaling::Client.new
|
473
|
+
created_launch_configurations = []
|
474
|
+
configuration[:services].each do |service_name, service|
|
475
|
+
service[:regions].each do |region_name, region|
|
476
|
+
region[:environments].each do |environment_name|
|
477
|
+
launch_configuration_name = "#{project_name}_#{environment_name}-v1"
|
478
|
+
unless created_launch_configurations.include? launch_configuration_name
|
479
|
+
begin
|
480
|
+
ec2 = Aws::EC2::Client.new(region: region_name.to_s)
|
481
|
+
images = ec2.describe_images({
|
482
|
+
filters: [
|
483
|
+
{
|
484
|
+
name: 'name',
|
485
|
+
values: ['amzn-ami-201*-amazon-ecs-optimized']
|
486
|
+
},
|
487
|
+
{
|
488
|
+
name: 'owner-alias',
|
489
|
+
values: ['amazon']
|
490
|
+
},
|
491
|
+
{
|
492
|
+
name: 'state',
|
493
|
+
values: ['available']
|
494
|
+
},
|
495
|
+
],
|
496
|
+
}).images
|
497
|
+
image = images.sort_by(&:name).last # get the newest version
|
498
|
+
vpcs = ec2.describe_vpcs.vpcs
|
499
|
+
vpc = vpcs.find{ |v| v.tags.find{|t| t.key == "Name" }.value == "#{project_name}_#{environment_name}" }
|
500
|
+
security_groups = ec2.describe_security_groups({
|
501
|
+
filters: [
|
502
|
+
{
|
503
|
+
name: "vpc-id",
|
504
|
+
values: [
|
505
|
+
vpc.vpc_id
|
506
|
+
],
|
507
|
+
},
|
508
|
+
],
|
509
|
+
}).security_groups
|
510
|
+
security_group = security_groups.find{ |group| group.group_name == "ecs-#{project_name}_#{environment_name}" }
|
511
|
+
autoscaling.create_launch_configuration({
|
512
|
+
block_device_mappings: [
|
513
|
+
{
|
514
|
+
device_name: "/dev/xvdcz",
|
515
|
+
ebs: {
|
516
|
+
delete_on_termination: true,
|
517
|
+
encrypted: false,
|
518
|
+
volume_size: 22,
|
519
|
+
volume_type: "gp2",
|
520
|
+
},
|
521
|
+
},
|
522
|
+
],
|
523
|
+
iam_instance_profile: "#{project_name}_#{environment_name}-ecsInstanceRole",
|
524
|
+
image_id: image.image_id,
|
525
|
+
instance_type: "t2.small",
|
526
|
+
key_name: "#{project_name}",
|
527
|
+
launch_configuration_name: launch_configuration_name,
|
528
|
+
security_groups: [ security_group.group_id ],
|
529
|
+
user_data: Base64.encode64("#!/bin/bash
|
530
|
+
echo ECS_CLUSTER=#{project_name}_#{environment_name} >> /etc/ecs/ecs.config"),
|
531
|
+
})
|
532
|
+
rescue Aws::AutoScaling::Errors::AlreadyExistsFault
|
533
|
+
say "TODO: update LaunchConfiguration with latest stuff.", :blue
|
534
|
+
end
|
535
|
+
created_launch_configurations << launch_configuration_name
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
say "Created EC2 LaunchConfigurations!", :green
|
134
541
|
end
|
135
542
|
|
136
543
|
def create_ec2_autoscaling_groups
|
137
|
-
say "
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
544
|
+
say "Creating EC2 AutoScaling Groups..."
|
545
|
+
autoscaling = Aws::AutoScaling::Client.new
|
546
|
+
created_auto_scaling_groups = []
|
547
|
+
configuration[:services].each do |service_name, service|
|
548
|
+
service[:regions].each do |region_name, region|
|
549
|
+
region[:environments].each do |environment_name|
|
550
|
+
group_name = "#{project_name}_#{environment_name}"
|
551
|
+
unless created_auto_scaling_groups.include? group_name
|
552
|
+
ec2 = Aws::EC2::Client.new region: region_name.to_s
|
553
|
+
vpcs = ec2.describe_vpcs.vpcs
|
554
|
+
vpc = vpcs.find{ |v| v.tags.find{|t| t.key == "Name" }.value == "#{project_name}_#{environment_name}" }
|
555
|
+
subnets = ec2.describe_subnets({
|
556
|
+
filters: [
|
557
|
+
{
|
558
|
+
name: "vpc-id",
|
559
|
+
values: [
|
560
|
+
vpc.vpc_id
|
561
|
+
],
|
562
|
+
},
|
563
|
+
],
|
564
|
+
}).subnets
|
565
|
+
zones_in_region = subnets.map(&:availability_zone)
|
566
|
+
subnets_in_region = subnets.map(&:subnet_id)
|
567
|
+
begin
|
568
|
+
autoscaling.create_auto_scaling_group({
|
569
|
+
auto_scaling_group_name: group_name,
|
570
|
+
availability_zones: zones_in_region,
|
571
|
+
default_cooldown: 300,
|
572
|
+
health_check_grace_period: 300,
|
573
|
+
health_check_type: "EC2",
|
574
|
+
launch_configuration_name: "#{project_name}_#{environment_name}-v1",
|
575
|
+
max_size: 10,
|
576
|
+
min_size: 1,
|
577
|
+
vpc_zone_identifier: subnets_in_region.join(',')
|
578
|
+
})
|
579
|
+
rescue Aws::AutoScaling::Errors::AlreadyExistsFault
|
580
|
+
say "TODO: update AutoScaling Group with latest stuff like LaunchConfiguration name.", :blue
|
581
|
+
end
|
582
|
+
created_auto_scaling_groups << group_name
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
say "Created EC2 LaunchConfigurations!", :green
|
142
588
|
end
|
143
589
|
|
144
590
|
def create_ecs_services
|
@@ -237,6 +683,10 @@ module Shiprails
|
|
237
683
|
say "Created ECS services!", :green
|
238
684
|
end
|
239
685
|
|
686
|
+
def create_cloudwatch_ecs_alarms
|
687
|
+
say "TODO: create cloudwatch alarms for cluster memory", :blue
|
688
|
+
end
|
689
|
+
|
240
690
|
def create_cloudwatch_elb_alarms
|
241
691
|
say "TODO: create cloudwatch alarms for elb latency / service units", :blue
|
242
692
|
end
|
@@ -259,6 +709,10 @@ module Shiprails
|
|
259
709
|
@aws_access_key_secret ||= ask "AWS Access Key Secret", default: ENV.fetch("AWS_SECRET_ACCESS_KEY")
|
260
710
|
end
|
261
711
|
|
712
|
+
def aws_account_number
|
713
|
+
@aws_account_number ||= Aws::STS::Client.new().get_caller_identity.account
|
714
|
+
end
|
715
|
+
|
262
716
|
def configuration
|
263
717
|
YAML.load(File.read("#{options[:path]}/.shiprails.yml")).deep_symbolize_keys
|
264
718
|
end
|
data/lib/shiprails/version.rb
CHANGED
data/shiprails.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency "activesupport", "~> 5"
|
23
23
|
spec.add_dependency "aws-sdk", "~> 2"
|
24
24
|
spec.add_dependency "git", "~> 1.3"
|
25
|
+
spec.add_dependency "netaddr", "~> 1.5"
|
25
26
|
spec.add_dependency "thor", "~> 0.14"
|
26
27
|
spec.add_dependency "s3_config", "~> 0.1.0"
|
27
28
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shiprails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zane Shannon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: netaddr
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: thor
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|