sfn 3.0.28 → 3.0.30
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 +5 -5
- data/CHANGELOG.md +5 -0
- data/docs/callbacks.md +1 -0
- data/lib/chef/knife/knife_plugin_seed.rb +11 -17
- data/lib/sfn.rb +0 -2
- data/lib/sfn/api_provider.rb +0 -2
- data/lib/sfn/api_provider/google.rb +6 -9
- data/lib/sfn/api_provider/terraform.rb +4 -6
- data/lib/sfn/cache.rb +36 -39
- data/lib/sfn/callback.rb +0 -2
- data/lib/sfn/callback/aws_assume_role.rb +7 -8
- data/lib/sfn/callback/aws_mfa.rb +7 -8
- data/lib/sfn/callback/stack_policy.rb +15 -17
- data/lib/sfn/command.rb +9 -11
- data/lib/sfn/command/conf.rb +7 -10
- data/lib/sfn/command/create.rb +8 -12
- data/lib/sfn/command/describe.rb +6 -8
- data/lib/sfn/command/destroy.rb +8 -10
- data/lib/sfn/command/diff.rb +18 -25
- data/lib/sfn/command/events.rb +15 -16
- data/lib/sfn/command/export.rb +13 -17
- data/lib/sfn/command/graph.rb +11 -13
- data/lib/sfn/command/graph/aws.rb +27 -29
- data/lib/sfn/command/graph/terraform.rb +22 -23
- data/lib/sfn/command/import.rb +13 -16
- data/lib/sfn/command/init.rb +5 -7
- data/lib/sfn/command/inspect.rb +26 -29
- data/lib/sfn/command/lint.rb +10 -12
- data/lib/sfn/command/list.rb +5 -8
- data/lib/sfn/command/print.rb +3 -5
- data/lib/sfn/command/promote.rb +0 -2
- data/lib/sfn/command/update.rb +42 -46
- data/lib/sfn/command/validate.rb +4 -6
- data/lib/sfn/command_module/base.rb +17 -25
- data/lib/sfn/command_module/callbacks.rb +12 -8
- data/lib/sfn/command_module/stack.rb +39 -43
- data/lib/sfn/command_module/template.rb +89 -90
- data/lib/sfn/config.rb +30 -31
- data/lib/sfn/config/conf.rb +1 -3
- data/lib/sfn/config/create.rb +5 -7
- data/lib/sfn/config/describe.rb +3 -5
- data/lib/sfn/config/diff.rb +1 -1
- data/lib/sfn/config/events.rb +6 -8
- data/lib/sfn/config/export.rb +4 -7
- data/lib/sfn/config/graph.rb +4 -6
- data/lib/sfn/config/import.rb +3 -5
- data/lib/sfn/config/init.rb +0 -1
- data/lib/sfn/config/inspect.rb +7 -9
- data/lib/sfn/config/lint.rb +4 -4
- data/lib/sfn/config/list.rb +3 -5
- data/lib/sfn/config/print.rb +3 -5
- data/lib/sfn/config/promote.rb +3 -5
- data/lib/sfn/config/update.rb +10 -12
- data/lib/sfn/config/validate.rb +18 -20
- data/lib/sfn/lint.rb +0 -2
- data/lib/sfn/lint/definition.rb +3 -5
- data/lib/sfn/lint/rule.rb +7 -8
- data/lib/sfn/lint/rule_set.rb +11 -20
- data/lib/sfn/monkey_patch/stack.rb +32 -34
- data/lib/sfn/monkey_patch/stack/azure.rb +0 -1
- data/lib/sfn/monkey_patch/stack/google.rb +15 -16
- data/lib/sfn/planner.rb +1 -3
- data/lib/sfn/planner/aws.rb +82 -89
- data/lib/sfn/provider.rb +21 -23
- data/lib/sfn/utils.rb +0 -2
- data/lib/sfn/utils/debug.rb +1 -2
- data/lib/sfn/utils/json.rb +3 -2
- data/lib/sfn/utils/object_storage.rb +1 -2
- data/lib/sfn/utils/output.rb +8 -9
- data/lib/sfn/utils/path_selector.rb +9 -10
- data/lib/sfn/utils/ssher.rb +2 -3
- data/lib/sfn/utils/stack_exporter.rb +20 -21
- data/lib/sfn/utils/stack_parameter_scrubber.rb +6 -7
- data/lib/sfn/utils/stack_parameter_validator.rb +14 -16
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +1 -1
- metadata +8 -8
data/lib/sfn/callback.rb
CHANGED
@@ -3,7 +3,6 @@ require 'sfn'
|
|
3
3
|
module Sfn
|
4
4
|
# Interface for injecting custom functionality
|
5
5
|
class Callback
|
6
|
-
|
7
6
|
autoload :AwsAssumeRole, 'sfn/callback/aws_assume_role'
|
8
7
|
autoload :AwsMfa, 'sfn/callback/aws_mfa'
|
9
8
|
autoload :StackPolicy, 'sfn/callback/stack_policy'
|
@@ -49,6 +48,5 @@ module Sfn
|
|
49
48
|
raise
|
50
49
|
end
|
51
50
|
end
|
52
|
-
|
53
51
|
end
|
54
52
|
end
|
@@ -10,7 +10,7 @@ module Sfn
|
|
10
10
|
:aws_sts_token,
|
11
11
|
:aws_sts_access_key_id,
|
12
12
|
:aws_sts_secret_access_key,
|
13
|
-
:aws_sts_token_expires
|
13
|
+
:aws_sts_token_expires,
|
14
14
|
]
|
15
15
|
|
16
16
|
# Prevent callback output to user
|
@@ -21,7 +21,7 @@ module Sfn
|
|
21
21
|
# Inject STS related configuration into
|
22
22
|
# API provider credentials
|
23
23
|
def after_config(*_)
|
24
|
-
if
|
24
|
+
if enabled? && config.fetch(:credentials, :aws_sts_role_arn)
|
25
25
|
load_stored_session
|
26
26
|
end
|
27
27
|
end
|
@@ -29,8 +29,8 @@ module Sfn
|
|
29
29
|
# Store session token if available for
|
30
30
|
# later use
|
31
31
|
def after(*_)
|
32
|
-
if
|
33
|
-
if
|
32
|
+
if enabled?
|
33
|
+
if api.connection.aws_sts_role_arn && api.connection.aws_sts_token
|
34
34
|
path = config.fetch(:aws_assume_role, :cache_file, '.sfn-aws')
|
35
35
|
FileUtils.touch(path)
|
36
36
|
File.chmod(0600, path)
|
@@ -55,12 +55,12 @@ module Sfn
|
|
55
55
|
# @return [TrueClass, FalseClass]
|
56
56
|
def load_stored_session
|
57
57
|
path = config.fetch(:aws_assume_role, :cache_file, '.sfn-aws')
|
58
|
-
if
|
58
|
+
if File.exists?(path)
|
59
59
|
values = load_stored_values(path)
|
60
60
|
STS_STORE_ITEMS.each do |key|
|
61
61
|
api.connection.data[key] = values[key]
|
62
62
|
end
|
63
|
-
if
|
63
|
+
if values[:aws_sts_token_expires]
|
64
64
|
begin
|
65
65
|
api.connection.data[:aws_sts_token_expires] = Time.parse(values[:aws_sts_token_expires])
|
66
66
|
rescue
|
@@ -78,7 +78,7 @@ module Sfn
|
|
78
78
|
# @return [Hash]
|
79
79
|
def load_stored_values(path)
|
80
80
|
begin
|
81
|
-
if
|
81
|
+
if File.exists?(path)
|
82
82
|
MultiJson.load(File.read(path)).to_smash
|
83
83
|
else
|
84
84
|
Smash.new
|
@@ -87,7 +87,6 @@ module Sfn
|
|
87
87
|
Smash.new
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
91
90
|
end
|
92
91
|
end
|
93
92
|
end
|
data/lib/sfn/callback/aws_mfa.rb
CHANGED
@@ -10,7 +10,7 @@ module Sfn
|
|
10
10
|
:aws_sts_session_token,
|
11
11
|
:aws_sts_session_access_key_id,
|
12
12
|
:aws_sts_session_secret_access_key,
|
13
|
-
:aws_sts_session_token_expires
|
13
|
+
:aws_sts_session_token_expires,
|
14
14
|
]
|
15
15
|
|
16
16
|
# Prevent callback output to user
|
@@ -21,7 +21,7 @@ module Sfn
|
|
21
21
|
# Inject MFA related configuration into
|
22
22
|
# API provider credentials
|
23
23
|
def after_config(*_)
|
24
|
-
if
|
24
|
+
if enabled?
|
25
25
|
load_stored_session
|
26
26
|
api.connection.aws_sts_session_token_code = method(:prompt_for_code)
|
27
27
|
end
|
@@ -30,8 +30,8 @@ module Sfn
|
|
30
30
|
# Store session token if available for
|
31
31
|
# later use
|
32
32
|
def after(*_)
|
33
|
-
if
|
34
|
-
if
|
33
|
+
if enabled?
|
34
|
+
if api.connection.aws_sts_session_token
|
35
35
|
path = config.fetch(:aws_mfa, :cache_file, '.sfn-aws')
|
36
36
|
FileUtils.touch(path)
|
37
37
|
File.chmod(0600, path)
|
@@ -56,12 +56,12 @@ module Sfn
|
|
56
56
|
# @return [TrueClass, FalseClass]
|
57
57
|
def load_stored_session
|
58
58
|
path = config.fetch(:aws_mfa, :cache_file, '.sfn-aws')
|
59
|
-
if
|
59
|
+
if File.exists?(path)
|
60
60
|
values = load_stored_values(path)
|
61
61
|
SESSION_STORE_ITEMS.each do |key|
|
62
62
|
api.connection.data[key] = values[key]
|
63
63
|
end
|
64
|
-
if
|
64
|
+
if values[:aws_sts_session_token_expires]
|
65
65
|
begin
|
66
66
|
api.connection.data[:aws_sts_session_token_expires] = Time.parse(values[:aws_sts_session_token_expires])
|
67
67
|
rescue
|
@@ -79,7 +79,7 @@ module Sfn
|
|
79
79
|
# @return [Hash]
|
80
80
|
def load_stored_values(path)
|
81
81
|
begin
|
82
|
-
if
|
82
|
+
if File.exists?(path)
|
83
83
|
MultiJson.load(File.read(path)).to_smash
|
84
84
|
else
|
85
85
|
Smash.new
|
@@ -96,7 +96,6 @@ module Sfn
|
|
96
96
|
result = ui.ask 'AWS MFA code', :valid => /^\d{6}$/
|
97
97
|
result.strip
|
98
98
|
end
|
99
|
-
|
100
99
|
end
|
101
100
|
end
|
102
101
|
end
|
@@ -7,11 +7,11 @@ module Sfn
|
|
7
7
|
# Policy to apply prior to stack deletion
|
8
8
|
DEFENSELESS_POLICY = {
|
9
9
|
'Statement' => [{
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
'Effect' => 'Allow',
|
11
|
+
'Action' => 'Update:*',
|
12
|
+
'Resource' => '*',
|
13
|
+
'Principal' => '*',
|
14
|
+
}],
|
15
15
|
}
|
16
16
|
|
17
17
|
# @return [Smash] cached policies
|
@@ -38,6 +38,7 @@ module Sfn
|
|
38
38
|
end
|
39
39
|
ui.info 'Stack policy documents successfully submitted!'
|
40
40
|
end
|
41
|
+
|
41
42
|
alias_method :after_create, :submit_policy
|
42
43
|
alias_method :after_update, :submit_policy
|
43
44
|
|
@@ -45,7 +46,7 @@ module Sfn
|
|
45
46
|
#
|
46
47
|
# @param args [Hash]
|
47
48
|
def before_update(args)
|
48
|
-
if
|
49
|
+
if config.get(:stack_policy, :update).to_s == 'defenseless'
|
49
50
|
ui.warn 'Disabling all stack policies for update.'
|
50
51
|
stack = args[:api_stack]
|
51
52
|
([stack] + stack.nested_stacks).compact.each do |p_stack|
|
@@ -62,10 +63,9 @@ module Sfn
|
|
62
63
|
#
|
63
64
|
# @param info [Hash]
|
64
65
|
def template(info)
|
65
|
-
if
|
66
|
+
if info[:sparkle_stack]
|
66
67
|
@policies.set(info.fetch(:stack_name, 'unknown'),
|
67
|
-
|
68
|
-
)
|
68
|
+
info[:sparkle_stack].generate_policy)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -76,15 +76,14 @@ module Sfn
|
|
76
76
|
def save_stack_policy(p_stack)
|
77
77
|
valid_logical_ids = p_stack.resources.reload.all.map(&:logical_id)
|
78
78
|
stack_policy = @policies.fetch(p_stack.id,
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
if(stack_policy)
|
79
|
+
@policies.fetch(p_stack.data[:logical_id]),
|
80
|
+
@policies[p_stack.name]).to_smash
|
81
|
+
if stack_policy
|
83
82
|
stack_policy[:Statement].delete_if do |policy_item|
|
84
83
|
policy_match = policy_item[:Resource].to_s.match(
|
85
84
|
%r{LogicalResourceId/(?<logical_id>.+)$}
|
86
85
|
)
|
87
|
-
if
|
86
|
+
if policy_match
|
88
87
|
!valid_logical_ids.include?(policy_match["logical_id"])
|
89
88
|
end
|
90
89
|
end
|
@@ -95,11 +94,10 @@ module Sfn
|
|
95
94
|
:form => Smash.new(
|
96
95
|
'Action' => 'SetStackPolicy',
|
97
96
|
'StackName' => p_stack.id,
|
98
|
-
'StackPolicyBody' => MultiJson.dump(stack_policy)
|
99
|
-
)
|
97
|
+
'StackPolicyBody' => MultiJson.dump(stack_policy),
|
98
|
+
),
|
100
99
|
)
|
101
100
|
end
|
102
|
-
|
103
101
|
end
|
104
102
|
end
|
105
103
|
end
|
data/lib/sfn/command.rb
CHANGED
@@ -3,7 +3,6 @@ require 'bogo-cli'
|
|
3
3
|
|
4
4
|
module Sfn
|
5
5
|
class Command < Bogo::Cli::Command
|
6
|
-
|
7
6
|
include CommandModule::Callbacks
|
8
7
|
|
9
8
|
autoload :Conf, 'sfn/command/conf'
|
@@ -34,15 +33,15 @@ module Sfn
|
|
34
33
|
'.json',
|
35
34
|
'.yaml',
|
36
35
|
'.yml',
|
37
|
-
'.xml'
|
36
|
+
'.xml',
|
38
37
|
]
|
39
38
|
|
40
39
|
# Override to provide config file searching
|
41
40
|
def initialize(cli_opts, args)
|
42
|
-
unless
|
41
|
+
unless cli_opts['config']
|
43
42
|
discover_config(cli_opts)
|
44
43
|
end
|
45
|
-
unless
|
44
|
+
unless ENV['DEBUG']
|
46
45
|
ENV['DEBUG'] = 'true' if cli_opts[:debug]
|
47
46
|
end
|
48
47
|
super(cli_opts, args)
|
@@ -64,14 +63,14 @@ module Sfn
|
|
64
63
|
#
|
65
64
|
# @return [TrueClass, FalseClass]
|
66
65
|
def load_api_provider_extensions!
|
67
|
-
if
|
66
|
+
if config.get(:credentials, :provider)
|
68
67
|
base_ext = Bogo::Utility.camel(config.get(:credentials, :provider)).to_sym
|
69
68
|
targ_ext = self.class.name.split('::').last
|
70
|
-
if
|
69
|
+
if ApiProvider.constants.include?(base_ext)
|
71
70
|
base_module = ApiProvider.const_get(base_ext)
|
72
71
|
ui.debug "Loading core provider extensions via `#{base_module}`"
|
73
72
|
extend base_module
|
74
|
-
if
|
73
|
+
if base_module.constants.include?(targ_ext)
|
75
74
|
targ_module = base_module.const_get(targ_ext)
|
76
75
|
ui.debug "Loading targeted provider extensions via `#{targ_module}`"
|
77
76
|
extend targ_module
|
@@ -89,7 +88,7 @@ module Sfn
|
|
89
88
|
def discover_config(opts)
|
90
89
|
cwd = Dir.pwd.split(File::SEPARATOR)
|
91
90
|
detected_path = ''
|
92
|
-
until
|
91
|
+
until cwd.empty? || File.exists?(detected_path.to_s)
|
93
92
|
detected_path = Dir.glob(
|
94
93
|
(cwd + ["#{CONFIG_BASE_NAME}{#{VALID_CONFIG_EXTENSIONS.join(',')}}"]).join(
|
95
94
|
File::SEPARATOR
|
@@ -97,7 +96,7 @@ module Sfn
|
|
97
96
|
).first
|
98
97
|
cwd.pop
|
99
98
|
end
|
100
|
-
if
|
99
|
+
if opts.respond_to?(:fetch_option)
|
101
100
|
opts.fetch_option('config').value = detected_path if detected_path
|
102
101
|
else
|
103
102
|
opts['config'] = detected_path if detected_path
|
@@ -108,12 +107,11 @@ module Sfn
|
|
108
107
|
# @return [Class] attempt to return customized configuration class
|
109
108
|
def config_class
|
110
109
|
klass_name = self.class.name.split('::').last
|
111
|
-
if
|
110
|
+
if Sfn::Config.const_defined?(klass_name)
|
112
111
|
Sfn::Config.const_get(klass_name)
|
113
112
|
else
|
114
113
|
super
|
115
114
|
end
|
116
115
|
end
|
117
|
-
|
118
116
|
end
|
119
117
|
end
|
data/lib/sfn/command/conf.rb
CHANGED
@@ -4,19 +4,18 @@ module Sfn
|
|
4
4
|
class Command
|
5
5
|
# Config command
|
6
6
|
class Conf < Command
|
7
|
-
|
8
7
|
include Sfn::CommandModule::Base
|
9
8
|
|
10
9
|
# Run the list command
|
11
10
|
def execute!
|
12
11
|
ui.info ui.color("Current configuration state:")
|
13
12
|
Config::Conf.attributes.sort_by(&:first).each do |k, val|
|
14
|
-
if
|
13
|
+
if config.has_key?(k)
|
15
14
|
ui.print " #{ui.color(k, :bold, :green)}: "
|
16
15
|
format_value(config[k], ' ')
|
17
16
|
end
|
18
17
|
end
|
19
|
-
if
|
18
|
+
if config[:generate]
|
20
19
|
ui.puts
|
21
20
|
ui.info 'Generating .sfn configuration file..'
|
22
21
|
generate_config!
|
@@ -25,7 +24,7 @@ module Sfn
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def generate_config!
|
28
|
-
if
|
27
|
+
if File.exists?('.sfn')
|
29
28
|
ui.warn 'Existing .sfn configuration file detected!'
|
30
29
|
ui.confirm 'Overwrite current .sfn configuration file?'
|
31
30
|
end
|
@@ -37,14 +36,14 @@ module Sfn
|
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
|
-
def format_value(value, indent='')
|
41
|
-
if
|
39
|
+
def format_value(value, indent = '')
|
40
|
+
if value.is_a?(Hash)
|
42
41
|
ui.puts
|
43
|
-
value.sort_by(&:first).each do |k,v|
|
42
|
+
value.sort_by(&:first).each do |k, v|
|
44
43
|
ui.print "#{indent} #{ui.color(k, :bold)}: "
|
45
44
|
format_value(v, indent + ' ')
|
46
45
|
end
|
47
|
-
elsif
|
46
|
+
elsif value.is_a?(Array)
|
48
47
|
ui.puts
|
49
48
|
value.map(&:to_s).sort.each do |v|
|
50
49
|
ui.print "#{indent} "
|
@@ -134,8 +133,6 @@ Configuration.new do
|
|
134
133
|
end
|
135
134
|
end
|
136
135
|
EOF
|
137
|
-
|
138
|
-
|
139
136
|
end
|
140
137
|
end
|
141
138
|
end
|
data/lib/sfn/command/create.rb
CHANGED
@@ -5,7 +5,6 @@ module Sfn
|
|
5
5
|
class Command
|
6
6
|
# Create command
|
7
7
|
class Create < Command
|
8
|
-
|
9
8
|
include Sfn::CommandModule::Base
|
10
9
|
include Sfn::CommandModule::Template
|
11
10
|
include Sfn::CommandModule::Stack
|
@@ -18,22 +17,22 @@ module Sfn
|
|
18
17
|
# NOTE: Always disable plans on create
|
19
18
|
config[:plan] = false
|
20
19
|
|
21
|
-
if
|
20
|
+
if config[:template]
|
22
21
|
file = config[:template]
|
23
22
|
else
|
24
23
|
file = load_template_file
|
25
24
|
end
|
26
25
|
|
27
|
-
unless
|
26
|
+
unless config[:print_only]
|
28
27
|
ui.info "#{ui.color('SparkleFormation:', :bold)} #{ui.color('create', :green)}"
|
29
28
|
end
|
30
29
|
|
31
30
|
stack_info = "#{ui.color('Name:', :bold)} #{name}"
|
32
|
-
if
|
31
|
+
if config[:path]
|
33
32
|
stack_info << " #{ui.color('Path:', :bold)} #{config[:file]}"
|
34
33
|
end
|
35
34
|
|
36
|
-
if
|
35
|
+
if config[:print_only]
|
37
36
|
ui.puts format_json(parameter_scrub!(template_content(file)))
|
38
37
|
return
|
39
38
|
else
|
@@ -44,7 +43,7 @@ module Sfn
|
|
44
43
|
config.fetch(:options, Smash.new).dup.merge(
|
45
44
|
:name => name,
|
46
45
|
:template => template_content(file),
|
47
|
-
:parameters => Smash.new
|
46
|
+
:parameters => Smash.new,
|
48
47
|
)
|
49
48
|
)
|
50
49
|
|
@@ -53,7 +52,7 @@ module Sfn
|
|
53
52
|
|
54
53
|
stack.parameters = config_root_parameters
|
55
54
|
|
56
|
-
if
|
55
|
+
if config[:upload_root_template]
|
57
56
|
upload_result = store_template(name, file, Smash.new)
|
58
57
|
stack.template_url = upload_result[:url]
|
59
58
|
else
|
@@ -62,11 +61,11 @@ module Sfn
|
|
62
61
|
|
63
62
|
api_action!(:api_stack => stack) do
|
64
63
|
stack.save
|
65
|
-
if
|
64
|
+
if config[:poll]
|
66
65
|
poll_stack(stack.name)
|
67
66
|
stack = provider.stack(name)
|
68
67
|
|
69
|
-
if
|
68
|
+
if stack.reload.state == :create_complete
|
70
69
|
ui.info "Stack create complete: #{ui.color('SUCCESS', :green)}"
|
71
70
|
namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
|
72
71
|
else
|
@@ -78,10 +77,7 @@ module Sfn
|
|
78
77
|
ui.info "Stack creation initialized for #{ui.color(name, :green)}"
|
79
78
|
end
|
80
79
|
end
|
81
|
-
|
82
80
|
end
|
83
|
-
|
84
81
|
end
|
85
|
-
|
86
82
|
end
|
87
83
|
end
|
data/lib/sfn/command/describe.rb
CHANGED
@@ -4,11 +4,10 @@ module Sfn
|
|
4
4
|
class Command
|
5
5
|
# Cloudformation describe command
|
6
6
|
class Describe < Command
|
7
|
-
|
8
7
|
include Sfn::CommandModule::Base
|
9
8
|
|
10
9
|
# information available
|
11
|
-
unless
|
10
|
+
unless defined?(AVAILABLE_DISPLAYS)
|
12
11
|
AVAILABLE_DISPLAYS = [:resources, :outputs, :tags]
|
13
12
|
end
|
14
13
|
|
@@ -19,12 +18,12 @@ module Sfn
|
|
19
18
|
root_stack = api_action! do
|
20
19
|
provider.stack(stack_name)
|
21
20
|
end
|
22
|
-
if
|
21
|
+
if root_stack
|
23
22
|
([root_stack] + root_stack.nested_stacks).compact.each do |stack|
|
24
23
|
ui.info "Stack description of #{ui.color(stack.name, :bold)}:"
|
25
24
|
display = [].tap do |to_display|
|
26
25
|
AVAILABLE_DISPLAYS.each do |display_option|
|
27
|
-
if
|
26
|
+
if config[display_option]
|
28
27
|
to_display << display_option
|
29
28
|
end
|
30
29
|
end
|
@@ -54,7 +53,7 @@ module Sfn
|
|
54
53
|
table(:border => false) do
|
55
54
|
row(:header => true) do
|
56
55
|
allowed_attributes.each do |attr|
|
57
|
-
column as_title(attr), :width => stack_resources.map{|r| r[attr].to_s.length}.push(as_title(attr).length).max + 2
|
56
|
+
column as_title(attr), :width => stack_resources.map { |r| r[attr].to_s.length }.push(as_title(attr).length).max + 2
|
58
57
|
end
|
59
58
|
end
|
60
59
|
stack_resources.each do |resource|
|
@@ -73,7 +72,7 @@ module Sfn
|
|
73
72
|
# @param stack [Miasma::Models::Orchestration::Stack]
|
74
73
|
def outputs(stack)
|
75
74
|
ui.info "Outputs for stack: #{ui.color(stack.name, :bold)}"
|
76
|
-
unless
|
75
|
+
unless stack.outputs.nil? || stack.outputs.empty?
|
77
76
|
stack.outputs.each do |output|
|
78
77
|
key, value = output.key, output.value
|
79
78
|
key = snake(key).to_s.split('_').map(&:capitalize).join(' ')
|
@@ -89,7 +88,7 @@ module Sfn
|
|
89
88
|
# @param stack [Miasma::Models::Orchestration::Stack]
|
90
89
|
def tags(stack)
|
91
90
|
ui.info "Tags for stack: #{ui.color(stack.name, :bold)}"
|
92
|
-
if
|
91
|
+
if stack.tags && !stack.tags.empty?
|
93
92
|
stack.tags.each do |key, value|
|
94
93
|
ui.info [' ', ui.color("#{key}:", :bold), value].join(' ')
|
95
94
|
end
|
@@ -102,7 +101,6 @@ module Sfn
|
|
102
101
|
def default_attributes
|
103
102
|
%w(updated logical_id type status status_reason)
|
104
103
|
end
|
105
|
-
|
106
104
|
end
|
107
105
|
end
|
108
106
|
end
|