stack_master 2.8.0 → 2.13.0

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: 7d401f198bf80974977c8b031f27422ea84aa171f18747fa6064cf6d9d2af784
4
- data.tar.gz: dd930994d8034f57d60ba1a77d8bfee0f524301501306a3d8cee64502c27029e
3
+ metadata.gz: 8c0add9f29f6f809207e0b64969e084172dc194c77ae1636ceb073000e8020b4
4
+ data.tar.gz: f5e2a4a3a84a55a74bc29525067691a847f24b9c4256108d3ec9c086cd82ab6a
5
5
  SHA512:
6
- metadata.gz: de26f0ce262ef2b4b11cced8789a8093896d9bd7db6950008ad7e0e469ea43a9752fbbcb0e4b57271656442aa7bb13dc159697690d0a0754fcbc9ecce39d07b0
7
- data.tar.gz: 0ef954037a433821d09b90acbbd39da5a881044f305353267cba379a07e77bd2ffe7645700b8ce927d15d7f518c823aa17a42f0c9971ce3c37b29f5164a8b219
6
+ metadata.gz: addcb8147d827d7f403018c72a44a4fb1ca1d5536e7d74abe0c32e3645c1eded4278c761d7bb48d861e2857d7cd64ae9e61d69fb70d560f1aa44b79672ccc178
7
+ data.tar.gz: 98d47ddfcc3e928f55d7946d50f4bab280c04bb4d0eb0b8aade5616c1274ab542755ef616fdec3ccacce739832300bf202ba84e2d22e213f11f9ba62b91b349d
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/envato/stack_master/blob/master/LICENSE.md)
4
4
  [![Gem Version](https://badge.fury.io/rb/stack_master.svg)](https://badge.fury.io/rb/stack_master)
5
- [![Build Status](https://travis-ci.org/envato/stack_master.svg?branch=master)](https://travis-ci.org/envato/stack_master)
5
+ [![Build Status](https://github.com/envato/stack_master/workflows/tests/badge.svg?branch=master)](https://github.com/envato/stack_master/actions?query=workflow%3Atests+branch%3Amaster)
6
6
 
7
7
  StackMaster is a CLI tool to manage [CloudFormation](https://aws.amazon.com/cloudformation/) stacks, with the following features:
8
8
 
@@ -143,7 +143,8 @@ stacks:
143
143
  ## Templates
144
144
 
145
145
  StackMaster supports CloudFormation templates in plain JSON or YAML. Any `.yml` or `.yaml` file will be processed as
146
- YAML, while any `.json` file will be processed as JSON.
146
+ YAML, while any `.json` file will be processed as JSON. Additionally, YAML files can be pre-processed using ERB and
147
+ compile-time parameters.
147
148
 
148
149
  ### Ruby DSLs
149
150
  By default, any template ending with `.rb` will be processed as a [SparkleFormation](https://github.com/sparkleformation/sparkle_formation)
@@ -199,12 +200,13 @@ stacks:
199
200
 
200
201
  ### Compile Time Parameters
201
202
 
202
- Compile time parameters can be used for [SparkleFormation](http://www.sparkleformation.io) templates. It conforms and
203
- allows you to use the [Compile Time Parameters](http://www.sparkleformation.io/docs/sparkle_formation/compile-time-parameters.html) feature.
203
+ Compile time parameters can be defined in a stack's parameters file, using the key `compile_time_parameters`. Keys in
204
+ parameter files are automatically converted to camel case.
204
205
 
205
- A simple example looks like this
206
+ As an example:
206
207
 
207
208
  ```yaml
209
+ # parameters/some_stack.yml
208
210
  vpc_cidr: 10.0.0.0/16
209
211
  compile_time_parameters:
210
212
  subnet_cidrs:
@@ -212,7 +214,37 @@ compile_time_parameters:
212
214
  - 10.0.2.0/28
213
215
  ```
214
216
 
215
- Keys in parameter files are automatically converted to camel case.
217
+ #### SparkleFormation
218
+
219
+ Compile time parameters can be used for [SparkleFormation](http://www.sparkleformation.io) templates. It conforms and
220
+ allows you to use the [Compile Time Parameters](http://www.sparkleformation.io/docs/sparkle_formation/compile-time-parameters.html) feature.
221
+
222
+ #### CloudFormation YAML ERB
223
+
224
+ Compile time parameters can be used to pre-process YAML CloudFormation templates. An example template:
225
+
226
+ ```yaml
227
+ # templates/some_stack_template.yml.erb
228
+ Parameters:
229
+ VpcCidr:
230
+ Type: String
231
+ Resources:
232
+ Vpc:
233
+ Type: AWS::EC2::VPC
234
+ Properties:
235
+ CidrBlock: !Ref VpcCidr
236
+ # Given the two subnet_cidrs parameters, this creates two resources:
237
+ # SubnetPrivate0 with a CidrBlock of 10.0.0.0/28, and
238
+ # SubnetPrivate1 with a CidrBlock of 10.0.2.0/28
239
+ <% params["SubnetCidrs"].each_with_index do |cidr, index| %>
240
+ SubnetPrivate<%= index %>:
241
+ Type: AWS::EC2::Subnet
242
+ Properties:
243
+ VpcId: !Ref Vpc
244
+ AvailabilityZone: ap-southeast-2
245
+ CidrBlock: <%= cidr %>
246
+ <% end %>
247
+ ```
216
248
 
217
249
  ## Parameter Resolvers
218
250
 
@@ -709,6 +741,10 @@ stack_master outputs [region-or-alias] [stack-name] # Display outputs for a stac
709
741
  stack_master resources [region-or-alias] [stack-name] # Display outputs for a stack
710
742
  stack_master status # Displays the status of each stack
711
743
  stack_master tidy # Find missing or extra templates or parameter files
744
+ stack_master compile # Print the compiled version of a given stack
745
+ stack_master validate # Validate a template
746
+ stack_master lint # Check the stack definition locally using cfn-lint
747
+ stack_master nag # Check the stack template with cfn_nag
712
748
  ```
713
749
 
714
750
  ## Applying updates - `stack_master apply`
data/lib/stack_master.rb CHANGED
@@ -52,6 +52,7 @@ module StackMaster
52
52
  require 'stack_master/template_compilers/sparkle_formation'
53
53
  require 'stack_master/template_compilers/json'
54
54
  require 'stack_master/template_compilers/yaml'
55
+ require 'stack_master/template_compilers/yaml_erb'
55
56
  require 'stack_master/template_compilers/cfndsl'
56
57
 
57
58
  module Commands
@@ -70,6 +71,7 @@ module StackMaster
70
71
  autoload :Delete, 'stack_master/commands/delete'
71
72
  autoload :Status, 'stack_master/commands/status'
72
73
  autoload :Tidy, 'stack_master/commands/tidy'
74
+ autoload :Nag, 'stack_master/commands/nag'
73
75
  end
74
76
 
75
77
  module ParameterResolvers
@@ -146,6 +146,17 @@ module StackMaster
146
146
  end
147
147
  end
148
148
 
149
+ command :nag do |c|
150
+ c.syntax = 'stack_master nag [region_or_alias] [stack_name]'
151
+ c.summary = "Check this stack's template with cfn_nag"
152
+ c.description = "Runs SAST scan cfn_nag on the template"
153
+ c.example 'run cfn_nag on stack myapp-vpc with us-east-1 settings', 'stack_master nag us-east-1 myapp-vpc'
154
+ c.action do |args, options|
155
+ options.default config: default_config_file
156
+ execute_stacks_command(StackMaster::Commands::Nag, args, options)
157
+ end
158
+ end
159
+
149
160
  command :compile do |c|
150
161
  c.syntax = 'stack_master compile [region_or_alias] [stack_name]'
151
162
  c.summary = "Print the compiled version of a given stack"
@@ -219,9 +230,10 @@ module StackMaster
219
230
  c.syntax = 'stack_master drift [region_or_alias] [stack_name]'
220
231
  c.summary = 'Detects and displays stack drift using the CloudFormation Drift API'
221
232
  c.description = 'Detects and displays stack drift'
233
+ c.option '--timeout SECONDS', Integer, "The number of seconds to wait for drift detection to complete"
222
234
  c.example 'view stack drift for a stack named myapp-vpc in us-east-1', 'stack_master drift us-east-1 myapp-vpc'
223
235
  c.action do |args, options|
224
- options.default config: default_config_file
236
+ options.default config: default_config_file, timeout: 120
225
237
  execute_stacks_command(StackMaster::Commands::Drift, args, options)
226
238
  end
227
239
  end
@@ -253,6 +265,7 @@ module StackMaster
253
265
  stack_definitions = config.filter(region, stack_name)
254
266
  if stack_definitions.empty?
255
267
  StackMaster.stdout.puts "Could not find stack definition #{stack_name} in region #{region}"
268
+ show_other_region_candidates(config, stack_name)
256
269
  success = false
257
270
  end
258
271
  stack_definitions = stack_definitions.select do |stack_definition|
@@ -269,6 +282,13 @@ module StackMaster
269
282
  @kernel.exit false unless success
270
283
  end
271
284
 
285
+ def show_other_region_candidates(config, stack_name)
286
+ candidates = config.filter(region="", stack_name=stack_name)
287
+ return if candidates.empty?
288
+
289
+ StackMaster.stdout.puts "Stack name #{stack_name} exists in regions: #{candidates.map(&:region).join(', ')}"
290
+ end
291
+
272
292
  def execute_if_allowed_account(allowed_accounts, &block)
273
293
  raise ArgumentError, "Block required to execute this method" unless block_given?
274
294
  if running_in_allowed_account?(allowed_accounts)
@@ -5,7 +5,7 @@ module StackMaster
5
5
  include Commander::UI
6
6
 
7
7
  def perform
8
- puts(proposed_stack.template_body)
8
+ StackMaster.stdout.puts(proposed_stack.template_body)
9
9
  end
10
10
 
11
11
  private
@@ -88,17 +88,17 @@ module StackMaster
88
88
  end
89
89
 
90
90
  def wait_for_drift_results(detection_id)
91
- try_count = 0
92
91
  resp = nil
92
+ start_time = Time.now
93
93
  loop do
94
- if try_count >= 10
95
- raise 'Failed to wait for stack drift detection after 10 tries'
96
- end
97
-
98
94
  resp = cf.describe_stack_drift_detection_status(stack_drift_detection_id: detection_id)
99
95
  break if DETECTION_COMPLETE_STATES.include?(resp.detection_status)
100
96
 
101
- try_count += 1
97
+ elapsed_time = Time.now - start_time
98
+ if elapsed_time > @options.timeout
99
+ raise "Timeout waiting for stack drift detection"
100
+ end
101
+
102
102
  sleep SLEEP_SECONDS
103
103
  end
104
104
  resp
@@ -0,0 +1,30 @@
1
+ module StackMaster
2
+ module Commands
3
+ class Nag
4
+ include Command
5
+ include Commander::UI
6
+
7
+ def perform
8
+ rv = Tempfile.open(['stack', "___#{stack_definition.stack_name}.#{proposed_stack.template_format}"]) do |f|
9
+ f.write(proposed_stack.template_body)
10
+ f.flush
11
+ system('cfn_nag', f.path)
12
+ $?.exitstatus
13
+ end
14
+
15
+ failed!("cfn_nag check failed with exit status #{rv}") if rv > 0
16
+ end
17
+
18
+ private
19
+
20
+ def stack_definition
21
+ @stack_definition ||= @config.find_stack(@region, @stack_name)
22
+ end
23
+
24
+ def proposed_stack
25
+ @proposed_stack ||= Stack.generate(stack_definition, @config)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -92,6 +92,7 @@ module StackMaster
92
92
  json: :json,
93
93
  yml: :yaml,
94
94
  yaml: :yaml,
95
+ erb: :yaml_erb,
95
96
  }
96
97
  end
97
98
 
@@ -19,7 +19,7 @@ module StackMaster
19
19
 
20
20
  def has_invalid_values?
21
21
  values = build_values(@definition, @parameter)
22
- values.include?(nil) || values.include?('')
22
+ values.include?(nil)
23
23
  end
24
24
 
25
25
  def create_error
@@ -2,14 +2,15 @@ module StackMaster::TemplateCompilers
2
2
  class Cfndsl
3
3
  def self.require_dependencies
4
4
  require 'cfndsl'
5
+ require 'json'
5
6
  end
6
7
 
7
8
  def self.compile(template_dir, template, compile_time_parameters, _compiler_options = {})
8
- CfnDsl.disable_binding
9
9
  CfnDsl::ExternalParameters.defaults.clear # Ensure there's no leakage across invocations
10
10
  CfnDsl::ExternalParameters.defaults(compile_time_parameters.symbolize_keys)
11
11
  template_file_path = File.join(template_dir, template)
12
- ::CfnDsl.eval_file_with_extras(template_file_path).to_json
12
+ json_hash = ::CfnDsl.eval_file_with_extras(template_file_path).as_json
13
+ JSON.pretty_generate(json_hash)
13
14
  end
14
15
 
15
16
  StackMaster::TemplateCompiler.register(:cfndsl, self)
@@ -22,7 +22,7 @@ module StackMaster::TemplateCompilers
22
22
  sparkle_template.compile_state = create_state(definitions, compile_time_parameters)
23
23
  end
24
24
 
25
- JSON.pretty_generate(sparkle_template)
25
+ JSON.pretty_generate(sparkle_template.dump)
26
26
  end
27
27
 
28
28
  private
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StackMaster::TemplateCompilers
4
+ class YamlErb
5
+ def self.require_dependencies
6
+ require 'erubis'
7
+ require 'yaml'
8
+ end
9
+
10
+ def self.compile(template_dir, template, compile_time_parameters, _compiler_options = {})
11
+ template_file_path = File.join(template_dir, template)
12
+ template = Erubis::Eruby.new(File.read(template_file_path))
13
+ template.filename = template_file_path
14
+
15
+ template.result(params: compile_time_parameters)
16
+ end
17
+
18
+ StackMaster::TemplateCompiler.register(:yaml_erb, self)
19
+ end
20
+ end
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "2.8.0"
2
+ VERSION = "2.13.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Hodgkiss
8
8
  - Glen Stampoultzis
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-06-24 00:00:00.000000000 Z
12
+ date: 2021-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -371,16 +371,16 @@ dependencies:
371
371
  name: cfndsl
372
372
  requirement: !ruby/object:Gem::Requirement
373
373
  requirements:
374
- - - "<"
374
+ - - "~>"
375
375
  - !ruby/object:Gem::Version
376
- version: '1.0'
376
+ version: '1'
377
377
  type: :runtime
378
378
  prerelease: false
379
379
  version_requirements: !ruby/object:Gem::Requirement
380
380
  requirements:
381
- - - "<"
381
+ - - "~>"
382
382
  - !ruby/object:Gem::Version
383
- version: '1.0'
383
+ version: '1'
384
384
  - !ruby/object:Gem::Dependency
385
385
  name: multi_json
386
386
  requirement: !ruby/object:Gem::Requirement
@@ -437,6 +437,26 @@ dependencies:
437
437
  - - ">="
438
438
  - !ruby/object:Gem::Version
439
439
  version: '0'
440
+ - !ruby/object:Gem::Dependency
441
+ name: cfn-nag
442
+ requirement: !ruby/object:Gem::Requirement
443
+ requirements:
444
+ - - ">="
445
+ - !ruby/object:Gem::Version
446
+ version: 0.6.7
447
+ - - "<"
448
+ - !ruby/object:Gem::Version
449
+ version: 0.8.0
450
+ type: :runtime
451
+ prerelease: false
452
+ version_requirements: !ruby/object:Gem::Requirement
453
+ requirements:
454
+ - - ">="
455
+ - !ruby/object:Gem::Version
456
+ version: 0.6.7
457
+ - - "<"
458
+ - !ruby/object:Gem::Version
459
+ version: 0.8.0
440
460
  description: ''
441
461
  email:
442
462
  - steve@hodgkiss.me
@@ -464,6 +484,7 @@ files:
464
484
  - lib/stack_master/commands/init.rb
465
485
  - lib/stack_master/commands/lint.rb
466
486
  - lib/stack_master/commands/list_stacks.rb
487
+ - lib/stack_master/commands/nag.rb
467
488
  - lib/stack_master/commands/outputs.rb
468
489
  - lib/stack_master/commands/resources.rb
469
490
  - lib/stack_master/commands/status.rb
@@ -524,6 +545,7 @@ files:
524
545
  - lib/stack_master/template_compilers/json.rb
525
546
  - lib/stack_master/template_compilers/sparkle_formation.rb
526
547
  - lib/stack_master/template_compilers/yaml.rb
548
+ - lib/stack_master/template_compilers/yaml_erb.rb
527
549
  - lib/stack_master/template_utils.rb
528
550
  - lib/stack_master/test_driver/cloud_formation.rb
529
551
  - lib/stack_master/test_driver/s3.rb
@@ -541,9 +563,9 @@ licenses:
541
563
  metadata:
542
564
  bug_tracker_uri: https://github.com/envato/stack_master/issues
543
565
  changelog_uri: https://github.com/envato/stack_master/blob/master/CHANGELOG.md
544
- documentation_uri: https://www.rubydoc.info/gems/stack_master/2.8.0
545
- source_code_uri: https://github.com/envato/stack_master/tree/v2.8.0
546
- post_install_message:
566
+ documentation_uri: https://www.rubydoc.info/gems/stack_master/2.13.0
567
+ source_code_uri: https://github.com/envato/stack_master/tree/v2.13.0
568
+ post_install_message:
547
569
  rdoc_options: []
548
570
  require_paths:
549
571
  - lib
@@ -558,8 +580,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
558
580
  - !ruby/object:Gem::Version
559
581
  version: '0'
560
582
  requirements: []
561
- rubygems_version: 3.0.3
562
- signing_key:
583
+ rubygems_version: 3.2.8
584
+ signing_key:
563
585
  specification_version: 4
564
586
  summary: StackMaster is a sure-footed way of creating, updating and keeping track
565
587
  of Amazon (AWS) CloudFormation stacks.