cloudformation-ruby-dsl 1.4.6 → 1.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa81a5113abb0ee72e9abaac42fc8128012449ce
4
- data.tar.gz: 9a8d10f20443f9ada8534a7dd485bbe40e742883
3
+ metadata.gz: 922a754ed43415e7919a4e4b6793c14ed596ec62
4
+ data.tar.gz: cdbdcedd3c9a48a194c0ba38cc2ddb7462cd5fbf
5
5
  SHA512:
6
- metadata.gz: 0c83e68921de83c6b2cab289b5c3de09a3cde4d306021a4ee262e8f5084319c392951dfa566d8b9528a6a0bbb2bc729ccf73cf974960725a37617efecd8f93bc
7
- data.tar.gz: cead01a51502610a2ad58948f366d827eb4d8f7e52d73d0579e605f79e17d2d200d570b5c71090b78aca35c5f22d4065ac5f9d3784d2807fec78e1dffc88ae5d
6
+ metadata.gz: 63e08da62b61214f641fb651457c1cfb4114ae3eea242a49a6b0939f913184bd5f658471e98176e173c5820ed5fc289e41bf071e99cbd1e0b712be760590295a
7
+ data.tar.gz: ae973485d3a5cfde77175006ee831467ba9ebc4c23231d17b81818741df20f59ff78d10462896af4866ef8d0d5d609b5dffe129f4267fab83ee8257f2defb088
data/OWNERS CHANGED
@@ -1,4 +1,6 @@
1
1
  # Owners.
2
2
 
3
3
  jonaf
4
- temujin9
4
+ temujin9
5
+ mike-unitskyi
6
+ shawnsmith
data/README.md CHANGED
@@ -45,8 +45,8 @@ Make the resulting file executable (`chmod +x [NEW_NAME.rb]`). It can respond to
45
45
  2 - there are differences between an existing stack and your template
46
46
  ```
47
47
  - `validate`: run validation against the stack definition
48
- - `create`: create a new stack from the output
49
- - `update`: update an existing stack from the output. Produces following exit codes:
48
+ - `create`: create a new stack from the output (takes optional `--s3-bucket` to upload the template to the specified S3 bucket prior to creating the stack)
49
+ - `update`: update an existing stack from the output (takes optional `--s3-bucket` to upload the template to the specified S3 bucket prior to creating the stack). Produces following exit codes:
50
50
  ```
51
51
  0 - update finished successfully
52
52
  1 - no updates to perform, stack doesn't exist, unable to update immutable parameter or tag, AWS ServiceError exception
@@ -62,7 +62,7 @@ Command line options similar to cloudformation commands, but parsed by the dsl.
62
62
  - `--stack-name`
63
63
  - `--region`
64
64
  - `--parameters`
65
- - `--tag `
65
+ - `--tag`
66
66
 
67
67
  Any other parameters are passed directly onto cloudformation. (--disable-rollback for instance)
68
68
 
@@ -31,7 +31,7 @@ require 'highline/import'
31
31
 
32
32
  ############################# AWS SDK Support
33
33
 
34
- class AwsCfn
34
+ class AwsClients
35
35
  attr_accessor :cfn_client_instance
36
36
 
37
37
  def initialize(args)
@@ -58,6 +58,13 @@ class AwsCfn
58
58
  end
59
59
  @cfn_client_instance
60
60
  end
61
+
62
+ def s3_client
63
+ if @s3_client_instance == nil
64
+ @s3_client_instance = Aws::S3::Client.new()
65
+ end
66
+ @s3_client_instance
67
+ end
61
68
  end
62
69
 
63
70
  # utility class to deserialize Structs as JSON
@@ -85,13 +92,14 @@ def parse_args
85
92
  :region => default_region,
86
93
  :profile => nil,
87
94
  :nopretty => false,
95
+ :s3_bucket => nil,
88
96
  }
89
97
  ARGV.slice_before(/^--/).each do |name, value|
90
98
  case name
91
99
  when '--stack-name'
92
100
  args[:stack_name] = value
93
101
  when '--parameters'
94
- args[:parameters] = Hash[value.split(/;/).map { |pair| parts = pair.split(/=/, 2); [ parts[0], Parameter.new(parts[1]) ] }] #/# fix for syntax highlighting
102
+ args[:parameters] = Hash[value.split(/;/).map { |pair| parts = pair.split(/=/, 2); [ parts[0], Parameter.new(parts[1]) ] }]
95
103
  when '--interactive'
96
104
  args[:interactive] = true
97
105
  when '--region'
@@ -100,6 +108,8 @@ def parse_args
100
108
  args[:profile] = value
101
109
  when '--nopretty'
102
110
  args[:nopretty] = true
111
+ when '--s3-bucket'
112
+ args[:s3_bucket] = value
103
113
  end
104
114
  end
105
115
 
@@ -151,8 +161,9 @@ def validate_action(action)
151
161
  end
152
162
 
