sumomo 0.8.10 → 0.8.14

Sign up to get free protection for your applications and to get access to all the features.
data/exe/sumomo CHANGED
@@ -30,11 +30,21 @@ cmd_opts = case cmd
30
30
  when 'delete'
31
31
  Sumomo.delete_stack(name: ARGV[0], region: global_opts[:region])
32
32
 
33
- when 'create', 'update'
33
+ when 'create'
34
34
  local_opts = Trollop.options do
35
35
  opt :filename, 'File that describes the stack', type: :string, default: 'Sumomofile'
36
36
  end
37
- Sumomo.send("#{cmd}_stack", name: ARGV[0], region: global_opts[:region]) do
37
+ Sumomo.create_stack(name: ARGV[0], region: global_opts[:region]) do
38
+ proc = proc {}
39
+ eval File.read(local_opts[:filename]), proc.binding, local_opts[:filename]
40
+ end
41
+
42
+ when 'update'
43
+ local_opts = Trollop.options do
44
+ opt :filename, 'File that describes the stack', type: :string, default: 'Sumomofile'
45
+ opt :changeset, 'Create a changeset instead of directly update', type: :boolean, default: false
46
+ end
47
+ Sumomo.update_stack(name: ARGV[0], changeset: !!local_opts[:changeset], region: global_opts[:region]) do
38
48
  proc = proc {}
39
49
  eval File.read(local_opts[:filename]), proc.binding, local_opts[:filename]
40
50
  end
@@ -46,7 +56,10 @@ cmd_opts = case cmd
46
56
  when 'login'
47
57
  puts "Login to stack #{ARGV[0]} instance at #{ARGV[1]}"
48
58
  `aws s3 cp s3://#{ARGV[0]}/cloudformation/#{ARGV[0]}_master_key.pem x.txt`
49
- key = JSON.parse(File.read('x.txt'))['value']
59
+ key = JSON.parse(File.read('x.txt'))['value'].
60
+ gsub('-----BEGIN RSA PRIVATE KEY----- ', "-----BEGIN RSA PRIVATE KEY-----\n").
61
+ gsub(' -----END RSA PRIVATE KEY-----', "\n-----END RSA PRIVATE KEY-----").
62
+ gsub(/(.{64}) /, "\\1\n")
50
63
  File.write('key.pem', key)
51
64
  `chmod 0600 key.pem`
52
65
  exec "ssh -i 'key.pem' ec2-user@#{ARGV[1]} #{ARGV[2]}"
data/lib/sumomo/api.rb CHANGED
@@ -159,9 +159,45 @@ module Sumomo
159
159
  end
160
160
  end
161
161
 
162
- def make_api(domain_name, name:, script: nil, dns: nil, cert: nil, with_statements: [], &block)
162
+ def make_api(
163
+ domain_name,
164
+ name:,
165
+ script: nil,
166
+ dns: nil,
167
+ cert: nil,
168
+ mtls_truststore: nil,
169
+ logging: true,
170
+ with_statements: [], &block)
171
+
163
172
  api = make 'AWS::ApiGateway::RestApi', name: name do
164
173
  Name name
174
+ DisableExecuteApiEndpoint true
175
+ end
176
+
177
+ if logging
178
+ cloudwatchRole = make 'AWS::IAM::Role', name: "#{name}LoggingRole" do
179
+ AssumeRolePolicyDocument do
180
+ Version "2012-10-17"
181
+ Statement [
182
+ {
183
+ "Effect" => "Allow",
184
+ "Principal" => {
185
+ "Service" => [
186
+ "apigateway.amazonaws.com"
187
+ ]
188
+ },
189
+ "Action" => "sts:AssumeRole"
190
+ }
191
+ ]
192
+ end
193
+ Path '/'
194
+ ManagedPolicyArns [ "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" ]
195
+ end
196
+
197
+ make 'AWS::ApiGateway::Account' do
198
+ depends_on api
199
+ CloudWatchRoleArn cloudwatchRole.Arn
200
+ end
165
201
  end
166
202
 
167
203
  script ||= File.read(File.join(Gem.loaded_specs['sumomo'].full_gem_path, 'data', 'sumomo', 'api_modules', 'real_script.js'))
@@ -183,7 +219,10 @@ module Sumomo
183
219
 
184
220
  files += [{ name: 'index.js', code: script }]
185
221
 
186
- fun = make_lambda(name: "#{name}Lambda#{@version_number}", files: files, with_statements: with_statements)
222
+ fun = make_lambda(
223
+ name: "#{name}Lambda#{@version_number}",
224
+ files: files,
225
+ role: custom_resource_exec_role(with_statements: with_statements) )
187
226
 
188
227
  resource = make 'AWS::ApiGateway::Resource', name: "#{name}Resource" do
189
228
  ParentId api.RootResourceId
