villein 0.0.2 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: df2731fb88973b484824361021f7e95383f6642c
4
- data.tar.gz: 9b68ffc3464ee705d645446fdf017819da130340
3
+ metadata.gz: 7f55592c52186b2368ce3cdee25bc3726321ab5b
4
+ data.tar.gz: 6f20e0f243da17e2c400d1207069fe796a2022f0
5
5
  SHA512:
6
- metadata.gz: a375d7bc0d40dc65b5fe94bc5b80ed0074a1efd53c48b5ced070d7bb4ed8cab085ecad3cea4994c3a79bf7512338995db5b65b9e7f093f3dcd46fcd8596d056a
7
- data.tar.gz: 4eadcdd42d2619e7d77c5ee1ece33029fb5218f437ed9c4b10a80a0b06a1edcc278f357ac1c195475120f14e3516090f025b2cfe7cbbcf41b56ef80123c37980
6
+ metadata.gz: 202eda9a335d1239cb69f025c9239d715ca566cc710e8e2a0239bf42e1b2542b90cfea5948b65b08442770fe373b5abb2c32dbd459ca4018f8a0428f916e4f42
7
+ data.tar.gz: 320efc986bf0c185db5ce68dcecb296a5e5a4a9b97204927a61ba42c7b90f02d283150e2af9776d16555493de324dea15bc5b61c28e30f703bcc030ed8c2a5f8
@@ -6,6 +6,19 @@ module Villein
6
6
  # Villein::Client allows you to order existing serf agent.
7
7
  # You will need RPC address and agent name to command.
8
8
  class Client
9
+
10
+ ##
11
+ # for serf command failures
12
+ class SerfError < Exception; end
13
+
14
+ ##
15
+ # Error for the given argument exceeds the limit of serf when setting tags and sending events.
16
+ class LengthExceedsLimitError < SerfError; end
17
+
18
+ ##
19
+ # Error for connection failures
20
+ class SerfConnectionError < SerfError; end
21
+
9
22
  def initialize(rpc_addr, name: nil, serf: 'serf', silence: true)
10
23
  @rpc_addr = rpc_addr
11
24
  @name = name
@@ -56,7 +69,7 @@ module Villein
56
69
  options.push('-tag', "#{tag}=#{val}")
57
70
  end
58
71
 
59
- json = IO.popen(['serf', 'members', "-rpc-addr=#{rpc_addr}", *options], 'r', &:read)
72
+ json = call_serf('members', *options)
60
73
  response = JSON.parse(json)
61
74
 
62
75
  response["members"]
@@ -94,14 +107,23 @@ module Villein
94
107
  private
95
108
 
96
109
  def call_serf(cmd, *args)
97
- options = {}
110
+ status, out = IO.popen([@serf, cmd, "-rpc-addr=#{rpc_addr}", *args, err: [:child, :out]], 'r') do |io|
111
+ _, s = Process.waitpid2(io.pid)
112
+ [s, io.read]
113
+ end
98
114
 
99
- if silence?
100
- options[:out] = File::NULL
101
- options[:err] = File::NULL
115
+ unless status.success?
116
+ case out
117
+ when /^Error connecting to Serf agent:/
118
+ raise SerfConnectionError, out.chomp
119
+ when /exceeds limit of \d+ bytes$/
120
+ raise LengthExceedsLimitError, out.chomp
121
+ else
122
+ raise SerfError, out.chomp
123
+ end
102
124
  end
103
125
 
104
- system @serf, cmd, "-rpc-addr=#{rpc_addr}", *args, options
126
+ out
105
127
  end
106
128
  end
107
129
  end
@@ -1,3 +1,3 @@
1
1
  module Villein
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -5,58 +5,132 @@ describe Villein::Client do
5
5
  let(:name) { 'the-node' }
6
6
  subject(:client) { described_class.new('x.x.x.x:nnnn', name: name) }
7
7
 
