stackup 1.4.3 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01e367ca4b2044872b8bffc12075970ad962f5542e143a3d8f47cc6cd9ec6773
4
- data.tar.gz: a3b4dd683a84e01885ffdc60ec306e18d212e24fefddec660cd451b8ca8c5d23
3
+ metadata.gz: 7a60dfe3184679f98c43d28590feadf40faa968bf5b75531951510d96d38a02f
4
+ data.tar.gz: ab5010d36407547ba7c1f5b09e190c776023303227b72881ea80b2b49a41b717
5
5
  SHA512:
6
- metadata.gz: 1fc1090d8365094a4ec26df52d8f4ba745d5ff9dc275001630d4ebb013a7673105d658749ee0d3214da89c1559c0acbaa3a5f9ee1cb17ab8e643ab16436d0ac0
7
- data.tar.gz: 578e511731086edfe83a22245bde31c50ec8c194504772f6f4ae3cd2ac56fe5819e2adfc2c11e34b576e07071207f70b2f3f2c38f61d16a0ca74f639e1668333
6
+ metadata.gz: cf63917e39f450c29d98e420f872aa5f1d7bd00fbd2543eece6d81795ec64ec349e66ba507230e212d30961a390a8a9f587c0dc45e08b823c78c518f700425ff
7
+ data.tar.gz: 15a86e361a985ca59c7714025fa47308a4e165b5abdf2f0bf8e3020d13a73636e219a6693b208f6d51e4fed8aa28587e7dbd1dda03a654d471a8a432ca4e4632
data/CHANGES.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # CHANGES
2
2
 
3
+ ## 1.5.1 (2020-11-16)
4
+
5
+ * Fix: Recognise that template is in S3 when URL is formatted like `s3.REGION.amazonaws.com`
6
+
7
+ ## 1.5.0 (2020-04-21)
8
+
9
+ * Feature: --preserve-template-formatting
10
+
11
+ ## 1.4.6 (2019-12-09)
12
+
13
+ * Fix: Don't error out when receiving tags in AWS style (array of hashes) from YAML or JSON file
14
+
15
+ ## 1.4.5 (2019-10-03)
16
+
17
+ * Fix: Tags in RakeTasks
18
+
19
+ ## 1.4.4 (2019-10-03)
20
+
21
+ * Fix: Loading RakeTasks
22
+ * Removes CI support for older rubies
23
+
3
24
  ## 1.4.3 (2019-09-05)
4
25
 
5
26
  * Add support for CloudFormation capabilities via CLI and Rake
data/README.md CHANGED
@@ -78,10 +78,12 @@ For more details on usage, see
78
78
 
79
79
  ### Specifying parameters
80
80
 
81
- Stack parameters can be be read from a file, e.g.
81
+ Stack parameters can be read from a file, e.g.
82
82
 
83
83
  $ stackup myapp-test up -t template.json -p parameters.json
84
84
 
