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