stack_master 2.2.0 → 2.6.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 +4 -4
- data/LICENSE.txt +22 -0
- data/README.md +21 -23
- data/bin/stack_master +0 -1
- data/lib/stack_master.rb +7 -3
- data/lib/stack_master/change_set.rb +2 -2
- data/lib/stack_master/cli.rb +22 -19
- data/lib/stack_master/command.rb +25 -0
- data/lib/stack_master/commands/apply.rb +5 -14
- data/lib/stack_master/commands/compile.rb +0 -5
- data/lib/stack_master/commands/delete.rb +2 -1
- data/lib/stack_master/commands/diff.rb +0 -5
- data/lib/stack_master/commands/events.rb +0 -6
- data/lib/stack_master/commands/init.rb +5 -9
- data/lib/stack_master/commands/lint.rb +0 -5
- data/lib/stack_master/commands/list_stacks.rb +0 -4
- data/lib/stack_master/commands/outputs.rb +0 -5
- data/lib/stack_master/commands/resources.rb +0 -5
- data/lib/stack_master/commands/status.rb +3 -3
- data/lib/stack_master/commands/tidy.rb +0 -4
- data/lib/stack_master/commands/validate.rb +1 -6
- data/lib/stack_master/identity.rb +25 -4
- data/lib/stack_master/parameter_resolvers/latest_ami.rb +1 -1
- data/lib/stack_master/parameter_resolvers/latest_ami_by_tags.rb +1 -1
- data/lib/stack_master/parameter_validator.rb +36 -0
- data/lib/stack_master/role_assumer.rb +1 -0
- data/lib/stack_master/sparkle_formation/template_file.rb +1 -1
- data/lib/stack_master/stack.rb +19 -6
- data/lib/stack_master/stack_definition.rb +14 -11
- data/lib/stack_master/stack_differ.rb +1 -1
- data/lib/stack_master/stack_events/presenter.rb +1 -1
- data/lib/stack_master/template_compiler.rb +1 -1
- data/lib/stack_master/template_utils.rb +9 -3
- data/lib/stack_master/validator.rb +25 -8
- data/lib/stack_master/version.rb +1 -1
- metadata +21 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f146a3b9b4ca20e6c3fdf98d3620886663ec113cb81f7d763918aad28d5d42c
|
4
|
+
data.tar.gz: c7ebfef287797cff8cbb1ee74bafcbe583da1eb14079ea4b94d2102fbc48ea18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45ca7571feb3989ba167eec7b7dc27ba3ed003aec6890e6c172c4ced6dc432fb29bcc618481880604783f02138ca644b17d9f329f73dcab81d73585104a768c9
|
7
|
+
data.tar.gz: dead78c859b1d6cda3148a045c99d31c116a2849ccb2112d231561ae708e619236e4951754d7cdeecf53e08dd68ce99f2f8e242f255c6a168257c6b7cdaec021
|
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
|
@@ -157,18 +157,16 @@ template_compilers:
|
|
157
157
|
|
158
158
|
Parameters are loaded from multiple YAML files, merged from the following lookup paths from bottom to top:
|
159
159
|
|
160
|
-
- parameters/[
|
161
|
-
- parameters/[
|
162
|
-
- parameters/[region]/[
|
163
|
-
- parameters/[region]/[
|
164
|
-
- parameters/[region_alias]/[
|
165
|
-
- parameters/[region_alias]/[
|
166
|
-
|
167
|
-
**Note:** The file names must be underscored, not hyphenated, even if the stack names are hyphenated.
|
160
|
+
- parameters/[stack_name].yaml
|
161
|
+
- parameters/[stack_name].yml
|
162
|
+
- parameters/[region]/[stack_name].yaml
|
163
|
+
- parameters/[region]/[stack_name].yml
|
164
|
+
- parameters/[region_alias]/[stack_name].yaml
|
165
|
+
- parameters/[region_alias]/[stack_name].yml
|
168
166
|
|
169
167
|
A simple parameter file could look like this:
|
170
168
|
|
171
|
-
```
|
169
|
+
```yaml
|
172
170
|
key_name: myapp-us-east-1
|
173
171
|
```
|
174
172
|
|
@@ -179,7 +177,7 @@ allows you to use the [Compile Time Parameters](http://www.sparkleformation.io/d
|
|
179
177
|
|
180
178
|
A simple example looks like this
|
181
179
|
|
182
|
-
```
|
180
|
+
```yaml
|
183
181
|
vpc_cidr: 10.0.0.0/16
|
184
182
|
compile_time_parameters:
|
185
183
|
subnet_cidrs:
|
@@ -288,8 +286,8 @@ db_password:
|
|
288
286
|
An alternative to the secrets store is accessing 1password secrets using the 1password cli (`op`).
|
289
287
|
You declare a 1password lookup with the following parameters in your parameters file:
|
290
288
|
|
291
|
-
```
|
292
|
-
parameters/database.yml
|
289
|
+
```yaml
|
290
|
+
# parameters/database.yml
|
293
291
|
database_password:
|
294
292
|
one_password:
|
295
293
|
title: production database
|
@@ -479,7 +477,7 @@ name of the original resolver.
|
|
479
477
|
|
480
478
|
When creating a new resolver, one can automatically create the array resolver by adding a `array_resolver` statement
|
481
479
|
in the class definition, with an optional class name if different from the default one.
|
482
|
-
```
|
480
|
+
```ruby
|
483
481
|
module StackMaster
|
484
482
|
module ParameterResolvers
|
485
483
|
class MyResolver < Resolver
|
@@ -490,7 +488,7 @@ module StackMaster
|
|
490
488
|
end
|
491
489
|
```
|
492
490
|
In that example, using the array resolver would look like:
|
493
|
-
```
|
491
|
+
```yaml
|
494
492
|
my_parameter:
|
495
493
|
my_custom_array_resolver:
|
496
494
|
- value1
|
@@ -500,13 +498,13 @@ my_parameter:
|
|
500
498
|
Array parameter values can include nested parameter resolvers.
|
501
499
|
|
502
500
|
For example, given the following parameter definition:
|
503
|
-
```
|
501
|
+
```yaml
|
504
502
|
my_parameter:
|
505
503
|
- stack_output: my-stack/output # value resolves to 'value1'
|
506
504
|
- value2
|
507
505
|
```
|
508
506
|
The parameter value will resolve to:
|
509
|
-
```
|
507
|
+
```yaml
|
510
508
|
my_parameter: 'value1,value2'
|
511
509
|
```
|
512
510
|
|
@@ -522,7 +520,7 @@ ROLE=<%= role %>
|
|
522
520
|
|
523
521
|
And used like this in SparkleFormation templates:
|
524
522
|
|
525
|
-
```
|
523
|
+
```ruby
|
526
524
|
# templates/app.rb
|
527
525
|
user_data user_data_file!('app.erb', role: :worker)
|
528
526
|
```
|
@@ -535,7 +533,7 @@ my_variable=<%= ref!(:foo) %>
|
|
535
533
|
my_other_variable=<%= account_id! %>
|
536
534
|
```
|
537
535
|
|
538
|
-
```
|
536
|
+
```ruby
|
539
537
|
# templates/ecs_task.rb
|
540
538
|
container_definitions array!(
|
541
539
|
-> {
|
@@ -567,7 +565,7 @@ project-root
|
|
567
565
|
|
568
566
|
Your env-1/stack_master.yml files can reference common templates by setting:
|
569
567
|
|
570
|
-
```
|
568
|
+
```yaml
|
571
569
|
template_dir: ../../sparkle/templates
|
572
570
|
stack_defaults:
|
573
571
|
compiler_options:
|
@@ -627,7 +625,7 @@ stacks:
|
|
627
625
|
|
628
626
|
## Allowed accounts
|
629
627
|
|
630
|
-
The AWS account the command is executing in can be restricted to a specific list of allowed accounts. This is useful in reducing the possibility of applying non-production changes in a production account. Each stack definition can specify the `allowed_accounts` property with an array of AWS account IDs the stack is allowed to work with.
|
628
|
+
The AWS account the command is executing in can be restricted to a specific list of allowed accounts. This is useful in reducing the possibility of applying non-production changes in a production account. Each stack definition can specify the `allowed_accounts` property with an array of AWS account IDs or aliases the stack is allowed to work with.
|
631
629
|
|
632
630
|
This is an opt-in feature which is enabled by specifying at least one account to allow.
|
633
631
|
|
@@ -646,7 +644,7 @@ stacks:
|
|
646
644
|
template: myapp_db.rb
|
647
645
|
allowed_accounts: # only allow these accounts (overrides the stack defaults)
|
648
646
|
- '1234567890'
|
649
|
-
-
|
647
|
+
- my-account-alias
|
650
648
|
tags:
|
651
649
|
purpose: back-end
|
652
650
|
myapp-web:
|
@@ -661,7 +659,7 @@ stacks:
|
|
661
659
|
purpose: back-end
|
662
660
|
```
|
663
661
|
|
664
|
-
In the cases where you want to bypass the account check, there is StackMaster flag `--skip-account-check` that can be used.
|
662
|
+
In the cases where you want to bypass the account check, there is the StackMaster flag `--skip-account-check` that can be used.
|
665
663
|
|
666
664
|
## Commands
|
667
665
|
|
data/bin/stack_master
CHANGED
data/lib/stack_master.rb
CHANGED
@@ -7,8 +7,11 @@ require 'aws-sdk-ecr'
|
|
7
7
|
require 'aws-sdk-s3'
|
8
8
|
require 'aws-sdk-sns'
|
9
9
|
require 'aws-sdk-ssm'
|
10
|
-
require '
|
11
|
-
require '
|
10
|
+
require 'aws-sdk-iam'
|
11
|
+
require 'rainbow'
|
12
|
+
require 'active_support/core_ext/hash/keys'
|
13
|
+
require 'active_support/core_ext/object/blank'
|
14
|
+
require 'active_support/core_ext/string/inflections'
|
12
15
|
require 'multi_json'
|
13
16
|
|
14
17
|
MultiJson.use :json_gem
|
@@ -43,6 +46,7 @@ module StackMaster
|
|
43
46
|
|
44
47
|
autoload :StackDiffer, 'stack_master/stack_differ'
|
45
48
|
autoload :Validator, 'stack_master/validator'
|
49
|
+
autoload :ParameterValidator, 'stack_master/parameter_validator'
|
46
50
|
|
47
51
|
require 'stack_master/template_compilers/sparkle_formation'
|
48
52
|
require 'stack_master/template_compilers/json'
|
@@ -126,7 +130,7 @@ module StackMaster
|
|
126
130
|
|
127
131
|
def debug(message)
|
128
132
|
return unless debug?
|
129
|
-
stderr.puts "[DEBUG] #{message}".
|
133
|
+
stderr.puts Rainbow("[DEBUG] #{message}").color(:green)
|
130
134
|
end
|
131
135
|
|
132
136
|
def quiet!
|
@@ -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,11 +67,11 @@ 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
|
74
|
-
StackMaster::Commands::Init.perform(options
|
74
|
+
StackMaster::Commands::Init.perform(options, *args)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -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,10 +116,10 @@ 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
|
-
StackMaster::Commands::ListStacks.perform(config)
|
122
|
+
StackMaster::Commands::ListStacks.perform(config, nil, options)
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
@@ -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,10 +163,10 @@ 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
|
-
StackMaster::Commands::Status.perform(config)
|
169
|
+
StackMaster::Commands::Status.perform(config, nil, options)
|
169
170
|
end
|
170
171
|
end
|
171
172
|
|
@@ -175,10 +176,10 @@ 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
|
-
StackMaster::Commands::Tidy.perform(config)
|
182
|
+
StackMaster::Commands::Tidy.perform(config, nil, options)
|
182
183
|
end
|
183
184
|
end
|
184
185
|
|
@@ -208,7 +209,7 @@ module StackMaster
|
|
208
209
|
|
209
210
|
success = execute_if_allowed_account(allowed_accounts) do
|
210
211
|
StackMaster.cloud_formation_driver.set_region(region)
|
211
|
-
StackMaster::Commands::Delete.perform(region, stack_name).success?
|
212
|
+
StackMaster::Commands::Delete.perform(region, stack_name, options).success?
|
212
213
|
end
|
213
214
|
@kernel.exit false unless success
|
214
215
|
end
|
@@ -262,13 +263,15 @@ module StackMaster
|
|
262
263
|
if running_in_allowed_account?(allowed_accounts)
|
263
264
|
block.call
|
264
265
|
else
|
265
|
-
|
266
|
+
account_text = "'#{identity.account}'"
|
267
|
+
account_text << " (#{identity.account_aliases.join(', ')})" if identity.account_aliases.any?
|
268
|
+
StackMaster.stdout.puts "Account #{account_text} is not an allowed account. Allowed accounts are #{allowed_accounts}."
|
266
269
|
false
|
267
270
|
end
|
268
271
|
end
|
269
272
|
|
270
273
|
def running_in_allowed_account?(allowed_accounts)
|
271
|
-
StackMaster.skip_account_check? || identity.
|
274
|
+
StackMaster.skip_account_check? || identity.running_in_account?(allowed_accounts)
|
272
275
|
end
|
273
276
|
|
274
277
|
def identity
|
data/lib/stack_master/command.rb
CHANGED
@@ -27,6 +27,12 @@ module StackMaster
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def initialize(config, stack_definition = nil, options = Commander::Command::Options.new)
|
31
|
+
@config = config
|
32
|
+
@stack_definition = stack_definition
|
33
|
+
@options = options
|
34
|
+
end
|
35
|
+
|
30
36
|
def success?
|
31
37
|
@failed != true
|
32
38
|
end
|
@@ -36,9 +42,24 @@ module StackMaster
|
|
36
42
|
def error_message(e)
|
37
43
|
msg = "#{e.class} #{e.message}"
|
38
44
|
msg << "\n Caused by: #{e.cause.class} #{e.cause.message}" if e.cause
|
45
|
+
if options.trace
|
46
|
+
msg << "\n#{backtrace(e)}"
|
47
|
+
else
|
48
|
+
msg << "\n Use --trace to view backtrace"
|
49
|
+
end
|
39
50
|
msg
|
40
51
|
end
|
41
52
|
|
53
|
+
def backtrace(error)
|
54
|
+
if error.respond_to?(:full_message)
|
55
|
+
error.full_message
|
56
|
+
else
|
57
|
+
# full_message was introduced in Ruby 2.5
|
58
|
+
# remove this conditional when StackMaster no longer supports Ruby 2.4
|
59
|
+
error.backtrace.join("\n")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
42
63
|
def failed(message = nil)
|
43
64
|
StackMaster.stderr.puts(message) if message
|
44
65
|
@failed = true
|
@@ -53,5 +74,9 @@ module StackMaster
|
|
53
74
|
StackMaster.stdout.puts(message) if message
|
54
75
|
throw :halt
|
55
76
|
end
|
77
|
+
|
78
|
+
def options
|
79
|
+
@options ||= Commander::Command::Options.new
|
80
|
+
end
|
56
81
|
end
|
57
82
|
end
|
@@ -6,14 +6,10 @@ module StackMaster
|
|
6
6
|
include StackMaster::Prompter
|
7
7
|
TEMPLATE_TOO_LARGE_ERROR_MESSAGE = 'The (space compressed) stack is larger than the limit set by AWS. See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html'.freeze
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
@s3_config = stack_definition.s3
|
12
|
-
@stack_definition = stack_definition
|
9
|
+
def initialize(*_args)
|
10
|
+
super
|
11
|
+
@s3_config = @stack_definition.s3
|
13
12
|
@from_time = Time.now
|
14
|
-
@options = options
|
15
|
-
@options.on_failure ||= nil
|
16
|
-
@options.yes_param ||= nil
|
17
13
|
end
|
18
14
|
|
19
15
|
def perform
|
@@ -207,13 +203,8 @@ module StackMaster
|
|
207
203
|
end
|
208
204
|
|
209
205
|
def ensure_valid_parameters!
|
210
|
-
|
211
|
-
|
212
|
-
@stack_definition.parameter_files.each do |parameter_file|
|
213
|
-
StackMaster.stderr.puts " - #{parameter_file}"
|
214
|
-
end
|
215
|
-
halt!
|
216
|
-
end
|
206
|
+
pv = ParameterValidator.new(stack: @proposed_stack, stack_definition: @stack_definition)
|
207
|
+
failed!(pv.error_message) if pv.missing_parameters?
|
217
208
|
end
|
218
209
|
|
219
210
|
def ensure_valid_template_body_size!
|
@@ -4,11 +4,6 @@ module StackMaster
|
|
4
4
|
include Command
|
5
5
|
include Commander::UI
|
6
6
|
|
7
|
-
def initialize(config, stack_definition, options = {})
|
8
|
-
@config = config
|
9
|
-
@stack_definition = stack_definition
|
10
|
-
end
|
11
|
-
|
12
7
|
def perform
|
13
8
|
StackMaster::StackDiffer.new(proposed_stack, stack).output_diff
|
14
9
|
end
|
@@ -4,12 +4,6 @@ module StackMaster
|
|
4
4
|
include Command
|
5
5
|
include Commander::UI
|
6
6
|
|
7
|
-
def initialize(config, stack_definition, options = {})
|
8
|
-
@config = config
|
9
|
-
@stack_definition = stack_definition
|
10
|
-
@options = options
|
11
|
-
end
|
12
|
-
|
13
7
|
def perform
|
14
8
|
events = StackEvents::Fetcher.fetch(@stack_definition.stack_name, @stack_definition.region)
|
15
9
|
filter_events(events).each do |event|
|
@@ -5,8 +5,8 @@ module StackMaster
|
|
5
5
|
class Init
|
6
6
|
include Command
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
|
8
|
+
def initialize(options, region, stack_name)
|
9
|
+
super(nil, nil, options)
|
10
10
|
@region = region
|
11
11
|
@stack_name = stack_name
|
12
12
|
end
|
@@ -24,10 +24,10 @@ module StackMaster
|
|
24
24
|
def check_files
|
25
25
|
@stack_master_filename = "stack_master.yml"
|
26
26
|
@stack_json_filename = "templates/#{@stack_name}.json"
|
27
|
-
@parameters_filename = File.join("parameters", "#{
|
28
|
-
@region_parameters_filename = File.join("parameters", @region, "#{
|
27
|
+
@parameters_filename = File.join("parameters", "#{@stack_name}.yml")
|
28
|
+
@region_parameters_filename = File.join("parameters", @region, "#{@stack_name}.yml")
|
29
29
|
|
30
|
-
if !@overwrite
|
30
|
+
if !@options.overwrite
|
31
31
|
[@stack_master_filename, @stack_json_filename, @parameters_filename, @region_parameters_filename].each do |filename|
|
32
32
|
if File.exists?(filename)
|
33
33
|
StackMaster.stderr.puts("Aborting: #{filename} already exists. Use --overwrite to force overwriting file.")
|
@@ -89,10 +89,6 @@ module StackMaster
|
|
89
89
|
File.join(StackMaster.base_dir, "stacktemplates", "parameter_region.yml")
|
90
90
|
end
|
91
91
|
|
92
|
-
def underscored_stack_name
|
93
|
-
@stack_name.gsub('-', '_')
|
94
|
-
end
|
95
|
-
|
96
92
|
def render(renderer)
|
97
93
|
binding = InitBinding.new(region: @region, stack_name: @stack_name).get_binding
|
98
94
|
renderer.result(binding)
|
@@ -6,11 +6,6 @@ module StackMaster
|
|
6
6
|
include Command
|
7
7
|
include Commander::UI
|
8
8
|
|
9
|
-
def initialize(config, stack_definition, options = {})
|
10
|
-
@config = config
|
11
|
-
@stack_definition = stack_definition
|
12
|
-
end
|
13
|
-
|
14
9
|
def perform
|
15
10
|
unless cfn_lint_available
|
16
11
|
failed! 'Failed to run cfn-lint. You may need to install it using'\
|
@@ -7,11 +7,6 @@ module StackMaster
|
|
7
7
|
include Commander::UI
|
8
8
|
include StackMaster::Commands::TerminalHelper
|
9
9
|
|
10
|
-
def initialize(config, stack_definition, options = {})
|
11
|
-
@config = config
|
12
|
-
@stack_definition = stack_definition
|
13
|
-
end
|
14
|
-
|
15
10
|
def perform
|
16
11
|
if stack
|
17
12
|
tp.set :max_width, self.window_size
|
@@ -6,11 +6,6 @@ module StackMaster
|
|
6
6
|
include Command
|
7
7
|
include Commander::UI
|
8
8
|
|
9
|
-
def initialize(config, stack_definition, options = {})
|
10
|
-
@config = config
|
11
|
-
@stack_definition = stack_definition
|
12
|
-
end
|
13
|
-
|
14
9
|
def perform
|
15
10
|
if stack_resources
|
16
11
|
tp stack_resources, :logical_resource_id, :resource_type, :timestamp, :resource_status, :resource_status_reason, :description
|
@@ -7,8 +7,8 @@ module StackMaster
|
|
7
7
|
include Command
|
8
8
|
include StackMaster::Commands::TerminalHelper
|
9
9
|
|
10
|
-
def initialize(config, show_progress = true)
|
11
|
-
|
10
|
+
def initialize(config, options, show_progress = true)
|
11
|
+
super(config, nil, options)
|
12
12
|
@show_progress = show_progress
|
13
13
|
end
|
14
14
|
|
@@ -44,7 +44,7 @@ module StackMaster
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def running_in_allowed_account?(allowed_accounts)
|
47
|
-
StackMaster.skip_account_check? || identity.
|
47
|
+
StackMaster.skip_account_check? || identity.running_in_account?(allowed_accounts)
|
48
48
|
end
|
49
49
|
|
50
50
|
def identity
|
@@ -4,13 +4,8 @@ module StackMaster
|
|
4
4
|
include Command
|
5
5
|
include Commander::UI
|
6
6
|
|
7
|
-
def initialize(config, stack_definition, options = {})
|
8
|
-
@config = config
|
9
|
-
@stack_definition = stack_definition
|
10
|
-
end
|
11
|
-
|
12
7
|
def perform
|
13
|
-
failed unless Validator.valid?(@stack_definition, @config)
|
8
|
+
failed unless Validator.valid?(@stack_definition, @config, @options)
|
14
9
|
end
|
15
10
|
end
|
16
11
|
end
|
@@ -1,16 +1,25 @@
|
|
1
1
|
module StackMaster
|
2
2
|
class Identity
|
3
|
-
|
4
|
-
|
3
|
+
MissingIamPermissionsError = Class.new(StandardError)
|
4
|
+
|
5
|
+
def running_in_account?(accounts)
|
6
|
+
accounts.nil? ||
|
7
|
+
accounts.empty? ||
|
8
|
+
contains_account_id?(accounts) ||
|
9
|
+
contains_account_alias?(accounts)
|
5
10
|
end
|
6
11
|
|
7
12
|
def account
|
8
13
|
@account ||= sts.get_caller_identity.account
|
9
14
|
end
|
10
15
|
|
11
|
-
|
16
|
+
def account_aliases
|
17
|
+
@aliases ||= iam.list_account_aliases.account_aliases
|
18
|
+
rescue Aws::IAM::Errors::AccessDenied
|
19
|
+
raise MissingIamPermissionsError, 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases'
|
20
|
+
end
|
12
21
|
|
13
|
-
|
22
|
+
private
|
14
23
|
|
15
24
|
def region
|
16
25
|
@region ||= ENV['AWS_REGION'] || Aws.config[:region] || Aws.shared_config.region || 'us-east-1'
|
@@ -19,5 +28,17 @@ module StackMaster
|
|
19
28
|
def sts
|
20
29
|
@sts ||= Aws::STS::Client.new(region: region)
|
21
30
|
end
|
31
|
+
|
32
|
+
def iam
|
33
|
+
@iam ||= Aws::IAM::Client.new(region: region)
|
34
|
+
end
|
35
|
+
|
36
|
+
def contains_account_id?(ids)
|
37
|
+
ids.include?(account)
|
38
|
+
end
|
39
|
+
|
40
|
+
def contains_account_alias?(aliases)
|
41
|
+
account_aliases.any? { |account_alias| aliases.include?(account_alias) }
|
42
|
+
end
|
22
43
|
end
|
23
44
|
end
|
@@ -12,7 +12,7 @@ module StackMaster
|
|
12
12
|
owners = Array(value.fetch('owners', 'self').to_s)
|
13
13
|
ami_finder = AmiFinder.new(@stack_definition.region)
|
14
14
|
filters = ami_finder.build_filters_from_hash(value.fetch('filters'))
|
15
|
-
ami_finder.find_latest_ami(filters, owners)
|
15
|
+
ami_finder.find_latest_ami(filters, owners)&.image_id
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
class ParameterValidator
|
5
|
+
def initialize(stack:, stack_definition:)
|
6
|
+
@stack = stack
|
7
|
+
@stack_definition = stack_definition
|
8
|
+
end
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
return nil unless missing_parameters?
|
12
|
+
message = "Empty/blank parameters detected. Please provide values for these parameters:"
|
13
|
+
missing_parameters.each do |parameter_name|
|
14
|
+
message << "\n - #{parameter_name}"
|
15
|
+
end
|
16
|
+
message << "\nParameters will be read from files matching the following globs:"
|
17
|
+
base_dir = Pathname.new(@stack_definition.base_dir)
|
18
|
+
@stack_definition.parameter_file_globs.each do |glob|
|
19
|
+
parameter_file = Pathname.new(glob).relative_path_from(base_dir)
|
20
|
+
message << "\n - #{parameter_file}"
|
21
|
+
end
|
22
|
+
message
|
23
|
+
end
|
24
|
+
|
25
|
+
def missing_parameters?
|
26
|
+
missing_parameters.any?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def missing_parameters
|
32
|
+
@missing_parameters ||=
|
33
|
+
@stack.parameters_with_defaults.select { |_key, value| value.nil? }.keys
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -45,6 +45,7 @@ module StackMaster
|
|
45
45
|
credentials_key = "#{account}:#{role}"
|
46
46
|
@credentials.fetch(credentials_key) do
|
47
47
|
@credentials[credentials_key] = Aws::AssumeRoleCredentials.new(
|
48
|
+
region: StackMaster.cloud_formation_driver.region,
|
48
49
|
role_arn: "arn:aws:iam::#{account}:role/#{role}",
|
49
50
|
role_session_name: "stack-master-role-assumer"
|
50
51
|
)
|
data/lib/stack_master/stack.rb
CHANGED
@@ -27,12 +27,6 @@ module StackMaster
|
|
27
27
|
template_default_parameters.merge(parameters)
|
28
28
|
end
|
29
29
|
|
30
|
-
def missing_parameters?
|
31
|
-
parameters_with_defaults.any? do |key, value|
|
32
|
-
value == nil
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
30
|
def self.find(region, stack_name)
|
37
31
|
cf = StackMaster.cloud_formation_driver
|
38
32
|
cf_stack = cf.describe_stacks(stack_name: stack_name).stacks.first
|
@@ -81,6 +75,25 @@ module StackMaster
|
|
81
75
|
stack_policy_body: stack_policy_body)
|
82
76
|
end
|
83
77
|
|
78
|
+
def self.generate_without_parameters(stack_definition, config)
|
79
|
+
parameter_hash = ParameterLoader.load(stack_definition.parameter_files)
|
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
|
+
|
84
97
|
def max_template_size(use_s3)
|
85
98
|
return TemplateUtils::MAX_S3_TEMPLATE_SIZE if use_s3
|
86
99
|
TemplateUtils::MAX_TEMPLATE_SIZE
|
@@ -23,7 +23,6 @@ module StackMaster
|
|
23
23
|
include Utils::Initializable
|
24
24
|
|
25
25
|
def initialize(attributes = {})
|
26
|
-
@additional_parameter_lookup_dirs = []
|
27
26
|
@compiler_options = {}
|
28
27
|
@notification_arns = []
|
29
28
|
@s3 = {}
|
@@ -32,6 +31,7 @@ module StackMaster
|
|
32
31
|
@ejson_file_kms = true
|
33
32
|
@compiler = nil
|
34
33
|
super
|
34
|
+
@additional_parameter_lookup_dirs ||= []
|
35
35
|
@template_dir ||= File.join(@base_dir, 'templates')
|
36
36
|
@allowed_accounts = Array(@allowed_accounts)
|
37
37
|
end
|
@@ -86,7 +86,11 @@ module StackMaster
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def parameter_files
|
89
|
-
|
89
|
+
parameter_file_globs.map(&Dir.method(:glob)).flatten
|
90
|
+
end
|
91
|
+
|
92
|
+
def parameter_file_globs
|
93
|
+
[ default_parameter_glob, region_parameter_glob ] + additional_parameter_lookup_globs
|
90
94
|
end
|
91
95
|
|
92
96
|
def stack_policy_file_path
|
@@ -99,23 +103,22 @@ module StackMaster
|
|
99
103
|
|
100
104
|
private
|
101
105
|
|
102
|
-
def
|
103
|
-
return unless additional_parameter_lookup_dirs
|
106
|
+
def additional_parameter_lookup_globs
|
104
107
|
additional_parameter_lookup_dirs.map do |a|
|
105
|
-
|
108
|
+
File.join(base_dir, 'parameters', a, "#{stack_name_glob}.y*ml")
|
106
109
|
end
|
107
110
|
end
|
108
111
|
|
109
|
-
def
|
110
|
-
|
112
|
+
def region_parameter_glob
|
113
|
+
File.join(base_dir, 'parameters', "#{region}", "#{stack_name_glob}.y*ml")
|
111
114
|
end
|
112
115
|
|
113
|
-
def
|
114
|
-
|
116
|
+
def default_parameter_glob
|
117
|
+
File.join(base_dir, 'parameters', "#{stack_name_glob}.y*ml")
|
115
118
|
end
|
116
119
|
|
117
|
-
def
|
118
|
-
stack_name.gsub('-', '_')
|
120
|
+
def stack_name_glob
|
121
|
+
stack_name.gsub('-', '[-_]')
|
119
122
|
end
|
120
123
|
end
|
121
124
|
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)
|
@@ -11,7 +11,7 @@ module StackMaster
|
|
11
11
|
compiler.require_dependencies
|
12
12
|
compiler.compile(template_dir, template, compile_time_parameters, compiler_options)
|
13
13
|
rescue StandardError => e
|
14
|
-
raise TemplateCompilationFailed
|
14
|
+
raise TemplateCompilationFailed, "Failed to compile #{template}"
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.register(name, klass)
|
@@ -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,21 +1,22 @@
|
|
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
|
-
parameter_hash = ParameterLoader.load(@stack_definition.parameter_files)
|
14
|
-
compile_time_parameters = ParameterResolver.resolve(@config, @stack_definition, parameter_hash[:compile_time_parameters])
|
15
|
-
|
16
14
|
StackMaster.stdout.print "#{@stack_definition.stack_name}: "
|
17
|
-
|
18
|
-
|
15
|
+
if validate_template_parameters? && parameter_validator.missing_parameters?
|
16
|
+
StackMaster.stdout.puts "invalid\n#{parameter_validator.error_message}"
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
cf.validate_template(template_body: TemplateUtils.maybe_compressed_template_body(stack.template_body))
|
19
20
|
StackMaster.stdout.puts "valid"
|
20
21
|
true
|
21
22
|
rescue Aws::CloudFormation::Errors::ValidationError => e
|
@@ -25,8 +26,24 @@ 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
|
36
|
+
|
37
|
+
def 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
|
43
|
+
end
|
44
|
+
|
45
|
+
def parameter_validator
|
46
|
+
@parameter_validator ||= ParameterValidator.new(stack: stack, stack_definition: @stack_definition)
|
47
|
+
end
|
31
48
|
end
|
32
49
|
end
|
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.6.1
|
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-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -255,6 +255,20 @@ dependencies:
|
|
255
255
|
- - "~>"
|
256
256
|
- !ruby/object:Gem::Version
|
257
257
|
version: '1'
|
258
|
+
- !ruby/object:Gem::Dependency
|
259
|
+
name: aws-sdk-iam
|
260
|
+
requirement: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - "~>"
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '1'
|
265
|
+
type: :runtime
|
266
|
+
prerelease: false
|
267
|
+
version_requirements: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - "~>"
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '1'
|
258
272
|
- !ruby/object:Gem::Dependency
|
259
273
|
name: diffy
|
260
274
|
requirement: !ruby/object:Gem::Requirement
|
@@ -284,7 +298,7 @@ dependencies:
|
|
284
298
|
- !ruby/object:Gem::Version
|
285
299
|
version: '0'
|
286
300
|
- !ruby/object:Gem::Dependency
|
287
|
-
name:
|
301
|
+
name: rainbow
|
288
302
|
requirement: !ruby/object:Gem::Requirement
|
289
303
|
requirements:
|
290
304
|
- - ">="
|
@@ -432,6 +446,7 @@ executables:
|
|
432
446
|
extensions: []
|
433
447
|
extra_rdoc_files: []
|
434
448
|
files:
|
449
|
+
- LICENSE.txt
|
435
450
|
- README.md
|
436
451
|
- bin/stack_master
|
437
452
|
- lib/stack_master.rb
|
@@ -472,6 +487,7 @@ files:
|
|
472
487
|
- lib/stack_master/parameter_resolvers/security_group.rb
|
473
488
|
- lib/stack_master/parameter_resolvers/sns_topic_name.rb
|
474
489
|
- lib/stack_master/parameter_resolvers/stack_output.rb
|
490
|
+
- lib/stack_master/parameter_validator.rb
|
475
491
|
- lib/stack_master/prompter.rb
|
476
492
|
- lib/stack_master/resolver_array.rb
|
477
493
|
- lib/stack_master/role_assumer.rb
|
@@ -523,8 +539,8 @@ licenses:
|
|
523
539
|
metadata:
|
524
540
|
bug_tracker_uri: https://github.com/envato/stack_master/issues
|
525
541
|
changelog_uri: https://github.com/envato/stack_master/blob/master/CHANGELOG.md
|
526
|
-
documentation_uri: https://www.rubydoc.info/gems/stack_master/2.
|
527
|
-
source_code_uri: https://github.com/envato/stack_master/tree/v2.
|
542
|
+
documentation_uri: https://www.rubydoc.info/gems/stack_master/2.6.1
|
543
|
+
source_code_uri: https://github.com/envato/stack_master/tree/v2.6.1
|
528
544
|
post_install_message:
|
529
545
|
rdoc_options: []
|
530
546
|
require_paths:
|