sfn 3.0.30 → 3.0.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/bin/sfn +16 -14
- data/lib/chef/knife/knife_plugin_seed.rb +12 -12
- data/lib/sfn.rb +17 -17
- data/lib/sfn/api_provider.rb +3 -3
- data/lib/sfn/api_provider/google.rb +2 -2
- data/lib/sfn/api_provider/terraform.rb +2 -2
- data/lib/sfn/cache.rb +9 -9
- data/lib/sfn/callback.rb +6 -6
- data/lib/sfn/callback/aws_assume_role.rb +5 -5
- data/lib/sfn/callback/aws_mfa.rb +8 -6
- data/lib/sfn/callback/stack_policy.rb +15 -15
- data/lib/sfn/command.rb +37 -36
- data/lib/sfn/command/conf.rb +12 -12
- data/lib/sfn/command/create.rb +9 -9
- data/lib/sfn/command/describe.rb +6 -6
- data/lib/sfn/command/destroy.rb +8 -8
- data/lib/sfn/command/diff.rb +31 -31
- data/lib/sfn/command/events.rb +6 -6
- data/lib/sfn/command/export.rb +8 -8
- data/lib/sfn/command/graph.rb +21 -21
- data/lib/sfn/command/graph/aws.rb +34 -34
- data/lib/sfn/command/graph/provider.rb +1 -1
- data/lib/sfn/command/graph/terraform.rb +41 -41
- data/lib/sfn/command/import.rb +17 -17
- data/lib/sfn/command/init.rb +15 -15
- data/lib/sfn/command/inspect.rb +16 -16
- data/lib/sfn/command/lint.rb +6 -6
- data/lib/sfn/command/list.rb +2 -2
- data/lib/sfn/command/plan.rb +227 -0
- data/lib/sfn/command/print.rb +4 -4
- data/lib/sfn/command/promote.rb +2 -2
- data/lib/sfn/command/update.rb +19 -144
- data/lib/sfn/command/validate.rb +17 -13
- data/lib/sfn/command_module.rb +6 -5
- data/lib/sfn/command_module/base.rb +8 -8
- data/lib/sfn/command_module/callbacks.rb +5 -5
- data/lib/sfn/command_module/planning.rb +151 -0
- data/lib/sfn/command_module/stack.rb +34 -34
- data/lib/sfn/command_module/template.rb +50 -50
- data/lib/sfn/config.rb +46 -44
- data/lib/sfn/config/conf.rb +3 -3
- data/lib/sfn/config/create.rb +9 -9
- data/lib/sfn/config/describe.rb +7 -7
- data/lib/sfn/config/destroy.rb +1 -1
- data/lib/sfn/config/diff.rb +3 -3
- data/lib/sfn/config/events.rb +9 -9
- data/lib/sfn/config/export.rb +5 -5
- data/lib/sfn/config/graph.rb +10 -10
- data/lib/sfn/config/import.rb +4 -4
- data/lib/sfn/config/init.rb +1 -1
- data/lib/sfn/config/inspect.rb +16 -16
- data/lib/sfn/config/lint.rb +5 -5
- data/lib/sfn/config/list.rb +6 -6
- data/lib/sfn/config/plan.rb +28 -0
- data/lib/sfn/config/print.rb +5 -5
- data/lib/sfn/config/promote.rb +4 -4
- data/lib/sfn/config/update.rb +18 -18
- data/lib/sfn/config/validate.rb +30 -30
- data/lib/sfn/lint.rb +5 -5
- data/lib/sfn/lint/definition.rb +3 -3
- data/lib/sfn/lint/rule.rb +3 -3
- data/lib/sfn/lint/rule_set.rb +2 -2
- data/lib/sfn/monkey_patch.rb +2 -2
- data/lib/sfn/monkey_patch/stack.rb +27 -27
- data/lib/sfn/monkey_patch/stack/azure.rb +1 -1
- data/lib/sfn/monkey_patch/stack/google.rb +5 -5
- data/lib/sfn/planner.rb +4 -4
- data/lib/sfn/planner/aws.rb +114 -70
- data/lib/sfn/provider.rb +13 -13
- data/lib/sfn/utils.rb +10 -10
- data/lib/sfn/utils/debug.rb +2 -2
- data/lib/sfn/utils/json.rb +1 -1
- data/lib/sfn/utils/object_storage.rb +3 -3
- data/lib/sfn/utils/output.rb +4 -4
- data/lib/sfn/utils/path_selector.rb +15 -15
- data/lib/sfn/utils/ssher.rb +4 -4
- data/lib/sfn/utils/stack_exporter.rb +16 -16
- data/lib/sfn/utils/stack_parameter_scrubber.rb +6 -6
- data/lib/sfn/utils/stack_parameter_validator.rb +22 -22
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +32 -32
- metadata +16 -13
data/lib/sfn/command.rb
CHANGED
@@ -1,53 +1,54 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "sfn"
|
2
|
+
require "bogo-cli"
|
3
3
|
|
4
4
|
module Sfn
|
5
5
|
class Command < Bogo::Cli::Command
|
6
6
|
include CommandModule::Callbacks
|
7
7
|
|
8
|
-
autoload :Conf,
|
9
|
-
autoload :Create,
|
10
|
-
autoload :Describe,
|
11
|
-
autoload :Destroy,
|
12
|
-
autoload :Diff,
|
13
|
-
autoload :Events,
|
14
|
-
autoload :Export,
|
15
|
-
autoload :Graph,
|
16
|
-
autoload :Import,
|
17
|
-
autoload :Init,
|
18
|
-
autoload :Inspect,
|
19
|
-
autoload :Lint,
|
20
|
-
autoload :List,
|
21
|
-
autoload :
|
22
|
-
autoload :
|
23
|
-
autoload :
|
24
|
-
autoload :
|
8
|
+
autoload :Conf, "sfn/command/conf"
|
9
|
+
autoload :Create, "sfn/command/create"
|
10
|
+
autoload :Describe, "sfn/command/describe"
|
11
|
+
autoload :Destroy, "sfn/command/destroy"
|
12
|
+
autoload :Diff, "sfn/command/diff"
|
13
|
+
autoload :Events, "sfn/command/events"
|
14
|
+
autoload :Export, "sfn/command/export"
|
15
|
+
autoload :Graph, "sfn/command/graph"
|
16
|
+
autoload :Import, "sfn/command/import"
|
17
|
+
autoload :Init, "sfn/command/init"
|
18
|
+
autoload :Inspect, "sfn/command/inspect"
|
19
|
+
autoload :Lint, "sfn/command/lint"
|
20
|
+
autoload :List, "sfn/command/list"
|
21
|
+
autoload :Plan, "sfn/command/plan"
|
22
|
+
autoload :Print, "sfn/command/print"
|
23
|
+
autoload :Promote, "sfn/command/promote"
|
24
|
+
autoload :Update, "sfn/command/update"
|
25
|
+
autoload :Validate, "sfn/command/validate"
|
25
26
|
|
26
27
|
# Base name of configuration file
|
27
|
-
CONFIG_BASE_NAME =
|
28
|
+
CONFIG_BASE_NAME = ".sfn"
|
28
29
|
|
29
30
|
# Supported configuration file extensions
|
30
31
|
VALID_CONFIG_EXTENSIONS = [
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
"",
|
33
|
+
".rb",
|
34
|
+
".json",
|
35
|
+
".yaml",
|
36
|
+
".yml",
|
37
|
+
".xml",
|
37
38
|
]
|
38
39
|
|
39
40
|
# Override to provide config file searching
|
40
41
|
def initialize(cli_opts, args)
|
41
|
-
unless cli_opts[
|
42
|
+
unless cli_opts["config"]
|
42
43
|
discover_config(cli_opts)
|
43
44
|
end
|
44
|
-
unless ENV[
|
45
|
-
ENV[
|
45
|
+
unless ENV["DEBUG"]
|
46
|
+
ENV["DEBUG"] = "true" if cli_opts[:debug]
|
46
47
|
end
|
47
48
|
super(cli_opts, args)
|
48
49
|
load_api_provider_extensions!
|
49
50
|
run_callbacks_for(:after_config)
|
50
|
-
run_callbacks_for("after_config_#{Bogo::Utility.snake(self.class.name.split(
|
51
|
+
run_callbacks_for("after_config_#{Bogo::Utility.snake(self.class.name.split("::").last)}")
|
51
52
|
end
|
52
53
|
|
53
54
|
# @return [Smash]
|
@@ -65,7 +66,7 @@ module Sfn
|
|
65
66
|
def load_api_provider_extensions!
|
66
67
|
if config.get(:credentials, :provider)
|
67
68
|
base_ext = Bogo::Utility.camel(config.get(:credentials, :provider)).to_sym
|
68
|
-
targ_ext = self.class.name.split(
|
69
|
+
targ_ext = self.class.name.split("::").last
|
69
70
|
if ApiProvider.constants.include?(base_ext)
|
70
71
|
base_module = ApiProvider.const_get(base_ext)
|
71
72
|
ui.debug "Loading core provider extensions via `#{base_module}`"
|
@@ -87,26 +88,26 @@ module Sfn
|
|
87
88
|
# @return [Slop]
|
88
89
|
def discover_config(opts)
|
89
90
|
cwd = Dir.pwd.split(File::SEPARATOR)
|
90
|
-
detected_path =
|
91
|
+
detected_path = ""
|
91
92
|
until cwd.empty? || File.exists?(detected_path.to_s)
|
92
93
|
detected_path = Dir.glob(
|
93
|
-
(cwd + ["#{CONFIG_BASE_NAME}{#{VALID_CONFIG_EXTENSIONS.join(
|
94
|
+
(cwd + ["#{CONFIG_BASE_NAME}{#{VALID_CONFIG_EXTENSIONS.join(",")}}"]).join(
|
94
95
|
File::SEPARATOR
|
95
96
|
)
|
96
97
|
).first
|
97
98
|
cwd.pop
|
98
99
|
end
|
99
100
|
if opts.respond_to?(:fetch_option)
|
100
|
-
opts.fetch_option(
|
101
|
+
opts.fetch_option("config").value = detected_path if detected_path
|
101
102
|
else
|
102
|
-
opts[
|
103
|
+
opts["config"] = detected_path if detected_path
|
103
104
|
end
|
104
105
|
opts
|
105
106
|
end
|
106
107
|
|
107
108
|
# @return [Class] attempt to return customized configuration class
|
108
109
|
def config_class
|
109
|
-
klass_name = self.class.name.split(
|
110
|
+
klass_name = self.class.name.split("::").last
|
110
111
|
if Sfn::Config.const_defined?(klass_name)
|
111
112
|
Sfn::Config.const_get(klass_name)
|
112
113
|
else
|
data/lib/sfn/command/conf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "sfn"
|
2
2
|
|
3
3
|
module Sfn
|
4
4
|
class Command
|
@@ -12,42 +12,42 @@ module Sfn
|
|
12
12
|
Config::Conf.attributes.sort_by(&:first).each do |k, val|
|
13
13
|
if config.has_key?(k)
|
14
14
|
ui.print " #{ui.color(k, :bold, :green)}: "
|
15
|
-
format_value(config[k],
|
15
|
+
format_value(config[k], " ")
|
16
16
|
end
|
17
17
|
end
|
18
18
|
if config[:generate]
|
19
19
|
ui.puts
|
20
|
-
ui.info
|
20
|
+
ui.info "Generating .sfn configuration file.."
|
21
21
|
generate_config!
|
22
|
-
ui.info "Generation of .sfn configuration file #{ui.color(
|
22
|
+
ui.info "Generation of .sfn configuration file #{ui.color("complete!", :green, :bold)}"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
def generate_config!
|
27
|
-
if File.exists?(
|
28
|
-
ui.warn
|
29
|
-
ui.confirm
|
27
|
+
if File.exists?(".sfn")
|
28
|
+
ui.warn "Existing .sfn configuration file detected!"
|
29
|
+
ui.confirm "Overwrite current .sfn configuration file?"
|
30
30
|
end
|
31
|
-
run_action
|
32
|
-
File.open(
|
31
|
+
run_action "Writing .sfn file" do
|
32
|
+
File.open(".sfn", "w") do |file|
|
33
33
|
file.write SFN_CONFIG_CONTENTS
|
34
34
|
end
|
35
35
|
nil
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def format_value(value, indent =
|
39
|
+
def format_value(value, indent = "")
|
40
40
|
if value.is_a?(Hash)
|
41
41
|
ui.puts
|
42
42
|
value.sort_by(&:first).each do |k, v|
|
43
43
|
ui.print "#{indent} #{ui.color(k, :bold)}: "
|
44
|
-
format_value(v, indent +
|
44
|
+
format_value(v, indent + " ")
|
45
45
|
end
|
46
46
|
elsif value.is_a?(Array)
|
47
47
|
ui.puts
|
48
48
|
value.map(&:to_s).sort.each do |v|
|
49
49
|
ui.print "#{indent} "
|
50
|
-
format_value(v, indent +
|
50
|
+
format_value(v, indent + " ")
|
51
51
|
end
|
52
52
|
else
|
53
53
|
ui.puts value.to_s
|
data/lib/sfn/command/create.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "sparkle_formation"
|
2
|
+
require "sfn"
|
3
3
|
|
4
4
|
module Sfn
|
5
5
|
class Command
|
@@ -24,12 +24,12 @@ module Sfn
|
|
24
24
|
end
|
25
25
|
|
26
26
|
unless config[:print_only]
|
27
|
-
ui.info "#{ui.color(
|
27
|
+
ui.info "#{ui.color("SparkleFormation:", :bold)} #{ui.color("create", :green)}"
|
28
28
|
end
|
29
29
|
|
30
|
-
stack_info = "#{ui.color(
|
30
|
+
stack_info = "#{ui.color("Name:", :bold)} #{name}"
|
31
31
|
if config[:path]
|
32
|
-
stack_info << " #{ui.color(
|
32
|
+
stack_info << " #{ui.color("Path:", :bold)} #{config[:file]}"
|
33
33
|
end
|
34
34
|
|
35
35
|
if config[:print_only]
|
@@ -66,14 +66,14 @@ module Sfn
|
|
66
66
|
stack = provider.stack(name)
|
67
67
|
|
68
68
|
if stack.reload.state == :create_complete
|
69
|
-
ui.info "Stack create complete: #{ui.color(
|
69
|
+
ui.info "Stack create complete: #{ui.color("SUCCESS", :green)}"
|
70
70
|
namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
|
71
71
|
else
|
72
|
-
ui.fatal "Create of new stack #{ui.color(name, :bold)}: #{ui.color(
|
73
|
-
raise
|
72
|
+
ui.fatal "Create of new stack #{ui.color(name, :bold)}: #{ui.color("FAILED", :red, :bold)}"
|
73
|
+
raise "Stack did not reach a successful completion state."
|
74
74
|
end
|
75
75
|
else
|
76
|
-
ui.warn
|
76
|
+
ui.warn "Stack state polling has been disabled."
|
77
77
|
ui.info "Stack creation initialized for #{ui.color(name, :green)}"
|
78
78
|
end
|
79
79
|
end
|
data/lib/sfn/command/describe.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "sfn"
|
2
2
|
|
3
3
|
module Sfn
|
4
4
|
class Command
|
@@ -75,11 +75,11 @@ module Sfn
|
|
75
75
|
unless stack.outputs.nil? || stack.outputs.empty?
|
76
76
|
stack.outputs.each do |output|
|
77
77
|
key, value = output.key, output.value
|
78
|
-
key = snake(key).to_s.split(
|
79
|
-
ui.info [
|
78
|
+
key = snake(key).to_s.split("_").map(&:capitalize).join(" ")
|
79
|
+
ui.info [" ", ui.color("#{key}:", :bold), value].join(" ")
|
80
80
|
end
|
81
81
|
else
|
82
|
-
ui.info " #{ui.color(
|
82
|
+
ui.info " #{ui.color("No outputs found")}"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -90,10 +90,10 @@ module Sfn
|
|
90
90
|
ui.info "Tags for stack: #{ui.color(stack.name, :bold)}"
|
91
91
|
if stack.tags && !stack.tags.empty?
|
92
92
|
stack.tags.each do |key, value|
|
93
|
-
ui.info [
|
93
|
+
ui.info [" ", ui.color("#{key}:", :bold), value].join(" ")
|
94
94
|
end
|
95
95
|
else
|
96
|
-
ui.info " #{ui.color(
|
96
|
+
ui.info " #{ui.color("No tags found")}"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
data/lib/sfn/command/destroy.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "sfn"
|
2
2
|
|
3
3
|
module Sfn
|
4
4
|
class Command
|
@@ -9,7 +9,7 @@ module Sfn
|
|
9
9
|
def execute!
|
10
10
|
name_required!
|
11
11
|
stacks = name_args.sort
|
12
|
-
plural =
|
12
|
+
plural = "s" if stacks.size > 1
|
13
13
|
globs = stacks.find_all do |s|
|
14
14
|
s !~ /^[a-zA-Z0-9-]+$/
|
15
15
|
end
|
@@ -23,7 +23,7 @@ module Sfn
|
|
23
23
|
stacks -= globs
|
24
24
|
stacks.sort!
|
25
25
|
end
|
26
|
-
ui.warn "Destroying Stack#{plural}: #{ui.color(stacks.join(
|
26
|
+
ui.warn "Destroying Stack#{plural}: #{ui.color(stacks.join(", "), :bold)}"
|
27
27
|
ui.confirm "Destroy listed stack#{plural}?"
|
28
28
|
stacks.each do |stack_name|
|
29
29
|
stack = provider.connection.stacks.get(stack_name)
|
@@ -56,7 +56,7 @@ module Sfn
|
|
56
56
|
ui.error "Stack polling is not available when multiple stack deletion is requested!"
|
57
57
|
end
|
58
58
|
end
|
59
|
-
ui.info " -> Destroyed SparkleFormation#{plural}: #{ui.color(stacks.join(
|
59
|
+
ui.info " -> Destroyed SparkleFormation#{plural}: #{ui.color(stacks.join(", "), :bold, :red)}"
|
60
60
|
end
|
61
61
|
|
62
62
|
# Cleanup persisted templates if nested stack resources are included
|
@@ -64,12 +64,12 @@ module Sfn
|
|
64
64
|
stack.nested_stacks.each do |n_stack|
|
65
65
|
nested_stack_cleanup!(n_stack)
|
66
66
|
end
|
67
|
-
nest_stacks = stack.template.fetch(
|
68
|
-
provider.connection.data[:stack_types].include?(resource[
|
67
|
+
nest_stacks = stack.template.fetch("Resources", {}).values.find_all do |resource|
|
68
|
+
provider.connection.data[:stack_types].include?(resource["Type"])
|
69
69
|
end.each do |resource|
|
70
|
-
url = resource[
|
70
|
+
url = resource["Properties"]["TemplateURL"]
|
71
71
|
if url && url.is_a?(String)
|
72
|
-
_, bucket_name, path = URI.parse(url).path.split(
|
72
|
+
_, bucket_name, path = URI.parse(url).path.split("/", 3)
|
73
73
|
bucket = provider.connection.api_for(:storage).buckets.get(bucket_name)
|
74
74
|
if bucket
|
75
75
|
file = bucket.files.get(path)
|
data/lib/sfn/command/diff.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "sparkle_formation"
|
2
|
+
require "sfn"
|
3
|
+
require "hashdiff"
|
4
4
|
|
5
5
|
module Sfn
|
6
6
|
class Command
|
@@ -26,7 +26,7 @@ module Sfn
|
|
26
26
|
file = load_template_file
|
27
27
|
file = parameter_scrub!(file.dump)
|
28
28
|
|
29
|
-
ui.info "#{ui.color(
|
29
|
+
ui.info "#{ui.color("SparkleFormation:", :bold)} #{ui.color("diff", :blue)} - #{name}"
|
30
30
|
ui.puts
|
31
31
|
|
32
32
|
diff_stack(stack, MultiJson.load(MultiJson.dump(file)).to_smash)
|
@@ -40,8 +40,8 @@ module Sfn
|
|
40
40
|
def diff_stack(stack, file, parent_names = [])
|
41
41
|
stack_template = stack.template
|
42
42
|
nested_stacks = Hash[
|
43
|
-
file.fetch(
|
44
|
-
value.fetch(
|
43
|
+
file.fetch("Resources", file.fetch("resources", {})).find_all do |name, value|
|
44
|
+
value.fetch("Properties", {})["Stack"]
|
45
45
|
end
|
46
46
|
]
|
47
47
|
nested_stacks.each do |name, value|
|
@@ -49,58 +49,58 @@ module Sfn
|
|
49
49
|
ns.data[:logical_id] == name
|
50
50
|
end
|
51
51
|
if n_stack
|
52
|
-
diff_stack(n_stack, value[
|
52
|
+
diff_stack(n_stack, value["Properties"]["Stack"], [*parent_names, stack.data.fetch(:logical_id, stack.name)].compact)
|
53
53
|
end
|
54
|
-
file[
|
54
|
+
file["Resources"][name]["Properties"].delete("Stack")
|
55
55
|
end
|
56
56
|
|
57
|
-
ui.info "#{ui.color(
|
57
|
+
ui.info "#{ui.color("Stack diff:", :bold)} #{ui.color((parent_names + [stack.data.fetch(:logical_id, stack.name)]).compact.join(" > "), :blue)}"
|
58
58
|
|
59
59
|
stack_diff = HashDiff.diff(stack.template, file)
|
60
60
|
|
61
61
|
if config[:raw_diff]
|
62
62
|
ui.info "Dumping raw template diff:"
|
63
|
-
require
|
63
|
+
require "pp"
|
64
64
|
pp stack_diff
|
65
65
|
else
|
66
66
|
added_resources = stack_diff.find_all do |item|
|
67
|
-
item.first ==
|
67
|
+
item.first == "+" && item[1].match(/Resources\.[^.]+$/)
|
68
68
|
end
|
69
69
|
removed_resources = stack_diff.find_all do |item|
|
70
|
-
item.first ==
|
70
|
+
item.first == "-" && item[1].match(/Resources\.[^.]+$/)
|
71
71
|
end
|
72
72
|
modified_resources = stack_diff.find_all do |item|
|
73
|
-
item[1].start_with?(
|
74
|
-
!item[1].end_with?(
|
75
|
-
!item[1].include?(
|
73
|
+
item[1].start_with?("Resources.") &&
|
74
|
+
!item[1].end_with?("TemplateURL") &&
|
75
|
+
!item[1].include?("Properties.Parameters")
|
76
76
|
end - added_resources - removed_resources
|
77
77
|
|
78
78
|
if added_resources.empty? && removed_resources.empty? && modified_resources.empty?
|
79
|
-
ui.info
|
79
|
+
ui.info "No changes detected"
|
80
80
|
ui.puts
|
81
81
|
else
|
82
82
|
unless added_resources.empty?
|
83
|
-
ui.info ui.color(
|
83
|
+
ui.info ui.color("Added Resources:", :green, :bold)
|
84
84
|
added_resources.each do |item|
|
85
|
-
ui.print ui.color(" -> #{item[1].split(
|
86
|
-
ui.puts " [#{item[2][
|
85
|
+
ui.print ui.color(" -> #{item[1].split(".").last}", :green)
|
86
|
+
ui.puts " [#{item[2]["Type"]}]"
|
87
87
|
end
|
88
88
|
ui.puts
|
89
89
|
end
|
90
90
|
|
91
91
|
unless modified_resources.empty?
|
92
|
-
ui.info ui.color(
|
92
|
+
ui.info ui.color("Modified Resources:", :yellow, :bold)
|
93
93
|
m_resources = Hash.new.tap do |hash|
|
94
94
|
modified_resources.each do |item|
|
95
|
-
_, key, path = item[1].split(
|
95
|
+
_, key, path = item[1].split(".", 3)
|
96
96
|
hash[key] ||= {}
|
97
|
-
prefix, a_key = path.split(
|
97
|
+
prefix, a_key = path.split(".", 2)
|
98
98
|
hash[key][prefix] ||= []
|
99
99
|
matched = hash[key][prefix].detect do |i|
|
100
100
|
i[:path] == a_key
|
101
101
|
end
|
102
102
|
if matched
|
103
|
-
if item.first ==
|
103
|
+
if item.first == "-"
|
104
104
|
matched[:original] = item[2]
|
105
105
|
else
|
106
106
|
matched[:new] = item[2]
|
@@ -109,10 +109,10 @@ module Sfn
|
|
109
109
|
hash[key][prefix] << Hash.new.tap do |info|
|
110
110
|
info[:path] = a_key
|
111
111
|
case item.first
|
112
|
-
when
|
112
|
+
when "~"
|
113
113
|
info[:original] = item[2]
|
114
114
|
info[:new] = item[3]
|
115
|
-
when
|
115
|
+
when "+"
|
116
116
|
info[:new] = item[2]
|
117
117
|
else
|
118
118
|
info[:original] = item[2]
|
@@ -121,12 +121,12 @@ module Sfn
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
end.to_smash(:sorted).each do |key, value|
|
124
|
-
ui.puts ui.color(" - #{key}", :yellow) + " [#{stack.template[
|
124
|
+
ui.puts ui.color(" - #{key}", :yellow) + " [#{stack.template["Resources"][key]["Type"]}]"
|
125
125
|
value.each do |prefix, items|
|
126
126
|
ui.puts ui.color(" #{prefix}:", :bold)
|
127
127
|
items.each do |item|
|
128
|
-
original = item[:original].nil? ? ui.color(
|
129
|
-
new_val = item[:new].nil? ? ui.color(
|
128
|
+
original = item[:original].nil? ? ui.color("(none)", :yellow) : ui.color(item[:original].inspect, :red)
|
129
|
+
new_val = item[:new].nil? ? ui.color("(deleted)", :red) : ui.color(item[:new].inspect, :green)
|
130
130
|
ui.puts " #{item[:path]}: #{original} -> #{new_val}"
|
131
131
|
end
|
132
132
|
end
|
@@ -135,10 +135,10 @@ module Sfn
|
|
135
135
|
end
|
136
136
|
|
137
137
|
unless removed_resources.empty?
|
138
|
-
ui.info ui.color(
|
138
|
+
ui.info ui.color("Removed Resources:", :red, :bold)
|
139
139
|
removed_resources.each do |item|
|
140
|
-
ui.print ui.color(" <- #{item[1].split(
|
141
|
-
ui.puts " [#{item[2][
|
140
|
+
ui.print ui.color(" <- #{item[1].split(".").last}", :red)
|
141
|
+
ui.puts " [#{item[2]["Type"]}]"
|
142
142
|
end
|
143
143
|
ui.puts
|
144
144
|
end
|