isono 0.1.0 → 0.2.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.
- data/.gitignore +2 -0
- data/Rakefile +38 -0
- data/isono.gemspec +13 -12
- data/lib/isono.rb +5 -4
- data/lib/isono/amqp_client.rb +71 -42
- data/lib/isono/logger.rb +19 -9
- data/lib/isono/manifest.rb +9 -10
- data/lib/isono/node.rb +41 -25
- data/lib/isono/node_modules/base.rb +25 -9
- data/lib/isono/node_modules/event_channel.rb +18 -7
- data/lib/isono/node_modules/job_channel.rb +20 -21
- data/lib/isono/node_modules/job_worker.rb +47 -28
- data/lib/isono/node_modules/rpc_channel.rb +46 -96
- data/lib/isono/rack/job.rb +19 -32
- data/lib/isono/runner/base.rb +150 -0
- data/lib/isono/runner/cli.rb +28 -0
- data/lib/isono/runner/rpc_server.rb +21 -53
- data/lib/isono/thread_pool.rb +24 -19
- data/lib/isono/util.rb +12 -4
- data/lib/isono/version.rb +5 -0
- data/spec/amqp_client_spec.rb +71 -0
- data/spec/event_observable_spec.rb +6 -0
- data/spec/file_channel_spec.rb +263 -0
- data/spec/job_channel_spec.rb +47 -0
- data/spec/logger_spec.rb +45 -0
- data/spec/manifest_spec.rb +43 -0
- data/spec/node_spec.rb +64 -0
- data/spec/resource_loader_spec.rb +113 -0
- data/spec/rpc_channel_spec.rb +172 -0
- data/spec/spec_helper.rb +62 -0
- data/spec/thread_pool_spec.rb +35 -0
- data/spec/util_spec.rb +38 -0
- data/tasks/load_resource_manifest.rake +7 -0
- metadata +79 -43
- data/lib/isono/runner/agent.rb +0 -89
data/spec/node_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
require File.expand_path('../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
require 'isono'
|
5
|
+
include Isono
|
6
|
+
|
7
|
+
class HookTest < Isono::NodeModules::Base
|
8
|
+
before_connect_hook do
|
9
|
+
$pass.shift.should.equal :before_connect
|
10
|
+
end
|
11
|
+
|
12
|
+
after_connect_hook do
|
13
|
+
$pass.shift.should.equal :after_connect
|
14
|
+
end
|
15
|
+
|
16
|
+
before_close_hook do
|
17
|
+
$pass.shift.should.equal :before_close
|
18
|
+
end
|
19
|
+
|
20
|
+
after_close_hook do
|
21
|
+
$pass.shift.should.equal :after_close
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class MockNode < Isono::Node
|
26
|
+
def initialize()
|
27
|
+
super(Isono::Manifest.new do
|
28
|
+
end)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe Isono::Node do
|
33
|
+
|
34
|
+
em "connects to AMQP broker" do
|
35
|
+
a = MockNode.new
|
36
|
+
a.connect('amqp://localhost/') {
|
37
|
+
a.amqp_client.should.not.nil?
|
38
|
+
a.amqp_client.instance_variable_get(:@connection_status).should.is_a?(Proc)
|
39
|
+
EM.next_tick {
|
40
|
+
a.close {
|
41
|
+
EM.stop
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
em "call node_module hooks" do
|
48
|
+
$pass = [:before_connect, :after_connect,
|
49
|
+
:before_close, :after_close]
|
50
|
+
a = Node.new(Isono::Manifest.new do
|
51
|
+
load_module HookTest
|
52
|
+
end)
|
53
|
+
a.connect('amqp://localhost/') {
|
54
|
+
EM.next_tick {
|
55
|
+
a.close {
|
56
|
+
$pass.size.should.equal 0
|
57
|
+
EM.stop
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
require 'isono'
|
4
|
+
|
5
|
+
MM = Isono::ManagerModules
|
6
|
+
|
7
|
+
describe "ResourceLoader Test" do
|
8
|
+
|
9
|
+
it "loads manifest block" do
|
10
|
+
rm = Isono::ResourceManifest.new('./')
|
11
|
+
|
12
|
+
Isono::ResourceManifest::Loader.new(rm).instance_eval {
|
13
|
+
state_monitor 'Hva::XenInstanceStore::XenMonitor'
|
14
|
+
#monitor Hva::XenCapacityMonitor
|
15
|
+
|
16
|
+
description "resource1"
|
17
|
+
|
18
|
+
statemachine {
|
19
|
+
trans :init, :on_load, :ready
|
20
|
+
trans :ready, :on_start, :starting
|
21
|
+
trans :starting, :on_online, :running
|
22
|
+
trans :running, :on_attach_volume, :attaching_volume
|
23
|
+
trans :attaching_volume, :on_back_to_run, :running
|
24
|
+
trans :running, :on_stop, :shuttingdown
|
25
|
+
trans :shuttingdown, :on_offline, :terminated
|
26
|
+
}
|
27
|
+
|
28
|
+
#entry_state(:running) do
|
29
|
+
# resource_graph.find(:connected, my_resource_uuid).each { |res_uuid|
|
30
|
+
# on_event :stopped, res_uuid do
|
31
|
+
# #do something
|
32
|
+
# end
|
33
|
+
# }
|
34
|
+
#end
|
35
|
+
|
36
|
+
entry_state(:running) do
|
37
|
+
on_event :stop_vm, 'mgr-master' do
|
38
|
+
process_event(:on_stop)
|
39
|
+
end
|
40
|
+
|
41
|
+
on_event(:attach_volume, 'storage_node') {
|
42
|
+
process_event(:on_attach_volume)
|
43
|
+
}
|
44
|
+
|
45
|
+
task {
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
entry_state(:ready) do
|
50
|
+
task do
|
51
|
+
# immediatry change the state
|
52
|
+
state_monitor.start
|
53
|
+
process_event(:on_start)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
entry_state(:starting) {
|
58
|
+
task :rake, 'start_vm'
|
59
|
+
}
|
60
|
+
|
61
|
+
entry_state(:shuttingdown) {
|
62
|
+
task :rake, 'stop_vm'
|
63
|
+
}
|
64
|
+
|
65
|
+
entry_state(:attaching_volume) {
|
66
|
+
task :rake, 'attach_file_vol'
|
67
|
+
}
|
68
|
+
|
69
|
+
entry_state(:terminated) {
|
70
|
+
task do
|
71
|
+
state_monitor.stop
|
72
|
+
end
|
73
|
+
}
|
74
|
+
|
75
|
+
}
|
76
|
+
|
77
|
+
rm.stm.should.is_a? Statemachine::Statemachine
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
it "resource instance process" do
|
84
|
+
|
85
|
+
rm = Isono::ResourceManifest.new('./')
|
86
|
+
|
87
|
+
Isono::ResourceManifest::Loader.new(rm).instance_eval {
|
88
|
+
state_monitor 'Hva::XenInstanceStore::XenMonitor'
|
89
|
+
#monitor Hva::XenCapacityMonitor
|
90
|
+
|
91
|
+
description "resource1"
|
92
|
+
|
93
|
+
statemachine {
|
94
|
+
trans :init, :on_load, :ready
|
95
|
+
trans :ready, :on_start, :starting
|
96
|
+
trans :starting, :on_online, :running
|
97
|
+
trans :running, :on_attach_volume, :attaching_volume
|
98
|
+
trans :attaching_volume, :on_back_to_run, :running
|
99
|
+
trans :running, :on_stop, :shuttingdown
|
100
|
+
trans :shuttingdown, :on_offline, :terminated
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
EM.run {
|
105
|
+
Isono::ResourceInstance.start('testuuid', rm, {:amqp_server_uri => URI.parse('amqp://guest:guest@localhost/'),
|
106
|
+
})
|
107
|
+
EM.add_timer(1) {
|
108
|
+
Isono::ResourceInstance.stop
|
109
|
+
EM.stop
|
110
|
+
}
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
|
2
|
+
require File.expand_path('../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
require 'isono'
|
5
|
+
|
6
|
+
MM = Isono::NodeModules
|
7
|
+
include Isono
|
8
|
+
|
9
|
+
def client_connect(main_cb, pre_cb=nil, post_cb=nil)
|
10
|
+
manifest = Manifest.new(File.expand_path('../', __FILE__)) {
|
11
|
+
node_name :cli
|
12
|
+
node_instance_id :xxx
|
13
|
+
|
14
|
+
load_module MM::EventChannel
|
15
|
+
load_module MM::RpcChannel
|
16
|
+
}
|
17
|
+
c = Node.new(manifest)
|
18
|
+
pre_cb.call if pre_cb
|
19
|
+
c.connect('amqp://localhost/') {
|
20
|
+
main_cb.call(c)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def svr_connect(main_cb, pre_cb=nil, post_cb=nil)
|
26
|
+
manifest = Manifest.new(File.expand_path('../', __FILE__)) {
|
27
|
+
node_name :endpoint
|
28
|
+
node_instance_id :xxx
|
29
|
+
|
30
|
+
load_module MM::EventChannel
|
31
|
+
load_module MM::RpcChannel
|
32
|
+
}
|
33
|
+
c = Node.new(manifest)
|
34
|
+
pre_cb.call if pre_cb
|
35
|
+
c.connect('amqp://localhost/') {
|
36
|
+
main_cb.call(c)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
describe Isono::NodeModules::RpcChannel do
|
42
|
+
em "creates connection" do
|
43
|
+
done = []
|
44
|
+
svr_connect(proc{ |c|
|
45
|
+
c.close {
|
46
|
+
done << 1
|
47
|
+
}
|
48
|
+
})
|
49
|
+
|
50
|
+
client_connect(proc {|c|
|
51
|
+
c.close {
|
52
|
+
done << 1
|
53
|
+
}
|
54
|
+
})
|
55
|
+
|
56
|
+
EM.tick_loop {
|
57
|
+
if done == [1, 1]
|
58
|
+
done.should.equal [1, 1]
|
59
|
+
EM.stop
|
60
|
+
end
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
em "send async request" do
|
65
|
+
svr_connect(proc{|c|
|
66
|
+
rpc = MM::RpcChannel.new(c)
|
67
|
+
rpc.register_endpoint('endpoint1', Isono::Rack::Map.build { |t|
|
68
|
+
t.map('kill') {
|
69
|
+
request.args[0].should.equal 'arg1'
|
70
|
+
request.args[1].should.equal 'arg2'
|
71
|
+
request.args[2].should.equal 'arg3'
|
72
|
+
|
73
|
+
EM.next_tick { EM.stop }
|
74
|
+
response.response({:code=>1})
|
75
|
+
}
|
76
|
+
})
|
77
|
+
})
|
78
|
+
client_connect(proc {|c|
|
79
|
+
rpc = MM::RpcChannel.new(c)
|
80
|
+
req0 = rpc.request('endpoint1', 'kill', 'arg1', "arg2", "arg3") { |req|
|
81
|
+
req.on_success { |res|
|
82
|
+
req0.ticket.should.equal req.ticket
|
83
|
+
res[:code].should.equal 1
|
84
|
+
c.close
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
)
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
em "request timeout" do
|
94
|
+
client_connect(proc {|c|
|
95
|
+
rpc = MM::RpcChannel.new(c)
|
96
|
+
rpc.request('test', 'test1') { |req|
|
97
|
+
req.timeout_sec = 0.2
|
98
|
+
req.on_error { |e|
|
99
|
+
e.should.equal :timeout
|
100
|
+
c.close { EM.stop }
|
101
|
+
}
|
102
|
+
}
|
103
|
+
})
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
em "use Isono::Rack dispatcher" do
|
108
|
+
func1_count = 0
|
109
|
+
svr_connect(proc{|c|
|
110
|
+
rpc = MM::RpcChannel.new(c)
|
111
|
+
endpoint1 = Isono::Rack::Map.build { |t|
|
112
|
+
t.map('kill') {
|
113
|
+
func1_count.should.equal 10
|
114
|
+
EM.next_tick { EM.stop }
|
115
|
+
}
|
116
|
+
t.map('func1') {
|
117
|
+
request.args[0].should.equal 'arg1'
|
118
|
+
func1_count += 1
|
119
|
+
response.response({:code=>1})
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
rpc.register_endpoint('endpoint1', Isono::Rack::ThreadPass.new(endpoint1))
|
124
|
+
})
|
125
|
+
client_connect(proc {|c|
|
126
|
+
rpc = MM::RpcChannel.new(c)
|
127
|
+
10.times { |no|
|
128
|
+
req0 = rpc.request('endpoint1', 'func1', 'arg1') { |req|
|
129
|
+
req.on_success { |res|
|
130
|
+
req0.ticket.should.equal req.ticket
|
131
|
+
req0.complete_status.should.equal :success
|
132
|
+
#((req0.completed_at - req0.sent_at) > 1.5).should.be.true
|
133
|
+
res[:code].should.equal 1
|
134
|
+
#puts "#{no} elapesed: #{req0.elapsed_time}"
|
135
|
+
if no == 9
|
136
|
+
rpc.request('endpoint1', 'kill') do |req|
|
137
|
+
req.on_success { |res|
|
138
|
+
res[:code].should.equal 1
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
})
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
em "catch remote exception" do
|
150
|
+
svr_connect(proc{|c|
|
151
|
+
rpc = MM::RpcChannel.new(c)
|
152
|
+
rpc.register_endpoint('endpoint1', Isono::Rack::Map.build { |t|
|
153
|
+
t.map('kill') {
|
154
|
+
raise StandardError, "message"
|
155
|
+
response.response({:code=>1})
|
156
|
+
}
|
157
|
+
})
|
158
|
+
}, proc{
|
159
|
+
})
|
160
|
+
client_connect(proc {|c|
|
161
|
+
rpc = MM::RpcChannel.new(c)
|
162
|
+
rpc.request('endpoint1', 'kill') { |req|
|
163
|
+
req.on_error { |e|
|
164
|
+
e.should.equal({:error_type=>'StandardError', :message=>'message'})
|
165
|
+
EM.stop
|
166
|
+
}
|
167
|
+
}
|
168
|
+
})
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
5
|
+
|
6
|
+
require 'bacon'
|
7
|
+
#require 'spec'
|
8
|
+
require 'isono'
|
9
|
+
|
10
|
+
class AmqpStub < Isono::Node
|
11
|
+
include Isono::Logger
|
12
|
+
|
13
|
+
|
14
|
+
def fork_and_connect(broker_uri='amqp://localhost/', *args, &blk)
|
15
|
+
EM.fork_reactor {
|
16
|
+
connect(broker_uri, *args, &blk)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect(broker_uri='amqp://localhost/', *args, &blk)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_connect
|
25
|
+
manifest.managers.each { |a|
|
26
|
+
a[0].class.reset_instance
|
27
|
+
}
|
28
|
+
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
#def on_close
|
33
|
+
#end
|
34
|
+
|
35
|
+
|
36
|
+
def mm_instance(mgr_class, *args)
|
37
|
+
raise ArgumentError unless mgr_class < Isono::ManagerModules::Base
|
38
|
+
|
39
|
+
m = mgr_class.instance
|
40
|
+
m.agent = self
|
41
|
+
m.on_init(args)
|
42
|
+
m
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def em_fork(main_cb, post_cb=nil)
|
48
|
+
fork {
|
49
|
+
EM.run {
|
50
|
+
main_cb.call
|
51
|
+
}
|
52
|
+
post_cb.call if post_cb
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
class Bacon::Context
|
57
|
+
def em(desc, &blk)
|
58
|
+
it(desc) {
|
59
|
+
EM.run &blk
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
require 'isono'
|
4
|
+
|
5
|
+
|
6
|
+
describe "ThreadPool Test" do
|
7
|
+
|
8
|
+
it "create a thread pool" do
|
9
|
+
a = Isono::ThreadPool.new
|
10
|
+
#a.should Isono::ThreadPool
|
11
|
+
end
|
12
|
+
|
13
|
+
it "call pass() with single thread" do
|
14
|
+
a = Isono::ThreadPool.new
|
15
|
+
t = 0
|
16
|
+
a.pass { t = 1 }
|
17
|
+
|
18
|
+
t.should eql(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "call barrier() with single thread" do
|
22
|
+
a = Isono::ThreadPool.new
|
23
|
+
t = 0
|
24
|
+
a.barrier { t = 1 }
|
25
|
+
|
26
|
+
t.should eql(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "catch exception from barrier()" do
|
30
|
+
a = Isono::ThreadPool.new
|
31
|
+
lambda {
|
32
|
+
a.barrier { raise "Error" }
|
33
|
+
}.should raise_error(RuntimeError, "Error")
|
34
|
+
end
|
35
|
+
end
|