sumomo 0.8.9 → 0.8.13

Sign up to get free protection for your applications and to get access to all the features.
data/exe/sumomo CHANGED
@@ -30,7 +30,7 @@ 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
@@ -39,6 +39,16 @@ cmd_opts = case cmd
39
39
  eval File.read(local_opts[:filename]), proc.binding, local_opts[:filename]
40
40
  end
41
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
48
+ proc = proc {}
49
+ eval File.read(local_opts[:filename]), proc.binding, local_opts[:filename]
50
+ end
51
+
42
52
  when 'outputs'
43
53
  puts "Outputs for stack #{ARGV[0]}"
44
54
  puts Sumomo.get_stack_outputs(name: ARGV[0], region: global_opts[:region]).to_yaml
@@ -49,7 +59,7 @@ cmd_opts = case cmd
49
59
  key = JSON.parse(File.read('x.txt'))['value']
50
60
  File.write('key.pem', key)
51
61
  `chmod 0600 key.pem`
52
- exec "ssh -i 'key.pem' ec2-user@#{ARGV[1]}"
62
+ exec "ssh -i 'key.pem' ec2-user@#{ARGV[1]} #{ARGV[2]}"
53
63
 
54
64
  when 'testapi'
55
65
  local_opts = Trollop.options do
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
@@ -254,6 +254,7 @@ module Sumomo
254
254
  has_public_ips: true,
255
255
  ingress: nil,
256
256
  egress: nil,
257
+ security_groups: [],
257
258
  machine_tag: nil,
258
259
  ec2_sns_arn: nil,
259
260
  ami_name: nil,
@@ -297,10 +298,12 @@ module Sumomo
297
298
 
298
299
  bucket_name = @bucket_name
299
300
 
300
- script += "\n#{task_script}\n"
301
+ script_arr = [script]
302
+
303
+ script_arr << task_script
301
304
 
302
305
  if ecs_cluster
303
- script += <<~ECS_START
306
+ script_arr << <<~ECS_START
304
307
 
305
308
  yum update
306
309
  yum groupinstall "Development Tools"
@@ -318,12 +321,12 @@ module Sumomo
318
321
  end
319
322
 
320
323
  if eip
321
- script += <<~EIP_ALLOCATE
324
+ script_arr << <<~EIP_ALLOCATE
322
325
  aws ec2 associate-address --region `cat /etc/aws_region` --instance-id `curl http://169.254.169.254/latest/meta-data/instance-id` --allocation-id `cat /etc/eip_allocation_id`
323
326
  EIP_ALLOCATE
324
327
  end
325
328
 
326
- script += "\nservice spot-watcher start" if spot_price && ec2_sns_arn
329
+ script_arr << "service spot-watcher start" if(spot_price && ec2_sns_arn)
327
330
 
328
331
  unless ingress.is_a? Array
329
332
  raise 'ec2: ingress option needs to be an array'
@@ -339,7 +342,7 @@ module Sumomo
339
342
 
340
343
  wait_handle = make 'AWS::CloudFormation::WaitConditionHandle'
341
344
 
342
- user_data = initscript(wait_handle, name, script)
345
+ user_data = initscript(wait_handle, name, call('Fn::Join', "\n", script_arr))
343
346
 
344
347
  role_policy_doc = {
345
348
  'Version' => '2012-10-17',
@@ -407,7 +410,7 @@ module Sumomo
407
410
  launch_config = make 'AWS::AutoScaling::LaunchConfiguration' do
408
411
  AssociatePublicIpAddress has_public_ips
409
412
  KeyName keypair
410
- SecurityGroups [web_sec_group]
413
+ SecurityGroups [web_sec_group] + security_groups
411
414
  ImageId ami_name
412
415
  UserData user_data
413
416
  InstanceType type
data/lib/sumomo/stack.rb CHANGED
@@ -23,7 +23,7 @@ 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
29
  role: nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sumomo
4
- VERSION = '0.8.9'
4
+ VERSION = '0.8.13'
5
5
  end
data/lib/sumomo.rb CHANGED
@@ -26,7 +26,17 @@ module Sumomo
26
26
  "cloudformation/#{make_master_key_name(name: name)}.pem"
27
27
  end
28
28
 
29
- def self.update_stack(name:, region:, sns_arn: nil, &block)
29
+ def self.create_stack(name:, region:, sns_arn: nil, &block)
30
+ cf = Aws::CloudFormation::Client.new(region: region)
31
+ begin
32
+ cf.describe_stacks(stack_name: name)
33
+ raise "There is already a stack named '#{name}'"
34
+ rescue Aws::CloudFormation::Errors::ValidationError
35
+ update_stack(name: name, region: region, sns_arn: sns_arn, &block)
36
+ end
37
+ end
38
+
39
+ def self.update_stack(name:, region:, sns_arn: nil, changeset: false, &block)
30
40
  cf = Aws::CloudFormation::Client.new(region: region)
31
41
  s3 = Aws::S3::Client.new(region: region)
32
42
  ec2 = Aws::EC2::Client.new(region: region)
@@ -107,11 +117,20 @@ module Sumomo
107
117
  stack_name: name,
108
118
  template_url: store.url('cloudformation/template'),
109
119
  parameters: hidden_values,
120
+ disable_rollback: true,
110
121
  capabilities: ['CAPABILITY_IAM']
111
122
  }
112
123
 
113
124
  begin
114
- 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
+
115
134
  rescue StandardError => e
116
135
  if e.message.end_with? 'does not exist'
117
136
  update_options[:timeout_in_minutes] = @timeout if @timeout
@@ -124,6 +143,10 @@ module Sumomo
124
143
  end
125
144
  end
126
145
 
146
+ def self.curtimestr
147
+ Time.now.strftime('%Y%m%d%H%M%S')
148
+ end
149
+
127
150
  def self.wait_for_stack(name:, region:)
128
151
  cf = Aws::CloudFormation::Client.new(region: region)
129
152
 
@@ -187,7 +210,14 @@ module Sumomo
187
210
  instance_eval(&block)
188
211
  end
189
212
 
190
- 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
191
221
  @apis[name] = block
192
222
  end
193
223
 
@@ -249,6 +279,4 @@ module Sumomo
249
279
 
250
280
  map
251
281
  end
252
-
253
- singleton_class.send(:alias_method, :create_stack, :update_stack)
254
282
  end
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