corosync 0.0.3 → 0.1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/README.md +24 -5
- data/Rakefile +62 -1
- data/VERSION +1 -0
- data/corosync.gemspec +1 -3
- data/examples/cmap-cli.rb +72 -0
- data/examples/cpg-chat.rb +75 -0
- data/examples/{example.rb → cpg-monitor.rb} +1 -1
- data/ffi/cmap.i +14 -0
- data/ffi/cmap.rb +91 -0
- data/ffi/common.rb +1 -1
- data/ffi/cpg.rb +57 -15
- data/ffi/quorum.i +14 -0
- data/ffi/quorum.rb +36 -0
- data/ffi/votequorum.i +14 -0
- data/ffi/votequorum.rb +87 -0
- data/lib/corosync.rb +69 -1
- data/lib/corosync/cmap.rb +381 -0
- data/lib/corosync/cpg.rb +27 -46
- data/lib/corosync/exceptions.rb +34 -0
- data/lib/corosync/quorum.rb +143 -0
- data/lib/corosync/votequorum.rb +218 -0
- data/lib/ffi_pointer.rb +28 -0
- data/spec/corosync/cmap.rb +99 -0
- data/spec/corosync/cpg.rb +1 -0
- data/spec/corosync/quorum.rb +66 -0
- data/spec/corosync/votequorum.rb +81 -0
- data/spec/spec_helper.rb +1 -1
- metadata +20 -4
- data/lib/version.rb +0 -3
data/lib/ffi_pointer.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
# We create these 2 methods because of types like `size_t`. The type changes by platform, so we don't know which write/read method to use. So we create a generic read/write that we can pass a type to and it will figure out which method needs to be used.
|
4
|
+
|
5
|
+
class FFI::Pointer
|
6
|
+
def read_type(type)
|
7
|
+
type = FFI.find_type(type) if type.is_a?(Symbol)
|
8
|
+
type = type.native_type if type.is_a?(FFI::Type::Mapped)
|
9
|
+
raise ArgumentError, "Can only read built-in types (type=#{type})" unless type.is_a?(FFI::Type::Builtin)
|
10
|
+
name = type.inspect.match(/<#{type.class}:(\S+)/)[1].downcase
|
11
|
+
method = "read_#{name}".to_sym
|
12
|
+
self.send(method)
|
13
|
+
end
|
14
|
+
def write_type(type, value)
|
15
|
+
type = FFI.find_type(type) if type.is_a?(Symbol)
|
16
|
+
type = type.native_type if type.is_a?(FFI::Type::Mapped)
|
17
|
+
raise ArgumentError, "Can only write built-in types (type=#{type})" unless type.is_a?(FFI::Type::Builtin)
|
18
|
+
name = type.inspect.match(/<#{type.class}:(\S+)/)[1].downcase
|
19
|
+
method = "write_#{name}".to_sym
|
20
|
+
self.send(method, value)
|
21
|
+
end
|
22
|
+
|
23
|
+
# these are methods where the type name doesn't match the method
|
24
|
+
alias_method :write_float32, :write_float
|
25
|
+
alias_method :read_float32, :read_float
|
26
|
+
alias_method :write_float64, :write_double
|
27
|
+
alias_method :read_float64, :read_double
|
28
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
require 'corosync/cmap'
|
5
|
+
describe Corosync::CMAP do
|
6
|
+
before(:all) do
|
7
|
+
@cmap = Corosync::CMAP.new
|
8
|
+
@cmap.connect
|
9
|
+
end
|
10
|
+
|
11
|
+
around :each do |example|
|
12
|
+
Timeout::timeout(1) do
|
13
|
+
example.run
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Corosync::CMAP::SIZEMAP.each do |type, info|
|
18
|
+
it "can set a #{type}" do
|
19
|
+
expect{@cmap.set("test.#{type}", type, info.max)}.to_not raise_error
|
20
|
+
end
|
21
|
+
it "can get a #{type}" do
|
22
|
+
expect(@cmap.get("test.#{type}")).to eq([type, info.max])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
it 'can set a float' do
|
26
|
+
expect{@cmap.set('test.float', :float, 1234.4321)}.to_not raise_error
|
27
|
+
end
|
28
|
+
it 'can get a float' do
|
29
|
+
type, value = @cmap.get('test.float')
|
30
|
+
expect(type).to eq(:float)
|
31
|
+
expect(value).to be_within(0.00005).of(1234.4321)
|
32
|
+
end
|
33
|
+
it 'can set a double' do
|
34
|
+
expect{@cmap.set('test.double', :double, 12345.54321)}.to_not raise_error
|
35
|
+
end
|
36
|
+
it 'can get a double' do
|
37
|
+
type, value = @cmap.get('test.double')
|
38
|
+
expect(type).to eq(:double)
|
39
|
+
expect(value).to be_within(0.000005).of(12345.54321)
|
40
|
+
end
|
41
|
+
it 'cat set a string' do
|
42
|
+
expect{@cmap.set("test.string", :string, 'xyzzy')}.to_not raise_error
|
43
|
+
end
|
44
|
+
it 'can get a string' do
|
45
|
+
expect(@cmap.get("test.string")).to eq([:string, 'xyzzy'])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'can increment a value' do
|
49
|
+
@cmap.set('test.inc', :int32, 100)
|
50
|
+
expect{@cmap.inc('test.inc')}.to_not raise_error
|
51
|
+
expect(@cmap.get('test.inc')).to eq([:int32, 101])
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can decrement a value' do
|
55
|
+
@cmap.set('test.dec', :int32, 100)
|
56
|
+
expect{@cmap.dec('test.dec')}.to_not raise_error
|
57
|
+
expect(@cmap.get('test.dec')).to eq([:int32, 99])
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'can delete a value' do
|
61
|
+
expect{@cmap.delete('test.string')}.to_not raise_error
|
62
|
+
expect{@cmap.get('test.string')}.to raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'can list keys' do
|
66
|
+
keys = @cmap.keys
|
67
|
+
|
68
|
+
expect(keys).to be_a(Array)
|
69
|
+
keys.each do |key|
|
70
|
+
expect(key).to be_a(String)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can track a value' do
|
75
|
+
@cmap.delete('test.track') rescue Exception
|
76
|
+
|
77
|
+
events = []
|
78
|
+
track_id = @cmap.track_add('test.track', [:add, :delete, :modify]) do |*args|
|
79
|
+
events << args
|
80
|
+
end
|
81
|
+
|
82
|
+
@cmap.set('test.track', :uint32, 1234)
|
83
|
+
@cmap.dispatch
|
84
|
+
@cmap.set('test.track', :int32, 1235)
|
85
|
+
@cmap.dispatch
|
86
|
+
@cmap.delete('test.track')
|
87
|
+
@cmap.dispatch
|
88
|
+
|
89
|
+
expect(events).to eq([
|
90
|
+
[:add, 'test.track', :uint32, 1234, nil, nil],
|
91
|
+
[:modify, 'test.track', :int32, 1235, :uint32, 1234],
|
92
|
+
[:delete, 'test.track', nil, nil, :int32, 1235]
|
93
|
+
])
|
94
|
+
|
95
|
+
@cmap.track_delete(track_id)
|
96
|
+
@cmap.set('test.track', :uint32, 1236)
|
97
|
+
expect{@cmap.dispatch}.to raise_error # our timeout defined at the top should kick in
|
98
|
+
end
|
99
|
+
end
|
data/spec/corosync/cpg.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'corosync/quorum'
|
4
|
+
describe Corosync::Quorum do
|
5
|
+
context '#initialize offline' do
|
6
|
+
before(:all) do
|
7
|
+
@quorum = Corosync::Quorum.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'creates a Quorum object' do
|
11
|
+
expect(@quorum).to be_an_instance_of(Corosync::Quorum)
|
12
|
+
expect(@quorum.fd).to be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'connects' do
|
16
|
+
have_callback = false
|
17
|
+
@quorum.on_notify do
|
18
|
+
have_callback = true
|
19
|
+
end
|
20
|
+
|
21
|
+
@quorum.start(true)
|
22
|
+
|
23
|
+
expect(@quorum.fd).to be_an_instance_of(IO)
|
24
|
+
expect(have_callback).to be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#initialize with connect' do
|
29
|
+
before(:all) do
|
30
|
+
@quorum = Corosync::Quorum.new(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'connects' do
|
34
|
+
expect(@quorum).to be_an_instance_of(Corosync::Quorum)
|
35
|
+
expect(@quorum.fd).to_not be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'gets quorum state' do
|
39
|
+
expect([TrueClass,FalseClass]).to include(@quorum.quorate?.class)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'responds to inquorate change' do
|
43
|
+
is_quorate = nil
|
44
|
+
@quorum.on_notify {|quorate| is_quorate = quorate}
|
45
|
+
|
46
|
+
handle = @quorum.instance_variable_get(:@handle)
|
47
|
+
view_list = FFI::MemoryPointer.new(FFI.find_type(:uint32), 1)
|
48
|
+
view_list.write_array_of_type(FFI.find_type(:uint32), :write_uint32, [1])
|
49
|
+
@quorum.send(:callback_notify, handle, 0, nil, 1, view_list)
|
50
|
+
|
51
|
+
expect(is_quorate).to eq(false)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'responds to quorate change' do
|
55
|
+
is_quorate = nil
|
56
|
+
@quorum.on_notify {|quorate| is_quorate = quorate}
|
57
|
+
|
58
|
+
handle = @quorum.instance_variable_get(:@handle)
|
59
|
+
view_list = FFI::MemoryPointer.new(FFI.find_type(:uint32), 2)
|
60
|
+
view_list.write_array_of_type(FFI.find_type(:uint32), :write_uint32, [1,2])
|
61
|
+
@quorum.send(:callback_notify, handle, 1, nil, 1, view_list)
|
62
|
+
|
63
|
+
expect(is_quorate).to eq(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'corosync/votequorum'
|
4
|
+
describe Corosync::Votequorum do
|
5
|
+
context '#initialize offline' do
|
6
|
+
before(:all) do
|
7
|
+
@vq = Corosync::Votequorum.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'creates a Votequorum object' do
|
11
|
+
expect(@vq).to be_an_instance_of(Corosync::Votequorum)
|
12
|
+
expect(@vq.fd).to be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'connects' do
|
16
|
+
have_callback = false
|
17
|
+
@vq.on_notify do
|
18
|
+
have_callback = true
|
19
|
+
end
|
20
|
+
|
21
|
+
@vq.start(true)
|
22
|
+
|
23
|
+
expect(@vq.fd).to be_an_instance_of(IO)
|
24
|
+
expect(have_callback).to be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#initialize with connect' do
|
29
|
+
before(:all) do
|
30
|
+
@vq = Corosync::Votequorum.new(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'connects' do
|
34
|
+
expect(@vq).to be_an_instance_of(Corosync::Votequorum)
|
35
|
+
expect(@vq.fd).to_not be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'gets quorum state' do
|
39
|
+
expect([TrueClass,FalseClass]).to include(@vq.quorate?.class)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'responds to inquorate change' do
|
43
|
+
is_quorate = nil
|
44
|
+
@vq.on_notify {|quorate| is_quorate = quorate}
|
45
|
+
|
46
|
+
handle = @vq.instance_variable_get(:@handle)
|
47
|
+
node_states = {
|
48
|
+
1 => Corosync::VOTEQUORUM_NODESTATE_DEAD,
|
49
|
+
}
|
50
|
+
node_list = FFI::MemoryPointer.new(Corosync::VotequorumNodeT, node_states.size)
|
51
|
+
node_states.to_a.each_with_index do |node_state, i|
|
52
|
+
node = Corosync::VotequorumNodeT.new(node_list + i * Corosync::VotequorumNodeT.size)
|
53
|
+
node[:nodeid] = node_state[0]
|
54
|
+
node[:state] = node_state[1]
|
55
|
+
end
|
56
|
+
@vq.send(:callback_notify, handle, nil, 0, node_states.size, node_list)
|
57
|
+
|
58
|
+
expect(is_quorate).to eq(false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'responds to quorate change' do
|
62
|
+
is_quorate = nil
|
63
|
+
@vq.on_notify {|quorate| is_quorate = quorate}
|
64
|
+
|
65
|
+
handle = @vq.instance_variable_get(:@handle)
|
66
|
+
node_states = {
|
67
|
+
1 => Corosync::VOTEQUORUM_NODESTATE_MEMBER,
|
68
|
+
2 => Corosync::VOTEQUORUM_NODESTATE_MEMBER,
|
69
|
+
}
|
70
|
+
node_list = FFI::MemoryPointer.new(Corosync::VotequorumNodeT, node_states.size)
|
71
|
+
node_states.to_a.each_with_index do |node_state, i|
|
72
|
+
node = Corosync::VotequorumNodeT.new(node_list + i * Corosync::VotequorumNodeT.size)
|
73
|
+
node[:nodeid] = node_state[0]
|
74
|
+
node[:state] = node_state[1]
|
75
|
+
end
|
76
|
+
@vq.send(:callback_notify, handle, nil, 1, node_states.size, node_list)
|
77
|
+
|
78
|
+
expect(is_quorate).to eq(true)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# we have to use the full path because rspec puts itself higher on the list, and we end up requiring `spec/corosync/cpg`
|
2
|
-
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: corosync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Hemmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -36,21 +36,37 @@ files:
|
|
36
36
|
- LICENSE
|
37
37
|
- README.md
|
38
38
|
- Rakefile
|
39
|
+
- VERSION
|
39
40
|
- corosync.gemspec
|
40
|
-
- examples/
|
41
|
+
- examples/cmap-cli.rb
|
42
|
+
- examples/cpg-chat.rb
|
43
|
+
- examples/cpg-monitor.rb
|
44
|
+
- ffi/cmap.i
|
45
|
+
- ffi/cmap.rb
|
41
46
|
- ffi/common.i
|
42
47
|
- ffi/common.rb
|
43
48
|
- ffi/cpg.i
|
44
49
|
- ffi/cpg.rb
|
50
|
+
- ffi/quorum.i
|
51
|
+
- ffi/quorum.rb
|
45
52
|
- ffi/service.i.erb
|
53
|
+
- ffi/votequorum.i
|
54
|
+
- ffi/votequorum.rb
|
46
55
|
- lib/corosync.rb
|
56
|
+
- lib/corosync/cmap.rb
|
47
57
|
- lib/corosync/cpg.rb
|
48
58
|
- lib/corosync/cpg/member.rb
|
49
59
|
- lib/corosync/cpg/member_list.rb
|
50
|
-
- lib/
|
60
|
+
- lib/corosync/exceptions.rb
|
61
|
+
- lib/corosync/quorum.rb
|
62
|
+
- lib/corosync/votequorum.rb
|
63
|
+
- lib/ffi_pointer.rb
|
64
|
+
- spec/corosync/cmap.rb
|
51
65
|
- spec/corosync/cpg.rb
|
52
66
|
- spec/corosync/cpg/member.rb
|
53
67
|
- spec/corosync/cpg/member_list.rb
|
68
|
+
- spec/corosync/quorum.rb
|
69
|
+
- spec/corosync/votequorum.rb
|
54
70
|
- spec/spec_helper.rb
|
55
71
|
homepage: http://github.com/phemmer/ruby-corosync/
|
56
72
|
licenses:
|
data/lib/version.rb
DELETED