sumomo 0.8.3 → 0.8.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +169 -0
- data/Gemfile +2 -0
- data/Rakefile +5 -3
- data/bin/console +4 -3
- data/data/sumomo/api_modules/node_modules/.bin/uuid +1 -1
- data/data/sumomo/api_modules/real_script.js +37 -1
- data/data/sumomo/api_modules/test_script.js +212 -175
- data/data/sumomo/custom_resources/AMILookup.js +146 -58
- data/data/sumomo/custom_resources/Echo.js +25 -0
- data/data/sumomo/custom_resources/SelectSpot.js +142 -54
- data/data/sumomo/custom_resources/TempS3Bucket.js +213 -0
- data/data/sumomo/custom_resources/USEastCertificate.js +44 -31
- data/data/sumomo/custom_resources/USEastCertificateWaiter.js +60 -0
- data/exe/sumomo +50 -41
- data/lib/sumomo.rb +236 -233
- data/lib/sumomo/api.rb +148 -151
- data/lib/sumomo/cdn.rb +119 -113
- data/lib/sumomo/dns.rb +20 -20
- data/lib/sumomo/ec2.rb +490 -491
- data/lib/sumomo/ecs.rb +256 -262
- data/lib/sumomo/irregular.rb +9 -0
- data/lib/sumomo/momo_extensions/resource.rb +8 -7
- data/lib/sumomo/momo_extensions/stack.rb +4 -3
- data/lib/sumomo/network.rb +109 -106
- data/lib/sumomo/stack.rb +191 -189
- data/lib/sumomo/version.rb +3 -1
- data/sumomo.gemspec +23 -22
- metadata +27 -22
data/lib/sumomo/ecs.rb
CHANGED
@@ -1,265 +1,259 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Sumomo
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
ecs
|
263
|
-
end
|
264
|
-
end
|
4
|
+
module Stack
|
5
|
+
def sluggify(str)
|
6
|
+
str.gsub(/[^0-9a-zA-Z]/, '_')
|
7
|
+
end
|
8
|
+
|
9
|
+
def make_ecs_role
|
10
|
+
make 'AWS::IAM::Role', name: 'ECSServiceRole' do
|
11
|
+
role_policy_doc = {
|
12
|
+
'Version' => '2012-10-17',
|
13
|
+
'Statement' => [{
|
14
|
+
'Effect' => 'Allow',
|
15
|
+
'Principal' => { 'Service' => ['ecs.amazonaws.com'] },
|
16
|
+
'Action' => ['sts:AssumeRole']
|
17
|
+
}]
|
18
|
+
}
|
19
|
+
|
20
|
+
AssumeRolePolicyDocument role_policy_doc
|
21
|
+
Path '/'
|
22
|
+
Policies [
|
23
|
+
{
|
24
|
+
'PolicyName' => 'ecs-service',
|
25
|
+
'PolicyDocument' => {
|
26
|
+
'Version' => '2012-10-17',
|
27
|
+
'Statement' => [{
|
28
|
+
'Effect' => 'Allow',
|
29
|
+
'Action' => [
|
30
|
+
'ec2:AuthorizeSecurityGroupIngress',
|
31
|
+
'ec2:Describe*',
|
32
|
+
'elasticloadbalancing:DeregisterInstancesFromLoadBalancer',
|
33
|
+
'elasticloadbalancing:DeregisterTargets',
|
34
|
+
'elasticloadbalancing:Describe*',
|
35
|
+
'elasticloadbalancing:RegisterInstancesWithLoadBalancer',
|
36
|
+
'elasticloadbalancing:RegisterTargets'
|
37
|
+
],
|
38
|
+
'Resource' => '*'
|
39
|
+
}]
|
40
|
+
}
|
41
|
+
}
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def make_ecs_cluster(name: make_default_resource_name('ECSCluster'), services: [], machine_config: {}, network:, log_retention: 30, dependencies: [])
|
47
|
+
ecs = make 'AWS::ECS::Cluster', name: name.to_s do
|
48
|
+
dependencies.each do |x|
|
49
|
+
depends_on x
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
volumes = []
|
54
|
+
machine_volume_locations = {}
|
55
|
+
|
56
|
+
service_number = 0
|
57
|
+
|
58
|
+
services.each do |service|
|
59
|
+
alb = service[:alb]
|
60
|
+
certificate = service[:certificate]
|
61
|
+
alb_ports = {}
|
62
|
+
|
63
|
+
service_number += 1
|
64
|
+
|
65
|
+
containers = service[:containers]
|
66
|
+
service_name = service[:name] || "Service#{service_number}"
|
67
|
+
service_count = service[:count] || 1
|
68
|
+
|
69
|
+
container_defs = containers.map do |container|
|
70
|
+
definition = {}
|
71
|
+
|
72
|
+
definition['Name'] = sluggify(container[:image]).camelize.to_s
|
73
|
+
definition['Name'] = container[:name] if container[:name]
|
74
|
+
|
75
|
+
definition['Memory'] = container[:memory] || 1024
|
76
|
+
|
77
|
+
loggroup = make 'AWS::Logs::LogGroup', name: "#{name}#{definition['Name']}Logs" do
|
78
|
+
LogGroupName "#{definition['Name'].underscore}_logs"
|
79
|
+
RetentionInDays log_retention
|
80
|
+
end
|
81
|
+
|
82
|
+
definition['LogConfiguration'] = {
|
83
|
+
'LogDriver' => 'awslogs',
|
84
|
+
'Options' => {
|
85
|
+
'awslogs-group' => loggroup,
|
86
|
+
'awslogs-region' => ref('AWS::Region')
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
if container[:files]
|
91
|
+
definition['MountPoints'] = container[:files].map do |file, destination|
|
92
|
+
s3_location = "container_files/#{sluggify(service_name)}/#{definition['Name']}/#{file}"
|
93
|
+
volume_name = sluggify("#{definition['Name'].underscore}_#{destination}").camelize
|
94
|
+
|
95
|
+
upload_file s3_location, File.read(file)
|
96
|
+
|
97
|
+
machine_volume_locations[s3_location] = "/opt/s3/#{s3_location}"
|
98
|
+
|
99
|
+
volumes << {
|
100
|
+
'Name' => volume_name,
|
101
|
+
'Host' => { 'SourcePath' => machine_volume_locations[s3_location] }
|
102
|
+
}
|
103
|
+
|
104
|
+
{
|
105
|
+
'ContainerPath' => destination,
|
106
|
+
'SourceVolume' => volume_name
|
107
|
+
}
|
108
|
+
end
|
109
|
+
container.delete(:files)
|
110
|
+
end
|
111
|
+
|
112
|
+
if container[:ports]
|
113
|
+
if !alb
|
114
|
+
definition['PortMappings'] = container[:ports].map do |from_port, to_port|
|
115
|
+
{
|
116
|
+
'ContainerPort' => from_port,
|
117
|
+
'HostPort' => to_port
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
else
|
122
|
+
definition['PortMappings'] = container[:ports].map do |from_port, _to_port|
|
123
|
+
{
|
124
|
+
'ContainerPort' => from_port
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
container[:ports].each do |container_port, host_port|
|
129
|
+
if alb_ports[host_port.to_i]
|
130
|
+
raise "Container #{alb_ports[host_port][:name]} is already using #{host_port}"
|
131
|
+
end
|
132
|
+
|
133
|
+
alb_target = make 'AWS::ElasticLoadBalancingV2::TargetGroup', name: "#{name}#{definition['Name']}Target" do
|
134
|
+
HealthCheckIntervalSeconds 60
|
135
|
+
UnhealthyThresholdCount 10
|
136
|
+
HealthCheckPath '/'
|
137
|
+
Name "#{name}Port#{host_port}Target"
|
138
|
+
Port container_port
|
139
|
+
Protocol 'HTTP'
|
140
|
+
VpcId network[:vpc]
|
141
|
+
|
142
|
+
if container[:alb_sticky]
|
143
|
+
TargetGroupAttributes({
|
144
|
+
'stickiness.enabled' => true,
|
145
|
+
'stickiness.type' => 'lb_cookie'
|
146
|
+
}.map { |k, v| { Key: k, Value: v } })
|
147
|
+
container.delete(:alb_sticky)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
alb_action = {
|
152
|
+
'Type' => 'forward',
|
153
|
+
'TargetGroupArn' => alb_target
|
154
|
+
}
|
155
|
+
|
156
|
+
if certificate
|
157
|
+
alb_listener = make 'AWS::ElasticLoadBalancingV2::Listener', name: "#{name}#{definition['Name']}Listener" do
|
158
|
+
Certificates [{ CertificateArn: certificate }]
|
159
|
+
DefaultActions [alb_action]
|
160
|
+
LoadBalancerArn alb
|
161
|
+
Port host_port
|
162
|
+
Protocol 'HTTPS'
|
163
|
+
end
|
164
|
+
else
|
165
|
+
alb_listener = make 'AWS::ElasticLoadBalancingV2::Listener', name: "#{name}#{definition['Name']}Listener" do
|
166
|
+
DefaultActions [alb_action]
|
167
|
+
LoadBalancerArn alb
|
168
|
+
Port host_port
|
169
|
+
Protocol 'HTTP'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
alb_ports[host_port.to_i] = {
|
174
|
+
listener: alb_listener,
|
175
|
+
target: alb_target,
|
176
|
+
port: container_port,
|
177
|
+
name: definition['Name']
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
container.delete(:ports)
|
183
|
+
end
|
184
|
+
|
185
|
+
if container[:envvars]
|
186
|
+
definition['Environment'] = container[:envvars].map do |var_name, var_value|
|
187
|
+
{
|
188
|
+
'Name' => var_name,
|
189
|
+
'Value' => var_value
|
190
|
+
}
|
191
|
+
end
|
192
|
+
container.delete(:envvars)
|
193
|
+
end
|
194
|
+
|
195
|
+
container.each do |key, value|
|
196
|
+
definition[key.to_s.camelize] = value
|
197
|
+
end
|
198
|
+
|
199
|
+
definition
|
200
|
+
end
|
201
|
+
|
202
|
+
deployment_config = {
|
203
|
+
'MaximumPercent' => 200,
|
204
|
+
'MinimumHealthyPercent' => 50
|
205
|
+
}
|
206
|
+
|
207
|
+
ecs_task = make 'AWS::ECS::TaskDefinition', name: "#{name}#{service_name}Task" do
|
208
|
+
ContainerDefinitions container_defs
|
209
|
+
Volumes volumes
|
210
|
+
end
|
211
|
+
|
212
|
+
stack = self
|
213
|
+
|
214
|
+
ecs_service = make 'AWS::ECS::Service', name: "#{name}#{service_name}" do
|
215
|
+
alb_ports.each do |_host_port, info|
|
216
|
+
depends_on info[:listener]
|
217
|
+
end
|
218
|
+
|
219
|
+
Cluster ecs
|
220
|
+
DesiredCount service_count
|
221
|
+
TaskDefinition ecs_task
|
222
|
+
DeploymentConfiguration deployment_config
|
223
|
+
|
224
|
+
if alb_ports.keys.count != 0
|
225
|
+
Role stack.make_ecs_role
|
226
|
+
LoadBalancers alb_ports.values.map { |info|
|
227
|
+
{
|
228
|
+
'TargetGroupArn' => info[:target],
|
229
|
+
'ContainerPort' => info[:port],
|
230
|
+
'ContainerName' => info[:name]
|
231
|
+
}
|
232
|
+
}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end # services
|
236
|
+
|
237
|
+
machine_config[:methods].each do |method_name|
|
238
|
+
parameters = { ecs_cluster: ecs }
|
239
|
+
|
240
|
+
method(method_name).parameters.each do |param|
|
241
|
+
if ((param[0] == :keyreq) || (param[0] == :key)) && machine_config[param[1]]
|
242
|
+
parameters[param[1]] = machine_config[param[1]]
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
parameters[:network] = network unless parameters[:network]
|
247
|
+
|
248
|
+
method(method_name).call(parameters) do
|
249
|
+
machine_volume_locations.each do |s3_loc, machine_loc|
|
250
|
+
mkdir File.dirname(machine_loc)
|
251
|
+
download_file s3_loc, machine_loc
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
ecs
|
257
|
+
end
|
258
|
+
end
|
265
259
|
end
|