8
- def expect_serf(cmd, *args, retval: true, out: File::NULL)
9
- expect(subject).to receive(:system) \
10
- .with('serf', cmd, '-rpc-addr=x.x.x.x:nnnn', *args, out: out, err: out) \
11
- .and_return(retval)
8
+ def expect_serf(cmd, *args, success: true, message: '')
9
+ if [cmd, *args].compact.empty?
10
+ expect(IO).to receive(:popen) \
11
+ .with(any_args)
12
+ .and_yield(double('io', read: message, pid: 727272))
13
+
14
+ else
15
+ expect(IO).to receive(:popen) \
16
+ .with(['serf', cmd, '-rpc-addr=x.x.x.x:nnnn', *args,
17
+ err: [:child, :out]],
18
+ 'r') \
19
+ .and_yield(double('io', read: message, pid: 727272))
20
+ end
21
+
22
+ status = double('proc-status', pid: 727272, success?: success)
23
+
24
+ allow(Process).to receive(:waitpid2).with(727272).and_return([727272, status])
25
+ end
26
+
27
+ shared_examples "failure cases" do
28
+ context "when command failed" do
29
+ it "raises error" do
30
+ expect_serf(nil, success: false, message: 'err')
31
+
32
+ expect {
33
+ subject
34
+ }.to raise_error(Villein::Client::SerfError, 'err')
35
+ end
36
+ end
37
+
38
+ context "when connection failed" do
39
+ it "raises error" do
40
+ expect_serf(nil,
41
+ success: false,
42
+ message: 'Error connecting to Serf agent: dial tcp x.x.x.x:nnnn: connection refused')
43
+
44
+ expect {
45
+ subject
46
+ }.to raise_error(
47
+ Villein::Client::SerfConnectionError,
48
+ 'Error connecting to Serf agent: dial tcp x.x.x.x:nnnn: connection refused')
49
+ end
50
+ end
12
51
  end
13
52
 
14
53
  describe "#event" do
54
+ subject { client.event('test', 'payload') }
55
+
15
56
  it "sends user event" do
16
57
  expect_serf('event', 'test', 'payload')
17
58
 
18
- client.event('test', 'payload')
59
+ subject
19
60
  end
20
61
 
21
62
  context "with coalesce=false" do
63
+ subject { client.event('test', 'payload', coalesce: false) }
64
+
22
65
  it "sends user event with the option" do
23
66
  expect_serf('event', '-coalesce=false', 'test', 'payload')
24
67
 
25
- client.event('test', 'payload', coalesce: false)
68
+ subject
69
+ end
70
+ end
71
+
72
+ include_examples "failure cases"
73
+
74
+ context "when length exceeds limit" do
75
+ it "raises error" do
76
+ expect_serf('event', 'test', 'payload',
77
+ success: false,
78
+ message: 'Error sending event: user event exceeds limit of 256 bytes')
79
+
80
+ expect {
81
+ subject
82
+ }.to raise_error(
83
+ Villein::Client::LengthExceedsLimitError,
84
+ 'Error sending event: user event exceeds limit of 256 bytes')
26
85
  end
27
86
  end
87
+
28
88
  end
29
89
 
30
90
  describe "#join" do
91
+ subject { client.join('y.y.y.y:nnnn') }
92
+
31
93
  it "attempts to join another node" do
32
94
  expect_serf('join', 'y.y.y.y:nnnn')
33
95
 
34
- client.join('y.y.y.y:nnnn')
96
+ subject
35
97
  end
36
98
 
37
99
  context "with replay=true" do
100
+ subject { client.join('y.y.y.y:nnnn', replay: true) }
101
+
38
102
  it "attempts to join another node with replaying" do
39
103
  expect_serf('join', '-replay', 'y.y.y.y:nnnn')
40
104
 
41
- client.join('y.y.y.y:nnnn', replay: true)
105
+ subject
42
106
  end
43
107
  end
108
+
109
+ include_examples "failure cases"
44
110
  end
45
111
 
46
112
  describe "#leave" do
113
+ subject { client.leave }
114
+
47
115
  it "attempts to leave from cluster" do
48
116
  expect_serf('leave')
49
117
 
50
- client.leave
118
+ subject
51
119
  end
120
+
121
+ include_examples "failure cases"
52
122
  end
53
123
 
54
124
  describe "#force_leave" do
125
+ subject { client.force_leave('the-node') }
126
+
55
127
  it "attempts to remove member forcely" do
56
128
  expect_serf('force-leave', 'the-node')
57
129
 
58
- client.force_leave('the-node')
130
+ subject
59
131
  end
132
+
133
+ include_examples "failure cases"
60
134
  end
61
135
 
62
136
  describe "#members" do
@@ -65,18 +139,18 @@ describe Villein::Client do
65
139
  "tags":{"key":"val"},"status":"alive","protocol":{"max":4,"min":2,"version":4}}]}
66
140
  EOJ
67
141
 
142
+ subject(:members) { client.members }
143
+
68
144
  it "returns member list" do
