knife-cloudformation 0.2.24 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +16 -0
  4. data/knife-cloudformation.gemspec +14 -4
  5. data/lib/knife-cloudformation.rb +0 -28
  6. data/lib/knife-cloudformation/version.rb +1 -1
  7. metadata +18 -80
  8. data/lib/chef/knife/cloudformation_create.rb +0 -147
  9. data/lib/chef/knife/cloudformation_describe.rb +0 -99
  10. data/lib/chef/knife/cloudformation_destroy.rb +0 -84
  11. data/lib/chef/knife/cloudformation_events.rb +0 -117
  12. data/lib/chef/knife/cloudformation_export.rb +0 -162
  13. data/lib/chef/knife/cloudformation_import.rb +0 -141
  14. data/lib/chef/knife/cloudformation_inspect.rb +0 -206
  15. data/lib/chef/knife/cloudformation_list.rb +0 -72
  16. data/lib/chef/knife/cloudformation_promote.rb +0 -40
  17. data/lib/chef/knife/cloudformation_update.rb +0 -137
  18. data/lib/chef/knife/cloudformation_validate.rb +0 -36
  19. data/lib/knife-cloudformation/cache.rb +0 -385
  20. data/lib/knife-cloudformation/knife.rb +0 -9
  21. data/lib/knife-cloudformation/knife/base.rb +0 -195
  22. data/lib/knife-cloudformation/knife/stack.rb +0 -197
  23. data/lib/knife-cloudformation/knife/template.rb +0 -213
  24. data/lib/knife-cloudformation/monkey_patch.rb +0 -8
  25. data/lib/knife-cloudformation/monkey_patch/stack.rb +0 -195
  26. data/lib/knife-cloudformation/provider.rb +0 -225
  27. data/lib/knife-cloudformation/utils.rb +0 -24
  28. data/lib/knife-cloudformation/utils/animal_strings.rb +0 -28
  29. data/lib/knife-cloudformation/utils/debug.rb +0 -31
  30. data/lib/knife-cloudformation/utils/json.rb +0 -64
  31. data/lib/knife-cloudformation/utils/object_storage.rb +0 -28
  32. data/lib/knife-cloudformation/utils/output.rb +0 -79
  33. data/lib/knife-cloudformation/utils/path_selector.rb +0 -99
  34. data/lib/knife-cloudformation/utils/ssher.rb +0 -29
  35. data/lib/knife-cloudformation/utils/stack_exporter.rb +0 -271
  36. data/lib/knife-cloudformation/utils/stack_parameter_scrubber.rb +0 -37
  37. data/lib/knife-cloudformation/utils/stack_parameter_validator.rb +0 -124
