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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/README.md +56 -2
- data/knife-cloudformation.gemspec +4 -7
- data/lib/chef/knife/cloudformation_create.rb +105 -245
- data/lib/chef/knife/cloudformation_describe.rb +50 -26
- data/lib/chef/knife/cloudformation_destroy.rb +17 -18
- data/lib/chef/knife/cloudformation_events.rb +48 -14
- data/lib/chef/knife/cloudformation_export.rb +117 -34
- data/lib/chef/knife/cloudformation_import.rb +124 -18
- data/lib/chef/knife/cloudformation_inspect.rb +159 -71
- data/lib/chef/knife/cloudformation_list.rb +20 -24
- data/lib/chef/knife/cloudformation_promote.rb +40 -0
- data/lib/chef/knife/cloudformation_update.rb +132 -15
- data/lib/chef/knife/cloudformation_validate.rb +35 -0
- data/lib/knife-cloudformation.rb +28 -0
- data/lib/knife-cloudformation/cache.rb +213 -35
- data/lib/knife-cloudformation/knife.rb +9 -0
- data/lib/knife-cloudformation/knife/base.rb +179 -0
- data/lib/knife-cloudformation/knife/stack.rb +94 -0
- data/lib/knife-cloudformation/knife/template.rb +174 -0
- data/lib/knife-cloudformation/monkey_patch.rb +8 -0
- data/lib/knife-cloudformation/monkey_patch/stack.rb +195 -0
- data/lib/knife-cloudformation/provider.rb +225 -0
- data/lib/knife-cloudformation/utils.rb +18 -98
- data/lib/knife-cloudformation/utils/animal_strings.rb +28 -0
- data/lib/knife-cloudformation/utils/debug.rb +31 -0
- data/lib/knife-cloudformation/utils/json.rb +64 -0
- data/lib/knife-cloudformation/utils/object_storage.rb +28 -0
- data/lib/knife-cloudformation/utils/output.rb +79 -0
- data/lib/knife-cloudformation/utils/path_selector.rb +99 -0
- data/lib/knife-cloudformation/utils/ssher.rb +29 -0
- data/lib/knife-cloudformation/utils/stack_exporter.rb +271 -0
- data/lib/knife-cloudformation/utils/stack_parameter_scrubber.rb +35 -0
- data/lib/knife-cloudformation/utils/stack_parameter_validator.rb +124 -0
- data/lib/knife-cloudformation/version.rb +2 -4
- metadata +47 -94
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -90
- data/knife-cloudformation-0.1.20.gem +0 -0
- data/lib/knife-cloudformation/aws_commons.rb +0 -267
- data/lib/knife-cloudformation/aws_commons/stack.rb +0 -435
- data/lib/knife-cloudformation/aws_commons/stack_parameter_validator.rb +0 -79
- data/lib/knife-cloudformation/cloudformation_base.rb +0 -168
- data/lib/knife-cloudformation/export.rb +0 -174
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'knife-cloudformation'
|
3
|
+
|
4
|
+
module KnifeCloudformation
|
5
|
+
module MonkeyPatch
|
6
|
+
|
7
|
+
# Expand stack model functionality
|
8
|
+
module Stack
|
9
|
+
|
10
|
+
include KnifeCloudformation::Utils::AnimalStrings
|
11
|
+
|
12
|
+
## Status helpers
|
13
|
+
|
14
|
+
# Check for state suffix
|
15
|
+
#
|
16
|
+
# @param args [String, Symbol] state suffix to check for (multiple allowed)
|
17
|
+
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
18
|
+
def status_ends_with?(*args)
|
19
|
+
stat = status.to_s.downcase
|
20
|
+
!!args.map(&:to_s).map(&:downcase).detect do |suffix|
|
21
|
+
stat.end_with?(suffix)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Check for state prefix
|
26
|
+
#
|
27
|
+
# @param args [String, Symbol] state prefix to check for (multiple allowed)
|
28
|
+
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
29
|
+
def status_starts_with?(*args)
|
30
|
+
stat = status.to_s.downcase
|
31
|
+
!!args.map(&:to_s).map(&:downcase).detect do |prefix|
|
32
|
+
stat.start_with?(prefix)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check for state inclusion
|
37
|
+
#
|
38
|
+
# @param args [String, Symbol] state string to check for (multiple allowed)
|
39
|
+
# @return [TrueClass, FalseClass] true if any matches found in argument list
|
40
|
+
def status_includes?(*args)
|
41
|
+
stat = status.to_s.downcase
|
42
|
+
!!args.map(&:to_s).map(&:downcase).detect do |string|
|
43
|
+
stat.include?(string)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [TrueClass, FalseClass] stack is in progress
|
48
|
+
def in_progress?
|
49
|
+
status_ends_with?(:in_progress)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [TrueClass, FalseClass] stack is in complete state
|
53
|
+
def complete?
|
54
|
+
status_ends_with?(:complete, :failed)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [TrueClass, FalseClass] stack is failed state
|
58
|
+
def failed?
|
59
|
+
status_ends_with?(:failed) ||
|
60
|
+
(status_includes?(:rollback) && status_ends_with?(:complete))
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [TrueClass, FalseClass] stack is in success state
|
64
|
+
def success?
|
65
|
+
!failed? && complete?
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [TrueClass, FalseClass] stack is creating
|
69
|
+
def creating?
|
70
|
+
in_progress? && status_starts_with?(:create)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [TrueClass, FalseClass] stack is deleting
|
74
|
+
def deleting?
|
75
|
+
in_progress? && status_starts_with?(:delete)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [TrueClass, FalseClass] stack is updating
|
79
|
+
def updating?
|
80
|
+
in_progress? && status_starts_with?(:update)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [TrueClass, FalseClass] stack is rolling back
|
84
|
+
def rollbacking?
|
85
|
+
in_progress? && status_starts_with?(:rollback)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [String] action currently being performed
|
89
|
+
def performing
|
90
|
+
if(in_progress?)
|
91
|
+
status.to_s.downcase.split('_').first.to_sym
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
### Color coders
|
96
|
+
|
97
|
+
# @return [TrueClass, FalseClass] stack is in red state
|
98
|
+
def red?
|
99
|
+
failed? || deleting?
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [TrueClass, FalseClass] stack is in green state
|
103
|
+
def green?
|
104
|
+
success?
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [TrueClass, FalseClass] stack is in yellow state
|
108
|
+
def yellow?
|
109
|
+
!red? && !green?
|
110
|
+
end
|
111
|
+
|
112
|
+
# Provides color of stack state. Red is an error state, yellow
|
113
|
+
# is a warning state and green is a success state
|
114
|
+
#
|
115
|
+
# @return [Symbol] color of state (:red, :yellow, :green)
|
116
|
+
def color_state
|
117
|
+
red? ? :red : green? ? :green : :yellow
|
118
|
+
end
|
119
|
+
|
120
|
+
# Provides text of stack state. Danger is an error state, warning
|
121
|
+
# is a warning state and success is a success state
|
122
|
+
#
|
123
|
+
# @return [Symbol] color of state (:danger, :warning, :success)
|
124
|
+
def text_state
|
125
|
+
red? ? :danger : green? ? :success : :warning
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [String] URL safe encoded stack id
|
129
|
+
def encoded_id
|
130
|
+
Base64.urlsafe_encode64(id)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Whole number representation of current completion
|
134
|
+
#
|
135
|
+
# @param min [Integer] lowest allowed return value (defaults 5)
|
136
|
+
# @return [Integer] percent complete (0..100)
|
137
|
+
def percent_complete(min = 5)
|
138
|
+
if(in_progress?)
|
139
|
+
total_resources = load_template.fetch('Resources', []).size
|
140
|
+
total_complete = resources.all.find_all do |resource|
|
141
|
+
resource.resource_status.downcase.end_with?('complete')
|
142
|
+
end.size
|
143
|
+
result = ((total_complete.to_f / total_resources) * 100).to_i
|
144
|
+
result > min.to_i ? result : min
|
145
|
+
else
|
146
|
+
100
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Apply stack outputs to current stack parameters
|
151
|
+
#
|
152
|
+
# @param remote_stack [Miasma::Orchestration::Stack]
|
153
|
+
# @return [self]
|
154
|
+
# @note setting `DisableApply` within parameter hash will
|
155
|
+
# prevent parameters being overridden
|
156
|
+
def apply_stack(remote_stack)
|
157
|
+
default_key = 'Default'
|
158
|
+
stack_parameters = template.fetch('Parameters',
|
159
|
+
template.fetch('parameters', {})
|
160
|
+
)
|
161
|
+
valid_parameters = Hash[
|
162
|
+
stack_parameters.map do |key, val|
|
163
|
+
unless(val['DisableApply'])
|
164
|
+
[snake(key), key]
|
165
|
+
end
|
166
|
+
end.compact
|
167
|
+
]
|
168
|
+
if(defined?(Chef::Config) && Chef::Config[:knife][:cloudformation][:ignore_parameters])
|
169
|
+
valid_parameters = valid_parameters.map do |snake_param, camel_param|
|
170
|
+
unless(Chef::Config[:knife][:cloudformation][:ignore_parameters].include?(camel_param))
|
171
|
+
[snake_param, camel_param]
|
172
|
+
end
|
173
|
+
end.compact
|
174
|
+
end
|
175
|
+
if(persisted?)
|
176
|
+
remote_stack.outputs.each do |output|
|
177
|
+
if(param_key = valid_parameters[snake(output.key)])
|
178
|
+
parameters.merge!(param_key => output.value)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
else
|
182
|
+
remote_stack.outputs.each do |output|
|
183
|
+
if(param_key = valid_parameters[snake(output.key)])
|
184
|
+
stack_parameters[param_key][default_key] = output.value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Infect miasma
|
195
|
+
Miasma::Models::Orchestration::Stack.send(:include, KnifeCloudformation::MonkeyPatch::Stack)
|
@@ -0,0 +1,225 @@
|
|
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,104 +1,24 @@
|
|
1
|
+
require 'knife-cloudformation'
|
2
|
+
|
1
3
|
module KnifeCloudformation
|
4
|
+
# Utility classes and modules
|
2
5
|
module Utils
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
module JSON
|
22
|
-
|
23
|
-
def try_json_compat
|
24
|
-
unless(@_json_loaded)
|
25
|
-
begin
|
26
|
-
require 'chef/json_compat'
|
27
|
-
rescue
|
28
|
-
require "#{ENV['RUBY_JSON_LIB'] || 'json'}"
|
29
|
-
end
|
30
|
-
@_json_loaded = true
|
31
|
-
end
|
32
|
-
defined?(Chef::JSONCompat)
|
33
|
-
end
|
34
|
-
|
35
|
-
def _to_json(thing)
|
36
|
-
if(try_json_compat)
|
37
|
-
Chef::JSONCompat.to_json(thing)
|
38
|
-
else
|
39
|
-
JSON.dump(thing)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def _from_json(thing)
|
44
|
-
if(try_json_compat)
|
45
|
-
Chef::JSONCompat.from_json(thing)
|
46
|
-
else
|
47
|
-
JSON.read(thing)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def _format_json(thing)
|
52
|
-
thing = _from_json(thing) if thing.is_a?(String)
|
53
|
-
if(try_json_compat)
|
54
|
-
Chef::JSONCompat.to_json_pretty(thing)
|
55
|
-
else
|
56
|
-
JSON.pretty_generate(thing)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
module AnimalStrings
|
63
|
-
|
64
|
-
def camel(string)
|
65
|
-
string.to_s.split('_').map{|k| "#{k.slice(0,1).upcase}#{k.slice(1,k.length)}"}.join
|
66
|
-
end
|
67
|
-
|
68
|
-
def snake(string)
|
69
|
-
string.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
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
|
73
22
|
|
74
|
-
module Ssher
|
75
|
-
def remote_file_contents(address, user, path, ssh_opts={})
|
76
|
-
require 'net/sftp'
|
77
|
-
content = ''
|
78
|
-
ssh_session = Net::SSH.start(address, user, ssh_opts)
|
79
|
-
con = Net::SFTP::Session.new(ssh_session)
|
80
|
-
con.loop{ con.opening? }
|
81
|
-
f_handle = con.open!(path)
|
82
|
-
data = ''
|
83
|
-
count = 0
|
84
|
-
while(data)
|
85
|
-
data = nil
|
86
|
-
request = con.read(f_handle, count, 1024) do |response|
|
87
|
-
unless(response.eof?)
|
88
|
-
if(response.ok?)
|
89
|
-
count += 1024
|
90
|
-
content << response[:data]
|
91
|
-
data = true
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
request.wait
|
96
|
-
end
|
97
|
-
con.close!(f_handle)
|
98
|
-
con.close_channel
|
99
|
-
ssh_session.close
|
100
|
-
content.empty? ? nil : content
|
101
|
-
end
|
102
|
-
end
|
103
23
|
end
|
104
24
|
end
|