sumomo 0.8.10 → 0.8.14

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.
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