stack_master 2.7.0 → 2.12.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: f94d2bab69225428425d5e3bc426ca572c781aa5d9e069420c198c86640f84c5
4
- data.tar.gz: f4f164e4390d568e9a7511013a33796ad04862d18510ec5683c2024b9952781f
3
+ metadata.gz: 02eda4742884cf2aa48568ad0e330b375f7548f12f3077be3167bd782a51868d
4
+ data.tar.gz: 6f3159eb1b681bda06e4c128d4746f05484a75f91c1a2119d9c02523f912b48f
5
5
  SHA512:
6
- metadata.gz: 81122997265f0aa25d24f54ee3ccbb5a0a3689b362b37445bd0c12435dc0fcbb24e0d8ce277c949c1e3af5c01d3b5ff938227f6b6f051b97cc8da66f400519d6
7
- data.tar.gz: b5f8114a90fc7cc402e07e34676b7142b3849c4e8eecdc43cb67651358e5e7e6228ab04b68ef5b769b98ff91e7efd2ec9667a5c197699bccbfb96d49848585ed
6
+ metadata.gz: 4670acd897af5bd58083f65187c23c7e7add969ca1d906899ce18065bcc24287d78854bd67baa82a1225dab4277b3392fa03cc3a5ffe49c13cffd3665ca2ea99
7
+ data.tar.gz: 8ea47d21747c13e9685f0f5cacbb12663c28df649823981c5e1a94e982bc7798bd2b93828be921e7e2e4267e3c3aa3d1f246aeb8f99f0eb91d34d2ce24594263
data/README.md CHANGED
@@ -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
 
@@ -688,6 +720,7 @@ stacks:
688
720
 
689
721
  In the cases where you want to bypass the account check, there is the StackMaster flag `--skip-account-check` that can be used.
690
722
 
723
+
691
724
  ## Commands
692
725
 
693
726
  ```bash
@@ -701,15 +734,20 @@ stack_master apply # Create or update all stacks
701
734
  stack_master --changed apply # Create or update all stacks that have changed
702
735
  stack_master --yes apply [region-or-alias] [stack-name] # Create or update a stack non-interactively (forcing yes)
703
736
  stack_master diff [region-or-alias] [stack-name] # Display a stack template and parameter diff
737
+ stack_master drift [region-or-alias] [stack-name] # Detects and displays stack drift using the CloudFormation Drift API
704
738
  stack_master delete [region-or-alias] [stack-name] # Delete a stack
705
739
  stack_master events [region-or-alias] [stack-name] # Display events for a stack
706
740
  stack_master outputs [region-or-alias] [stack-name] # Display outputs for a stack
707
741
  stack_master resources [region-or-alias] [stack-name] # Display outputs for a stack
708
742
  stack_master status # Displays the status of each stack
709
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
710
748
  ```
711
749
 
712
- ## Applying updates
750
+ ## Applying updates - `stack_master apply`
713
751
 
714
752
  The apply command does the following:
715
753
 
@@ -726,6 +764,18 @@ Demo:
726
764
 
727
765
  ![Apply Demo](/apply_demo.gif?raw=true)
728
766
 
767
+ ## Drift Detection - `stack_master drift`
768
+
769
+ `stack_master drift us-east-1 mystack` uses the CloudFormation APIs to trigger drift detection and display resources
770
+ that have changed outside of the CloudFormation stack. This can happen if a resource has been updated via the console or
771
+ CLI directly rather than via a stack update.
772
+
773
+ ## Diff - `stack_master diff`
774
+
775
+ `stack_master diff us-east-1 mystack` displays whether the computed parameters or template differ to what was last
776
+ applied in CloudFormation. This can happen if the template or computed parameters have changed in code and the change
777
+ hasn't been applied to this stack.
778
+
729
779
  ## Maintainers
730
780
 