@@ -230,18 +269,79 @@ module Sumomo
230
269
  stage = make 'AWS::ApiGateway::Stage', name: "#{name}Stage" do
231
270
  RestApiId api
232
271
  DeploymentId deployment
233
- StageName 'test'
272
+
273
+ if logging
274
+ MethodSettings [
275
+ {
276
+ "ResourcePath" => "/*",
277
+ "HttpMethod" => "*",
278
+ "DataTraceEnabled" => true,
279
+ "LoggingLevel" => 'INFO'
280
+ }
281
+ ]
282
+ end
234
283
  end
235
284
 
236
285
  root_name = /(?<root_name>[^.]+\.[^.]+)$/.match(domain_name)[:root_name]
237
286
 
238
- cert ||= make 'Custom::USEastCertificate', name: "#{name}Certificate" do
239
- DomainName domain_name
287
+ certificate_completion = cert
288
+
289
+ bucket_name = @bucket_name
290
+ mtls = nil
291
+ if mtls_truststore
292
+ filename = "#{domain_name}.truststore.pem"
293
+ upload_file(filename, mtls_truststore)
294
+ truststore_uri = "s3://#{bucket_name}/uploads/#{filename}"
295
+ mtls = {
296
+ "TruststoreUri" => truststore_uri
297
+ }
240
298
  end
241
299
 
242
- domain = make 'Custom::APIDomainName', name: "#{name}DomainName" do
300
+ if cert.nil?
301
+ cert = make 'Custom::ACMCertificate', name: "#{name}Certificate" do
302
+ DomainName domain_name
303
+ ValidationMethod 'DNS' if dns[:type] == :route53
304
+ RegionOverride 'us-east-1' if !mtls
305
+ end
306
+
307
+ certificate_completion = cert
308
+
309
+ if dns[:type] == :route53
310
+ make 'AWS::Route53::RecordSet', name: "#{name}CertificateRoute53Entry" do
311
+ HostedZoneId dns[:hosted_zone]
312
+ Name cert.RecordName
313
+ Type cert.RecordType
314
+ TTL 60
315
+ ResourceRecords [cert.RecordValue]
316
+ end
317
+
318
+ cert_waiter = make 'Custom::ACMCertificateWaiter', name: "#{name}CertificateWaiter" do
319
+ Certificate cert
320
+ RegionOverride 'us-east-1' if !mtls
321
+ end
322
+
323
+ certificate_completion = cert_waiter
324
+ end
325
+ end
326
+
327
+ domain = make 'AWS::ApiGateway::DomainName', name: "#{name}DomainName" do
328
+ depends_on certificate_completion
329
+
243
330
  DomainName domain_name
244
- CertificateArn cert
331
+
332
+ if mtls != nil
333
+ RegionalCertificateArn cert
334
+ MutualTlsAuthentication mtls
335
+ SecurityPolicy 'TLS_1_2'
336
+ EndpointConfiguration do
337
+ Types [ 'REGIONAL' ]
338
+ end
339
+ else
340
+ CertificateArn cert
341
+ EndpointConfiguration do
342
+ Types [ 'EDGE' ]
343
+ end
344
+ end
245
345
  end
246
346
 
247
347
  make 'AWS::ApiGateway::BasePathMapping', name: "#{name}BasePathMapping" do
@@ -264,8 +364,19 @@ module Sumomo
264
364
  make 'AWS::Route53::RecordSet', name: "#{name}Route53Entry" do
265
365
  HostedZoneId dns[:hosted_zone]
266
366
  Name domain_name
267
- Type 'CNAME'
268
- ResourceRecords [call('Fn::Join', '', [api, '.execute-api.', ref('AWS::Region'), '.amazonaws.com'])]
367
+
368
+ if mtls != nil
369
+ Type 'A'
370
+ AliasTarget do
371
+ DNSName domain.RegionalDomainName
372
+ HostedZoneId domain.RegionalHostedZoneId
373
+ end
374
+ else
375
+ Type 'A'
376
+ AliasTarget do
377
+ DNSName domain.DistributionDomainName
378
+ HostedZoneId domain.DistributionHostedZoneId
379
+ end end
269
380
  end
270
381
  domain_name
271
382
  else
