knife-cloudformation 0.1.18 → 0.1.20

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.
@@ -1,3 +1,9 @@
1
+ ## v0.1.20
2
+ * Update some caching behavior
3
+ * Add more logging especially around remote calls
4
+ * Add support for request throttling
5
+ * Disable local caching when stack is in `in_progress` state
6
+
1
7
  ## v0.1.18
2
8
  * Replace constant with inline value to prevent warnings
3
9
  * Explicitly load file to ensure proper load ordering
@@ -9,6 +9,20 @@ end
9
9
  module KnifeCloudformation
10
10
  class AwsCommons
11
11
 
12
+ class << self
13
+ def logger=(l)
14
+ @logger = l
15
+ end
16
+
17
+ def logger
18
+ unless(@logger)
19
+ require 'logger'
20
+ @logger = Logger.new($stdout)
21
+ end
22
+ @logger
23
+ end
24
+ end
25
+
12
26
  include KnifeCloudformation::Utils::AnimalStrings
13
27
  include KnifeCloudformation::Utils::Debug
14
28
 
@@ -21,11 +35,21 @@ module KnifeCloudformation
21
35
  def initialize(args={})
22
36
  @ui = args[:ui]
23
37
  @credentials = @creds = args[:fog]
38
+ @disconnect_long_jobs = args[:disconnect_long_jobs]
39
+ @throttled = []
24
40
  @connections = {}
25
41
  @memo = Cache.new(credentials)
26
42
  @local = {:stacks => {}}
27
43
  end
28
44
 
45
+ def logger
46
+ @logger || self.class.logger
47
+ end
48
+
49
+ def logger=(l)
50
+ @logger = l
51
+ end
52
+
29
53
  def cache
30
54
  @memo
31
55
  end
@@ -63,7 +87,13 @@ module KnifeCloudformation
63
87
  end
64
88
  end
65
89
  end
66
- @connections[type]
90
+ if(block_given?)
91
+ throttleable do
92
+ yield @connections[type]
93
+ end
94
+ else
95
+ @connections[type]
96
+ end
67
97
  end
68
98
  alias_method :aws, :build_connection
69
99
 
@@ -89,9 +119,17 @@ module KnifeCloudformation
89
119
  cache.apply_limit(:stacks, args[:refresh_every].to_i)
90
120
  end
91
121
  if(@memo[:stacks].update_allowed? || args[:force_refresh])
92
- @memo[:stacks_lock].lock do
93
- @_stacks_cached = true
94
- @memo[:stacks].value = aws(:cloud_formation).describe_stacks.body['Stacks']
122
+ long_running_job(:stacks) do
123
+ logger.debug 'Populating full cloudformation list from remote end point'
124
+ stack_result = throttleable do
125
+ aws(:cloud_formation).describe_stacks.body['Stacks']
126
+ end
127
+ if(stack_result)
128
+ @memo[:stacks_lock].lock do
129
+ @memo[:stacks].value = stack_result
130
+ end
131
+ end
132
+ logger.debug 'Full cloudformation list from remote end point complete'
95
133
  end
96
134
  end
97
135
  end
@@ -100,6 +138,51 @@ module KnifeCloudformation
100
138
  end
101
139
  end
102
140
 
141
+ def throttleable
142
+ if(@throttled.size > 0)
143
+ if(Time.now.to_i - @throttled.last < Time.now.to_i - @throttled.size * 15)
144
+ logger.error "Currently being throttled. Not running request!"
145
+ return nil
146
+ end
147
+ end
148
+ begin
149
+ result = yield
150
+ @throttled.clear
151
+ result
152
+ rescue Fog::Service::Error => e
153
+ if(e.message == 'Throttling => Rate exceeded')
154
+ logger.error "Remote end point is is currently throttling. Rate has been exceeded."
155
+ @throttled << Time.now.to_i
156
+ end
157
+ nil
158
+ end
159
+ end
160
+
161
+ def long_running_job(name)
162
+ if(@disconnect_long_jobs)
163
+ logger.debug "Disconnected long running jobs enabled. Starting: #{name}"
164
+ lock_key = "long_jobs_lock_#{name}".to_sym
165
+ @memo.init(lock_key, :lock)
166
+ Thread.new do
167
+ begin
168
+ @memo[lock_key].lock do
169
+ begin
170
+ logger.info "Long running job started disconnected (#{name})"
171
+ yield
172
+ rescue => e
173
+ logger.error "Long running job failure (#{name}): #{e.class} - #{e}\n#{e.backtrace.join("\n")}"
174
+ end
175
+ end
176
+ rescue Redis::Lock::Timeout
177
+ logger.warn "Long running process failed to aquire lock. Request not run (#{name})"
178
+ end
179
+ end
180
+ else
181
+ logger.debug "Disconnected long running jobs disabled. Starting #{name} inline"
182
+ yield
183
+ end
184
+ end
185
+
103
186
  def name_from_stack_id(s_id)
