cloudformation-ruby-dsl 1.4.6 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|