data/lib/sumomo/ec2.rb CHANGED
@@ -96,6 +96,7 @@ module Sumomo
96
96
  call('Fn::Join', '', [
97
97
 
98
98
  "#!/bin/bash -v\n",
99
+ "yum install -y aws-cfn-bootstrap\n",
99
100
  "yum update -y aws-cfn-bootstrap\n",
100
101
 
101
102
  "# Helper function\n",
@@ -510,7 +511,7 @@ module Sumomo
510
511
 
511
512
  if ecs_cluster
512
513
  ecs_config = <<~CONFIG
513
- ECS_CLUSTER={{cluster_name}}
514
+ ECS_CLUSTER={{ cluster_name }}
514
515
  ECS_ENGINE_AUTH_TYPE=docker
515
516
  ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/":{"username":"{{docker_username}}","password":"{{docker_password}}","email":"{{docker_email}}"}}
516
517
  CONFIG
data/lib/sumomo/stack.rb CHANGED
@@ -23,9 +23,10 @@ module Sumomo
23
23
  description: "Lambda Function in #{@bucket_name}",
24
24
  function_key: "cloudformation/lambda/function_#{name}",
25
25
  handler: 'index.handler',
26
- runtime: 'nodejs10.x',
26
+ runtime: 'nodejs14.x',
27
27
  memory_size: 128,
28
28
  timeout: 30,
29
+ enable_logging: true,
29
30
  role: nil)
30
31
 
31
32
  name ||= make_default_resource_name('Lambda')
@@ -59,9 +60,11 @@ module Sumomo
59
60
  Role role.Arn
60
61
  end
61
62
 
62
- log_group = make 'AWS::Logs::LogGroup', name: "#{name}LogGroup" do
63
- LogGroupName call('Fn::Join', '', ['/aws/lambda/', fun])
64
- RetentionInDays 30
63
+ if enable_logging
64
+ make 'AWS::Logs::LogGroup', name: "#{name}LogGroup" do
65
+ LogGroupName call('Fn::Join', '', ['/aws/lambda/', fun])
66
+ RetentionInDays 30
67
+ end
65
68
  end
66
69
 
67
70
  fun
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sumomo
4
- VERSION = '0.8.10'
4
+ VERSION = '0.8.14'
5
5
  end
data/lib/sumomo.rb CHANGED
@@ -36,7 +36,7 @@ module Sumomo
36
36
  end
37
37
  end
38
38
 
39
- def self.update_stack(name:, region:, sns_arn: nil, &block)
39
+ def self.update_stack(name:, region:, sns_arn: nil, changeset: false, &block)
40
40
  cf = Aws::CloudFormation::Client.new(region: region)
41
41
  s3 = Aws::S3::Client.new(region: region)
42
42
  ec2 = Aws::EC2::Client.new(region: region)
@@ -117,11 +117,20 @@ module Sumomo
117
117
  stack_name: name,
118
118
  template_url: store.url('cloudformation/template'),
119
119
  parameters: hidden_values,
120
+ disable_rollback: false,
120
121
  capabilities: ['CAPABILITY_IAM']
121
122
  }
122
123
 
123
124
  begin
124
- cf.update_stack(update_options)
125
+ if changeset
126
+ cf.create_change_set(
127
+ **update_options,
128
+ change_set_name: "Change#{curtimestr}"
129
+ )
130
+ else
131
+ cf.update_stack(update_options)
132
+ end
133
+
125
134
  rescue StandardError => e
126
135
  if e.message.end_with? 'does not exist'
127
136
  update_options[:timeout_in_minutes] = @timeout if @timeout
@@ -134,6 +143,10 @@ module Sumomo
134
143
  end
135
144
  end
136
145
 
146
+ def self.curtimestr
147
+ Time.now.strftime('%Y%m%d%H%M%S')
148
+ end
149
+
137
150
  def self.wait_for_stack(name:, region:)
138
151
  cf = Aws::CloudFormation::Client.new(region: region)
139
152
 
@@ -197,7 +210,14 @@ module Sumomo
197
210
  instance_eval(&block)
198
211
  end
199
212
 
200
- def make_api(_domain_name, name:, script: nil, dns: nil, cert: nil, with_statements: [], &block)
213
+ def make_api(_domain_name,
214
+ name:, script: nil,
215
+ dns: nil,
216
+ mtls_truststore: nil,
217
+ cert: nil,
218
+ with_statements: [], &block)
219
+
220
+ # we ignore mtls_truststore here
201
221
  @apis[name] = block
202
222
  end
203
223
 
data/sumomo.gemspec CHANGED
@@ -27,15 +27,17 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.add_development_dependency 'bundler', '~> 1.11'
31
- spec.add_development_dependency 'rake', '~> 10.0'
32
- spec.add_development_dependency 'rspec', '~> 3.0'
30
+ spec.add_development_dependency 'bundler'
31
+ spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rspec'
33
33
 
34
34
  spec.add_dependency 'activesupport'
35
- spec.add_dependency 'aws-sdk', '~> 2'
35
+ spec.add_dependency 'aws-sdk', '~> 3'
36
+ spec.add_dependency 'ox'
36
37
  spec.add_dependency 'hashie'
37
38
  spec.add_dependency 'momo', '0.4.1'
38
39
  spec.add_dependency 'rubyzip'
39
40
  spec.add_dependency 's3cabinet'
40
41
  spec.add_dependency 'trollop'
42
+ spec.add_dependency 'webrick'
41
43
  end