104
187
  found = stacks.detect do |s|
105
188
  s['StackId'] == s_id
@@ -115,15 +198,21 @@ module KnifeCloudformation
115
198
  end
116
199
 
117
200
  def stack(*names)
201
+ direct_load = names.delete(:ignore_seeds)
118
202
  result = names.map do |name|
119
203
  [name, name.start_with?('arn:') ? name : id_from_stack_name(name)]
120
204
  end.map do |name, s_id|
121
205
  unless(@local[:stacks][s_id])
122
- if(@_stacks_cached)
206
+ unless(direct_load)
123
207
  seed = stacks.detect do |stk|
124
208
  stk['StackId'] == s_id
125
209
  end
126
210
  end
211
+ if(seed)
212
+ logger.debug "Requested stack (#{name}) loaded via cached seed"
213
+ else
214
+ logger.debug "Requested stack (#{name}) loaded directly with no seed"
215
+ end
127
216
  @local[:stacks][s_id] = Stack.new(name, self, seed)
128
217
  end
129
218
  @local[:stacks][s_id]
@@ -399,14 +399,15 @@ module KnifeCloudformation
399
399
  as_resources = resources.find_all do |r|
400
400
  r['ResourceType'] == 'AWS::AutoScaling::AutoScalingGroup'
401
401
  end
402
- @local[:nodes] = as_resources.map do |as_resource|
402
+ value = as_resources.map do |as_resource|
403
403
  as_group = expand_resource(as_resource)
404
404
  as_group.instances.map do |inst|
405
405
  common.aws(:ec2).servers.get(inst.id)
406
406
  end
407
407
  end.flatten
408
+ @local[:nodes] = value unless in_progress?
408
409
  end
409
- @local[:nodes]
410
+ value || @local[:nodes]
410
411
  end
411
412
 
412
413
  def nodes_data(*args)
@@ -420,9 +421,9 @@ module KnifeCloudformation
420
421
  end
421
422
  end
422
423
  unless(data.empty?)
423
- @memo[cache_key].value = data
424
+ @memo[cache_key].value = data unless in_progress?
424
425
  end
425
- @memo[cache_key].value || data
426
+ data || @memo[cache_key].value
426
427
  end
427
428
 
428
429
  end
@@ -22,7 +22,7 @@ module KnifeCloudformation
22
22
  end
23
23
 
24
24
  def stack(name)
25
- self.class.con(ui).stack(name)
25
+ self.class.con(ui).stack(name, :ignore_seeds)
26
26
  end
27
27
 
28
28
  def allowed_attributes
@@ -7,7 +7,8 @@ module KnifeCloudformation
7
7
  DEFAULT_OPTIONS = {
8
8
  :chef_popsicle => true,
9
9
  :ignored_parameters => ['Environment', 'StackCreator'],
10
- :chef_environment_parameter => 'Environment'
10
+ :chef_environment_parameter => 'Environment',
11
+ :aws_commons => nil
11
12
  }
12
13
 
13
14
  attr_reader :stack, :stack_name, :stack_id, :options, :aws_commons
@@ -2,5 +2,5 @@ module KnifeCloudformation
2
2
  class Version < Gem::Version
3
3
  end
4
4
 
5
- VERSION = Version.new('0.1.18')
5
+ VERSION = Version.new('0.1.20')
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-cloudformation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.1.20
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-13 00:00:00.000000000 Z
12
+ date: 2013-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chef
@@ -152,6 +152,7 @@ files:
152
152
  - knife-cloudformation.gemspec
153
153
  - CHANGELOG.md
154
154
  - Gemfile.lock
155
+ - knife-cloudformation-0.1.18.gem
155
156
  homepage: http://github.com/heavywater/knife-cloudformation
156
157
  licenses: []
157
158
  post_install_message: