knife-cloudformation 0.1.22 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +56 -2
  4. data/knife-cloudformation.gemspec +4 -7
  5. data/lib/chef/knife/cloudformation_create.rb +105 -245
  6. data/lib/chef/knife/cloudformation_describe.rb +50 -26
  7. data/lib/chef/knife/cloudformation_destroy.rb +17 -18
  8. data/lib/chef/knife/cloudformation_events.rb +48 -14
  9. data/lib/chef/knife/cloudformation_export.rb +117 -34
  10. data/lib/chef/knife/cloudformation_import.rb +124 -18
  11. data/lib/chef/knife/cloudformation_inspect.rb +159 -71
  12. data/lib/chef/knife/cloudformation_list.rb +20 -24
  13. data/lib/chef/knife/cloudformation_promote.rb +40 -0
  14. data/lib/chef/knife/cloudformation_update.rb +132 -15
  15. data/lib/chef/knife/cloudformation_validate.rb +35 -0
  16. data/lib/knife-cloudformation.rb +28 -0
  17. data/lib/knife-cloudformation/cache.rb +213 -35
  18. data/lib/knife-cloudformation/knife.rb +9 -0
  19. data/lib/knife-cloudformation/knife/base.rb +179 -0
  20. data/lib/knife-cloudformation/knife/stack.rb +94 -0
  21. data/lib/knife-cloudformation/knife/template.rb +174 -0
  22. data/lib/knife-cloudformation/monkey_patch.rb +8 -0
  23. data/lib/knife-cloudformation/monkey_patch/stack.rb +195 -0
  24. data/lib/knife-cloudformation/provider.rb +225 -0
  25. data/lib/knife-cloudformation/utils.rb +18 -98
  26. data/lib/knife-cloudformation/utils/animal_strings.rb +28 -0
  27. data/lib/knife-cloudformation/utils/debug.rb +31 -0
  28. data/lib/knife-cloudformation/utils/json.rb +64 -0
  29. data/lib/knife-cloudformation/utils/object_storage.rb +28 -0
  30. data/lib/knife-cloudformation/utils/output.rb +79 -0
  31. data/lib/knife-cloudformation/utils/path_selector.rb +99 -0
  32. data/lib/knife-cloudformation/utils/ssher.rb +29 -0
  33. data/lib/knife-cloudformation/utils/stack_exporter.rb +271 -0
  34. data/lib/knife-cloudformation/utils/stack_parameter_scrubber.rb +35 -0
  35. data/lib/knife-cloudformation/utils/stack_parameter_validator.rb +124 -0
  36. data/lib/knife-cloudformation/version.rb +2 -4
  37. metadata +47 -94
  38. data/Gemfile +0 -3
  39. data/Gemfile.lock +0 -90
  40. data/knife-cloudformation-0.1.20.gem +0 -0
  41. data/lib/knife-cloudformation/aws_commons.rb +0 -267
  42. data/lib/knife-cloudformation/aws_commons/stack.rb +0 -435
  43. data/lib/knife-cloudformation/aws_commons/stack_parameter_validator.rb +0 -79
  44. data/lib/knife-cloudformation/cloudformation_base.rb +0 -168
  45. data/lib/knife-cloudformation/export.rb +0 -174