@@ -1,99 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # Helper methods for path selection
7
- module PathSelector
8
-
9
- # Humanize the base name of path
10
- #
11
- # @param path [String]
12
- # @return [String]
13
- def humanize_path_basename(path)
14
- File.basename(path).sub(
15
- File.extname(path), ''
16
- ).split(/[-_]/).map(&:capitalize).join(' ')
17
- end
18
-
19
- # Prompt user for file selection
20
- #
21
- # @param directory [String] path to directory
22
- # @param opts [Hash] options
23
- # @option opts [Array<String>] :ignore_directories directory names
24
- # @option opts [String] :directories_name title for directories
25
- # @option opts [String] :files_name title for files
26
- # @option opts [String] :filter_prefix only return results matching filter
27
- # @return [String] file path
28
- def prompt_for_file(directory, opts={})
29
- file_list = Dir.glob(File.join(directory, '**', '**', '*')).find_all do |file|
30
- File.file?(file)
31
- end
32
- if(opts[:filter_prefix])
33
- file_list = file_list.find_all do |file|
34
- file.start_with?(options[:filter_prefix])
35
- end
36
- end
37
- directories = file_list.map do |file|
38
- File.dirname(file)
39
- end.uniq
40
- files = file_list.find_all do |path|
41
- path.sub(directory, '').split('/').size == 2
42
- end
43
- if(opts[:ignore_directories])
44
- directories.delete_if do |dir|
45
- opts[:ignore_directories].include?(File.basename(dir))
46
- end
47
- end
48
- if(directories.empty? && files.empty?)
49
- ui.fatal 'No formation paths discoverable!'
50
- else
51
- output = ['Please select an entry']
52
- output << '(or directory to list):' unless directories.empty?
53
- ui.info output.join(' ')
54
- output.clear
55
- idx = 1
56
- valid = {}
57
- unless(directories.empty?)
58
- output << ui.color("#{opts.fetch(:directories_name, 'Directories')}:", :bold)
59
- directories.each do |dir|
60
- valid[idx] = {:path => dir, :type => :directory}
61
- output << [idx, humanize_path_basename(dir)]
62
- idx += 1
63
- end
64
- end
65
- unless(files.empty?)
66
- output << ui.color("#{opts.fetch(:files_name, 'Files')}:", :bold)
67
- files.each do |file|
68
- valid[idx] = {:path => file, :type => :file}
69
- output << [idx, humanize_path_basename(file)]
70
- idx += 1
71
- end
72
- end
73
- max = idx.to_s.length
74
- output.map! do |o|
75
- if(o.is_a?(Array))
76
- " #{o.first}.#{' ' * (max - o.first.to_s.length)} #{o.last}"
77
- else
78
- o
79
- end
80
- end
81
- ui.info "#{output.join("\n")}\n"
82
- response = ask_question('Enter selection: ').to_i
83
- unless(valid[response])
84
- ui.fatal 'How about using a real value'
85
- exit 1
86
- else
87
- entry = valid[response.to_i]
88
- if(entry[:type] == :directory)
89
- prompt_for_file(entry[:path], opts)
90
- else
91
- "/#{entry[:path]}"
92
- end
93
- end
94
- end
95
- end
96
-
97
- end
98
- end
99
- end
@@ -1,29 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # Helper methods for SSH interactions
7
- module Ssher
8
-
9
- # Retrieve file from remote node
10
- #
11
- # @param address [String]
12
- # @param user [String]
13
- # @param path [String] remote file path
14
- # @param ssh_opts [Hash]
15
- # @return [String, NilClass]
16
- def remote_file_contents(address, user, path, ssh_opts={})
17
- if(path.to_s.strip.empty?)
18
- raise ArgumentError.new 'No file path provided!'
19
- end
20
- require 'net/ssh'
21
- content = ''
22
- ssh_session = Net::SSH.start(address, user, ssh_opts)
23
- content = ssh_session.exec!("sudo cat #{path}")
24
- content.empty? ? nil : content
25
- end
26
-
27
- end
28
- end
29
- end
@@ -1,271 +0,0 @@
1
- require 'chef'
2
- require 'knife-cloudformation'
3
-
4
- module KnifeCloudformation
5
- module Utils
6
-
7
- # Stack serialization helper
8
- class StackExporter
9
-
10
- include KnifeCloudformation::Utils::AnimalStrings
11
- include KnifeCloudformation::Utils::JSON
12
-
13
- # default chef environment name
14
- DEFAULT_CHEF_ENVIRONMENT = '_default'
15
- # default instance options
16
- DEFAULT_OPTIONS = Mash.new(
17
- :chef_popsicle => true,
18
- :ignored_parameters => ['Environment', 'StackCreator', 'Creator'],
19
- :chef_environment_parameter => 'Environment'
20
- )
21
- # default structure of export payload
22
- DEFAULT_EXPORT_STRUCTURE = {
23
- :stack => Mash.new(
24
- :template => nil,
25
- :options => {
26
- :parameters => Mash.new,
27
- :capabilities => [],
28
- :notification_topics => []
29
- }
30
- ),
31
- :generator => {
32
- :timestamp => Time.now.to_i,
33
- :name => 'knife-cloudformation',
34
- :version => KnifeCloudformation::VERSION.version,
35
- :provider => nil
36
- }
37
- }
38
-
39
- # @return [Miasma::Models::Orchestration::Stack]
40
- attr_reader :stack
41
- # @return [Hash]
42
- attr_reader :options
43
- # @return [Hash]
44
- attr_reader :stack_export
45
-
46
- # Create new instance
47
- #
48
- # @param stack [Miasma::Models::Orchestration::Stack]
49
- # @param options [Hash]
50
- # @option options [KnifeCloudformation::Provider] :provider
51
- # @option options [TrueClass, FalseClass] :chef_popsicle freeze run list
52
- # @option options [Array<String>] :ignored_parameters
53
- # @option options [String] :chef_environment_parameter
54
- def initialize(stack, options={})
55
- @stack = stack
56
- @options = DEFAULT_OPTIONS.merge(options)
57
- @stack_export = Mash.new
58
- end
59
-
60
- # Export stack
61
- #
62
- # @return [Hash] exported stack
63
- def export
64
- @stack_export = Mash.new(DEFAULT_EXPORT_STRUCTURE).tap do |stack_export|
65
- [:parameters, :capabilities, :notification_topics].each do |key|
66
- if(val = stack.send(key))
67
- stack_export[:stack][key] = val
68
- end
69
- end
70
- stack_export[:stack][:template] = stack.template
71
- stack_export[:generator][:timestamp] = Time.now.to_i
72
- stack_export[:generator][:provider] = stack.provider.connection.provider
73
- if(chef_popsicle?)
74
- freeze_runlists(stack_export)
75
- end
76
- remove_ignored_parameters(stack_export)
77
- stack_export[:stack][:template] = _to_json(
78
- stack_export[:stack][:template]
79
- )
80
- end
81
- end
82
-
83
- # Provide query methods on options hash
84
- #
85
- # @param args [Object] argument list
86
- # @return [Object]
87
- def method_missing(*args)
88
- m = args.first.to_s
89
- if(m.end_with?('?') && options.has_key?(k = m.sub('?', '').to_sym))
90
- !!options[k]
91
- else
92
- super
93
- end
94
- end
95
-
96
- protected
97
-
98
- # Remove parameter values from export that are configured to be
99
- # ignored
100
- #
101
- # @param export [Hash] stack export
102
- # @return [Hash]
103
- def remove_ignored_parameters(export)
104
- options[:ignored_parameters].each do |param|
105
- if(export[:stack][:options][:parameters])
106
- export[:stack][:options][:parameters].delete(param)
107
- end
108
- end
109
- export
110
- end
111
-
112
- # Environment name to use when interacting with Chef
113
- #
114
- # @param export [Hash] current export state
115
- # @return [String] environment name
116
- def chef_environment_name(export)
117
- if(chef_environment_parameter?)
118
- name = export[:stack][:options][:parameters][options[:chef_environment_parameter]]
119
- end
120
- name || DEFAULT_CHEF_ENVIRONMENT
121
- end
122
-
123
- # @return [Chef::Environment]
124
- def environment
125
- unless(@env)
126
- @env = Chef::Environment.load('_default')
127
- end
128
- @env
129
- end
130
-
131
- # Find latest available cookbook version within
132
- # the configured environment
133
- #
134
- # @param cookbook [String] name of cookbook
135
- # @return [Chef::Version]
136
- def allowed_cookbook_version(cookbook)
137
- restriction = environment.cookbook_versions[cookbook]
138
- requirement = Gem::Requirement.new(restriction)
139
- Chef::CookbookVersion.available_versions(cookbook).detect do |v|
140
- requirement.satisfied_by?(Gem::Version.new(v))
141
- end
142
- end
143
-
144
- # Extract the runlist item. Fully expands roles and provides
145
- # version pegged runlist.
146
- #
147
- # @param item [Chef::RunList::RunListItem, Array<String>]
148
- # @return [Hash] new chef configuration hash
149
- # @note this will expand all roles
150
- def extract_runlist_item(item)
151
- rl_item = item.is_a?(Chef::RunList::RunListItem) ? item : Chef::RunList::RunListItem.new(item)
152
- static_content = Mash.new(:run_list => [])
153
- if(rl_item.recipe?)
154
- cookbook, recipe = rl_item.name.split('::')
155
- peg_version = allowed_cookbook_version(cookbook)
156
- static_content[:run_list] << "recipe[#{[cookbook, recipe || 'default'].join('::')}@#{peg_version}]"
157
- elsif(rl_item.role?)
158
- role = Chef::Role.load(rl_item.name)
159
- role.run_list.each do |item|
160
- static_content = Chef::Mixin::DeepMerge.merge(static_content, extract_runlist_item(item))
161
- end
162
- static_content = Chef::Mixin::DeepMerge.merge(
163
- static_content, Chef::Mixin::DeepMerge.merge(role.default_attributes, role.override_attributes)
164
- )
165
- else
166
- raise TypeError.new("Unknown chef run list item encountered: #{rl_item.inspect}")
167
- end
168
- static_content
169
- end
170
-
171
- # Expand any detected chef run lists and freeze them within the
172
- # stack template
173
- #
174
- # @param first_run [Hash] chef first run hash
175
- # @return [Hash]
176
- def unpack_and_freeze_runlist(first_run)
177
- extracted_runlists = first_run['run_list'].map do |item|
178
- extract_runlist_item(cf_replace(item))
179
- end
180
- first_run.delete('run_list')
181
- first_run.replace(
182
- extracted_runlists.inject(first_run) do |memo, first_run_item|
183
- Chef::Mixin::DeepMerge.merge(memo, first_run_item)
184
- end
185
- )
186
- end
187
-
188
- # Freeze chef run lists
189
- #
190
- # @param exported [Hash] stack export
191
- # @return [Hash]
192
- def freeze_runlists(exported)
193
- first_runs = locate_runlists(exported)
194
- first_runs.each do |first_run|
195
- unpack_and_freeze_runlist(first_run)
196
- end
197
- exported
198
- end
199
-
200
- # Locate chef run lists within data collection
201
- #
202
- # @param thing [Enumerable] collection from export
203
- # @return [Enumerable] updated collection from export
204
- def locate_runlists(thing)
205
- result = []
206
- case thing
207
- when Hash
208
- if(thing['content'] && thing['content']['run_list'])
209
- result << thing['content']
210
- else
211
- thing.each do |k,v|
212
- result += locate_runlists(v)
213
- end
214
- end
215
- when Array
216
- thing.each do |v|
217
- result += locate_runlists(v)
218
- end
219
- end
220
- result
221
- end
222
-
223
- # Apply cloudformation function to data
224
- #
225
- # @param hsh [Object] stack template item
226
- # @return [Object]
227
- def cf_replace(hsh)
228
- if(hsh.is_a?(Hash))
229
- case hsh.keys.first
230
- when 'Fn::Join'
231
- cf_join(*hsh.values.first)
232
- when 'Ref'
233
- cf_ref(hsh.values.first)
234
- else
235
- hsh
236
- end
237
- else
238
- hsh
239
- end
240
- end
241
-
242
- # Apply Ref function
243
- #
244
- # @param ref_name [Hash]
245
- # @return [Object] value in parameters
246
- def cf_ref(ref_name)
247
- if(stack.parameters.has_key?(ref_name))
248
- stack.parameters[ref_name]
249
- else
250
- raise KeyError.new("No parameter found with given reference name (#{ref_name}). " <<
251
- "Only parameter based references supported!")
252
- end
253
- end
254
-
255
- # Apply Join function
256
- #
257
- # @param delim [String] join delimiter
258
- # @param args [String, Hash] items to join
259
- # @return [String]
260
- def cf_join(delim, args)
261
- args.map do |arg|
262
- if(arg.is_a?(Hash))
263
- cf_replace(arg)
264
- else
265
- arg.to_s
266
- end
267
- end.join(delim)
268
- end
269
- end
270
- end
271
- end
@@ -1,37 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
- # Helper for scrubbing stack parameters
6
- class StackParameterScrubber
7
-
8
- class << self
9
-
10
- # Validate attributes within Parameter blocks
11
- ALLOWED_PARAMETER_ATTRIBUTES = %w(
12
- Type Default NoEcho AllowedValues AllowedPattern
13
- MaxLength MinLength MaxValue MinValue Description
14
- ConstraintDescription
15
- )
16
-
17
- # Clean the parameters of the template
18
- #
19
- # @param template [Hash]
20
- # @return [Hash] template
21
- def scrub!(template)
22
- parameters = template['Parameters']
23
- if(parameters)
24
- parameters.each do |name, options|
25
- options.delete_if do |attribute, value|
26
- !ALLOWED_PARAMETER_ATTRIBUTES.include?(attribute)
27
- end
28
- end
29
- template['Parameters'] = parameters
30
- end
31
- template
32
- end
33
-
34
- end
35
- end
36
- end
37
- end
@@ -1,124 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # Helper utility for validating stack parameters
7
- class StackParameterValidator
8
- class << self
9
-
10
- include KnifeCloudformation::Utils::AnimalStrings
11
-
12
- # Validate a parameters
13
- #
14
- # @param value [Object] value for parameter
15
- # @param parameter_definition [Hash]
16
- # @option parameter_definition [Array<String>] 'AllowedValues'
17
- # @option parameter_definition [String] 'AllowedPattern'
18
- # @option parameter_definition [String, Integer] 'MaxLength'
19
- # @option parameter_definition [String, Integer] 'MinLength'
20
- # @option parameter_definition [String, Integer] 'MaxValue'
21
- # @option parameter_definition [String, Integer] 'MinValue'
22
- # @return [TrueClass, Array<String>] true if valid. array of string errors if invalid
23
- def validate(value, parameter_definition)
24
- return [[:blank, 'Value cannot be blank']] if value.to_s.strip.empty?
25
- result = %w(AllowedValues AllowedPattern MaxLength MinLength MaxValue MinValue).map do |key|
26
- if(parameter_definition[key])
27
- res = self.send(snake(key), value, parameter_definition)
28
- res == true ? true : [snake(key), res]
29
- else
30
- true
31
- end
32
- end
33
- result.delete_if{|x| x == true}
34
- result.empty? ? true : result
35
- end
36
-
37
- # Parameter is within allowed values
38
- #
39
- # @param value [String]
40
- # @param pdef [Hash] parameter definition
41
- # @option pdef [Array<String>] 'AllowedValues'
42
- # @return [TrueClass, String]
43
- def allowed_values(value, pdef)
44
- if(pdef['AllowedValues'].include?(value))
45
- true
46
- else
47
- "Not an allowed value: #{pdef['AllowedValues'].join(', ')}"
48
- end
49
- end
50
-
51
- # Parameter matches allowed pattern
52
- #
53
- # @param value [String]
54
- # @param pdef [Hash] parameter definition
55
- # @option pdef [String] 'AllowedPattern'
56
- # @return [TrueClass, String]
57
- def allowed_pattern(value, pdef)
58
- if(value.match(/#{pdef['AllowedPattern']}/))
59
- true
60
- else
61
- "Not a valid pattern. Must match: #{pdef['AllowedPattern']}"
62
- end
63
- end
64
-
65
- # Parameter length is less than or equal to max length
66
- #
67
- # @param value [String, Integer]
68
- # @param pdef [Hash] parameter definition
69
- # @option pdef [String] 'MaxLength'
70
- # @return [TrueClass, String]
71
- def max_length(value, pdef)
72
- if(value.length <= pdef['MaxLength'].to_i)
73
- true
74
- else
75
- "Value must not exceed #{pdef['MaxLength']} characters"
76
- end
77
- end
78
-
79
- # Parameter length is greater than or equal to min length
80
- #
81
- # @param value [String]
82
- # @param pdef [Hash] parameter definition
83
- # @option pdef [String] 'MinLength'
84
- # @return [TrueClass, String]
85
- def min_length(value, pdef)
86
- if(value.length >= pdef['MinLength'].to_i)
87
- true
88
- else
89
- "Value must be at least #{pdef['MinLength']} characters"
90
- end
91
- end
92
-
93
- # Parameter value is less than or equal to max value
94
- #
95
- # @param value [String]
96
- # @param pdef [Hash] parameter definition
97
- # @option pdef [String] 'MaxValue'
98
- # @return [TrueClass, String]
99
- def max_value(value, pdef)
100
- if(value.to_i <= pdef['MaxValue'].to_i)
101
- true
102
- else
103
- "Value must not be greater than #{pdef['MaxValue']}"
104
- end
105
- end
106
-
107
- # Parameter value is greater than or equal to min value
108
- #
109
- # @param value [String]
110
- # @param pdef [Hash] parameter definition
111
- # @option pdef [String] 'MinValue'
112
- # @return [TrueClass, String]
113
- def min_value(value, pdef)
114
- if(value.to_i >= pdef['MinValue'].to_i)
115
- true
116
- else
117
- "Value must not be less than #{pdef['MinValue']}"
118
- end
119
- end
120
-
121
- end
122
- end
123
- end
124
- end