69
- allow(IO).to receive(:popen).with(%w(serf members -rpc-addr=x.x.x.x:nnnn -format json), 'r') \
70
- .and_yield(double('io', read: json))
145
+ expect_serf('members', '-format', 'json', message: json)
71
146
 
72
- expect(client.members).to be_a_kind_of(Array)
73
- expect(client.members[0]["name"]).to eq "the-node"
147
+ expect(members).to be_a_kind_of(Array)
148
+ expect(members[0]["name"]).to eq "the-node"
74
149
  end
75
150
 
76
151
  context "with status filter" do
77
152
  it "returns member list" do
78
- allow(IO).to receive(:popen).with(%w(serf members -rpc-addr=x.x.x.x:nnnn -format json -status alive), 'r') \
79
- .and_yield(double('io', read: json))
153
+ expect_serf('members', '-format', 'json', '-status', 'alive', message: json)
80
154
 
81
155
  client.members(status: :alive)
82
156
  end
@@ -84,8 +158,7 @@ describe Villein::Client do
84
158
 
85
159
  context "with name filter" do
86
160
  it "returns member list" do
87
- allow(IO).to receive(:popen).with(%w(serf members -rpc-addr=x.x.x.x:nnnn -format json -name node), 'r') \
88
- .and_yield(double('io', read: json))
161
+ expect_serf('members', '-format', 'json', '-name', 'node', message: json)
89
162
 
90
163
  client.members(name: 'node')
91
164
  end
@@ -93,12 +166,13 @@ describe Villein::Client do
93
166
 
94
167
  context "with tag filter" do
95
168
  it "returns member list" do
96
- allow(IO).to receive(:popen).with(%w(serf members -rpc-addr=x.x.x.x:nnnn -format json -tag a=1 -tag b=2), 'r') \
97
- .and_yield(double('io', read: json))
169
+ expect_serf('members', *%w(-format json -tag a=1 -tag b=2), message: json)
98
170
 
99
171
  client.members(tags: {a: '1', b: '2'})
100
172
  end
101
173
  end
174
+
175
+ include_examples "failure cases"
102
176
  end
103
177
 
104
178
  describe "#tags" do
@@ -117,19 +191,41 @@ describe Villein::Client do
117
191
  end
118
192
 
119
193
  describe "#set_tag" do
194
+ subject { client.set_tag('newkey', 'newval') }
195
+
120
196
  it "sets tag" do
121
197
  expect_serf('tags', '-set', 'newkey=newval')
122
198
 
123
- client.set_tag('newkey', 'newval')
199
+ subject
200
+ end
201
+
202
+ include_examples "failure cases"
203
+
204
+ context "when length exceeds limit" do
205
+ it "raises error" do
206
+ expect_serf('tags', '-set', 'newkey=newval',
207
+ success: false,
208
+ message: 'Error setting tags: Encoded length of tags exceeds limit of 512 bytes')
209
+
210
+ expect {
211
+ client.set_tag('newkey', 'newval')
212
+ }.to raise_error(
213
+ Villein::Client::LengthExceedsLimitError,
214
+ 'Error setting tags: Encoded length of tags exceeds limit of 512 bytes')
215
+ end
124
216
  end
125
217
  end
126
218
 
127
219
  describe "#delete_tag" do
220
+ subject { client.delete_tag('newkey') }
221
+
128
222
  it "deletes tag" do
129
223
  expect_serf('tags', '-delete', 'newkey')
130
224
 
131
- client.delete_tag('newkey')
225
+ subject
132
226
  end
227
+
228
+ include_examples "failure cases"
133
229
  end
134
230
 
135
231
  describe "#get_tags" do
@@ -141,8 +237,7 @@ describe Villein::Client do
141
237
  "tags":{"key":"val"},"status":"alive","protocol":{"max":4,"min":2,"version":4}}]}
142
238
  EOJ
143
239
 
144
- allow(IO).to receive(:popen).with(%w(serf members -rpc-addr=x.x.x.x:nnnn -format json -name the-node), 'r') \
145
- .and_yield(double('io', read: json))
240
+ expect_serf('members', *%w(-format json -name the-node), message: json)
146
241
 
147
242
  expect(tags).to be_a_kind_of(Hash)
148
243
  expect(tags['key']).to eq 'val'
@@ -155,6 +250,8 @@ describe Villein::Client do
155
250
  expect { tags }.to raise_error
156
251
  end
157
252
  end
253
+
254
+ include_examples "failure cases"
158
255
  end
159
256
  end
160
257
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: villein
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Fukumori (sora_h)