731
781
  - [Steve Hodgkiss](https://github.com/stevehodgkiss)
@@ -24,6 +24,7 @@ module StackMaster
24
24
  autoload :CLI, 'stack_master/cli'
25
25
  autoload :CtrlC, 'stack_master/ctrl_c'
26
26
  autoload :Command, 'stack_master/command'
27
+ autoload :Diff, 'stack_master/diff'
27
28
  autoload :VERSION, 'stack_master/version'
28
29
  autoload :Stack, 'stack_master/stack'
29
30
  autoload :Prompter, 'stack_master/prompter'
@@ -51,11 +52,13 @@ module StackMaster
51
52
  require 'stack_master/template_compilers/sparkle_formation'
52
53
  require 'stack_master/template_compilers/json'
53
54
  require 'stack_master/template_compilers/yaml'
55
+ require 'stack_master/template_compilers/yaml_erb'
54
56
  require 'stack_master/template_compilers/cfndsl'
55
57
 
56
58
  module Commands
57
59
  autoload :TerminalHelper, 'stack_master/commands/terminal_helper'
58
60
  autoload :Apply, 'stack_master/commands/apply'
61
+ autoload :Drift, 'stack_master/commands/drift'
59
62
  autoload :Events, 'stack_master/commands/events'
60
63
  autoload :Outputs, 'stack_master/commands/outputs'
61
64
  autoload :Init, 'stack_master/commands/init'
@@ -68,6 +71,7 @@ module StackMaster
68
71
  autoload :Delete, 'stack_master/commands/delete'
69
72
  autoload :Status, 'stack_master/commands/status'
70
73
  autoload :Tidy, 'stack_master/commands/tidy'
74
+ autoload :Nag, 'stack_master/commands/nag'
71
75
  end
72
76
 
73
77
  module ParameterResolvers
@@ -198,4 +202,16 @@ module StackMaster
198
202
  def stderr=(io)
199
203
  @stderr = io
200
204
  end
205
+
206
+ def colorize(text, color)
207
+ if colorize?
208
+ Rainbow(text).color(color)
209
+ else
210
+ text
211
+ end
212
+ end
213
+
214
+ def colorize?
215
+ ENV.fetch('COLORIZE') { 'true' } == 'true'
216
+ end
201
217
  end
@@ -28,7 +28,10 @@ module StackMaster
28
28
  :update_stack,
29
29
  :create_stack,
30
30
  :validate_template,
31
- :describe_stacks
31
+ :describe_stacks,
32
+ :detect_stack_drift,
33
+ :describe_stack_drift_detection_status,
34
+ :describe_stack_resource_drifts
32
35
 
33
36
  private
34
37
 
@@ -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"
@@ -215,6 +226,18 @@ module StackMaster
215
226
  end
216
227
  end
217
228
 
229
+ command :drift do |c|
230
+ c.syntax = 'stack_master drift [region_or_alias] [stack_name]'
231
+ c.summary = 'Detects and displays stack drift using the CloudFormation Drift API'
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"
234
+ c.example 'view stack drift for a stack named myapp-vpc in us-east-1', 'stack_master drift us-east-1 myapp-vpc'
235
+ c.action do |args, options|
236
+ options.default config: default_config_file, timeout: 120
237
+ execute_stacks_command(StackMaster::Commands::Drift, args, options)
238
+ end
239
+ end
240
+
218
241
  run!
219
242
  end
220
243
 
@@ -242,6 +265,7 @@ module StackMaster
242
265
  stack_definitions = config.filter(region, stack_name)
243
266
  if stack_definitions.empty?
244
267
  StackMaster.stdout.puts "Could not find stack definition #{stack_name} in region #{region}"
268
+ show_other_region_candidates(config, stack_name)
245
269
  success = false
246
270
  end
247
271
  stack_definitions = stack_definitions.select do |stack_definition|
@@ -258,6 +282,13 @@ module StackMaster
258
282
  @kernel.exit false unless success
259
283
  end
260
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
+
261
292
  def execute_if_allowed_account(allowed_accounts, &block)
262
293
  raise ArgumentError, "Block required to execute this method" unless block_given?
263
294
  if running_in_allowed_account?(allowed_accounts)
@@ -0,0 +1,118 @@
1
+ require 'diffy'
2
+
3
+ module StackMaster
4
+ module Commands
5
+ class Drift
6
+ include Command
7
+ include Commander::UI
8
+
9
+ DETECTION_COMPLETE_STATES = [
10
+ 'DETECTION_COMPLETE',
11
+ 'DETECTION_FAILED'
12
+ ]
13
+
14
+ def perform
15
+ detect_stack_drift_result = cf.detect_stack_drift(stack_name: stack_name)
16
+ drift_results = wait_for_drift_results(detect_stack_drift_result.stack_drift_detection_id)
17
+
18
+ puts colorize("Drift Status: #{drift_results.stack_drift_status}", stack_drift_status_color(drift_results.stack_drift_status))
19
+ return if drift_results.stack_drift_status == 'IN_SYNC'
20
+
21
+ failed
22
+
23
+ resp = cf.describe_stack_resource_drifts(stack_name: stack_name)
24
+ resp.stack_resource_drifts.each do |drift|
25
+ display_drift(drift)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def cf
32
+ @cf ||= StackMaster.cloud_formation_driver
33
+ end
34
+
35
+ def display_drift(drift)
36
+ color = drift_color(drift)
37
+ puts colorize([drift.stack_resource_drift_status,
38
+ drift.resource_type,
39
+ drift.logical_resource_id,
40
+ drift.physical_resource_id].join(' '), color)
41
+ return unless drift.stack_resource_drift_status == 'MODIFIED'
42
+
43
+ unless drift.property_differences.empty?
44
+ puts colorize(' Property differences:', color)
45
+ end
46
+ drift.property_differences.each do |property_difference|
47
+ puts colorize(" - #{property_difference.difference_type} #{property_difference.property_path}", color)
48
+ end
49
+ puts colorize(' Resource diff:', color)
50
+ display_resource_drift(drift)
51
+ end
52
+
53
+ def display_resource_drift(drift)
54
+ diff = ::StackMaster::Diff.new(before: prettify_json(drift.expected_properties),
55
+ after: prettify_json(drift.actual_properties))
56
+ diff.display_colorized_diff
57
+ end
58
+
59
+ def prettify_json(string)
60
+ JSON.pretty_generate(JSON.parse(string)) + "\n"
61
+ rescue StandardError => e
62
+ puts "Failed to prettify drifted resource: #{e.message}"
63
+ string
64
+ end
65
+
66
+ def stack_drift_status_color(stack_drift_status)
67
+ case stack_drift_status
68
+ when 'IN_SYNC'
69
+ :green
70
+ when 'DRIFTED'
71
+ :yellow
72
+ else
73
+ :blue
74
+ end
75
+ end
76
+
77
+ def drift_color(drift)
78
+ case drift.stack_resource_drift_status
79
+ when 'IN_SYNC'
80
+ :green
81
+ when 'MODIFIED'
82
+ :yellow
83
+ when 'DELETED'
84
+ :red
85
+ else
86
+ :blue
87
+ end
88
+ end
89
+
90
+ def wait_for_drift_results(detection_id)
91
+ resp = nil
92
+ start_time = Time.now
93
+ loop do
94
+ resp = cf.describe_stack_drift_detection_status(stack_drift_detection_id: detection_id)
95
+ break if DETECTION_COMPLETE_STATES.include?(resp.detection_status)
96
+
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
+ sleep SLEEP_SECONDS
103
+ end
104
+ resp
105
+ end
106
+
107
+ def puts(string)
108
+ StackMaster.stdout.puts(string)
109
+ end
110
+
111
+ extend Forwardable
112
+ def_delegators :@stack_definition, :stack_name, :region
113
+ def_delegators :StackMaster, :colorize
114
+
115
+ SLEEP_SECONDS = 1
116
+ end
117
+ end
118
+ end
@@ -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
 
@@ -0,0 +1,45 @@
1
+ module StackMaster
2
+ class Diff
3
+ def initialize(name: nil, before:, after:, context: 10_000)
4
+ @name = name
5
+ @before = before
6
+ @after = after
7
+ @context = context
8
+ end
9
+
10
+ def display
11
+ stdout.print "#{@name} diff: "
12
+ if diff == ''
13
+ stdout.puts "No changes"
14
+ else
15
+ stdout.puts
16
+ display_colorized_diff
17
+ end
18
+ end
19
+
20
+ def display_colorized_diff
21
+ diff.each_line do |line|
22
+ if line.start_with?('+')
23
+ stdout.print colorize(line, :green)
24
+ elsif line.start_with?('-')
25
+ stdout.print colorize(line, :red)
26
+ else
27
+ stdout.print line
28
+ end
29
+ end
30
+ end
31
+
32
+ def different?
33
+ diff != ''
34
+ end
35
+
36
+ private
37
+
38
+ def diff
39
+ @diff ||= Diffy::Diff.new(@before, @after, context: @context).to_s
40
+ end
41
+
42
+ extend Forwardable
43
+ def_delegators :StackMaster, :colorize, :stdout
44
+ end
45
+ end
@@ -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
@@ -10,13 +10,13 @@ module StackMaster
10
10
 
11
11
  def proposed_template
12
12
  return @proposed_stack.template_body unless @proposed_stack.template_format == :json
13
- JSON.pretty_generate(JSON.parse(@proposed_stack.template_body))
13
+ JSON.pretty_generate(JSON.parse(@proposed_stack.template_body)) + "\n"
14
14
  end
15
15
 
16
16
  def current_template
17
17
  return '' unless @current_stack
18
18
  return @current_stack.template_body unless @current_stack.template_format == :json
19
- JSON.pretty_generate(TemplateUtils.template_hash(@current_stack.template_body))
19
+ JSON.pretty_generate(TemplateUtils.template_hash(@current_stack.template_body)) + "\n"
20
20
  end
21
21
 
22
22
  def current_parameters
@@ -39,24 +39,30 @@ module StackMaster
39
39
  end
40
40
 
41
41
  def body_different?
42
- body_diff != ''
42
+ body_diff.different?
43
43
  end
44
44
 
45
45
  def body_diff
46
- @body_diff ||= Diffy::Diff.new(current_template, proposed_template, context: 7, include_diff_info: true).to_s
46
+ @body_diff ||= Diff.new(name: 'Stack',
47
+ before: current_template,
48
+ after: proposed_template,
49
+ context: 7)
47
50
  end
48
51
 
49
52
  def params_different?
50
- params_diff != ''
53
+ parameters_diff.different?
51
54
  end
52
55
 
53
- def params_diff
54
- @param_diff ||= Diffy::Diff.new(current_parameters, proposed_parameters, {}).to_s
56
+ def parameters_diff
57
+ @param_diff ||= Diff.new(name: 'Parameters',
58
+ before: current_parameters,
59
+ after: proposed_parameters)
55
60
  end
56
61
 
57
62
  def output_diff
58
- display_diff('Stack', body_diff)
59
- display_diff('Parameters', params_diff)
63
+ body_diff.display
64
+ parameters_diff.display
65
+
60
66
  unless noecho_keys.empty?
61
67
  StackMaster.stdout.puts " * can not tell if NoEcho parameters are different."
62
68
  end
@@ -83,38 +89,8 @@ module StackMaster
83
89
 
84
90
  private
85
91
 
86
- def display_diff(thing, diff)
87
- StackMaster.stdout.print "#{thing} diff: "
88
- if diff == ''
89
- StackMaster.stdout.puts "No changes"
90
- else
91
- StackMaster.stdout.puts
92
- diff.each_line do |line|
93
- if line.start_with?('+')
94
- StackMaster.stdout.print colorize(line, :green)
95
- elsif line.start_with?('-')
96
- StackMaster.stdout.print colorize(line, :red)
97
- else
98
- StackMaster.stdout.print line
99
- end
100
- end
101
- end
102
- end
103
-
104
92
  def sort_params(hash)
105
93
  hash.sort.to_h
106
94
  end
107
-
108
- def colorize(text, color)
109
- if colorize?
110
- Rainbow(text).color(color)
111
- else
112
- text
113
- end
114
- end
115
-
116
- def colorize?
117
- ENV.fetch('COLORIZE') { 'true' } == 'true'
118
- end
119
95
  end
120
96
  end
@@ -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.7.0"
2
+ VERSION = "2.12.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Hodgkiss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-06-15 00:00:00.000000000 Z
12
+ date: 2020-10-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -437,6 +437,20 @@ 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
+ type: :runtime
448
+ prerelease: false
449
+ version_requirements: !ruby/object:Gem::Requirement
450
+ requirements:
451
+ - - "~>"
452
+ - !ruby/object:Gem::Version
453
+ version: 0.6.7
440
454
  description: ''
441
455
  email:
442
456
  - steve@hodgkiss.me
@@ -459,10 +473,12 @@ files:
459
473
  - lib/stack_master/commands/compile.rb
460
474
  - lib/stack_master/commands/delete.rb
461
475
  - lib/stack_master/commands/diff.rb
476
+ - lib/stack_master/commands/drift.rb
462
477
  - lib/stack_master/commands/events.rb
463
478
  - lib/stack_master/commands/init.rb
464
479
  - lib/stack_master/commands/lint.rb
465
480
  - lib/stack_master/commands/list_stacks.rb
481
+ - lib/stack_master/commands/nag.rb
466
482
  - lib/stack_master/commands/outputs.rb
467
483
  - lib/stack_master/commands/resources.rb
468
484
  - lib/stack_master/commands/status.rb
@@ -471,6 +487,7 @@ files:
471
487
  - lib/stack_master/commands/validate.rb
472
488
  - lib/stack_master/config.rb
473
489
  - lib/stack_master/ctrl_c.rb
490
+ - lib/stack_master/diff.rb
474
491
  - lib/stack_master/identity.rb
475
492
  - lib/stack_master/paged_response_accumulator.rb
476
493
  - lib/stack_master/parameter_loader.rb
@@ -522,6 +539,7 @@ files:
522
539
  - lib/stack_master/template_compilers/json.rb
523
540
  - lib/stack_master/template_compilers/sparkle_formation.rb
524
541
  - lib/stack_master/template_compilers/yaml.rb
542
+ - lib/stack_master/template_compilers/yaml_erb.rb
525
543
  - lib/stack_master/template_utils.rb
526
544
  - lib/stack_master/test_driver/cloud_formation.rb
527
545
  - lib/stack_master/test_driver/s3.rb
@@ -539,8 +557,8 @@ licenses:
539
557
  metadata:
540
558
  bug_tracker_uri: https://github.com/envato/stack_master/issues
541
559
  changelog_uri: https://github.com/envato/stack_master/blob/master/CHANGELOG.md
542
- documentation_uri: https://www.rubydoc.info/gems/stack_master/2.7.0
543
- source_code_uri: https://github.com/envato/stack_master/tree/v2.7.0
560
+ documentation_uri: https://www.rubydoc.info/gems/stack_master/2.12.0
561
+ source_code_uri: https://github.com/envato/stack_master/tree/v2.12.0
544
562
  post_install_message:
545
563
  rdoc_options: []
546
564
  require_paths:
@@ -556,7 +574,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
556
574
  - !ruby/object:Gem::Version
557
575
  version: '0'
558
576
  requirements: []
559
- rubygems_version: 3.0.3
577
+ rubygems_version: 3.1.2
560
578
  signing_key:
561
579
  specification_version: 4
562
580
  summary: StackMaster is a sure-footed way of creating, updating and keeping track