stack_master 2.4.0 → 2.8.0
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 +4 -4
- data/LICENSE.txt +22 -0
- data/README.md +55 -14
- data/lib/stack_master.rb +16 -2
- data/lib/stack_master/aws_driver/cloud_formation.rb +4 -1
- data/lib/stack_master/change_set.rb +2 -2
- data/lib/stack_master/cli.rb +24 -12
- data/lib/stack_master/commands/drift.rb +118 -0
- data/lib/stack_master/commands/tidy.rb +1 -1
- data/lib/stack_master/commands/validate.rb +1 -1
- data/lib/stack_master/config.rb +3 -0
- data/lib/stack_master/diff.rb +45 -0
- data/lib/stack_master/parameter_loader.rb +3 -4
- data/lib/stack_master/parameter_validator.rb +24 -7
- data/lib/stack_master/stack.rb +20 -1
- data/lib/stack_master/stack_definition.rb +27 -10
- data/lib/stack_master/stack_differ.rb +15 -39
- data/lib/stack_master/stack_events/presenter.rb +1 -1
- data/lib/stack_master/template_utils.rb +9 -3
- data/lib/stack_master/validator.rb +14 -5
- data/lib/stack_master/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d401f198bf80974977c8b031f27422ea84aa171f18747fa6064cf6d9d2af784
|
4
|
+
data.tar.gz: dd930994d8034f57d60ba1a77d8bfee0f524301501306a3d8cee64502c27029e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de26f0ce262ef2b4b11cced8789a8093896d9bd7db6950008ad7e0e469ea43a9752fbbcb0e4b57271656442aa7bb13dc159697690d0a0754fcbc9ecce39d07b0
|
7
|
+
data.tar.gz: 0ef954037a433821d09b90acbbd39da5a881044f305353267cba379a07e77bd2ffe7645700b8ce927d15d7f518c823aa17a42f0c9971ce3c37b29f5164a8b219
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Steve Hodgkiss
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ Stacks are defined inside a `stack_master.yml` YAML file. When running
|
|
53
53
|
directory, or that the file is passed in with `--config
|
54
54
|
/path/to/stack_master.yml`. Here's an example configuration file:
|
55
55
|
|
56
|
-
```
|
56
|
+
```yaml
|
57
57
|
region_aliases:
|
58
58
|
production: us-east-1
|
59
59
|
staging: ap-southeast-2
|
@@ -123,6 +123,7 @@ stack_defaults:
|
|
123
123
|
```
|
124
124
|
|
125
125
|
Additional files can be configured to be uploaded to S3 alongside the templates:
|
126
|
+
|
126
127
|
```yaml
|
127
128
|
stacks:
|
128
129
|
production:
|
@@ -131,6 +132,7 @@ stacks:
|
|
131
132
|
files:
|
132
133
|
- userdata.sh
|
133
134
|
```
|
135
|
+
|
134
136
|
## Directories
|
135
137
|
|
136
138
|
- `templates` - CloudFormation, SparkleFormation or CfnDsl templates.
|
@@ -155,7 +157,8 @@ template_compilers:
|
|
155
157
|
|
156
158
|
## Parameters
|
157
159
|
|
158
|
-
|
160
|
+
By default, parameters are loaded from multiple YAML files, merged from the
|
161
|
+
following lookup paths from bottom to top:
|
159
162
|
|
160
163
|
- parameters/[stack_name].yaml
|
161
164
|
- parameters/[stack_name].yml
|
@@ -166,10 +169,34 @@ Parameters are loaded from multiple YAML files, merged from the following lookup
|
|
166
169
|
|
167
170
|
A simple parameter file could look like this:
|
168
171
|
|
169
|
-
```
|
172
|
+
```yaml
|
170
173
|
key_name: myapp-us-east-1
|
171
174
|
```
|
172
175
|
|
176
|
+
Alternatively, a `parameter_files` array can be defined to explicitly list
|
177
|
+
parameter files that will be loaded. If `parameter_files` are defined, the
|
178
|
+
automatic search locations will not be used.
|
179
|
+
|
180
|
+
```yaml
|
181
|
+
parameters_dir: parameters # the default
|
182
|
+
stacks:
|
183
|
+
us-east-1:
|
184
|
+
my-app:
|
185
|
+
parameter_files:
|
186
|
+
- my-app.yml # parameters/my-app.yml
|
187
|
+
```
|
188
|
+
|
189
|
+
Parameters can also be defined inline with stack definitions:
|
190
|
+
|
191
|
+
```yaml
|
192
|
+
stacks:
|
193
|
+
us-east-1:
|
194
|
+
my-app:
|
195
|
+
parameters:
|
196
|
+
VpcId:
|
197
|
+
stack_output: my-vpc/VpcId
|
198
|
+
```
|
199
|
+
|
173
200
|
### Compile Time Parameters
|
174
201
|
|
175
202
|
Compile time parameters can be used for [SparkleFormation](http://www.sparkleformation.io) templates. It conforms and
|
@@ -177,7 +204,7 @@ allows you to use the [Compile Time Parameters](http://www.sparkleformation.io/d
|
|
177
204
|
|
178
205
|
A simple example looks like this
|
179
206
|
|
180
|
-
```
|
207
|
+
```yaml
|
181
208
|
vpc_cidr: 10.0.0.0/16
|
182
209
|
compile_time_parameters:
|
183
210
|
subnet_cidrs:
|
@@ -286,8 +313,8 @@ db_password:
|
|
286
313
|
An alternative to the secrets store is accessing 1password secrets using the 1password cli (`op`).
|
287
314
|
You declare a 1password lookup with the following parameters in your parameters file:
|
288
315
|
|
289
|
-
```
|
290
|
-
parameters/database.yml
|
316
|
+
```yaml
|
317
|
+
# parameters/database.yml
|
291
318
|
database_password:
|
292
319
|
one_password:
|
293
320
|
title: production database
|
@@ -477,7 +504,7 @@ name of the original resolver.
|
|
477
504
|
|
478
505
|
When creating a new resolver, one can automatically create the array resolver by adding a `array_resolver` statement
|
479
506
|
in the class definition, with an optional class name if different from the default one.
|
480
|
-
```
|
507
|
+
```ruby
|
481
508
|
module StackMaster
|
482
509
|
module ParameterResolvers
|
483
510
|
class MyResolver < Resolver
|
@@ -488,7 +515,7 @@ module StackMaster
|
|
488
515
|
end
|
489
516
|
```
|
490
517
|
In that example, using the array resolver would look like:
|
491
|
-
```
|
518
|
+
```yaml
|
492
519
|
my_parameter:
|
493
520
|
my_custom_array_resolver:
|
494
521
|
- value1
|
@@ -498,13 +525,13 @@ my_parameter:
|
|
498
525
|
Array parameter values can include nested parameter resolvers.
|
499
526
|
|
500
527
|
For example, given the following parameter definition:
|
501
|
-
```
|
528
|
+
```yaml
|
502
529
|
my_parameter:
|
503
530
|
- stack_output: my-stack/output # value resolves to 'value1'
|
504
531
|
- value2
|
505
532
|
```
|
506
533
|
The parameter value will resolve to:
|
507
|
-
```
|
534
|
+
```yaml
|
508
535
|
my_parameter: 'value1,value2'
|
509
536
|
```
|
510
537
|
|
@@ -520,7 +547,7 @@ ROLE=<%= role %>
|
|
520
547
|
|
521
548
|
And used like this in SparkleFormation templates:
|
522
549
|
|
523
|
-
```
|
550
|
+
```ruby
|
524
551
|
# templates/app.rb
|
525
552
|
user_data user_data_file!('app.erb', role: :worker)
|
526
553
|
```
|
@@ -533,7 +560,7 @@ my_variable=<%= ref!(:foo) %>
|
|
533
560
|
my_other_variable=<%= account_id! %>
|
534
561
|
```
|
535
562
|
|
536
|
-
```
|
563
|
+
```ruby
|
537
564
|
# templates/ecs_task.rb
|
538
565
|
container_definitions array!(
|
539
566
|
-> {
|
@@ -565,7 +592,7 @@ project-root
|
|
565
592
|
|
566
593
|
Your env-1/stack_master.yml files can reference common templates by setting:
|
567
594
|
|
568
|
-
```
|
595
|
+
```yaml
|
569
596
|
template_dir: ../../sparkle/templates
|
570
597
|
stack_defaults:
|
571
598
|
compiler_options:
|
@@ -661,6 +688,7 @@ stacks:
|
|
661
688
|
|
662
689
|
In the cases where you want to bypass the account check, there is the StackMaster flag `--skip-account-check` that can be used.
|
663
690
|
|
691
|
+
|
664
692
|
## Commands
|
665
693
|
|
666
694
|
```bash
|
@@ -674,6 +702,7 @@ stack_master apply # Create or update all stacks
|
|
674
702
|
stack_master --changed apply # Create or update all stacks that have changed
|
675
703
|
stack_master --yes apply [region-or-alias] [stack-name] # Create or update a stack non-interactively (forcing yes)
|
676
704
|
stack_master diff [region-or-alias] [stack-name] # Display a stack template and parameter diff
|
705
|
+
stack_master drift [region-or-alias] [stack-name] # Detects and displays stack drift using the CloudFormation Drift API
|
677
706
|
stack_master delete [region-or-alias] [stack-name] # Delete a stack
|
678
707
|
stack_master events [region-or-alias] [stack-name] # Display events for a stack
|
679
708
|
stack_master outputs [region-or-alias] [stack-name] # Display outputs for a stack
|
@@ -682,7 +711,7 @@ stack_master status # Displays the status of each stack
|
|
682
711
|
stack_master tidy # Find missing or extra templates or parameter files
|
683
712
|
```
|
684
713
|
|
685
|
-
## Applying updates
|
714
|
+
## Applying updates - `stack_master apply`
|
686
715
|
|
687
716
|
The apply command does the following:
|
688
717
|
|
@@ -699,6 +728,18 @@ Demo:
|
|
699
728
|
|
700
729
|

|
701
730
|
|
731
|
+
## Drift Detection - `stack_master drift`
|
732
|
+
|
733
|
+
`stack_master drift us-east-1 mystack` uses the CloudFormation APIs to trigger drift detection and display resources
|
734
|
+
that have changed outside of the CloudFormation stack. This can happen if a resource has been updated via the console or
|
735
|
+
CLI directly rather than via a stack update.
|
736
|
+
|
737
|
+
## Diff - `stack_master diff`
|
738
|
+
|
739
|
+
`stack_master diff us-east-1 mystack` displays whether the computed parameters or template differ to what was last
|
740
|
+
applied in CloudFormation. This can happen if the template or computed parameters have changed in code and the change
|
741
|
+
hasn't been applied to this stack.
|
742
|
+
|
702
743
|
## Maintainers
|
703
744
|
|
704
745
|
- [Steve Hodgkiss](https://github.com/stevehodgkiss)
|
data/lib/stack_master.rb
CHANGED
@@ -8,7 +8,7 @@ require 'aws-sdk-s3'
|
|
8
8
|
require 'aws-sdk-sns'
|
9
9
|
require 'aws-sdk-ssm'
|
10
10
|
require 'aws-sdk-iam'
|
11
|
-
require '
|
11
|
+
require 'rainbow'
|
12
12
|
require 'active_support/core_ext/hash/keys'
|
13
13
|
require 'active_support/core_ext/object/blank'
|
14
14
|
require 'active_support/core_ext/string/inflections'
|
@@ -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'
|
@@ -56,6 +57,7 @@ module StackMaster
|
|
56
57
|
module Commands
|
57
58
|
autoload :TerminalHelper, 'stack_master/commands/terminal_helper'
|
58
59
|
autoload :Apply, 'stack_master/commands/apply'
|
60
|
+
autoload :Drift, 'stack_master/commands/drift'
|
59
61
|
autoload :Events, 'stack_master/commands/events'
|
60
62
|
autoload :Outputs, 'stack_master/commands/outputs'
|
61
63
|
autoload :Init, 'stack_master/commands/init'
|
@@ -130,7 +132,7 @@ module StackMaster
|
|
130
132
|
|
131
133
|
def debug(message)
|
132
134
|
return unless debug?
|
133
|
-
stderr.puts "[DEBUG] #{message}".
|
135
|
+
stderr.puts Rainbow("[DEBUG] #{message}").color(:green)
|
134
136
|
end
|
135
137
|
|
136
138
|
def quiet!
|
@@ -198,4 +200,16 @@ module StackMaster
|
|
198
200
|
def stderr=(io)
|
199
201
|
@stderr = io
|
200
202
|
end
|
203
|
+
|
204
|
+
def colorize(text, color)
|
205
|
+
if colorize?
|
206
|
+
Rainbow(text).color(color)
|
207
|
+
else
|
208
|
+
text
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def colorize?
|
213
|
+
ENV.fetch('COLORIZE') { 'true' } == 'true'
|
214
|
+
end
|
201
215
|
end
|
@@ -75,7 +75,7 @@ io.puts "========================================"
|
|
75
75
|
end
|
76
76
|
message = "#{action_name} #{resource_change.resource_type} #{resource_change.logical_resource_id}"
|
77
77
|
color = action_color(action_name)
|
78
|
-
io.puts message.
|
78
|
+
io.puts Rainbow(message).color(color)
|
79
79
|
resource_change.details.each do |detail|
|
80
80
|
display_resource_change_detail(io, action_name, color, detail)
|
81
81
|
end
|
@@ -92,7 +92,7 @@ io.puts "========================================"
|
|
92
92
|
triggered_by << "(#{detail.evaluation})"
|
93
93
|
end
|
94
94
|
detail_messages << "Triggered by: #{triggered_by}"
|
95
|
-
io.puts "- #{detail_messages.join('. ')}. ".
|
95
|
+
io.puts Rainbow("- #{detail_messages.join('. ')}. ").color(color)
|
96
96
|
end
|
97
97
|
|
98
98
|
def action_color(action_name)
|
data/lib/stack_master/cli.rb
CHANGED
@@ -46,7 +46,7 @@ module StackMaster
|
|
46
46
|
c.option '--on-failure ACTION', String, "Action to take on CREATE_FAILURE. Valid Values: [ DO_NOTHING | ROLLBACK | DELETE ]. Default: ROLLBACK\nNote: You cannot use this option with Serverless Application Model (SAM) templates."
|
47
47
|
c.option '--yes-param PARAM_NAME', String, "Auto-approve stack updates when only parameter PARAM_NAME changes"
|
48
48
|
c.action do |args, options|
|
49
|
-
options.
|
49
|
+
options.default config: default_config_file
|
50
50
|
execute_stacks_command(StackMaster::Commands::Apply, args, options)
|
51
51
|
end
|
52
52
|
end
|
@@ -56,7 +56,7 @@ module StackMaster
|
|
56
56
|
c.summary = 'Displays outputs for a stack'
|
57
57
|
c.description = "Displays outputs for a stack"
|
58
58
|
c.action do |args, options|
|
59
|
-
options.
|
59
|
+
options.default config: default_config_file
|
60
60
|
execute_stacks_command(StackMaster::Commands::Outputs, args, options)
|
61
61
|
end
|
62
62
|
end
|
@@ -67,7 +67,7 @@ module StackMaster
|
|
67
67
|
c.description = 'Initialises the expected directory structure and stack_master.yml file'
|
68
68
|
c.option('--overwrite', 'Overwrite existing files')
|
69
69
|
c.action do |args, options|
|
70
|
-
options.
|
70
|
+
options.default config: default_config_file
|
71
71
|
unless args.size == 2
|
72
72
|
say "Invalid arguments. stack_master init [region] [stack_name]"
|
73
73
|
else
|
@@ -82,7 +82,7 @@ module StackMaster
|
|
82
82
|
c.description = "Shows a diff of the proposed stack's template and parameters"
|
83
83
|
c.example 'diff a stack named myapp-vpc in us-east-1', 'stack_master diff us-east-1 myapp-vpc'
|
84
84
|
c.action do |args, options|
|
85
|
-
options.
|
85
|
+
options.default config: default_config_file
|
86
86
|
execute_stacks_command(StackMaster::Commands::Diff, args, options)
|
87
87
|
end
|
88
88
|
end
|
@@ -96,7 +96,7 @@ module StackMaster
|
|
96
96
|
c.option '--all', 'Show all events'
|
97
97
|
c.option '--tail', 'Tail events'
|
98
98
|
c.action do |args, options|
|
99
|
-
options.
|
99
|
+
options.default config: default_config_file
|
100
100
|
execute_stacks_command(StackMaster::Commands::Events, args, options)
|
101
101
|
end
|
102
102
|
end
|
@@ -106,7 +106,7 @@ module StackMaster
|
|
106
106
|
c.summary = "Shows stack resources"
|
107
107
|
c.description = "Shows stack resources"
|
108
108
|
c.action do |args, options|
|
109
|
-
options.
|
109
|
+
options.default config: default_config_file
|
110
110
|
execute_stacks_command(StackMaster::Commands::Resources, args, options)
|
111
111
|
end
|
112
112
|
end
|
@@ -116,7 +116,7 @@ module StackMaster
|
|
116
116
|
c.summary = 'List stack definitions'
|
117
117
|
c.description = 'List stack definitions'
|
118
118
|
c.action do |args, options|
|
119
|
-
options.
|
119
|
+
options.default config: default_config_file
|
120
120
|
say "Invalid arguments." if args.size > 0
|
121
121
|
config = load_config(options.config)
|
122
122
|
StackMaster::Commands::ListStacks.perform(config, nil, options)
|
@@ -128,8 +128,9 @@ module StackMaster
|
|
128
128
|
c.summary = 'Validate a template'
|
129
129
|
c.description = 'Validate a template'
|
130
130
|
c.example 'validate a stack named myapp-vpc in us-east-1', 'stack_master validate us-east-1 myapp-vpc'
|
131
|
+
c.option '--[no-]validate-template-parameters', 'Validate template parameters. Default: validate'
|
131
132
|
c.action do |args, options|
|
132
|
-
options.
|
133
|
+
options.default config: default_config_file, validate_template_parameters: true
|
133
134
|
execute_stacks_command(StackMaster::Commands::Validate, args, options)
|
134
135
|
end
|
135
136
|
end
|
@@ -140,7 +141,7 @@ module StackMaster
|
|
140
141
|
c.description = "Runs cfn-lint on the template which would be sent to AWS on apply"
|
141
142
|
c.example 'run cfn-lint on stack myapp-vpc with us-east-1 settings', 'stack_master lint us-east-1 myapp-vpc'
|
142
143
|
c.action do |args, options|
|
143
|
-
options.
|
144
|
+
options.default config: default_config_file
|
144
145
|
execute_stacks_command(StackMaster::Commands::Lint, args, options)
|
145
146
|
end
|
146
147
|
end
|
@@ -151,7 +152,7 @@ module StackMaster
|
|
151
152
|
c.description = "Processes the stack and prints out a compiled version - same we'd send to AWS"
|
152
153
|
c.example 'print compiled stack myapp-vpc with us-east-1 settings', 'stack_master compile us-east-1 myapp-vpc'
|
153
154
|
c.action do |args, options|
|
154
|
-
options.
|
155
|
+
options.default config: default_config_file
|
155
156
|
execute_stacks_command(StackMaster::Commands::Compile, args, options)
|
156
157
|
end
|
157
158
|
end
|
@@ -162,7 +163,7 @@ module StackMaster
|
|
162
163
|
c.description = 'Checks the status of all stacks defined in the stack_master.yml file. Warning this operation can be somewhat slow.'
|
163
164
|
c.example 'description', 'Check the status of all stack definitions'
|
164
165
|
c.action do |args, options|
|
165
|
-
options.
|
166
|
+
options.default config: default_config_file
|
166
167
|
say "Invalid arguments. stack_master status" and return unless args.size == 0
|
167
168
|
config = load_config(options.config)
|
168
169
|
StackMaster::Commands::Status.perform(config, nil, options)
|
@@ -175,7 +176,7 @@ module StackMaster
|
|
175
176
|
c.description = 'Cross references stack_master.yml with the template and parameter directories to identify extra or missing files.'
|
176
177
|
c.example 'description', 'Check for missing or extra files'
|
177
178
|
c.action do |args, options|
|
178
|
-
options.
|
179
|
+
options.default config: default_config_file
|
179
180
|
say "Invalid arguments. stack_master tidy" and return unless args.size == 0
|
180
181
|
config = load_config(options.config)
|
181
182
|
StackMaster::Commands::Tidy.perform(config, nil, options)
|
@@ -214,6 +215,17 @@ module StackMaster
|
|
214
215
|
end
|
215
216
|
end
|
216
217
|
|
218
|
+
command :drift do |c|
|
219
|
+
c.syntax = 'stack_master drift [region_or_alias] [stack_name]'
|
220
|
+
c.summary = 'Detects and displays stack drift using the CloudFormation Drift API'
|
221
|
+
c.description = 'Detects and displays stack drift'
|
222
|
+
c.example 'view stack drift for a stack named myapp-vpc in us-east-1', 'stack_master drift us-east-1 myapp-vpc'
|
223
|
+
c.action do |args, options|
|
224
|
+
options.default config: default_config_file
|
225
|
+
execute_stacks_command(StackMaster::Commands::Drift, args, options)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
217
229
|
run!
|
218
230
|
end
|
219
231
|
|
@@ -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
|
+
try_count = 0
|
92
|
+
resp = nil
|
93
|
+
loop do
|
94
|
+
if try_count >= 10
|
95
|
+
raise 'Failed to wait for stack drift detection after 10 tries'
|
96
|
+
end
|
97
|
+
|
98
|
+
resp = cf.describe_stack_drift_detection_status(stack_drift_detection_id: detection_id)
|
99
|
+
break if DETECTION_COMPLETE_STATES.include?(resp.detection_status)
|
100
|
+
|
101
|
+
try_count += 1
|
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
|
@@ -12,7 +12,7 @@ module StackMaster
|
|
12
12
|
parameter_files = Set.new(find_parameter_files())
|
13
13
|
|
14
14
|
status = @config.stacks.each do |stack_definition|
|
15
|
-
parameter_files.subtract(stack_definition.
|
15
|
+
parameter_files.subtract(stack_definition.parameter_files_from_globs)
|
16
16
|
template = File.absolute_path(stack_definition.template_file_path)
|
17
17
|
|
18
18
|
if template
|
data/lib/stack_master/config.rb
CHANGED
@@ -17,6 +17,7 @@ module StackMaster
|
|
17
17
|
attr_accessor :stacks,
|
18
18
|
:base_dir,
|
19
19
|
:template_dir,
|
20
|
+
:parameters_dir,
|
20
21
|
:stack_defaults,
|
21
22
|
:region_defaults,
|
22
23
|
:region_aliases,
|
@@ -39,6 +40,7 @@ module StackMaster
|
|
39
40
|
@config = config
|
40
41
|
@base_dir = base_dir
|
41
42
|
@template_dir = config.fetch('template_dir', nil)
|
43
|
+
@parameters_dir = config.fetch('parameters_dir', nil)
|
42
44
|
@stack_defaults = config.fetch('stack_defaults', {})
|
43
45
|
@region_aliases = Utils.underscore_keys_to_hyphen(config.fetch('region_aliases', {}))
|
44
46
|
@region_to_aliases = @region_aliases.inject({}) do |hash, (key, value)|
|
@@ -115,6 +117,7 @@ module StackMaster
|
|
115
117
|
'stack_name' => stack_name,
|
116
118
|
'base_dir' => @base_dir,
|
117
119
|
'template_dir' => @template_dir,
|
120
|
+
'parameters_dir' => @parameters_dir,
|
118
121
|
'additional_parameter_lookup_dirs' => @region_to_aliases[region])
|
119
122
|
stack_attributes['allowed_accounts'] = attributes['allowed_accounts'] if attributes['allowed_accounts']
|
120
123
|
@stacks << StackDefinition.new(stack_attributes)
|
@@ -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
|
@@ -5,10 +5,10 @@ module StackMaster
|
|
5
5
|
|
6
6
|
COMPILE_TIME_PARAMETERS_KEY = 'compile_time_parameters'
|
7
7
|
|
8
|
-
def self.load(parameter_files)
|
8
|
+
def self.load(parameter_files: [], parameters: {})
|
9
9
|
StackMaster.debug 'Searching for parameter files...'
|
10
|
-
parameter_files.
|
11
|
-
|
10
|
+
all_parameters = parameter_files.map { |file_name| load_parameters(file_name) } + [parameters]
|
11
|
+
all_parameters.reduce({template_parameters: {}, compile_time_parameters: {}}) do |hash, parameters|
|
12
12
|
template_parameters = create_template_parameters(parameters)
|
13
13
|
compile_time_parameters = create_compile_time_parameters(parameters)
|
14
14
|
|
@@ -16,7 +16,6 @@ module StackMaster
|
|
16
16
|
merge_and_camelize(hash[:compile_time_parameters], compile_time_parameters)
|
17
17
|
hash
|
18
18
|
end
|
19
|
-
|
20
19
|
end
|
21
20
|
|
22
21
|
private
|
@@ -9,15 +9,14 @@ module StackMaster
|
|
9
9
|
|
10
10
|
def error_message
|
11
11
|
return nil unless missing_parameters?
|
12
|
-
message = "Empty/blank parameters detected. Please provide values for these parameters
|
12
|
+
message = "Empty/blank parameters detected. Please provide values for these parameters:\n"
|
13
13
|
missing_parameters.each do |parameter_name|
|
14
|
-
message << "
|
14
|
+
message << " - #{parameter_name}\n"
|
15
15
|
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
message << "\n - #{parameter_file}"
|
16
|
+
if @stack_definition.parameter_files.empty?
|
17
|
+
message << message_for_parameter_globs
|
18
|
+
else
|
19
|
+
message << message_for_parameter_files
|
21
20
|
end
|
22
21
|
message
|
23
22
|
end
|
@@ -28,6 +27,24 @@ module StackMaster
|
|
28
27
|
|
29
28
|
private
|
30
29
|
|
30
|
+
def message_for_parameter_files
|
31
|
+
"Parameters are configured to be read from the following files:\n".tap do |message|
|
32
|
+
@stack_definition.parameter_files.each do |parameter_file|
|
33
|
+
message << " - #{parameter_file}\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def message_for_parameter_globs
|
39
|
+
"Parameters will be read from files matching the following globs:\n".tap do |message|
|
40
|
+
base_dir = Pathname.new(@stack_definition.base_dir)
|
41
|
+
@stack_definition.parameter_file_globs.each do |glob|
|
42
|
+
parameter_file = Pathname.new(glob).relative_path_from(base_dir)
|
43
|
+
message << " - #{parameter_file}\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
31
48
|
def missing_parameters
|
32
49
|
@missing_parameters ||=
|
33
50
|
@stack.parameters_with_defaults.select { |_key, value| value.nil? }.keys
|
data/lib/stack_master/stack.rb
CHANGED
@@ -56,7 +56,7 @@ module StackMaster
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def self.generate(stack_definition, config)
|
59
|
-
parameter_hash = ParameterLoader.load(stack_definition.
|
59
|
+
parameter_hash = ParameterLoader.load(parameter_files: stack_definition.all_parameter_files, parameters: stack_definition.parameters)
|
60
60
|
template_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:template_parameters])
|
61
61
|
compile_time_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:compile_time_parameters])
|
62
62
|
template_body = TemplateCompiler.compile(config, stack_definition.compiler, stack_definition.template_dir, stack_definition.template, compile_time_parameters, stack_definition.compiler_options)
|
@@ -75,6 +75,25 @@ module StackMaster
|
|
75
75
|
stack_policy_body: stack_policy_body)
|
76
76
|
end
|
77
77
|
|
78
|
+
def self.generate_without_parameters(stack_definition, config)
|
79
|
+
parameter_hash = ParameterLoader.load(parameter_files: stack_definition.all_parameter_files, parameters: stack_definition.parameters)
|
80
|
+
compile_time_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:compile_time_parameters])
|
81
|
+
template_body = TemplateCompiler.compile(config, stack_definition.compiler, stack_definition.template_dir, stack_definition.template, compile_time_parameters, stack_definition.compiler_options)
|
82
|
+
template_format = TemplateUtils.identify_template_format(template_body)
|
83
|
+
stack_policy_body = if stack_definition.stack_policy_file_path
|
84
|
+
File.read(stack_definition.stack_policy_file_path)
|
85
|
+
end
|
86
|
+
new(region: stack_definition.region,
|
87
|
+
stack_name: stack_definition.stack_name,
|
88
|
+
tags: stack_definition.tags,
|
89
|
+
parameters: {},
|
90
|
+
template_body: template_body,
|
91
|
+
template_format: template_format,
|
92
|
+
role_arn: stack_definition.role_arn,
|
93
|
+
notification_arns: stack_definition.notification_arns,
|
94
|
+
stack_policy_body: stack_policy_body)
|
95
|
+
end
|
96
|
+
|
78
97
|
def max_template_size(use_s3)
|
79
98
|
return TemplateUtils::MAX_S3_TEMPLATE_SIZE if use_s3
|
80
99
|
TemplateUtils::MAX_TEMPLATE_SIZE
|
@@ -16,7 +16,10 @@ module StackMaster
|
|
16
16
|
:additional_parameter_lookup_dirs,
|
17
17
|
:s3,
|
18
18
|
:files,
|
19
|
-
:compiler_options
|
19
|
+
:compiler_options,
|
20
|
+
:parameters_dir,
|
21
|
+
:parameters,
|
22
|
+
:parameter_files
|
20
23
|
|
21
24
|
attr_reader :compiler
|
22
25
|
|
@@ -32,8 +35,12 @@ module StackMaster
|
|
32
35
|
@compiler = nil
|
33
36
|
super
|
34
37
|
@additional_parameter_lookup_dirs ||= []
|
38
|
+
@base_dir ||= ""
|
35
39
|
@template_dir ||= File.join(@base_dir, 'templates')
|
40
|
+
@parameters_dir ||= File.join(@base_dir, 'parameters')
|
36
41
|
@allowed_accounts = Array(@allowed_accounts)
|
42
|
+
@parameters ||= {}
|
43
|
+
@parameter_files ||= []
|
37
44
|
end
|
38
45
|
|
39
46
|
def ==(other)
|
@@ -56,13 +63,9 @@ module StackMaster
|
|
56
63
|
@compiler_options == other.compiler_options
|
57
64
|
end
|
58
65
|
|
59
|
-
def compiler=(compiler)
|
60
|
-
@compiler = compiler.&to_sym
|
61
|
-
end
|
62
|
-
|
63
66
|
def template_file_path
|
64
67
|
return unless template
|
65
|
-
File.expand_path(
|
68
|
+
File.expand_path(template, template_dir)
|
66
69
|
end
|
67
70
|
|
68
71
|
def files_dir
|
@@ -85,7 +88,15 @@ module StackMaster
|
|
85
88
|
Utils.change_extension(template, 'json')
|
86
89
|
end
|
87
90
|
|
88
|
-
def
|
91
|
+
def all_parameter_files
|
92
|
+
if parameter_files.empty?
|
93
|
+
parameter_files_from_globs
|
94
|
+
else
|
95
|
+
parameter_files
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def parameter_files_from_globs
|
89
100
|
parameter_file_globs.map(&Dir.method(:glob)).flatten
|
90
101
|
end
|
91
102
|
|
@@ -101,20 +112,26 @@ module StackMaster
|
|
101
112
|
!s3.nil?
|
102
113
|
end
|
103
114
|
|
115
|
+
def parameter_files
|
116
|
+
Array(@parameter_files).map do |file|
|
117
|
+
File.expand_path(file, parameters_dir)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
104
121
|
private
|
105
122
|
|
106
123
|
def additional_parameter_lookup_globs
|
107
124
|
additional_parameter_lookup_dirs.map do |a|
|
108
|
-
File.join(
|
125
|
+
File.join(parameters_dir, a, "#{stack_name_glob}.y*ml")
|
109
126
|
end
|
110
127
|
end
|
111
128
|
|
112
129
|
def region_parameter_glob
|
113
|
-
File.join(
|
130
|
+
File.join(parameters_dir, "#{region}", "#{stack_name_glob}.y*ml")
|
114
131
|
end
|
115
132
|
|
116
133
|
def default_parameter_glob
|
117
|
-
File.join(
|
134
|
+
File.join(parameters_dir, "#{stack_name_glob}.y*ml")
|
118
135
|
end
|
119
136
|
|
120
137
|
def stack_name_glob
|
@@ -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 ||=
|
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
|
-
|
53
|
+
parameters_diff.different?
|
51
54
|
end
|
52
55
|
|
53
|
-
def
|
54
|
-
@param_diff ||=
|
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
|
-
|
59
|
-
|
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
|
-
text.colorize(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
|
@@ -10,7 +10,7 @@ module StackMaster
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def print_event(event)
|
13
|
-
@io.puts "#{event.timestamp.localtime} #{event.logical_resource_id} #{event.resource_type} #{event.resource_status} #{event.resource_status_reason}".
|
13
|
+
@io.puts Rainbow("#{event.timestamp.localtime} #{event.logical_resource_id} #{event.resource_type} #{event.resource_status} #{event.resource_status_reason}").color(event_colour(event))
|
14
14
|
end
|
15
15
|
|
16
16
|
def event_colour(event)
|
@@ -2,12 +2,18 @@ module StackMaster
|
|
2
2
|
module TemplateUtils
|
3
3
|
MAX_TEMPLATE_SIZE = 51200
|
4
4
|
MAX_S3_TEMPLATE_SIZE = 460800
|
5
|
+
# Matches if the first non-whitespace character is a '{', handling cases
|
6
|
+
# with leading whitespace and extra (whitespace-only) lines.
|
7
|
+
JSON_IDENTIFICATION_PATTERN = Regexp.new('\A\s*{', Regexp::MULTILINE)
|
5
8
|
|
6
9
|
extend self
|
7
10
|
|
8
11
|
def identify_template_format(template_body)
|
9
|
-
|
10
|
-
|
12
|
+
if template_body =~ JSON_IDENTIFICATION_PATTERN
|
13
|
+
:json
|
14
|
+
else
|
15
|
+
:yaml
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
19
|
def template_hash(template_body=nil)
|
@@ -28,4 +34,4 @@ module StackMaster
|
|
28
34
|
JSON.dump(template_hash(template_body))
|
29
35
|
end
|
30
36
|
end
|
31
|
-
end
|
37
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
1
|
module StackMaster
|
2
2
|
class Validator
|
3
|
-
def self.valid?(stack_definition, config)
|
4
|
-
new(stack_definition, config).perform
|
3
|
+
def self.valid?(stack_definition, config, options)
|
4
|
+
new(stack_definition, config, options).perform
|
5
5
|
end
|
6
6
|
|
7
|
-
def initialize(stack_definition, config)
|
7
|
+
def initialize(stack_definition, config, options)
|
8
8
|
@stack_definition = stack_definition
|
9
9
|
@config = config
|
10
|
+
@options = options
|
10
11
|
end
|
11
12
|
|
12
13
|
def perform
|
13
14
|
StackMaster.stdout.print "#{@stack_definition.stack_name}: "
|
14
|
-
if parameter_validator.missing_parameters?
|
15
|
+
if validate_template_parameters? && parameter_validator.missing_parameters?
|
15
16
|
StackMaster.stdout.puts "invalid\n#{parameter_validator.error_message}"
|
16
17
|
return false
|
17
18
|
end
|
@@ -25,12 +26,20 @@ module StackMaster
|
|
25
26
|
|
26
27
|
private
|
27
28
|
|
29
|
+
def validate_template_parameters?
|
30
|
+
@options.validate_template_parameters
|
31
|
+
end
|
32
|
+
|
28
33
|
def cf
|
29
34
|
@cf ||= StackMaster.cloud_formation_driver
|
30
35
|
end
|
31
36
|
|
32
37
|
def stack
|
33
|
-
@stack ||=
|
38
|
+
@stack ||= if validate_template_parameters?
|
39
|
+
Stack.generate(@stack_definition, @config)
|
40
|
+
else
|
41
|
+
Stack.generate_without_parameters(@stack_definition, @config)
|
42
|
+
end
|
34
43
|
end
|
35
44
|
|
36
45
|
def parameter_validator
|
data/lib/stack_master/version.rb
CHANGED
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.
|
4
|
+
version: 2.8.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-
|
12
|
+
date: 2020-06-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -298,7 +298,7 @@ dependencies:
|
|
298
298
|
- !ruby/object:Gem::Version
|
299
299
|
version: '0'
|
300
300
|
- !ruby/object:Gem::Dependency
|
301
|
-
name:
|
301
|
+
name: rainbow
|
302
302
|
requirement: !ruby/object:Gem::Requirement
|
303
303
|
requirements:
|
304
304
|
- - ">="
|
@@ -446,6 +446,7 @@ executables:
|
|
446
446
|
extensions: []
|
447
447
|
extra_rdoc_files: []
|
448
448
|
files:
|
449
|
+
- LICENSE.txt
|
449
450
|
- README.md
|
450
451
|
- bin/stack_master
|
451
452
|
- lib/stack_master.rb
|
@@ -458,6 +459,7 @@ files:
|
|
458
459
|
- lib/stack_master/commands/compile.rb
|
459
460
|
- lib/stack_master/commands/delete.rb
|
460
461
|
- lib/stack_master/commands/diff.rb
|
462
|
+
- lib/stack_master/commands/drift.rb
|
461
463
|
- lib/stack_master/commands/events.rb
|
462
464
|
- lib/stack_master/commands/init.rb
|
463
465
|
- lib/stack_master/commands/lint.rb
|
@@ -470,6 +472,7 @@ files:
|
|
470
472
|
- lib/stack_master/commands/validate.rb
|
471
473
|
- lib/stack_master/config.rb
|
472
474
|
- lib/stack_master/ctrl_c.rb
|
475
|
+
- lib/stack_master/diff.rb
|
473
476
|
- lib/stack_master/identity.rb
|
474
477
|
- lib/stack_master/paged_response_accumulator.rb
|
475
478
|
- lib/stack_master/parameter_loader.rb
|
@@ -538,8 +541,8 @@ licenses:
|
|
538
541
|
metadata:
|
539
542
|
bug_tracker_uri: https://github.com/envato/stack_master/issues
|
540
543
|
changelog_uri: https://github.com/envato/stack_master/blob/master/CHANGELOG.md
|
541
|
-
documentation_uri: https://www.rubydoc.info/gems/stack_master/2.
|
542
|
-
source_code_uri: https://github.com/envato/stack_master/tree/v2.
|
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
|
543
546
|
post_install_message:
|
544
547
|
rdoc_options: []
|
545
548
|
require_paths:
|
@@ -555,7 +558,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
555
558
|
- !ruby/object:Gem::Version
|
556
559
|
version: '0'
|
557
560
|
requirements: []
|
558
|
-
rubygems_version: 3.
|
561
|
+
rubygems_version: 3.0.3
|
559
562
|
signing_key:
|
560
563
|
specification_version: 4
|
561
564
|
summary: StackMaster is a sure-footed way of creating, updating and keeping track
|