153
163
  def cfn(template)
154
- aws_cfn = AwsCfn.new({:region => template.aws_region, :aws_profile => template.aws_profile})
155
- cfn_client = aws_cfn.cfn_client
164
+ aws_clients = AwsClients.new({:region => template.aws_region, :aws_profile => template.aws_profile})
165
+ cfn_client = aws_clients.cfn_client
166
+ s3_client = aws_clients.s3_client
156
167
 
157
168
  action = validate_action( ARGV[0] )
158
169
 
@@ -170,14 +181,10 @@ def cfn(template)
170
181
 
171
182
  cfn_tags.each {|k, v| cfn_tags[k] = v[:Value].to_s}
172
183
 
173
- if action == 'diff' or (action == 'expand' and not template.nopretty)
174
- template_string = JSON.pretty_generate(template)
175
- else
176
- template_string = JSON.generate(template)
177
- end
184
+ template_string = generate_template(template)
178
185
 
179
186
  # Derive stack name from ARGV
180
- _, options = extract_options(ARGV[1..-1], %w(--nopretty), %w(--profile --stack-name --region --parameters --tag))
187
+ _, options = extract_options(ARGV[1..-1], %w(--nopretty), %w(--profile --stack-name --region --parameters --tag --s3-bucket))
181
188
  # If the first argument is not an option and stack_name is undefined, assume it's the stack name
182
189
  # The second argument, if present, is the resource name used by the describe-resource command
183
190
  if template.stack_name.nil?
@@ -222,7 +229,7 @@ Make the resulting file executable (`chmod +x [NEW_NAME.rb]`). It can respond to
222
229
  - `get-template`: get entire template output of an existing stack
223
230
 
224
231
  Command line options similar to cloudformation commands, but parsed by the dsl.
225
- --profile --stack-name --region --parameters --tag
232
+ --profile --stack-name --region --parameters --tag --s3-bucket
226
233
 
227
234
  Any other parameters are passed directly onto cloudformation. (--disable-rollback for instance)
228
235
 
@@ -237,12 +244,7 @@ template.rb create --stack-name my_stack --parameters "BucketName=bucket-s3-stat
237
244
  when 'expand'
238
245
  # Write the pretty-printed JSON template to stdout and exit. [--nopretty] option writes output with minimal whitespace
239
246
  # example: <template.rb> expand --parameters "Env=prod" --region eu-west-1 --nopretty
240
- if template.nopretty
241
- puts template_string
242
- else
243
- puts template_string
244
- end
245
- exit(true)
247
+ template_string
246
248
 
247
249
  when 'diff'
248
250
  # example: <template.rb> diff my-stack-name --parameters "Env=prod" --region eu-west-1
@@ -332,7 +334,28 @@ template.rb create --stack-name my_stack --parameters "BucketName=bucket-s3-stat
332
334
 
333
335
  when 'validate'
334
336
  begin
335
- valid = cfn_client.validate_template({template_body: template_string})
337
+ validation_payload = {}
338
+ if template.s3_bucket.nil? then
339
+ validation_payload = {template_body: template_string}
340
+ else
341
+ template_path = "#{Time.now.strftime("%s")}/#{stack_name}.json"
342
+ # assumption: JSON is the only supported serialization format (YAML not allowed)
343
+ template_url = "https://s3.amazonaws.com/#{template.s3_bucket}/#{template_path}"
344
+ begin
345
+ s3_client.put_object({
346
+ bucket: template.s3_bucket,
347
+ key: template_path,
348
+ # canned ACL for authorized users to read the bucket (that should be *this* IAM role!)
349
+ acl: "private",
350
+ body: template_string,
351
+ })
352
+ rescue Aws::S3::Errors::ServiceError => e
353
+ $stderr.puts "Failed to upload stack template to S3: #{e}"
354
+ exit(false)
355
+ end
356
+ validation_payload = {template_url: template_url}
357
+ end
358
+ valid = cfn_client.validate_template(validation_payload)
336
359
  if valid.successful?
337
360
  puts "Validation successful"
338
361
  exit(true)
@@ -351,12 +374,34 @@ template.rb create --stack-name my_stack --parameters "BucketName=bucket-s3-stat
351
374
  # default options (not overridable)
352
375
  create_stack_opts = {
353
376
  stack_name: stack_name,
354
- template_body: template_string,
355
377
  parameters: template.parameters.map { |k,v| {parameter_key: k, parameter_value: v}}.to_a,
356
378
  tags: cfn_tags.map { |k,v| {"key" => k.to_s, "value" => v} }.to_a,
357
379
  capabilities: ["CAPABILITY_NAMED_IAM"],
358
380
  }
359
381
 
