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.
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,225 +0,0 @@
1
- require 'chef/mash'
2
- require 'logger'
3
- require 'chef/mixin/deep_merge'
4
- require 'knife-cloudformation'
5
-
6
- module KnifeCloudformation
7
- # Remote provider interface
8
- class Provider
9
-
10
- include KnifeCloudformation::Utils::AnimalStrings
11
-
12
- # Minimum number of seconds to wait before re-expanding in
13
- # progress stack
14
- STACK_EXPAND_INTERVAL = 45
15
-
16
- # Default interval for refreshing stack list in cache
17
- STACK_LIST_INTERVAL = 120
18
-
19
- # @return [Miasma::Models::Orchestration]
20
- attr_reader :connection
21
- # @return [Cache]
22
- attr_reader :cache
23
- # @return [Thread, NilClass] stack list updater
24
- attr_accessor :updater
25
- # @return [TrueClass, FalseClass] async updates
26
- attr_reader :async
27
- # @return [Logger, NilClass] logger in use
28
- attr_reader :logger
29
- # @return [Numeric] interval between stack expansions
30
- attr_reader :stack_expansion_interval
31
- # @return [Numeric] interval between stack list updates
32
- attr_reader :stack_list_interval
33
-
34
- # Create new instance
35
- #
36
- # @param args [Hash]
37
- # @option args [Hash] :miasma miasma connection hash
38
- # @option args [Cache] :cache
39
- # @option args [TrueClass, FalseClass] :async fetch stacks async (defaults true)
40
- # @option args [Logger] :logger use custom logger
41
- # @option args [Numeric] :stack_expansion_interval interval to wait between stack data expands
42
- # @option args [Numeric] :stack_list_interval interval to wait between stack list refresh
43
- def initialize(args={})
44
- unless(args[:miasma][:provider])
45
- best_guess = args[:miasma].keys.group_by do |key|
46
- key.to_s.split('_').first
47
- end.sort do |x, y|
48
- y.size <=> x.size
49
- end.first
50
- if(best_guess)
51
- provider = best_guess.first.to_sym
52
- else
53
- raise ArgumentError.new 'Cannot auto determine :provider value for credentials'
54
- end
55
- else
56
- provider = args[:miasma].delete(:provider).to_sym
57
- end
58
- if(provider == :aws)
59
- if(args[:miasma][:region])
60
- args[:miasma][:aws_region] = args[:miasma].delete(:region)
61
- end
62
- end
63
- if(ENV['DEBUG'].to_s.downcase == 'true')
64
- log_to = STDOUT
65
- else
66
- if(Gem.win_platform?)
67
- log_to = 'NUL'
68
- else
69
- log_to = '/dev/null'
70
- end
71
- end
72
- @logger = args.fetch(:logger, Logger.new(log_to))
73
- @stack_expansion_interval = args.fetch(:stack_expansion_interval, STACK_EXPAND_INTERVAL)
74
- @stack_list_interval = args.fetch(:stack_list_interval, STACK_LIST_INTERVAL)
75
- @connection = Miasma.api(
76
- :provider => provider,
77
- :type => :orchestration,
78
- :credentials => args[:miasma]
79
- )
80
- @cache = args.fetch(:cache, Cache.new(:local))
81
- @async = args.fetch(:async, true)
82
- @miamsa_args = args[:miasma].dup
83
- cache.init(:stacks_lock, :lock, :timeout => 0.1)
84
- cache.init(:stacks, :stamped)
85
- cache.init(:stack_expansion_lock, :lock, :timeout => 0.1)
86
- if(args.fetch(:fetch, false))
87
- async ? update_stack_list! : fetch_stacks
88
- end
89
- end
90
-
91
- # @return [Miasma::Orchestration::Stacks]
92
- def stacks
93
- connection.stacks.from_json(cached_stacks)
94
- end
95
-
96
- # @return [String] json representation of cached stacks
97
- def cached_stacks
98
- fetch_stacks unless @initial_fetch_complete
99
- value = cache[:stacks].value
100
- value ? MultiJson.dump(MultiJson.load(value).values) : '[]'
101
- end
102
-
103
- # @return [Miasma::Orchestration::Stack, NilClass]
104
- def stack(stack_id)
105
- stacks.get(stack_id)
106
- end
107
-
108
- # Store stack attribute changes
109
- #
110
- # @param stack_id [String]
111
- # @param stack_attributes [Hash]
112
- # @return [TrueClass]
113
- def save_expanded_stack(stack_id, stack_attributes)
114
- current_stacks = MultiJson.load(cached_stacks)
115
- cache.locked_action(:stacks_lock) do
116
- logger.info "Saving expanded stack attributes in cache (#{stack_id})"
117
- current_stacks[stack_id] = stack_attributes.merge('Cached' => Time.now.to_i)
118
- cache[:stacks].value = MultiJson.dump(current_stacks)
119
- end
120
- true
121
- end
122
-
123
- # Remove stack from the cache
124
- #
125
- # @param stack_id [String]
126
- # @return [TrueClass, FalseClass]
127
- def remove_stack(stack_id)
128
- current_stacks = MultiJson.load(cached_stacks)
129
- logger.info "Attempting to remove stack from internal cache (#{stack_id})"
130
- cache.locked_action(:stacks_lock) do
131
- val = current_stacks.delete(stack_id)
132
- logger.info "Successfully removed stack from internal cache (#{stack_id})"
133
- cache[:stacks].value = MultiJson.dump(current_stacks)
134
- !!val
135
- end
136
- end
137
-
138
- # Expand all lazy loaded attributes within stack
139
- #
140
- # @param stack [Miasma::Models::Orchestration::Stack]
141
- def expand_stack(stack)
142
- logger.info "Stack expansion requested (#{stack.id})"
143
- if((stack.in_progress? && Time.now.to_i - stack.attributes['Cached'].to_i > stack_expansion_interval) ||
144
- !stack.attributes['Cached'])
145
- begin
146
- expanded = false
147
- cache.locked_action(:stack_expansion_lock) do
148
- expanded = true
149
- stack.reload
150
- stack.data['Cached'] = Time.now.to_i
151
- end
152
- if(expanded)
153
- save_expanded_stack(stack.id, stack.to_json)
154
- end
155
- rescue => e
156
- logger.error "Stack expansion failed (#{stack.id}) - #{e.class}: #{e}"
157
- end
158
- else
159
- logger.info "Stack has been cached within expand interval. Expansion prevented. (#{stack.id})"
160
- end
161
- end
162
-
163
- # Request stack information and store in cache
164
- #
165
- # @return [TrueClass]
166
- def fetch_stacks
167
- cache.locked_action(:stacks_lock) do
168
- logger.info "Lock aquired for stack update. Requesting stacks from upstream. (#{Thread.current})"
169
- stacks = Hash[
170
- connection.stacks.reload.all.map do |stack|
171
- [stack.id, stack.attributes]
172
- end
173
- ]
174
- if(cache[:stacks].value)
175
- existing_stacks = MultiJson.load(cache[:stacks].value)
176
- # Force common types
177
- stacks = MultiJson.load(MultiJson.dump(stacks))
178
- # Remove stacks that have been deleted
179
- stale_ids = existing_stacks.keys - stacks.keys
180
- stacks = Chef::Mixin::DeepMerge.merge(existing_stacks, stacks)
181
- stale_ids.each do |stale_id|
182
- stacks.delete(stale_id)
183
- end
184
- end
185
- cache[:stacks].value = stacks.to_json
186
- logger.info 'Stack list has been updated from upstream and cached locally'
187
- end
188
- @initial_fetch_complete = true
189
- end
190
-
191
- # Start async stack list update. Creates thread that loops every
192
- # `self.stack_list_interval` seconds and refreshes stack list in cache
193
- #
194
- # @return [TrueClass, FalseClass]
195
- def update_stack_list!
196
- if(updater.nil? || !updater.alive?)
197
- self.updater = Thread.new{
198
- loop do
199
- begin
200
- fetch_stacks
201
- sleep(stack_list_interval)
202
- rescue => e
203
- logger.error "Failure encountered on stack fetch: #{e.class} - #{e}"
204
- end
205
- end
206
- }
207
- true
208
- else
209
- false
210
- end
211
- end
212
-
213
- # Build API connection for service type
214
- #
215
- # @param service [String, Symbol]
216
- # @return [Miasma::Model]
217
- def service_for(service)
218
- connection.api_for(service)
219
- end
220
-
221
- end
222
- end
223
-
224
- # Release the monkeys!
225
- KnifeCloudformation::MonkeyPatch::Stack
@@ -1,24 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- # Utility classes and modules
5
- module Utils
6
-
7
- autoload :Output, 'knife-cloudformation/utils/output'
8
- autoload :StackParameterValidator, 'knife-cloudformation/utils/stack_parameter_validator'
9
- autoload :StackParameterScrubber, 'knife-cloudformation/utils/stack_parameter_scrubber'
10
- autoload :StackExporter, 'knife-cloudformation/utils/stack_exporter'
11
- autoload :Debug, 'knife-cloudformation/utils/debug'
12
- autoload :JSON, 'knife-cloudformation/utils/json'
13
- autoload :AnimalStrings, 'knife-cloudformation/utils/animal_strings'
14
- autoload :Ssher, 'knife-cloudformation/utils/ssher'
15
- autoload :ObjectStorage, 'knife-cloudformation/utils/object_storage'
16
- autoload :PathSelector, 'knife-cloudformation/utils/path_selector'
17
-
18
- # Provide methods directly from module for previous version compatibility
19
- extend JSON
20
- extend AnimalStrings
21
- extend ObjectStorage
22
-
23
- end
24
- end
@@ -1,28 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # Helper methods for string format modification
7
- module AnimalStrings
8
-
9
- # Camel case string
10
- #
11
- # @param string [String]
12
- # @return [String]
13
- def camel(string)
14
- string.to_s.split('_').map{|k| "#{k.slice(0,1).upcase}#{k.slice(1,k.length)}"}.join
15
- end
16
-
17
- # Snake case string
18
- #
19
- # @param string [String]
20
- # @return [Symbol]
21
- def snake(string)
22
- string.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
23
- end
24
-
25
- end
26
-
27
- end
28
- end
@@ -1,31 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
- # Debug helpers
6
- module Debug
7
- # Output helpers
8
- module Output
9
- # Write debug message
10
- #
11
- # @param msg [String]
12
- def debug(msg)
13
- puts "<KnifeCloudformation>: #{msg}" if ENV['DEBUG']
14
- end
15
- end
16
-
17
- class << self
18
- # Load module into class
19
- #
20
- # @param klass [Class]
21
- def included(klass)
22
- klass.class_eval do
23
- include Output
24
- extend Output
25
- end
26
- end
27
- end
28
- end
29
-
30
- end
31
- end
@@ -1,64 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # JSON helper methods
7
- module JSON
8
-
9
- # Attempt to load chef JSON compat helper
10
- #
11
- # @return [TrueClass, FalseClass] chef compat helper available
12
- def try_json_compat
13
- unless(@_json_loaded)
14
- begin
15
- require 'chef/json_compat'
16
- rescue
17
- require "#{ENV['RUBY_JSON_LIB'] || 'json'}"
18
- end
19
- @_json_loaded = true
20
- end
21
- defined?(Chef::JSONCompat)
22
- end
23
-
24
- # Convert to JSON
25
- #
26
- # @param thing [Object]
27
- # @return [String]
28
- def _to_json(thing)
29
- if(try_json_compat)
30
- Chef::JSONCompat.to_json(thing)
31
- else
32
- JSON.dump(thing)
33
- end
34
- end
35
-
36
- # Load JSON data
37
- #
38
- # @param thing [String]
39
- # @return [Object]
40
- def _from_json(thing)
41
- if(try_json_compat)
42
- Chef::JSONCompat.from_json(thing)
43
- else
44
- JSON.read(thing)
45
- end
46
- end
47
-
48
- # Format object into pretty JSON
49
- #
50
- # @param thing [Object]
51
- # @return [String]
52
- def _format_json(thing)
53
- thing = _from_json(thing) if thing.is_a?(String)
54
- if(try_json_compat)
55
- Chef::JSONCompat.to_json_pretty(thing)
56
- else
57
- JSON.pretty_generate(thing)
58
- end
59
- end
60
-
61
- end
62
-
63
- end
64
- end
@@ -1,28 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
-
6
- # Storage helpers
7
- module ObjectStorage
8
-
9
- # Write to file
10
- #
11
- # @param object [Object]
12
- # @param path [String] path to write object
13
- # @param directory [Miasma::Models::Storage::Directory]
14
- # @return [String] file path
15
- def file_store(object, path, directory)
16
- raise NotImplementedError.new 'Internal updated required! :('
17
- content = object.is_a?(String) ? object : Utils._format_json(object)
18
- directory.files.create(
19
- :identity => path,
20
- :body => content
21
- )
22
- loc = directory.service.service.name.split('::').last.downcase
23
- "#{loc}://#{directory.identity}/#{path}"
24
- end
25
-
26
- end
27
- end
28
- end
@@ -1,79 +0,0 @@
1
- require 'knife-cloudformation'
2
-
3
- module KnifeCloudformation
4
- module Utils
5
- # Output Helpers
6
- module Output
7
-
8
- # Process things and return items
9
- #
10
- # @param things [Array] items to process
11
- # @param args [Hash] options
12
- # @option args [TrueClass, FalseClass] :flat flatten result array
13
- # @option args [Array] :attributes attributes to extract
14
- # @todo this was extracted from events and needs to be cleaned up
15
- def process(things, args={})
16
- @event_ids ||= []
17
- processed = things.reverse.map do |thing|
18
- next if @event_ids.include?(thing['id'])
19
- @event_ids.push(thing['id']).compact!
20
- if(args[:attributes])
21
- args[:attributes].map do |key|
22
- thing[key].to_s
23
- end
24
- else
25
- thing.values
26
- end
27
- end
28
- args[:flat] ? processed.flatten : processed
29
- end
30
-
31
- # Generate formatted titles
32
- #
33
- # @param thing [Object] thing being processed
34
- # @param args [Hash]
35
- # @option args [Array] :attributes
36
- # @return [Array<String>] formatted titles
37
- def get_titles(thing, args={})
38
- attrs = args[:attributes] || []
39
- if(attrs.empty?)
40
- hash = thing.is_a?(Array) ? thing.first : thing
41
- hash ||= {}
42
- attrs = hash.keys
43
- end
44
- titles = attrs.map do |key|
45
- camel(key).gsub(/([a-z])([A-Z])/, '\1 \2')
46
- end.compact
47
- if(args[:format])
48
- titles.map{|s| @ui.color(s, :bold)}
49
- else
50
- titles
51
- end
52
- end
53
-
54
- # Output stack related things in nice format
55
- #
56
- # @param stack [String] name of stack
57
- # @param things [Array] things to display
58
- # @param what [String] description of things for output
59
- # @param args [Symbol] options (:ignore_empty_output)
60
- def things_output(stack, things, what, *args)
61
- unless(args.include?(:no_title))
62
- output = get_titles(things, :format => true, :attributes => allowed_attributes)
63
- else
64
- output = []
65
- end
66
- columns = allowed_attributes.size
67
- output += process(things, :flat => true, :attributes => allowed_attributes)
68
- output.compact!
69
- if(output.empty?)
70
- ui.warn 'No information found' unless args.include?(:ignore_empty_output)
71
- else
72
- ui.info "#{what.to_s.capitalize} for stack: #{ui.color(stack, :bold)}" if stack
73
- ui.info "#{ui.list(output, :uneven_columns_across, columns)}"
74
- end
75
- end
76
-
77
- end
78
- end
79
- end