85
+ These files can be either JSON or YAML format, see [YAML support](#yaml-support) for more information.
86
+
85
87
  Parameters can be specified as simple key-value pairs:
86
88
 
87
89
  ```json
@@ -116,11 +118,48 @@ Or, you can specify one or more override parameters on the command-line, using `
116
118
  -o IndexDoc=index-override.html
117
119
  -o ContentDoc=content-override.html
118
120
 
121
+ ### Specifying tags
122
+
123
+ Stack tags can be read from a file, e.g.
124
+
125
+ $ stackup myapp-test up -t template.json --tags tags.json
126
+
127
+ These files can be either JSON or YAML format, see [YAML support](#yaml-support) for more information.
128
+
129
+ Tags are specified as simple key-value pairs:
130
+
131
+ ```json
132
+ {
133
+ "environment": "dev"
134
+ }
135
+ ```
136
+
137
+ ### Acknowledging Capabilities
138
+
139
+ CloudFormation requires that some stacks explicitly acknowledge certain capabilities before creation. This helps to prevent the creation of stacks with unintended privileges.
140
+
141
+ If your stack includes IAM resources, you must specify either the `CAPABILITY_IAM` capability, or the `CAPABILITY_NAMED_IAM` capability if they have custom names.
142
+
143
+ If your stack template contains macros or nested stacks, you must specify the `CAPABILITY_AUTO_EXPAND` capability.
144
+
145
+ Capabilities can be provided via the `--capability` CLI option.
146
+
147
+ $ stackup myapp-test up -t template.json \
148
+ --capability CAPABILITY_NAMED_IAM \
149
+ --capability CAPABILITY_AUTO_EXPAND
150
+
151
+ `stackup` includes defaults to including `CAPABILITY_NAMED_IAM` capability if, and only if, no capabilities are specified.
152
+ This is to provide backwards compatibility with previously deployed stacks and may be removed in a future release.
153
+
119
154
  ### YAML support
120
155
 
121
156
  `stackup` supports input files (template, parameters, tags) in YAML format, as well as JSON.
122
157
 
123
- It also supports the [abbreviated YAML syntax for Cloudformation functions](https://aws.amazon.com/blogs/aws/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/), though unlike the [AWS CLI](https://aws.amazon.com/cli/), Stackup normalises YAML input to JSON before invoking CloudFormation APIs.
158
+ It also supports the [abbreviated YAML syntax for Cloudformation functions](https://aws.amazon.com/blogs/aws/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/), though unlike the [AWS CLI](https://aws.amazon.com/cli/), Stackup (by default) normalises YAML input to JSON before invoking CloudFormation APIs.
159
+
160
+ If you don't want normalisation of the YAML input to JSON, then use the `--preserve-template-formatting` flag to the `up` or `change-set create` commands.
161
+
162
+ Note: normalisation of S3 / HTTP URL stored templates is never done, as Cloudformation collects these directly.
124
163
 
125
164
  ### AWS credentials
126
165
 
@@ -268,11 +307,11 @@ The release process will push tags to GitHub, push the gem to rubygems and push
268
307
  Prerequisites:
269
308
 
270
309
  * logged into dockerhub via `docker login`. Your user must have permission to push to `realestate/stackup`
271
- * logged into rubygems via `gem push`. Your user must have permission to push to the `stackup` gem.
310
+ * You must have a rubygems account with permission to push to the `stackup` gem. (`auto/release` will ask for your username and password)
311
+ * You must have cloned this repo via HTTPS and have a github account with permission to push. (`auto/release` will ask for your username and a GitHub personal access token)
272
312
 
273
313
  To release:
274
314
 
275
315
  ```
276
- bundle install
277
316
  auto/release
278
317
  ```
@@ -41,7 +41,7 @@ Clamp do
41
41
  option ["--[no-]wait"], :flag, "wait for stack updates to complete",
42
42
  :default => true
43
43
 
44
- option ["--wait-poll-interval"], "N", "polling interval while waiting for updates",
44
+ option ["--wait-poll-interval"], "N", "polling interval (in seconds) while waiting for updates",
45
45
  :default => 5, &method(:Integer)
46
46
 
47
47
  option "--debug", :flag, "enable debugging"
@@ -181,6 +181,9 @@ Clamp do
181
181
  option ["-T", "--use-previous-template"], :flag,
182
182
  "reuse the existing template"
183
183
 
184
+ option ["-P", "--preserve-template-formatting"], :flag,
185
+ "do not normalise the template when calling the Cloudformation APIs; useful for preserving YAML and comments"
186
+
184
187
  include HasParameters
185
188
 
186
189
  option "--tags", "FILE", "stack tags file",
@@ -214,6 +217,7 @@ Clamp do
214
217
  options[:template_url] = template_source.location
215
218
  else
216
219
  options[:template] = template_source.data
220
+ options[:template_orig] = template_source.body
217
221
  end
218
222
  end
219
223
  options[:on_failure] = on_failure
@@ -229,6 +233,7 @@ Clamp do
229
233
  options[:role_arn] = service_role_arn if service_role_arn
230
234
  options[:use_previous_template] = use_previous_template?
231
235
  options[:capabilities] = capability_list
236
+ options[:preserve] = preserve_template_formatting?
232
237
  report_change do
233
238
  stack.create_or_update(options)
234
239
  end
@@ -274,6 +279,9 @@ Clamp do
274
279
  option ["-T", "--use-previous-template"], :flag,
275
280
  "reuse the existing template"
276
281
 
282
+ option ["-P", "--preserve-template-formatting"], :flag,
283
+ "do not normalise the template when calling the Cloudformation APIs; useful for preserving YAML and comments"
284
+
277
285
  option ["--force"], :flag,
278
286
  "replace existing change-set of the same name"
279
287
 
@@ -296,6 +304,7 @@ Clamp do
296
304
  options[:template_url] = template_source.location
297
305
  else
298
306
  options[:template] = template_source.data
307
+ options[:template_orig] = template_source.body
299
308
  end
300
309
  end
301
310
  options[:parameters] = parameters
@@ -304,6 +313,7 @@ Clamp do
304
313
  options[:use_previous_template] = use_previous_template?
305
314
  options[:force] = force?
306
315
  options[:capabilities] = capability_list
316
+ options[:preserve] = preserve_template_formatting?
307
317
  report_change do
308
318
  change_set.create(options)
309
319
  end
@@ -57,6 +57,9 @@ module Stackup
57
57
  options[:change_set_type] = stack.exists? ? "UPDATE" : "CREATE"
58
58
  force = options.delete(:force)
59
59
  options[:template_body] = MultiJson.dump(options.delete(:template)) if options[:template]
60
+ # optionally override template_body with the original template to preserve formatting (& comments in YAML)
61
+ template_orig = options.delete(:template_orig)
62
+ options[:template_body] = template_orig if options.delete(:preserve)
60
63
  options[:parameters] = Parameters.new(options[:parameters]).to_a if options[:parameters]
61
64
  options[:tags] = normalize_tags(options[:tags]) if options[:tags]
62
65
  options[:capabilities] ||= ["CAPABILITY_NAMED_IAM"]
@@ -1,7 +1,7 @@
1
1
  require "rake/tasklib"
2
2
  require "tempfile"
3
3
  require "yaml"
4
- require "Pathname"
4
+ require "pathname"
5
5
 
6
6
  module Stackup
7
7
 
@@ -42,7 +42,7 @@ module Stackup
42
42
  data_options = []
43
43
  data_options << DataOption.for("--template", template)
44
44
  data_options << DataOption.for("--parameters", parameters) if parameters
45
- data_options << DataOption.for("--tags", tags) if tag
45
+ data_options << DataOption.for("--tags", tags) if tags
46
46
 
47
47
  desc "Update #{stack} stack"
48
48
  task "up" => data_options.grep(DataOptionFile).map(&:argument) do
@@ -15,7 +15,7 @@ module Stackup
15
15
 
16
16
  def s3?
17
17
  uri.scheme == "https" &&
18
- uri.host =~ /(^|\.)s3(-\w+-\w+-\d)?\.amazonaws\.com$/
18
+ uri.host =~ /(^|\.)s3((\.|-)\w+-\w+-\d)?\.amazonaws\.com$/
19
19
  end
20
20
 
21
21
  def body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "aws-sdk-cloudformation"
2
4
  require "logger"
3
5
  require "multi_json"
@@ -16,10 +18,10 @@ module Stackup
16
18
  DEFAULT_WAIT_POLL_INTERVAL = 5 # seconds
17
19
 
18
20
  def initialize(name, client = {}, options = {})
19
- client = Aws::CloudFormation::Client.new(client) if client.is_a?(Hash)
20
- @name = name
21
+ client = Aws::CloudFormation::Client.new(client) if client.is_a?(Hash)
22
+ @name = name
21
23
  @cf_client = client
22
- @wait = true
24
+ @wait = true
23
25
  options.each do |key, value|
24
26
  public_send("#{key}=", value)
25
27
  end
@@ -117,6 +119,9 @@ module Stackup
117
119
  if (template_data = options.delete(:template))
118
120
  options[:template_body] = MultiJson.dump(template_data)
119
121
  end
122
+ # optionally override template_body with the original template to preserve formatting (& comments in YAML)
123
+ template_orig = options.delete(:template_orig)
124
+ options[:template_body] = template_orig if options.delete(:preserve)
120
125
  if (parameters = options[:parameters])
121
126
  options[:parameters] = Parameters.new(parameters).to_a
122
127
  end
@@ -282,7 +287,7 @@ module Stackup
282
287
  end
283
288
 
284
289
  def create(options)
285
- options = options.dup
290
+ options = options.dup
286
291
  options[:stack_name] = name
287
292
  options.delete(:stack_policy_during_update_body)
288
293
  options.delete(:stack_policy_during_update_url)
@@ -312,7 +317,7 @@ module Stackup
312
317
  def event_handler
313
318
  @event_handler ||= lambda do |e|
314
319
  fields = [e.logical_resource_id, e.resource_status, e.resource_status_reason]
315
- time = e.timestamp.localtime.strftime("%H:%M:%S")
320
+ time = e.timestamp.localtime.strftime("%H:%M:%S")
316
321
  logger.info("[#{time}] #{fields.compact.join(' - ')}")
317
322
  end
318
323
  end
@@ -369,7 +374,13 @@ module Stackup
369
374
  { :key => key, :value => value.to_s }
370
375
  end
371
376
  else
372
- tags
377
+ tags.map do |tag|
378
+ if tag.key?("Key")
379
+ { :key => tag["Key"], :value => tag["Value"].to_s }
380
+ else
381
+ { :key => tag[:key], :value => tag[:value].to_s }
382
+ end
383
+ end
373
384
  end
374
385
  end
375
386
 
@@ -384,8 +395,8 @@ module Stackup
384
395
  handling_cf_errors do
385
396
  {}.tap do |result|
386
397
  cf_stack.public_send(collection_name).each do |item|
387
- key = item.public_send(key_name)
388
- value = item.public_send(value_name)
398
+ key = item.public_send(key_name)
399
+ value = item.public_send(value_name)
389
400
  result[key] = value
390
401
  end
391
402
  end
@@ -1,5 +1,5 @@
1
1
  module Stackup
2
2
 
3
- VERSION = "1.4.3".freeze
3
+ VERSION = "1.5.1".freeze
4
4
 
5
5
  end
@@ -0,0 +1,8 @@
1
+ require "spec_helper"
2
+ require "stackup/rake_tasks"
3
+
4
+ RSpec.describe Stackup::RakeTasks do
5
+ it "can be required" do
6
+ expect(described_class).to be_truthy
7
+ end
8
+ end
@@ -124,6 +124,16 @@ describe Stackup::Source do
124
124
 
125
125
  end
126
126
 
127
+ context "with dot separated bucket and region" do
128
+
129
+ let(:s3_url) { "https://bucket.s3.us-east-1.amazonaws.com/cfn/template.yml" }
130
+
131
+ it "is S3" do
132
+ expect(subject).to be_s3
133
+ end
134
+
135
+ end
136
+
127
137
  end
128
138
 
129
139
  end
@@ -260,6 +260,26 @@ describe Stackup::Stack do
260
260
 
261
261
  end
262
262
 
263
+ context "with :tags in SDK form as they arrive from file" do
264
+
265
+ before do
266
+ options[:tags] = [
267
+ { "Key" => "foo", "Value" => "bar" }
268
+ ]
269
+ end
270
+
271
+ it "converts them to an Array, that uses symbols as keys" do
272
+ expected_tags = [
273
+ { :key => "foo", :value => "bar" }
274
+ ]
275
+ create_or_update
276
+ expect(cf_client).to have_received(:create_stack) do |options|
277
+ expect(options[:tags]).to eq(expected_tags)
278
+ end
279
+ end
280
+
281
+ end
282
+
263
283
  context "with :tags in SDK form" do
264
284
 
265
285
  before do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Williams
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-09-05 00:00:00.000000000 Z
12
+ date: 2020-11-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk-cloudformation
@@ -110,6 +110,7 @@ files:
110
110
  - lib/stackup/yaml.rb
111
111
  - spec/spec_helper.rb
112
112
  - spec/stackup/parameters_spec.rb
113
+ - spec/stackup/rake_tasks_spec.rb
113
114
  - spec/stackup/source_spec.rb
114
115
  - spec/stackup/stack_spec.rb
115
116
  - spec/stackup/stack_watcher_spec.rb
@@ -141,6 +142,7 @@ summary: Manage CloudFormation stacks
141
142
  test_files:
142
143
  - spec/spec_helper.rb
143
144
  - spec/stackup/parameters_spec.rb
145
+ - spec/stackup/rake_tasks_spec.rb
144
146
  - spec/stackup/source_spec.rb
145
147
  - spec/stackup/stack_spec.rb
146
148
  - spec/stackup/stack_watcher_spec.rb