382
+ # If the user supplied the --s3-bucket option and
383
+ # access to the bucket, upload the template body to S3
384
+ if template.s3_bucket.nil? then
385
+ create_stack_opts["template_body"] = template_string
386
+ else
387
+ template_path = "#{Time.now.strftime("%s")}/#{stack_name}.json"
388
+ # assumption: JSON is the only supported serialization format (YAML not allowed)
389
+ template_url = "https://s3.amazonaws.com/#{template.s3_bucket}/#{template_path}"
390
+ begin
391
+ s3_client.put_object({
392
+ bucket: template.s3_bucket,
393
+ key: template_path,
394
+ # canned ACL for authorized users to read the bucket (that should be *this* IAM role!)
395
+ acl: "private",
396
+ body: template_string,
397
+ })
398
+ rescue Aws::S3::Errors::ServiceError => e
399
+ $stderr.puts "Failed to upload stack template to S3: #{e}"
400
+ exit(false)
401
+ end
402
+ create_stack_opts["template_url"] = template_url
403
+ end
404
+
360
405
  # fill in options from the command line
361
406
  extra_options = parse_arg_array_as_hash(options)
362
407
  create_stack_opts = extra_options.merge(create_stack_opts)
@@ -563,12 +608,29 @@ template.rb create --stack-name my_stack --parameters "BucketName=bucket-s3-stat
563
608
  # default options (not overridable)
564
609
  update_stack_opts = {
565
610
  stack_name: stack_name,
566
- template_body: template_string,
567
611
  parameters: template.parameters.map { |k,v| (v.use_previous_value && old_parameters.include?([k,v])) ? {parameter_key: k, use_previous_value: v.use_previous_value.to_s} : {parameter_key: k, parameter_value: v}}.to_a,
568
612
  tags: cfn_tags.map { |k,v| {"key" => k.to_s, "value" => v.to_s} }.to_a,
569
613
  capabilities: ["CAPABILITY_NAMED_IAM"],
570
614
  }
571
615
 
616
+ # if the the user supplies a bucket bucket and
617
+ # access to it, upload the template body
618
+ if template.s3_bucket.nil? then
619
+ update_stack_opts["template_body"] = template_string
620
+ else
621
+ template_path = "#{Time.now.strftime("%s")}/#{stack_name}.json"
622
+ # assumption: JSON is the only supported serialization format (YAML not allowed)
623
+ template_url = "https://s3.amazonaws.com/#{template.s3_bucket}/#{template_path}"
624
+ s3_client.put_object({
625
+ bucket: template.s3_bucket,
626
+ key: template_path,
627
+ # canned ACL for authorized users to read the bucket (that should be *this* IAM role!)
628
+ acl: "private",
629
+ body: template_string,
630
+ })
631
+ update_stack_opts["template_url"] = template_url
632
+ end
633
+
572
634
  # fill in options from the command line
573
635
  extra_options = parse_arg_array_as_hash(options)
574
636
  update_stack_opts = extra_options.merge(update_stack_opts)
@@ -654,7 +716,10 @@ end
654
716
  ##################################### Additional dsl logic
655
717
  # Core interpreter for the DSL
656
718
  class TemplateDSL < JsonObjectDSL
657
- def exec!()
719
+ def exec!
720
+ puts cfn(self)
721
+ end
722
+ def exec
658
723
  cfn(self)
659
724
  end
660
725
  end
@@ -4,7 +4,7 @@ require 'json'
4
4
 
5
5
  # Formats a template as JSON
6
6
  def generate_template(template)
7
- format_json template, !template.nopretty
7
+ generate_json template, !template.nopretty
8
8
  end
9
9
 
10
10
  def generate_json(data, pretty = true)
@@ -67,7 +67,8 @@ class TemplateDSL < JsonObjectDSL
67
67
  :aws_region,
68
68
  :nopretty,
69
69
  :stack_name,
70
- :aws_profile
70
+ :aws_profile,
71
+ :s3_bucket
71
72
 
72
73
  def initialize(options)
73
74
  @parameters = options.fetch(:parameters, {})
@@ -76,6 +77,7 @@ class TemplateDSL < JsonObjectDSL
76
77
  @aws_region = options.fetch(:region, default_region)
77
78
  @aws_profile = options[:profile]
78
79
  @nopretty = options.fetch(:nopretty, false)
80
+ @s3_bucket = options.fetch(:s3_bucket, nil)
79
81
  super()
80
82
  end
81
83
 
@@ -15,7 +15,7 @@
15
15
  module Cfn
16
16
  module Ruby
17
17
  module Dsl
18
- VERSION = "1.4.6"
18
+ VERSION = "1.5.0"
19
19
  end
20
20
  end
21
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudformation-ruby-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.6
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shawn Smith
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2017-03-20 00:00:00.000000000 Z
18
+ date: 2018-03-27 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: detabulator
@@ -210,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
210
  version: '0'
211
211
  requirements: []
212
212
  rubyforge_project:
213
- rubygems_version: 2.5.1
213
+ rubygems_version: 2.4.6
214
214
  signing_key:
215
215
  specification_version: 4
216
216
  summary: Ruby DSL library that provides a wrapper around the CloudFormation. Written