wakame 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +20 -0
- data/README.rdoc +63 -0
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/app_generators/wakame/templates/README +0 -0
- data/app_generators/wakame/templates/Rakefile +18 -0
- data/app_generators/wakame/templates/bin/wakame-agent +9 -0
- data/app_generators/wakame/templates/bin/wakame-master +9 -0
- data/app_generators/wakame/templates/bin/wakameadm +9 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/apache_app.rb +54 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/conf/apache2.conf +46 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/conf/envvars-app +7 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/conf/sites-app.conf +23 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/conf/system-app.conf +67 -0
- data/app_generators/wakame/templates/cluster/resources/apache_app/init.d/apache2-app +192 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/apache_lb.rb +56 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/apache2.conf +46 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/envvars-lb +6 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/sites-lb.conf +54 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/system-lb.conf +75 -0
- data/app_generators/wakame/templates/cluster/resources/apache_lb/init.d/apache2-lb +192 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/apache_www.rb +50 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/conf/apache2.conf +47 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/conf/envvars-www +7 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/conf/sites-www.conf +23 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/conf/system-www.conf +63 -0
- data/app_generators/wakame/templates/cluster/resources/apache_www/init.d/apache2-www +192 -0
- data/app_generators/wakame/templates/cluster/resources/ec2_elastic_ip/ec2_elastic_ip.rb +39 -0
- data/app_generators/wakame/templates/cluster/resources/mysql_master/conf/my.cnf +154 -0
- data/app_generators/wakame/templates/cluster/resources/mysql_master/init.d/mysql +185 -0
- data/app_generators/wakame/templates/cluster/resources/mysql_master/mysql_master.rb +174 -0
- data/app_generators/wakame/templates/config/boot.rb +85 -0
- data/app_generators/wakame/templates/config/cluster.rb +64 -0
- data/app_generators/wakame/templates/config/environments/common.rb +0 -0
- data/app_generators/wakame/templates/config/environments/ec2.rb +3 -0
- data/app_generators/wakame/templates/config/environments/stand_alone.rb +0 -0
- data/app_generators/wakame/templates/config/init.d/wakame-agent +72 -0
- data/app_generators/wakame/templates/config/init.d/wakame-master +73 -0
- data/app_generators/wakame/wakame_generator.rb +124 -0
- data/bin/wakame +18 -0
- data/contrib/imagesetup.sh +77 -0
- data/lib/ext/eventmachine.rb +86 -0
- data/lib/ext/shellwords.rb +172 -0
- data/lib/ext/uri.rb +15 -0
- data/lib/wakame/action.rb +156 -0
- data/lib/wakame/actions/destroy_instances.rb +39 -0
- data/lib/wakame/actions/launch_cluster.rb +31 -0
- data/lib/wakame/actions/migrate_service.rb +65 -0
- data/lib/wakame/actions/propagate_instances.rb +95 -0
- data/lib/wakame/actions/reload_service.rb +21 -0
- data/lib/wakame/actions/scaleout_when_high_load.rb +44 -0
- data/lib/wakame/actions/shutdown_cluster.rb +22 -0
- data/lib/wakame/actions/shutdown_vm.rb +19 -0
- data/lib/wakame/actions/start_service.rb +64 -0
- data/lib/wakame/actions/stop_service.rb +49 -0
- data/lib/wakame/actions/util.rb +71 -0
- data/lib/wakame/actor/daemon.rb +37 -0
- data/lib/wakame/actor/service_monitor.rb +21 -0
- data/lib/wakame/actor/system.rb +46 -0
- data/lib/wakame/actor.rb +33 -0
- data/lib/wakame/agent.rb +226 -0
- data/lib/wakame/amqp_client.rb +219 -0
- data/lib/wakame/command/action_status.rb +62 -0
- data/lib/wakame/command/actor.rb +23 -0
- data/lib/wakame/command/clone_service.rb +12 -0
- data/lib/wakame/command/launch_cluster.rb +15 -0
- data/lib/wakame/command/migrate_service.rb +21 -0
- data/lib/wakame/command/propagate_service.rb +24 -0
- data/lib/wakame/command/shutdown_cluster.rb +15 -0
- data/lib/wakame/command/status.rb +81 -0
- data/lib/wakame/command.rb +31 -0
- data/lib/wakame/command_queue.rb +44 -0
- data/lib/wakame/configuration.rb +93 -0
- data/lib/wakame/daemonize.rb +96 -0
- data/lib/wakame/event.rb +232 -0
- data/lib/wakame/event_dispatcher.rb +154 -0
- data/lib/wakame/graph.rb +79 -0
- data/lib/wakame/initializer.rb +162 -0
- data/lib/wakame/instance_counter.rb +78 -0
- data/lib/wakame/logger.rb +12 -0
- data/lib/wakame/manager/commands.rb +134 -0
- data/lib/wakame/master.rb +369 -0
- data/lib/wakame/monitor/agent.rb +50 -0
- data/lib/wakame/monitor/service.rb +183 -0
- data/lib/wakame/monitor.rb +69 -0
- data/lib/wakame/packets.rb +160 -0
- data/lib/wakame/queue_declare.rb +14 -0
- data/lib/wakame/rule.rb +116 -0
- data/lib/wakame/rule_engine.rb +202 -0
- data/lib/wakame/runner/administrator_command.rb +112 -0
- data/lib/wakame/runner/agent.rb +81 -0
- data/lib/wakame/runner/master.rb +93 -0
- data/lib/wakame/scheduler.rb +251 -0
- data/lib/wakame/service.rb +914 -0
- data/lib/wakame/template.rb +189 -0
- data/lib/wakame/trigger.rb +66 -0
- data/lib/wakame/triggers/instance_count_update.rb +45 -0
- data/lib/wakame/triggers/load_history.rb +107 -0
- data/lib/wakame/triggers/maintain_ssh_known_hosts.rb +43 -0
- data/lib/wakame/triggers/process_command.rb +34 -0
- data/lib/wakame/triggers/shutdown_unused_vm.rb +16 -0
- data/lib/wakame/util.rb +569 -0
- data/lib/wakame/vm_manipulator.rb +186 -0
- data/lib/wakame.rb +59 -0
- data/tasks/ec2.rake +127 -0
- data/tests/cluster.json +3 -0
- data/tests/conf/a +1 -0
- data/tests/conf/b +1 -0
- data/tests/conf/c +1 -0
- data/tests/setup_agent.rb +39 -0
- data/tests/setup_master.rb +28 -0
- data/tests/test_actor.rb +54 -0
- data/tests/test_agent.rb +218 -0
- data/tests/test_amqp_client.rb +94 -0
- data/tests/test_graph.rb +36 -0
- data/tests/test_master.rb +167 -0
- data/tests/test_monitor.rb +47 -0
- data/tests/test_rule_engine.rb +127 -0
- data/tests/test_scheduler.rb +123 -0
- data/tests/test_service.rb +60 -0
- data/tests/test_template.rb +67 -0
- data/tests/test_uri_amqp.rb +19 -0
- data/tests/test_util.rb +71 -0
- data/wakame_generators/resource/resource_generator.rb +54 -0
- data/wakame_generators/resource/templates/apache_app/apache_app.rb +60 -0
- data/wakame_generators/resource/templates/apache_app/conf/apache2.conf +46 -0
- data/wakame_generators/resource/templates/apache_app/conf/envvars-app +7 -0
- data/wakame_generators/resource/templates/apache_app/conf/sites-app.conf +23 -0
- data/wakame_generators/resource/templates/apache_app/conf/system-app.conf +67 -0
- data/wakame_generators/resource/templates/apache_app/init.d/apache2-app +192 -0
- data/wakame_generators/resource/templates/apache_lb/apache_lb.rb +67 -0
- data/wakame_generators/resource/templates/apache_lb/conf/apache2.conf +46 -0
- data/wakame_generators/resource/templates/apache_lb/conf/envvars-lb +6 -0
- data/wakame_generators/resource/templates/apache_lb/conf/sites-lb.conf +54 -0
- data/wakame_generators/resource/templates/apache_lb/conf/system-lb.conf +75 -0
- data/wakame_generators/resource/templates/apache_lb/init.d/apache2-lb +192 -0
- data/wakame_generators/resource/templates/apache_www/apache_www.rb +56 -0
- data/wakame_generators/resource/templates/apache_www/conf/apache2.conf +47 -0
- data/wakame_generators/resource/templates/apache_www/conf/envvars-www +7 -0
- data/wakame_generators/resource/templates/apache_www/conf/sites-www.conf +23 -0
- data/wakame_generators/resource/templates/apache_www/conf/system-www.conf +63 -0
- data/wakame_generators/resource/templates/apache_www/init.d/apache2-www +192 -0
- data/wakame_generators/resource/templates/ec2_elastic_ip/ec2_elastic_ip.rb +39 -0
- data/wakame_generators/resource/templates/mysql_master/conf/my.cnf +154 -0
- data/wakame_generators/resource/templates/mysql_master/init.d/mysql +185 -0
- data/wakame_generators/resource/templates/mysql_master/mysql_master.rb +119 -0
- metadata +289 -0
data/lib/wakame/util.rb
ADDED
@@ -0,0 +1,569 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'hmac-sha1'
|
5
|
+
require 'open4'
|
6
|
+
|
7
|
+
module Wakame
|
8
|
+
module Util
|
9
|
+
|
10
|
+
def ssh_known_hosts_hash(hostname, key=nil)
|
11
|
+
# Generate 20bytes random value
|
12
|
+
key = Array.new(20).collect{rand(0xFF).to_i}.pack('c*') if key.nil?
|
13
|
+
|
14
|
+
"|1|#{[key].pack('m').chop}|#{[HMAC::SHA1.digest(key, hostname)].pack('m').chop}"
|
15
|
+
end
|
16
|
+
module_function :ssh_known_hosts_hash
|
17
|
+
|
18
|
+
|
19
|
+
def gen_id(str=nil)
|
20
|
+
Digest::SHA1.hexdigest( (str.nil? ? rand.to_s : str) )
|
21
|
+
end
|
22
|
+
module_function :gen_id
|
23
|
+
|
24
|
+
|
25
|
+
def build_const(name)
|
26
|
+
name.to_s.split(/::/).inject(Object) {|c,name| c.const_get(name) }
|
27
|
+
end
|
28
|
+
module_function :build_const
|
29
|
+
|
30
|
+
|
31
|
+
def new_(class_or_str, *args)
|
32
|
+
if class_or_str.is_a? Class
|
33
|
+
class_or_str.new(*args)
|
34
|
+
else
|
35
|
+
c = build_const(class_or_str.to_s)
|
36
|
+
c.new(*args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
module_function :new_
|
40
|
+
|
41
|
+
|
42
|
+
# Copied from http://github.com/ezmobius/nanite/
|
43
|
+
##
|
44
|
+
# Convert to snake case.
|
45
|
+
#
|
46
|
+
# "FooBar".snake_case #=> "foo_bar"
|
47
|
+
# "HeadlineCNNNews".snake_case #=> "headline_cnn_news"
|
48
|
+
# "CNN".snake_case #=> "cnn"
|
49
|
+
#
|
50
|
+
# @return [String] Receiver converted to snake case.
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def snake_case(const)
|
54
|
+
const = const.to_s
|
55
|
+
return const.downcase if const =~ /^[A-Z\d]+$/
|
56
|
+
const.gsub(/\B([A-Z\d]+)|([A-Z]+)(?=[A-Z][a-z]?)/, '_\&') =~ /_*(.*)/
|
57
|
+
return $+.downcase.gsub(/[_]+/, '_')
|
58
|
+
end
|
59
|
+
module_function :snake_case
|
60
|
+
|
61
|
+
# Copied from http://github.com/ezmobius/nanite/
|
62
|
+
##
|
63
|
+
# Convert a constant name to a path, assuming a conventional structure.
|
64
|
+
#
|
65
|
+
# "FooBar::Baz".to_const_path # => "foo_bar/baz"
|
66
|
+
#
|
67
|
+
# @return [String] Path to the file containing the constant named by receiver
|
68
|
+
# (constantized string), assuming a conventional structure.
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def to_const_path(const)
|
72
|
+
snake_case(const).gsub(/::/, "/")
|
73
|
+
end
|
74
|
+
module_function :to_const_path
|
75
|
+
|
76
|
+
|
77
|
+
def exec(command, &capture)
|
78
|
+
outputs = []
|
79
|
+
Wakame.log.debug("#{self}.exec(#{command})")
|
80
|
+
cmdstat = ::Open4.popen4(command) { |pid, stdin, stdout, stderr|
|
81
|
+
stdout.each { |l|
|
82
|
+
capture.call(l, :stdout) if capture
|
83
|
+
outputs << l
|
84
|
+
}
|
85
|
+
stderr.each { |l|
|
86
|
+
capture.call(l, :stderr) if capture
|
87
|
+
outputs << l
|
88
|
+
}
|
89
|
+
}
|
90
|
+
Wakame.log.debug(outputs.join(''))
|
91
|
+
raise "Command Failed (exit=#{cmdstat.exitstatus}): #{command}" unless cmdstat.exitstatus == 0
|
92
|
+
end
|
93
|
+
module_function :exec
|
94
|
+
|
95
|
+
def spawn(command, &capture)
|
96
|
+
outputs = []
|
97
|
+
Wakame.log.debug("#{self}.spawn(#{command})")
|
98
|
+
cmdstat = ::Open4.popen4(command) { |pid, stdin, stdout, stderr|
|
99
|
+
stdout.each { |l|
|
100
|
+
capture.call(l, :stdout) if capture
|
101
|
+
outputs << l
|
102
|
+
}
|
103
|
+
stderr.each { |l|
|
104
|
+
capture.call(l, :stderr) if capture
|
105
|
+
outputs << l
|
106
|
+
}
|
107
|
+
}
|
108
|
+
Wakame.log.debug(outputs.join(''))
|
109
|
+
cmdstat
|
110
|
+
end
|
111
|
+
module_function :spawn
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
module ThreadImmutable
|
118
|
+
class IllegalCrossThreadMethodCall < StandardError; end
|
119
|
+
|
120
|
+
|
121
|
+
module ClassMethods
|
122
|
+
def thread_immutable_methods(*args)
|
123
|
+
return if args.empty?
|
124
|
+
|
125
|
+
args.each { |n|
|
126
|
+
# Proc can not be passed a block due to 1.8's limitation. The following will work in 1.9.
|
127
|
+
#um = instance_method(n) || next
|
128
|
+
#define_method(n) { |*args, &blk|
|
129
|
+
# thread_check
|
130
|
+
# um.bind(self).call(*args, &blk)
|
131
|
+
#}
|
132
|
+
|
133
|
+
if method_defined?(n)
|
134
|
+
alias_method "#{n}_no_thread_check", n.to_sym
|
135
|
+
|
136
|
+
eval <<-__E__
|
137
|
+
def #{n}(*args, &blk)
|
138
|
+
thread_check
|
139
|
+
#{n}_no_thread_check(*args, &blk)
|
140
|
+
end
|
141
|
+
__E__
|
142
|
+
end
|
143
|
+
}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.included(klass)
|
148
|
+
klass.extend ClassMethods
|
149
|
+
end
|
150
|
+
|
151
|
+
# def self.included(klass)
|
152
|
+
# klass.class_eval {
|
153
|
+
# _um_constructor = self.instance_method(:initialize)
|
154
|
+
# if _um_constructor
|
155
|
+
# define_method(:initialize) { |*args|
|
156
|
+
# bind_thread
|
157
|
+
# _um_constructor.bind(self).call(*args)
|
158
|
+
# }
|
159
|
+
# end
|
160
|
+
# }
|
161
|
+
# end
|
162
|
+
|
163
|
+
# def self.method_added2(name)
|
164
|
+
# if name == :initialize
|
165
|
+
#
|
166
|
+
# _um_constructor = instance_method(:initialize)
|
167
|
+
# define_method(:initialize) { |*args|
|
168
|
+
# bind_thread
|
169
|
+
# _um_constructor.bind(self).call(*args)
|
170
|
+
# }
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
|
174
|
+
|
175
|
+
def bind_thread(thread=Thread.current)
|
176
|
+
@target_thread = thread
|
177
|
+
#puts "bound thread: #{@target_thread.inspect} to #{self.class} object"
|
178
|
+
end
|
179
|
+
|
180
|
+
def thread_check
|
181
|
+
#puts "@target_thread == Thread.main : #{@target_thread == Thread.main}"
|
182
|
+
raise "Thread is not bound." if @target_thread.nil?
|
183
|
+
raise IllegalCrossThreadMethodCall unless target_thread?
|
184
|
+
end
|
185
|
+
|
186
|
+
def target_thread?(t=Thread.current)
|
187
|
+
@target_thread == t
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
def target_thread
|
192
|
+
@target_thread
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
module AttributeHelper
|
200
|
+
|
201
|
+
PRIMITIVE_CLASSES=[NilClass, TrueClass, FalseClass, Numeric, String, Symbol]
|
202
|
+
CONVERT_CLASSES={Time => proc{|i| i.to_s } }
|
203
|
+
|
204
|
+
module ClassMethods
|
205
|
+
def attr_attributes
|
206
|
+
@attr_attributes ||= {}
|
207
|
+
end
|
208
|
+
|
209
|
+
def attr(name, assignable=false)
|
210
|
+
attr_attributes[name.to_sym]={}
|
211
|
+
attr_without_trap(name, assignable)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Override Object.attr_accessor to
|
215
|
+
def attr_accessor(*args)
|
216
|
+
args.each { |name|
|
217
|
+
attr(name, true)
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
def attr_reader(*args)
|
222
|
+
args.each { |name|
|
223
|
+
attr(name, false)
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
def attr_writer(*args)
|
228
|
+
args.each { |name|
|
229
|
+
attr(name, true)
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
def def_attribute(name, *args)
|
234
|
+
attr = {}
|
235
|
+
attr_attributes[name.to_sym] = begin
|
236
|
+
if args.size == 0
|
237
|
+
{:default=>nil}
|
238
|
+
else
|
239
|
+
case args[0]
|
240
|
+
when Hash
|
241
|
+
args[0].dup
|
242
|
+
else
|
243
|
+
{:default=>args[0]}
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
class_eval <<-__E__
|
248
|
+
def #{name}=(v)
|
249
|
+
@#{name}=v
|
250
|
+
end
|
251
|
+
|
252
|
+
def #{name}
|
253
|
+
if @#{name}.nil?
|
254
|
+
retrieve_attr_attribute { |a|
|
255
|
+
if a.has_key?(:#{name})
|
256
|
+
defval = a[:#{name}][:default]
|
257
|
+
case defval
|
258
|
+
when Proc
|
259
|
+
@#{name} = defval.call(self)
|
260
|
+
else
|
261
|
+
@#{name} = defval
|
262
|
+
end
|
263
|
+
break
|
264
|
+
end
|
265
|
+
}
|
266
|
+
end
|
267
|
+
@#{name}
|
268
|
+
end
|
269
|
+
|
270
|
+
public :#{name}, :#{name}=
|
271
|
+
__E__
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
def self.included(klass)
|
278
|
+
klass.class.class_eval {
|
279
|
+
alias :attr_without_trap :attr unless self.respond_to?(:attr_without_trap, true)
|
280
|
+
}
|
281
|
+
klass.extend ClassMethods
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
public
|
286
|
+
def dump_attrs(root=nil)
|
287
|
+
if root.nil?
|
288
|
+
root = self
|
289
|
+
end
|
290
|
+
|
291
|
+
return dump_internal(root)
|
292
|
+
end
|
293
|
+
#thread_immutable_method :dump_attrs if self.kind_of?(ThreadImmutable)
|
294
|
+
#module_function :dump_attrs
|
295
|
+
|
296
|
+
|
297
|
+
private
|
298
|
+
def retrieve_attr_attribute(&blk)
|
299
|
+
self.class.ancestors.each { |klass|
|
300
|
+
blk.call(klass.attr_attributes) if klass.include?(AttributeHelper)
|
301
|
+
}
|
302
|
+
end
|
303
|
+
|
304
|
+
def dump_internal(root)
|
305
|
+
case root
|
306
|
+
when AttributeHelper
|
307
|
+
t={}
|
308
|
+
t[:type] = root.class.to_s
|
309
|
+
|
310
|
+
retrieve_attr_attribute { |a|
|
311
|
+
a.each_key {|k| t[k] = dump_internal(root.__send__(k.to_sym)) }
|
312
|
+
}
|
313
|
+
t
|
314
|
+
when Array
|
315
|
+
root.collect { |a| dump_internal(a) }
|
316
|
+
when Hash
|
317
|
+
t={}
|
318
|
+
root.each {|k,v| t[k] = dump_internal(v) }
|
319
|
+
t
|
320
|
+
else
|
321
|
+
if CONVERT_CLASSES.any?{|t, p| root.kind_of?(t) }
|
322
|
+
CONVERT_CLASSES[root.class].call(root)
|
323
|
+
elsif PRIMITIVE_CLASSES.any?{|p| root.kind_of?(p) }
|
324
|
+
root
|
325
|
+
#elsif root.respond_to?(:dump_attrs)
|
326
|
+
#dump_internal(root.dump_attrs)
|
327
|
+
else
|
328
|
+
raise TypeError, "#{root.class} does not support to dump attributes"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
class SortedHash < Hash
|
337
|
+
def initialize
|
338
|
+
@keyorder=[]
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
def store(key, value)
|
343
|
+
raise TypeError, "#{key} is not Comparable" unless key.kind_of?(Comparable)
|
344
|
+
if has_key?(key)
|
345
|
+
ret = super(key, value)
|
346
|
+
else
|
347
|
+
ret = super(key, value)
|
348
|
+
@keyorder << key
|
349
|
+
@keyorder.sort!
|
350
|
+
|
351
|
+
end
|
352
|
+
ret
|
353
|
+
end
|
354
|
+
|
355
|
+
def []=(key, value)
|
356
|
+
store(key, value)
|
357
|
+
end
|
358
|
+
|
359
|
+
def delete(key, &blk)
|
360
|
+
if has_key?(key)
|
361
|
+
@keyorder.delete(key)
|
362
|
+
super(key, &blk)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def keys
|
367
|
+
@keyorder
|
368
|
+
end
|
369
|
+
|
370
|
+
def each(&blk)
|
371
|
+
@keyorder.each { |k|
|
372
|
+
blk.call(k, self[k])
|
373
|
+
}
|
374
|
+
end
|
375
|
+
|
376
|
+
def first_key
|
377
|
+
@keyorder.first
|
378
|
+
end
|
379
|
+
|
380
|
+
def first
|
381
|
+
self[first_key]
|
382
|
+
end
|
383
|
+
|
384
|
+
def last_key
|
385
|
+
@keyorder.last
|
386
|
+
end
|
387
|
+
|
388
|
+
def last
|
389
|
+
self[last_key]
|
390
|
+
end
|
391
|
+
|
392
|
+
def clear
|
393
|
+
super
|
394
|
+
@keyorder.clear
|
395
|
+
end
|
396
|
+
|
397
|
+
def inspect
|
398
|
+
str = "{"
|
399
|
+
str << @keyorder.collect{|k| "#{k}=>#{self[k]}" }.join(', ')
|
400
|
+
str << "}"
|
401
|
+
str
|
402
|
+
end
|
403
|
+
|
404
|
+
def invert
|
405
|
+
raise NotImplementedError
|
406
|
+
end
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
|
411
|
+
module FilterChain
|
412
|
+
def self.included(klass)
|
413
|
+
klass.class_eval {
|
414
|
+
def self.filter_chain
|
415
|
+
@filter_chain ||= []
|
416
|
+
end
|
417
|
+
|
418
|
+
def self.append_filter(&blk)
|
419
|
+
self.filter_chain << blk
|
420
|
+
end
|
421
|
+
}
|
422
|
+
end
|
423
|
+
|
424
|
+
def run_filter(pass_obj=nil)
|
425
|
+
retrieve_filter_chain { |filter_chain|
|
426
|
+
filter_chain.each { |filter_proc|
|
427
|
+
begin
|
428
|
+
ret = filter_proc.call(pass_obj)
|
429
|
+
rescue => e
|
430
|
+
ret = false
|
431
|
+
end
|
432
|
+
|
433
|
+
unless ret
|
434
|
+
raise
|
435
|
+
end
|
436
|
+
}
|
437
|
+
}
|
438
|
+
end
|
439
|
+
|
440
|
+
private
|
441
|
+
def retrieve_filter_chain(&blk)
|
442
|
+
order = []
|
443
|
+
self.class.ancestors.each { |klass|
|
444
|
+
order << klass if klass.include?(FilterChain)
|
445
|
+
}
|
446
|
+
|
447
|
+
order.reverse.each { |klass|
|
448
|
+
blk.call(klass.filter_chain)
|
449
|
+
}
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
|
455
|
+
class ConditionalWait
|
456
|
+
class TimeoutError < StandardError; end
|
457
|
+
include ThreadImmutable
|
458
|
+
|
459
|
+
def initialize(&blk)
|
460
|
+
bind_thread
|
461
|
+
@wait_queue = ::Queue.new
|
462
|
+
@wait_tickets = []
|
463
|
+
@poll_threads = []
|
464
|
+
@event_tickets = []
|
465
|
+
|
466
|
+
blk.call(self) if blk
|
467
|
+
end
|
468
|
+
|
469
|
+
def poll( period=5, max_retry=10, &blk)
|
470
|
+
wticket = Wakame::Util.gen_id
|
471
|
+
@poll_threads << Thread.new {
|
472
|
+
retry_count = 0
|
473
|
+
|
474
|
+
begin
|
475
|
+
catch(:finish) {
|
476
|
+
while retry_count < max_retry
|
477
|
+
start_at = Time.now
|
478
|
+
if blk.call == true
|
479
|
+
throw :finish
|
480
|
+
end
|
481
|
+
Thread.pass
|
482
|
+
if period > 0
|
483
|
+
t = Time.now - start_at
|
484
|
+
sleep (period - t) if period > t
|
485
|
+
end
|
486
|
+
retry_count += 1
|
487
|
+
end
|
488
|
+
}
|
489
|
+
|
490
|
+
if retry_count >= max_retry
|
491
|
+
Wakame.log.error('Over retry count')
|
492
|
+
raise 'Over retry count'
|
493
|
+
end
|
494
|
+
|
495
|
+
rescue => e
|
496
|
+
Wakame.log.error(e)
|
497
|
+
@wait_queue << [false, wticket, e]
|
498
|
+
else
|
499
|
+
@wait_queue << [true, wticket]
|
500
|
+
end
|
501
|
+
}
|
502
|
+
@poll_threads.last[:name]="#{self.class} poll"
|
503
|
+
|
504
|
+
@wait_tickets << wticket
|
505
|
+
end
|
506
|
+
thread_immutable_methods :poll
|
507
|
+
|
508
|
+
def wait_event(event_class, &blk)
|
509
|
+
wticket = Wakame::Util.gen_id
|
510
|
+
Wakame.log.debug("#{self.class} called wait_event(#{event_class}) on thread #{Thread.current} (target_thread=#{self.target_thread?}). has_blk=#{blk}")
|
511
|
+
ticket = Wakame::EventDispatcher.subscribe(event_class) { |event|
|
512
|
+
begin
|
513
|
+
if blk.call(event) == true
|
514
|
+
Wakame::EventDispatcher.unsubscribe(ticket)
|
515
|
+
@wait_queue << [true, wticket]
|
516
|
+
end
|
517
|
+
rescue => e
|
518
|
+
Wakame.log.error(e)
|
519
|
+
Wakame::EventDispatcher.unsubscribe(ticket)
|
520
|
+
@wait_queue << [false, wticket, e]
|
521
|
+
end
|
522
|
+
}
|
523
|
+
@event_tickets << ticket
|
524
|
+
|
525
|
+
@wait_tickets << wticket
|
526
|
+
end
|
527
|
+
thread_immutable_methods :wait_event
|
528
|
+
|
529
|
+
def wait(tout=nil)
|
530
|
+
|
531
|
+
unless @wait_tickets.empty?
|
532
|
+
Wakame.log.debug("#{self.class} waits for #{@wait_tickets.size} num of event(s)/polling(s).")
|
533
|
+
|
534
|
+
timeout(tout, TimeoutError) {
|
535
|
+
while @wait_tickets.size > 0 && q = @wait_queue.shift
|
536
|
+
@wait_tickets.delete(q[1])
|
537
|
+
|
538
|
+
unless q[0]
|
539
|
+
Wakame.log.debug("#{q[1]} failed with #{q[2]}")
|
540
|
+
raise q[2]
|
541
|
+
end
|
542
|
+
end
|
543
|
+
}
|
544
|
+
end
|
545
|
+
|
546
|
+
ensure
|
547
|
+
# Cleanup generated threads/event tickets
|
548
|
+
@poll_threads.each { |t|
|
549
|
+
begin
|
550
|
+
t.kill
|
551
|
+
rescue => e
|
552
|
+
Wakame.log.error(e)
|
553
|
+
end
|
554
|
+
}
|
555
|
+
@event_tickets.each { |t| Wakame::EventDispatcher.unsubscribe(t) }
|
556
|
+
end
|
557
|
+
thread_immutable_methods :wait
|
558
|
+
|
559
|
+
def self.wait(timeout=60*30, &blk)
|
560
|
+
cond = ConditionalWait.new
|
561
|
+
cond.bind_thread(Thread.current)
|
562
|
+
|
563
|
+
#cond.instance_eval(&blk)
|
564
|
+
blk.call(cond)
|
565
|
+
|
566
|
+
cond.wait(timeout)
|
567
|
+
end
|
568
|
+
|
569
|
+
end
|