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 +4 -4
- data/OWNERS +3 -1
- data/README.md +3 -3
- data/lib/cloudformation-ruby-dsl/cfntemplate.rb +86 -21
- data/lib/cloudformation-ruby-dsl/dsl.rb +4 -2
- data/lib/cloudformation-ruby-dsl/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 922a754ed43415e7919a4e4b6793c14ed596ec62
|
4
|
+
data.tar.gz: cdbdcedd3c9a48a194c0ba38cc2ddb7462cd5fbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63e08da62b61214f641fb651457c1cfb4114ae3eea242a49a6b0939f913184bd5f658471e98176e173c5820ed5fc289e41bf071e99cbd1e0b712be760590295a
|
7
|
+
data.tar.gz: ae973485d3a5cfde77175006ee831467ba9ebc4c23231d17b81818741df20f59ff78d10462896af4866ef8d0d5d609b5dffe129f4267fab83ee8257f2defb088
|
data/OWNERS
CHANGED
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
|
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]) ] }]
|
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
|
-
|
155
|
-
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|
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
|
+
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:
|
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.
|
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
|