knife-cloudformation 0.2.24 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +16 -0
- data/knife-cloudformation.gemspec +14 -4
- data/lib/knife-cloudformation.rb +0 -28
- data/lib/knife-cloudformation/version.rb +1 -1
- metadata +18 -80
- data/lib/chef/knife/cloudformation_create.rb +0 -147
- data/lib/chef/knife/cloudformation_describe.rb +0 -99
- data/lib/chef/knife/cloudformation_destroy.rb +0 -84
- data/lib/chef/knife/cloudformation_events.rb +0 -117
- data/lib/chef/knife/cloudformation_export.rb +0 -162
- data/lib/chef/knife/cloudformation_import.rb +0 -141
- data/lib/chef/knife/cloudformation_inspect.rb +0 -206
- data/lib/chef/knife/cloudformation_list.rb +0 -72
- data/lib/chef/knife/cloudformation_promote.rb +0 -40
- data/lib/chef/knife/cloudformation_update.rb +0 -137
- data/lib/chef/knife/cloudformation_validate.rb +0 -36
- data/lib/knife-cloudformation/cache.rb +0 -385
- data/lib/knife-cloudformation/knife.rb +0 -9
- data/lib/knife-cloudformation/knife/base.rb +0 -195
- data/lib/knife-cloudformation/knife/stack.rb +0 -197
- data/lib/knife-cloudformation/knife/template.rb +0 -213
- data/lib/knife-cloudformation/monkey_patch.rb +0 -8
- data/lib/knife-cloudformation/monkey_patch/stack.rb +0 -195
- data/lib/knife-cloudformation/provider.rb +0 -225
- data/lib/knife-cloudformation/utils.rb +0 -24
- data/lib/knife-cloudformation/utils/animal_strings.rb +0 -28
- data/lib/knife-cloudformation/utils/debug.rb +0 -31
- data/lib/knife-cloudformation/utils/json.rb +0 -64
- data/lib/knife-cloudformation/utils/object_storage.rb +0 -28
- data/lib/knife-cloudformation/utils/output.rb +0 -79
- data/lib/knife-cloudformation/utils/path_selector.rb +0 -99
- data/lib/knife-cloudformation/utils/ssher.rb +0 -29
- data/lib/knife-cloudformation/utils/stack_exporter.rb +0 -271
- data/lib/knife-cloudformation/utils/stack_parameter_scrubber.rb +0 -37
- data/lib/knife-cloudformation/utils/stack_parameter_validator.rb +0 -124
@@ -1,197 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
require 'sparkle_formation'
|
3
|
-
|
4
|
-
module KnifeCloudformation
|
5
|
-
module Knife
|
6
|
-
# Stack handling helper methods
|
7
|
-
module Stack
|
8
|
-
|
9
|
-
module InstanceMethods
|
10
|
-
|
11
|
-
# un-packed stack name joiner/identifier
|
12
|
-
UNPACK_NAME_JOINER = '-sfn-'
|
13
|
-
# maximum number of attempts to get valid parameter value
|
14
|
-
MAX_PARAMETER_ATTEMPTS = 5
|
15
|
-
|
16
|
-
# Apply any defined remote stacks
|
17
|
-
#
|
18
|
-
# @param stack [Miasma::Models::Orchestration::Stack]
|
19
|
-
# @return [Miasma::Models::Orchestration::Stack]
|
20
|
-
def apply_stacks!(stack)
|
21
|
-
action = self.class.name.downcase.end_with?('create') ? :create : :update
|
22
|
-
remote_stacks = Chef::Config[:knife][:cloudformation].
|
23
|
-
fetch(action, {}).fetch(:apply_stacks, [])
|
24
|
-
remote_stacks.each do |stack_name|
|
25
|
-
remote_stack = provider.connection.stacks.get(stack_name)
|
26
|
-
apply_nested_stacks!(remote_stack, stack)
|
27
|
-
if(remote_stack)
|
28
|
-
stack.apply_stack(remote_stack)
|
29
|
-
else
|
30
|
-
apply_unpacked_stack!(stack_name, stack)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
stack
|
34
|
-
end
|
35
|
-
|
36
|
-
# Detect nested stacks and apply
|
37
|
-
#
|
38
|
-
# @param remote_stack [Miasma::Models::Orchestration::Stack] nested stack
|
39
|
-
# @param stack [Miasma::Models::Orchestration::Stack] current stack
|
40
|
-
# @return [Miasma::Models::Orchestration::Stack]
|
41
|
-
# @todo ported from a proto branch and needs to be refactored.
|
42
|
-
# this implementation is some what shady
|
43
|
-
def apply_nested_stacks!(remote_stack, stack)
|
44
|
-
remote_stack.resources.all.each do |resource|
|
45
|
-
if(resource.type == 'AWS::CloudFormation::Stack')
|
46
|
-
nested_stack = provider.connection.stacks.get(resource.id)
|
47
|
-
apply_nested_stacks!(nested_stack, stack)
|
48
|
-
stack.apply_stack(nested_stack)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
stack
|
52
|
-
end
|
53
|
-
|
54
|
-
# Apply all stacks from an unpacked stack
|
55
|
-
#
|
56
|
-
# @param stack_name [String] name of parent stack
|
57
|
-
# @param stack [Miasma::Models::Orchestration::Stack]
|
58
|
-
# @return [Miasma::Models::Orchestration::Stack]
|
59
|
-
def apply_unpacked_stack!(stack_name, stack)
|
60
|
-
result = provider.connection.stacks.all.find_all do |remote_stack|
|
61
|
-
remote_stack.name.start_with?("#{stack_name}#{UNPACK_NAME_JOINER}")
|
62
|
-
end.sort_by(&:name).map do |remote_stack|
|
63
|
-
stack.apply_stack(remote_stack)
|
64
|
-
end
|
65
|
-
unless(result.empty?)
|
66
|
-
stack
|
67
|
-
else
|
68
|
-
ui.error "Failed to apply requested stack. Unable to locate. (#{stack_name})"
|
69
|
-
exit 1
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Unpack nested stack and run action on each stack, applying
|
74
|
-
# the previous stacks automatically
|
75
|
-
#
|
76
|
-
# @param name [String] container stack name
|
77
|
-
# @param file [Hash] stack template
|
78
|
-
# @param action [String] create or update
|
79
|
-
# @return [TrueClass]
|
80
|
-
def unpack_nesting(name, file, action)
|
81
|
-
|
82
|
-
# @todo move this init into setup
|
83
|
-
Chef::Config[:knife][:cloudformation][action.to_sym] ||= Mash.new
|
84
|
-
Chef::Config[:knife][:cloudformation][action.to_sym][:apply_stacks] ||= []
|
85
|
-
|
86
|
-
orig_options = Chef::Config[:knife][:cloudformation][:options].dup
|
87
|
-
stack_count = 0
|
88
|
-
|
89
|
-
file['Resources'].each do |stack_resource_name, stack_resource|
|
90
|
-
|
91
|
-
nested_stack_name = "#{name}#{UNPACK_NAME_JOINER}#{Kernel.sprintf('%0.3d', stack_count)}-#{stack_resource_name}"
|
92
|
-
nested_stack_template = stack_resource['Properties']['Stack']
|
93
|
-
Chef::Config[:knife][:cloudformation][:options] = orig_options.dup
|
94
|
-
|
95
|
-
klass = Chef::Knife.const_get("Cloudformation#{action.to_s.capitalize}")
|
96
|
-
nested_stack_runner = klass.new
|
97
|
-
nested_stack_runner.config = config.dup
|
98
|
-
nested_stack_runner.name_args.push(nested_stack_name)
|
99
|
-
Chef::Config[:knife][:cloudformation][:template] = nested_stack_template
|
100
|
-
nested_stack_runner.run
|
101
|
-
unless(config[:print_only])
|
102
|
-
Chef::Config[:knife][:cloudformation][action.to_sym][:apply_stacks].push(nested_stack_name).uniq!
|
103
|
-
end
|
104
|
-
Chef::Config[:knife][:cloudformation][:template] = nil
|
105
|
-
provider.connection.stacks.reload
|
106
|
-
stack_count += 1
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
true
|
111
|
-
end
|
112
|
-
|
113
|
-
# Prompt for parameter values and store result
|
114
|
-
#
|
115
|
-
# @param stack [Hash] stack template
|
116
|
-
# @return [Hash]
|
117
|
-
def populate_parameters!(stack, current_params={})
|
118
|
-
if(Chef::Config[:knife][:cloudformation][:interactive_parameters])
|
119
|
-
if(stack['Parameters'])
|
120
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters] ||= Mash.new
|
121
|
-
stack.fetch('Parameters', {}).each do |k,v|
|
122
|
-
next if Chef::Config[:knife][:cloudformation][:options][:parameters][k]
|
123
|
-
attempt = 0
|
124
|
-
valid = false
|
125
|
-
until(valid)
|
126
|
-
attempt += 1
|
127
|
-
default = Chef::Config[:knife][:cloudformation][:options][:parameters].fetch(
|
128
|
-
k, current_params.fetch(
|
129
|
-
k, v['Default']
|
130
|
-
)
|
131
|
-
)
|
132
|
-
answer = ui.ask_question("#{k.split(/([A-Z]+[^A-Z]*)/).find_all{|s|!s.empty?}.join(' ')}: ", :default => default)
|
133
|
-
validation = KnifeCloudformation::Utils::StackParameterValidator.validate(answer, v)
|
134
|
-
if(validation == true)
|
135
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters][k] = answer
|
136
|
-
valid = true
|
137
|
-
else
|
138
|
-
validation.each do |validation_error|
|
139
|
-
ui.error validation_error.last
|
140
|
-
end
|
141
|
-
end
|
142
|
-
if(attempt > MAX_PARAMETER_ATTEMPTS)
|
143
|
-
ui.fatal 'Failed to receive allowed parameter!'
|
144
|
-
exit 1
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
stack
|
151
|
-
end
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
module ClassMethods
|
156
|
-
end
|
157
|
-
|
158
|
-
# Load methods into class and define options
|
159
|
-
#
|
160
|
-
# @param klass [Class]
|
161
|
-
def self.included(klass)
|
162
|
-
klass.class_eval do
|
163
|
-
extend KnifeCloudformation::Knife::Stack::ClassMethods
|
164
|
-
include KnifeCloudformation::Knife::Stack::InstanceMethods
|
165
|
-
|
166
|
-
option(:parameter,
|
167
|
-
:short => '-p KEY:VALUE',
|
168
|
-
:long => '--parameter KEY:VALUE',
|
169
|
-
:description => 'Set parameter. Can be used multiple times.',
|
170
|
-
:proc => lambda {|val|
|
171
|
-
parts = val.split(':')
|
172
|
-
key = parts.first
|
173
|
-
value = parts[1, parts.size].join(':')
|
174
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters] ||= Mash.new
|
175
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters][key] = value
|
176
|
-
}
|
177
|
-
)
|
178
|
-
option(:polling,
|
179
|
-
:long => '--[no-]poll',
|
180
|
-
:description => 'Enable stack event polling.',
|
181
|
-
:boolean => true,
|
182
|
-
:default => true,
|
183
|
-
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:poll] = val }
|
184
|
-
)
|
185
|
-
option(:interactive_parameters,
|
186
|
-
:long => '--[no-]parameter-prompts',
|
187
|
-
:boolean => true,
|
188
|
-
:default => true,
|
189
|
-
:description => 'Do not prompt for input on dynamic parameters',
|
190
|
-
:proc => lambda{|val| Chef::Config[:knife][:cloudformation][:interactive_parameters] = val }
|
191
|
-
)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
@@ -1,213 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
require 'sparkle_formation'
|
3
|
-
|
4
|
-
module KnifeCloudformation
|
5
|
-
module Knife
|
6
|
-
# Template handling helper methods
|
7
|
-
module Template
|
8
|
-
|
9
|
-
# cloudformation directories that should be ignored
|
10
|
-
TEMPLATE_IGNORE_DIRECTORIES = %w(components dynamics registry)
|
11
|
-
|
12
|
-
module InstanceMethods
|
13
|
-
|
14
|
-
# Load the template file
|
15
|
-
#
|
16
|
-
# @param args [Symbol] options (:allow_missing)
|
17
|
-
# @return [Hash] loaded template
|
18
|
-
def load_template_file(*args)
|
19
|
-
unless(Chef::Config[:knife][:cloudformation][:template])
|
20
|
-
set_paths_and_discover_file!
|
21
|
-
unless(File.exists?(Chef::Config[:knife][:cloudformation][:file].to_s))
|
22
|
-
unless(args.include?(:allow_missing))
|
23
|
-
ui.fatal "Invalid formation file path provided: #{Chef::Config[:knife][:cloudformation][:file]}"
|
24
|
-
exit 1
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
if(Chef::Config[:knife][:cloudformation][:template])
|
29
|
-
Chef::Config[:knife][:cloudformation][:template]
|
30
|
-
elsif(Chef::Config[:knife][:cloudformation][:file])
|
31
|
-
if(Chef::Config[:knife][:cloudformation][:processing])
|
32
|
-
sf = SparkleFormation.compile(Chef::Config[:knife][:cloudformation][:file], :sparkle)
|
33
|
-
if(sf.nested? && !sf.isolated_nests?)
|
34
|
-
raise TypeError.new('Template does not contain isolated stack nesting! Cannot process in existing state.')
|
35
|
-
end
|
36
|
-
if(sf.nested? && Chef::Config[:knife][:cloudformation][:apply_nesting])
|
37
|
-
sf.apply_nesting do |stack_name, stack_definition|
|
38
|
-
bucket = provider.connection.api_for(:storage).buckets.get(
|
39
|
-
Chef::Config[:knife][:cloudformation][:nesting_bucket]
|
40
|
-
)
|
41
|
-
if(config[:print_only])
|
42
|
-
"http://example.com/bucket/#{name_args.first}_#{stack_name}.json"
|
43
|
-
else
|
44
|
-
unless(bucket)
|
45
|
-
raise "Failed to locate configured bucket for stack template storage (#{bucket})!"
|
46
|
-
end
|
47
|
-
file = bucket.files.build
|
48
|
-
file.name = "#{name_args.first}_#{stack_name}.json"
|
49
|
-
file.content_type = 'text/json'
|
50
|
-
file.body = MultiJson.dump(KnifeCloudformation::Utils::StackParameterScrubber.scrub!(stack_definition))
|
51
|
-
file.save
|
52
|
-
# TODO: what if we need extra params?
|
53
|
-
url = URI.parse(file.url)
|
54
|
-
"#{url.scheme}://#{url.host}#{url.path}"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
else
|
58
|
-
sf.dump.merge('sfn_nested_stack' => !!sf.nested?)
|
59
|
-
end
|
60
|
-
else
|
61
|
-
_from_json(File.read(Chef::Config[:knife][:cloudformation][:file]))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Apply template translation
|
67
|
-
#
|
68
|
-
# @param template [Hash]
|
69
|
-
# @return [Hash]
|
70
|
-
def translate_template(template)
|
71
|
-
if(klass_name = Chef::Config[:knife][:cloudformation][:translate])
|
72
|
-
klass = SparkleFormation::Translation.const_get(camel(klass_name))
|
73
|
-
args = {
|
74
|
-
:parameters => Chef::Config[:knife][:cloudformation][:options][:parameters]
|
75
|
-
}
|
76
|
-
if(chunk_size = Chef::Config[:knife][:cloudformation][:translate_chunk_size])
|
77
|
-
args.merge!(
|
78
|
-
:options => {
|
79
|
-
:serialization_chunk_size => chunk_size
|
80
|
-
}
|
81
|
-
)
|
82
|
-
end
|
83
|
-
translator = klass.new(template, args)
|
84
|
-
translator.translate!
|
85
|
-
template = translator.translated
|
86
|
-
ui.info "#{ui.color('Translation applied:', :bold)} #{ui.color(klass_name, :yellow)}"
|
87
|
-
end
|
88
|
-
template
|
89
|
-
end
|
90
|
-
|
91
|
-
# Set SparkleFormation paths and locate tempate
|
92
|
-
#
|
93
|
-
# @return [TrueClass]
|
94
|
-
def set_paths_and_discover_file!
|
95
|
-
if(Chef::Config[:knife][:cloudformation][:base_directory])
|
96
|
-
SparkleFormation.components_path = File.join(
|
97
|
-
Chef::Config[:knife][:cloudformation][:base_directory], 'components'
|
98
|
-
)
|
99
|
-
SparkleFormation.dynamics_path = File.join(
|
100
|
-
Chef::Config[:knife][:cloudformation][:base_directory], 'dynamics'
|
101
|
-
)
|
102
|
-
end
|
103
|
-
if(!Chef::Config[:knife][:cloudformation][:file] && Chef::Config[:knife][:cloudformation][:file_path_prompt])
|
104
|
-
root = File.expand_path(
|
105
|
-
Chef::Config[:knife][:cloudformation].fetch(:base_directory,
|
106
|
-
File.join(Dir.pwd, 'cloudformation')
|
107
|
-
)
|
108
|
-
).split('/')
|
109
|
-
bucket = root.pop
|
110
|
-
root = root.join('/')
|
111
|
-
directory = File.join(root, bucket)
|
112
|
-
Chef::Config[:knife][:cloudformation][:file] = prompt_for_file(directory,
|
113
|
-
:directories_name => 'Collections',
|
114
|
-
:files_name => 'Templates',
|
115
|
-
:ignore_directories => TEMPLATE_IGNORE_DIRECTORIES
|
116
|
-
)
|
117
|
-
else
|
118
|
-
unless(Pathname(Chef::Config[:knife][:cloudformation][:file].to_s).absolute?)
|
119
|
-
base_dir = Chef::Config[:knife][:cloudformation][:base_directory].to_s
|
120
|
-
file = Chef::Config[:knife][:cloudformation][:file].to_s
|
121
|
-
pwd = Dir.pwd
|
122
|
-
Chef::Config[:knife][:cloudformation][:file] = [
|
123
|
-
File.join(base_dir, file),
|
124
|
-
File.join(pwd, file),
|
125
|
-
File.join(pwd, 'cloudformation', file)
|
126
|
-
].detect do |file_path|
|
127
|
-
File.file?(file_path)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
true
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
module ClassMethods
|
137
|
-
end
|
138
|
-
|
139
|
-
# Load methods into class and define options
|
140
|
-
#
|
141
|
-
# @param klass [Class]
|
142
|
-
def self.included(klass)
|
143
|
-
klass.class_eval do
|
144
|
-
extend KnifeCloudformation::Knife::Template::ClassMethods
|
145
|
-
include KnifeCloudformation::Knife::Template::InstanceMethods
|
146
|
-
include KnifeCloudformation::Utils::PathSelector
|
147
|
-
|
148
|
-
option(:processing,
|
149
|
-
:long => '--[no-]processing',
|
150
|
-
:description => 'Call the unicorns and explode the glitter bombs',
|
151
|
-
:boolean => true,
|
152
|
-
:default => false,
|
153
|
-
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:processing] = val }
|
154
|
-
)
|
155
|
-
option(:file,
|
156
|
-
:short => '-f PATH',
|
157
|
-
:long => '--file PATH',
|
158
|
-
:description => 'Path to Cloud Formation to process',
|
159
|
-
:proc => lambda {|val|
|
160
|
-
Chef::Config[:knife][:cloudformation][:file] = val
|
161
|
-
}
|
162
|
-
)
|
163
|
-
option(:file_path_prompt,
|
164
|
-
:long => '--[no-]file-path-prompt',
|
165
|
-
:description => 'Interactive prompt for template path discovery',
|
166
|
-
:boolean => true,
|
167
|
-
:default => true,
|
168
|
-
:proc => lambda {|val|
|
169
|
-
Chef::Config[:knife][:cloudformation][:file_path_prompt] = val
|
170
|
-
}
|
171
|
-
)
|
172
|
-
option(:base_directory,
|
173
|
-
:long => '--cloudformation-directory PATH',
|
174
|
-
:description => 'Path to cloudformation directory',
|
175
|
-
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:base_directory] = val}
|
176
|
-
)
|
177
|
-
option(:no_base_directory,
|
178
|
-
:long => '--no-cloudformation-directory',
|
179
|
-
:description => 'Unset any value used for cloudformation path',
|
180
|
-
:proc => lambda {|*val| Chef::Config[:knife][:cloudformation][:base_directory] = nil}
|
181
|
-
)
|
182
|
-
option(:translate,
|
183
|
-
:long => '--translate PROVIDER',
|
184
|
-
:description => 'Translate generated template to given provider',
|
185
|
-
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:translate] = val}
|
186
|
-
)
|
187
|
-
option(:translate_chunk,
|
188
|
-
:long => '--translate-chunk-size SIZE',
|
189
|
-
:description => 'Chunk length for serialization',
|
190
|
-
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:translate_chunk_size] = val}
|
191
|
-
)
|
192
|
-
option(:apply_nesting,
|
193
|
-
:long => '--[no-]apply-nesting',
|
194
|
-
:description => 'Apply stack nesting',
|
195
|
-
:default => false,
|
196
|
-
:boolean => true,
|
197
|
-
:proc => lambda{|val| Chef::Config[:knife][:cloudformation][:apply_nesting] = val}
|
198
|
-
)
|
199
|
-
option(:nesting_bucket,
|
200
|
-
:long => '--nesting-bucket',
|
201
|
-
:description => 'Bucket to use for storing nested stack templates',
|
202
|
-
:proc => lambda{|val| Chef::Config[:knife][:cloudformation][:nesting_bucket] = val}
|
203
|
-
)
|
204
|
-
|
205
|
-
Chef::Config[:knife][:cloudformation][:file_path_prompt] = true
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
@@ -1,195 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
require 'knife-cloudformation'
|
3
|
-
|
4
|
-
module KnifeCloudformation
|
5
|
-
module MonkeyPatch
|
6
|
-
|
7
|
-
# Expand stack model functionality
|
8
|
-
module Stack
|
9
|
-
|
10
|
-
include KnifeCloudformation::Utils::AnimalStrings
|
11
|
-
|
12
|
-
## Status helpers
|
13
|
-
|
14
|
-
# Check for state suffix
|
15
|
-
#
|
16
|
-
# @param args [String, Symbol] state suffix to check for (multiple allowed)
|
17
|
-
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
18
|
-
def status_ends_with?(*args)
|
19
|
-
stat = status.to_s.downcase
|
20
|
-
!!args.map(&:to_s).map(&:downcase).detect do |suffix|
|
21
|
-
stat.end_with?(suffix)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Check for state prefix
|
26
|
-
#
|
27
|
-
# @param args [String, Symbol] state prefix to check for (multiple allowed)
|
28
|
-
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
29
|
-
def status_starts_with?(*args)
|
30
|
-
stat = status.to_s.downcase
|
31
|
-
!!args.map(&:to_s).map(&:downcase).detect do |prefix|
|
32
|
-
stat.start_with?(prefix)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Check for state inclusion
|
37
|
-
#
|
38
|
-
# @param args [String, Symbol] state string to check for (multiple allowed)
|
39
|
-
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
40
|
-
def status_includes?(*args)
|
41
|
-
stat = status.to_s.downcase
|
42
|
-
!!args.map(&:to_s).map(&:downcase).detect do |string|
|
43
|
-
stat.include?(string)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# @return [TrueClass, FalseClass] stack is in progress
|
48
|
-
def in_progress?
|
49
|
-
status_ends_with?(:in_progress)
|
50
|
-
end
|
51
|
-
|
52
|
-
# @return [TrueClass, FalseClass] stack is in complete state
|
53
|
-
def complete?
|
54
|
-
status_ends_with?(:complete, :failed)
|
55
|
-
end
|
56
|
-
|
57
|
-
# @return [TrueClass, FalseClass] stack is failed state
|
58
|
-
def failed?
|
59
|
-
status_ends_with?(:failed) ||
|
60
|
-
(status_includes?(:rollback) && status_ends_with?(:complete))
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [TrueClass, FalseClass] stack is in success state
|
64
|
-
def success?
|
65
|
-
!failed? && complete?
|
66
|
-
end
|
67
|
-
|
68
|
-
# @return [TrueClass, FalseClass] stack is creating
|
69
|
-
def creating?
|
70
|
-
in_progress? && status_starts_with?(:create)
|
71
|
-
end
|
72
|
-
|
73
|
-
# @return [TrueClass, FalseClass] stack is deleting
|
74
|
-
def deleting?
|
75
|
-
in_progress? && status_starts_with?(:delete)
|
76
|
-
end
|
77
|
-
|
78
|
-
# @return [TrueClass, FalseClass] stack is updating
|
79
|
-
def updating?
|
80
|
-
in_progress? && status_starts_with?(:update)
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [TrueClass, FalseClass] stack is rolling back
|
84
|
-
def rollbacking?
|
85
|
-
in_progress? && status_starts_with?(:rollback)
|
86
|
-
end
|
87
|
-
|
88
|
-
# @return [String] action currently being performed
|
89
|
-
def performing
|
90
|
-
if(in_progress?)
|
91
|
-
status.to_s.downcase.split('_').first.to_sym
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
### Color coders
|
96
|
-
|
97
|
-
# @return [TrueClass, FalseClass] stack is in red state
|
98
|
-
def red?
|
99
|
-
failed? || deleting?
|
100
|
-
end
|
101
|
-
|
102
|
-
# @return [TrueClass, FalseClass] stack is in green state
|
103
|
-
def green?
|
104
|
-
success?
|
105
|
-
end
|
106
|
-
|
107
|
-
# @return [TrueClass, FalseClass] stack is in yellow state
|
108
|
-
def yellow?
|
109
|
-
!red? && !green?
|
110
|
-
end
|
111
|
-
|
112
|
-
# Provides color of stack state. Red is an error state, yellow
|
113
|
-
# is a warning state and green is a success state
|
114
|
-
#
|
115
|
-
# @return [Symbol] color of state (:red, :yellow, :green)
|
116
|
-
def color_state
|
117
|
-
red? ? :red : green? ? :green : :yellow
|
118
|
-
end
|
119
|
-
|
120
|
-
# Provides text of stack state. Danger is an error state, warning
|
121
|
-
# is a warning state and success is a success state
|
122
|
-
#
|
123
|
-
# @return [Symbol] color of state (:danger, :warning, :success)
|
124
|
-
def text_state
|
125
|
-
red? ? :danger : green? ? :success : :warning
|
126
|
-
end
|
127
|
-
|
128
|
-
# @return [String] URL safe encoded stack id
|
129
|
-
def encoded_id
|
130
|
-
Base64.urlsafe_encode64(id)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Whole number representation of current completion
|
134
|
-
#
|
135
|
-
# @param min [Integer] lowest allowed return value (defaults 5)
|
136
|
-
# @return [Integer] percent complete (0..100)
|
137
|
-
def percent_complete(min = 5)
|
138
|
-
if(in_progress?)
|
139
|
-
total_resources = load_template.fetch('Resources', []).size
|
140
|
-
total_complete = resources.all.find_all do |resource|
|
141
|
-
resource.resource_status.downcase.end_with?('complete')
|
142
|
-
end.size
|
143
|
-
result = ((total_complete.to_f / total_resources) * 100).to_i
|
144
|
-
result > min.to_i ? result : min
|
145
|
-
else
|
146
|
-
100
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# Apply stack outputs to current stack parameters
|
151
|
-
#
|
152
|
-
# @param remote_stack [Miasma::Orchestration::Stack]
|
153
|
-
# @return [self]
|
154
|
-
# @note setting `DisableApply` within parameter hash will
|
155
|
-
# prevent parameters being overridden
|
156
|
-
def apply_stack(remote_stack)
|
157
|
-
default_key = 'Default'
|
158
|
-
stack_parameters = template['Parameters']
|
159
|
-
valid_parameters = Hash[
|
160
|
-
stack_parameters.map do |key, val|
|
161
|
-
unless(val['DisableApply'])
|
162
|
-
[snake(key), key]
|
163
|
-
end
|
164
|
-
end.compact
|
165
|
-
]
|
166
|
-
if(defined?(Chef::Config) && Chef::Config[:knife][:cloudformation][:ignore_parameters])
|
167
|
-
valid_parameters = Hash[
|
168
|
-
valid_parameters.map do |snake_param, camel_param|
|
169
|
-
unless(Chef::Config[:knife][:cloudformation][:ignore_parameters].include?(camel_param))
|
170
|
-
[snake_param, camel_param]
|
171
|
-
end
|
172
|
-
end.compact
|
173
|
-
]
|
174
|
-
end
|
175
|
-
if(persisted?)
|
176
|
-
remote_stack.outputs.each do |output|
|
177
|
-
if(param_key = valid_parameters[snake(output.key)])
|
178
|
-
parameters.merge!(param_key => output.value)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
else
|
182
|
-
remote_stack.outputs.each do |output|
|
183
|
-
if(param_key = valid_parameters[snake(output.key)])
|
184
|
-
stack_parameters[param_key][default_key] = output.value
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
# Infect miasma
|
195
|
-
Miasma::Models::Orchestration::Stack.send(:include, KnifeCloudformation::MonkeyPatch::Stack)
|