stack_master 2.2.0 → 2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|