@@ -1,79 +0,0 @@
1
- require 'knife-cloudformation/aws_commons/stack'
2
-
3
- module KnifeCloudformation
4
- class AwsCommons
5
-
6
- class Stack
7
-
8
- class ParameterValidator
9
- class << self
10
-
11
- include KnifeCloudformation::Utils::AnimalStrings
12
-
13
- def validate(value, parameter_definition)
14
- return [[:blank, 'Value cannot be blank']] if value.to_s.strip.empty?
15
- result = %w(AllowedValues AllowedPattern MaxLength MinLength MaxValue MinValue).map do |key|
16
- if(parameter_definition[key])
17
- res = self.send(snake(key), value, parameter_definition)
18
- res == true ? true : [snake(key), res]
19
- else
20
- true
21
- end
22
- end
23
- result.delete_if{|x| x == true}
24
- result.empty? ? true : result
25
- end
26
-
27
- def allowed_values(value, pdef)
28
- if(pdef['AllowedValues'].include?(value))
29
- true
30
- else
31
- "Not an allowed value: #{pdef['AllowedValues'].join(', ')}"
32
- end
33
- end
34
-
35
- def allowed_pattern(value, pdef)
36
- if(value.match(/#{pdef['AllowedPattern']}/))
37
- true
38
- else
39
- "Not a valid pattern. Must match: #{pdef['AllowedPattern']}"
40
- end
41
- end
42
-
43
- def max_length(value, pdef)
44
- if(value.length <= pdef['MaxLength'].to_i)
45
- true
46
- else
47
- "Value must not exceed #{pdef['MaxLength']} characters"
48
- end
49
- end
50
-
51
- def min_length(value, pdef)
52
- if(value.length >= pdef['MinLength'].to_i)
53
- true
54
- else
55
- "Value must be at least #{pdef['MinLength']} characters"
56
- end
57
- end
58
-
59
- def max_value(value, pdef)
60
- if(value.to_i <= pdef['MaxValue'].to_i)
61
- true
62
- else
63
- "Value must not be greater than #{pdef['MaxValue']}"
64
- end
65
- end
66
-
67
- def min_value(value, pdef)
68
- if(value.to_i >= pdef['MinValue'].to_i)
69
- true
70
- else
71
- "Value must not be less than #{pdef['MinValue']}"
72
- end
73
- end
74
-
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,168 +0,0 @@
1
- require 'chef/knife'
2
- require 'knife-cloudformation/utils'
3
- require 'knife-cloudformation/aws_commons'
4
-
5
- module KnifeCloudformation
6
-
7
- module KnifeBase
8
-
9
- module InstanceMethods
10
-
11
- def aws
12
- self.class.con(ui)
13
- end
14
-
15
- def _debug(e, *args)
16
- if(ENV['DEBUG'])
17
- ui.fatal "Exception information: #{e.class}: #{e}\n#{e.backtrace.join("\n")}\n"
18
- args.each do |string|
19
- ui.fatal string
20
- end
21
- end
22
- end
23
-
24
- def stack(name)
25
- self.class.con(ui).stack(name, :ignore_seeds)
26
- end
27
-
28
- def allowed_attributes
29
- Chef::Config[:knife][:cloudformation][:attributes] || default_attributes
30
- end
31
-
32
- def default_attributes
33
- %w(Timestamp StackName StackId)
34
- end
35
-
36
- def attribute_allowed?(attr)
37
- config[:all_attributes] || allowed_attributes.include?(attr)
38
- end
39
-
40
- def poll_stack(name)
41
- knife_events = Chef::Knife::CloudformationEvents.new
42
- knife_events.name_args.push(name)
43
- Chef::Config[:knife][:cloudformation][:poll] = true
44
- knife_events.run
45
- end
46
-
47
- def things_output(stack, things, what, *args)
48
- unless(args.include?(:no_title))
49
- output = aws.get_titles(things, :format => true, :attributes => allowed_attributes)
50
- else
51
- output = []
52
- end
53
- columns = allowed_attributes.size
54
- output += aws.process(things, :flat => true, :attributes => allowed_attributes)
55
- output.compact.flatten
56
- if(output.empty?)
57
- ui.warn 'No information found' unless args.include?(:ignore_empty_output)
58
- else
59
- ui.info "#{what.to_s.capitalize} for stack: #{ui.color(stack, :bold)}" if stack
60
- ui.info "#{ui.list(output, :uneven_columns_across, columns)}"
61
- end
62
- end
63
-
64
- def get_things(stack=nil, message=nil)
65
- begin
66
- yield
67
- rescue => e
68
- ui.fatal "#{message || 'Failed to retrieve information'}#{" for requested stack: #{stack}" if stack}"
69
- ui.fatal "Reason: #{e}"
70
- _debug(e)
71
- exit 1
72
- end
73
- end
74
-
75
- end
76
-
77
- module ClassMethods
78
-
79
- def con(ui=nil)
80
- unless(@common)
81
- @common = KnifeCloudformation::AwsCommons.new(
82
- :ui => ui,
83
- :fog => {
84
- :aws_access_key_id => _key,
85
- :aws_secret_access_key => _secret,
86
- :region => _region
87
- }
88
- )
89
- end
90
- @common
91
- end
92
-
93
- def _key
94
- Chef::Config[:knife][:cloudformation][:credentials][:key] ||
95
- Chef::Config[:knife][:aws_access_key_id]
96
- end
97
-
98
- def _secret
99
- Chef::Config[:knife][:cloudformation][:credentials][:secret] ||
100
- Chef::Config[:knife][:aws_secret_access_key]
101
- end
102
-
103
- def _region
104
- Chef::Config[:knife][:cloudformation][:credentials][:region] ||
105
- Chef::Config[:knife][:region]
106
- end
107
-
108
- end
109
-
110
- class << self
111
- def included(klass)
112
- klass.instance_eval do
113
-
114
- extend KnifeCloudformation::KnifeBase::ClassMethods
115
- include KnifeCloudformation::KnifeBase::InstanceMethods
116
- include KnifeCloudformation::Utils::JSON
117
- include KnifeCloudformation::Utils::AnimalStrings
118
-
119
- deps do
120
- require 'fog'
121
- Chef::Config[:knife][:cloudformation] ||= Mash.new
122
- Chef::Config[:knife][:cloudformation][:credentials] ||= Mash.new
123
- Chef::Config[:knife][:cloudformation][:options] ||= Mash.new
124
- end
125
-
126
- option(:key,
127
- :short => '-K KEY',
128
- :long => '--key KEY',
129
- :description => 'AWS access key id',
130
- :proc => lambda {|val|
131
- Chef::Config[:knife][:cloudformation][:credentials][:key] = val
132
- }
133
- )
134
- option(:secret,
135
- :short => '-S SECRET',
136
- :long => '--secret SECRET',
137
- :description => 'AWS secret access key',
138
- :proc => lambda {|val|
139
- Chef::Config[:knife][:cloudformation][:credentials][:secret] = val
140
- }
141
- )
142
- option(:region,
143
- :short => '-r REGION',
144
- :long => '--region REGION',
145
- :description => 'AWS region',
146
- :proc => lambda {|val|
147
- Chef::Config[:knife][:cloudformation][:credentials][:region] = val
148
- }
149
- )
150
-
151
-
152
- # Populate up the hashes so they are available for knife config
153
- # with issues of nils
154
- ['knife.cloudformation.credentials', 'knife.cloudformation.options'].each do |stack|
155
- stack.split('.').inject(Chef::Config) do |memo, item|
156
- memo[item.to_sym] = Mash.new unless memo[item.to_sym]
157
- memo[item.to_sym]
158
- end
159
- end
160
-
161
- Chef::Config[:knife][:cloudformation] ||= Mash.new
162
-
163
- end
164
- end
165
- end
166
- end
167
-
168
- end
@@ -1,174 +0,0 @@
1
- require 'knife-cloudformation/aws_commons'
2
- require 'chef'
3
-
4
- module KnifeCloudformation
5
- class Export
6
-
7
- DEFAULT_OPTIONS = {
8
- :chef_popsicle => true,
9
- :ignored_parameters => ['Environment', 'StackCreator'],
10
- :chef_environment_parameter => 'Environment',
11
- :aws_commons => nil
12
- }
13
-
14
- attr_reader :stack, :stack_name, :stack_id, :options, :aws_commons
15
-
16
- def initialize(stack_name, options={})
17
- @stack_name = stack_name
18
- @options = DEFAULT_OPTIONS.merge(options)
19
- if(aws_commons?)
20
- @aws_commons = options[:aws_commons]
21
- else
22
- raise ArgumentError.new('Expecting `AwsCommons` instance but none provided!')
23
- end
24
- load_stack
25
- end
26
-
27
- def export
28
- exported = stack.to_hash
29
- if(chef_popsicle?)
30
- freeze_runlists(exported)
31
- end
32
- remove_ignored_parameters(exported)
33
- exported
34
- end
35
-
36
- def method_missing(*args)
37
- m = args.first.to_s
38
- if(m.end_with?('?') && options.has_key?(k = m.sub('?', '').to_sym))
39
- !!options[k]
40
- else
41
- super
42
- end
43
- end
44
-
45
- protected
46
-
47
- def remove_ignored_parameters(export)
48
- options[:ignored_parameters].each do |param|
49
- export[:parameters].delete(param)
50
- end
51
- end
52
-
53
- def chef_environment_name
54
- if(chef_environment_parameter?)
55
- name = stack[:parameters][options[:chef_environment_parameter]]
56
- end
57
- name || '_default'
58
- end
59
-
60
- def environment
61
- unless(@env)
62
- @env = Chef::Environment.load('imdev')
63
- end
64
- @env
65
- end
66
-
67
- def load_stack
68
- @stack = AwsCommons::Stack.new(stack_name, aws_commons)
69
- @stack_id = @stack.stack_id
70
- @stack
71
- end
72
-
73
- def allowed_cookbook_version(cookbook)
74
- restriction = environment.cookbook_versions[cookbook]
75
- requirement = Gem::Requirement.new(restriction)
76
- Chef::CookbookVersion.available_versions(cookbook).detect do |v|
77
- requirement.satisfied_by?(Gem::Version.new(v))
78
- end
79
- end
80
-
81
- def extract_runlist_item(item)
82
- rl_item = item.is_a?(Chef::RunList::RunListItem) ? item : Chef::RunList::RunListItem.new(item)
83
- static_content = Mash.new(:run_list => [])
84
- if(rl_item.recipe?)
85
- cookbook, recipe = rl_item.name.split('::')
86
- peg_version = allowed_cookbook_version(cookbook)
87
- static_content[:run_list] << "recipe[#{[cookbook, recipe || 'default'].join('::')}@#{peg_version}]"
88
- elsif(rl_item.role?)
89
- role = Chef::Role.load(rl_item.name)
90
- role.run_list.each do |item|
91
- static_content = Chef::Mixin::DeepMerge.merge(static_content, extract_runlist_item(item))
92
- end
93
- static_content = Chef::Mixin::DeepMerge.merge(
94
- static_content, Chef::Mixin::DeepMerge.merge(role.default_attributes, role.override_attributes)
95
- )
96
- else
97
- # dunno what this is
98
- end
99
- static_content
100
- end
101
-
102
- def unpack_and_freeze_runlist(first_run)
103
- extracted_runlists = first_run['run_list'].map do |item|
104
- extract_runlist_item(cf_replace(item))
105
- end
106
- first_run.delete('run_list')
107
- first_run.replace(
108
- extracted_runlists.inject(first_run) do |memo, first_run_item|
109
- Chef::Mixin::DeepMerge.merge(memo, first_run_item)
110
- end
111
- )
112
- end
113
-
114
- def freeze_runlists(exported)
115
- first_runs = locate_runlists(exported)
116
- first_runs.each do |first_run|
117
- unpack_and_freeze_runlist(first_run)
118
- end
119
- end
120
-
121
- def locate_runlists(thing)
122
- result = []
123
- case thing
124
- when Hash
125
- if(thing['content'] && thing['content']['run_list'])
126
- result << thing['content']
127
- else
128
- thing.each do |k,v|
129
- result += locate_runlists(v)
130
- end
131
- end
132
- when Array
133
- thing.each do |v|
134
- result += locate_runlists(v)
135
- end
136
- end
137
- result
138
- end
139
-
140
- def cf_replace(hsh)
141
- if(hsh.is_a?(Hash))
142
- case hsh.keys.first
143
- when 'Fn::Join'
144
- cf_join(*hsh.values.first)
145
- when 'Ref'
146
- cf_ref(hsh.values.first)
147
- else
148
- hsh
149
- end
150
- else
151
- hsh
152
- end
153
- end
154
-
155
- def cf_ref(ref_name)
156
- if(stack.parameters.has_key?(ref_name))
157
- stack.parameters[ref_name]
158
- else
159
- raise KeyError.new("No parameter found with given reference name (#{ref_name}). " <<
160
- "Only parameter based references supported!")
161
- end
162
- end
163
-
164
- def cf_join(delim, args)
165
- args.map do |arg|
166
- if(arg.is_a?(Hash))
167
- cf_replace(arg)
168
- else
169
- arg.to_s
170
- end
171
- end.join(delim)
172
- end
173
- end
174
- end