stackup 1.4.3 → 1.5.1

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
  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