knife-cloudformation 0.1.18 → 0.1.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: