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.
- 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,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
|