etcdv3 0.10.1 → 0.10.2
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 +4 -4
- data/.gitignore +6 -5
- data/README.md +16 -1
- data/lib/etcdv3.rb +6 -2
- data/lib/etcdv3/connection_wrapper.rb +14 -5
- data/lib/etcdv3/version.rb +1 -1
- data/spec/etcdv3/connection_wrapper_spec.rb +39 -8
- data/spec/helpers/connections.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db0142aa621e3ec4612d3d2051b06f208382001d
|
4
|
+
data.tar.gz: a1d300e69e53c41a9a3864d6d480011cc7ffc6a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cd28535b2f39b4b04d0d426b1bbf940997e512922ddc5da85a86d69cf0c24319b40a187d1cde576c5a01ad33f9ee470a33ea02f9fa2c442f6aaee0484b61d36
|
7
|
+
data.tar.gz: 3bb79400389240448d945e9b41b967cf4c4f65d1454bebdcaff4d8c60cbc82023b950e707f70c6bb87d89b0e3e13546eb64a05f1adcdf7356b0a75a35e0d3241
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -32,8 +32,23 @@ conn = Etcdv3.new(endpoints: 'https://hostname:port', user: 'root', password: 'm
|
|
32
32
|
```
|
33
33
|
**High Availability**
|
34
34
|
|
35
|
-
In the event of a failure, the client will work to restore connectivity by cycling through the specified endpoints until a connection can be established. With that being said, it is encouraged to specify multiple endpoints when available.
|
35
|
+
In the event of a failure, the client will work to restore connectivity by cycling through the specified endpoints until a connection can be established. With that being said, it is encouraged to specify multiple endpoints when available. That's the default
|
36
|
+
behaviour.
|
36
37
|
|
38
|
+
However, sometimes this is not what you want. If you need more control over
|
39
|
+
failures, you can suppress this mechanism by using
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
conn = Etcdv3.new(endpoints: 'https://hostname:port', allow_reconnect: false)
|
43
|
+
```
|
44
|
+
|
45
|
+
This will still rotate the endpoints, but it will raise an exception so you can
|
46
|
+
handle the failure yourself. On next call new endpoint (since they were
|
47
|
+
rotated) is tried. One thing you need to keep in mind if you are using etcd with
|
48
|
+
authorization is that you need to take care of `GRPC::Unauthenticated` exceptions
|
49
|
+
and manually re-authenticate when token expires. To reiterate, you are
|
50
|
+
responsible for handling the errors, so some understanding of how this gem and
|
51
|
+
etcd works is recommended.
|
37
52
|
|
38
53
|
## Adding, Fetching and Deleting Keys
|
39
54
|
```ruby
|
data/lib/etcdv3.rb
CHANGED
@@ -21,10 +21,14 @@ class Etcdv3
|
|
21
21
|
attr_reader :conn, :credentials, :options
|
22
22
|
DEFAULT_TIMEOUT = 120
|
23
23
|
|
24
|
-
def initialize(options
|
24
|
+
def initialize(**options)
|
25
25
|
@options = options
|
26
26
|
@timeout = options[:command_timeout] || DEFAULT_TIMEOUT
|
27
|
-
@conn = ConnectionWrapper.new(
|
27
|
+
@conn = ConnectionWrapper.new(
|
28
|
+
@timeout,
|
29
|
+
*sanitized_endpoints,
|
30
|
+
@options.fetch(:allow_reconnect, true),
|
31
|
+
)
|
28
32
|
warn "WARNING: `url` is deprecated. Please use `endpoints` instead." if @options.key?(:url)
|
29
33
|
authenticate(@options[:user], @options[:password]) if @options.key?(:user)
|
30
34
|
end
|
@@ -3,31 +3,40 @@ class Etcdv3
|
|
3
3
|
|
4
4
|
attr_accessor :connection, :endpoints, :user, :password, :token, :timeout
|
5
5
|
|
6
|
-
def initialize(timeout, *endpoints)
|
6
|
+
def initialize(timeout, *endpoints, allow_reconnect)
|
7
7
|
@user, @password, @token = nil, nil, nil
|
8
8
|
@timeout = timeout
|
9
9
|
@endpoints = endpoints.map{|endpoint| Etcdv3::Connection.new(endpoint, @timeout) }
|
10
10
|
@connection = @endpoints.first
|
11
|
+
@allow_reconnect = allow_reconnect
|
12
|
+
end
|
13
|
+
|
14
|
+
private def retry_or_raise(*args)
|
15
|
+
if @allow_reconnect
|
16
|
+
handle(*args)
|
17
|
+
else
|
18
|
+
raise
|
19
|
+
end
|
11
20
|
end
|
12
21
|
|
13
22
|
def handle(stub, method, method_args=[], retries: 1)
|
14
23
|
@connection.call(stub, method, method_args)
|
15
24
|
|
16
|
-
rescue GRPC::Unavailable, GRPC::Core::CallError
|
25
|
+
rescue GRPC::Unavailable, GRPC::Core::CallError
|
17
26
|
$stderr.puts("Failed to connect to endpoint '#{@connection.hostname}'")
|
18
27
|
if @endpoints.size > 1
|
19
28
|
rotate_connection_endpoint
|
20
29
|
$stderr.puts("Failover event triggered. Failing over to '#{@connection.hostname}'")
|
21
|
-
return
|
30
|
+
return retry_or_raise(stub, method, method_args)
|
22
31
|
else
|
23
|
-
return
|
32
|
+
return retry_or_raise(stub, method, method_args)
|
24
33
|
end
|
25
34
|
rescue GRPC::Unauthenticated => exception
|
26
35
|
# Regenerate token in the event it expires.
|
27
36
|
if exception.details == 'etcdserver: invalid auth token'
|
28
37
|
if retries > 0
|
29
38
|
authenticate(@user, @password)
|
30
|
-
return
|
39
|
+
return retry_or_raise(stub, method, method_args, retries: retries - 1)
|
31
40
|
end
|
32
41
|
end
|
33
42
|
raise exception
|
data/lib/etcdv3/version.rb
CHANGED
@@ -3,9 +3,9 @@ require 'spec_helper'
|
|
3
3
|
describe Etcdv3::ConnectionWrapper do
|
4
4
|
let(:conn) { local_connection }
|
5
5
|
let(:endpoints) { ['http://localhost:2379', 'http://localhost:2389'] }
|
6
|
+
subject { Etcdv3::ConnectionWrapper.new(10, *endpoints, true) }
|
6
7
|
|
7
8
|
describe '#initialize' do
|
8
|
-
subject { Etcdv3::ConnectionWrapper.new(10, *endpoints) }
|
9
9
|
it { is_expected.to have_attributes(user: nil, password: nil, token: nil) }
|
10
10
|
it 'sets hostnames in correct order' do
|
11
11
|
expect(subject.endpoints.map(&:hostname)).to eq(['localhost:2379', 'localhost:2389'])
|
@@ -16,7 +16,6 @@ describe Etcdv3::ConnectionWrapper do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
describe "#rotate_connection_endpoint" do
|
19
|
-
subject { Etcdv3::ConnectionWrapper.new(10, *endpoints) }
|
20
19
|
before do
|
21
20
|
subject.rotate_connection_endpoint
|
22
21
|
end
|
@@ -29,11 +28,30 @@ describe Etcdv3::ConnectionWrapper do
|
|
29
28
|
end
|
30
29
|
|
31
30
|
describe "Failover Simulation" do
|
32
|
-
let(:
|
31
|
+
let(:allow_reconnect) { true }
|
32
|
+
let(:modified_conn) {
|
33
|
+
local_connection(
|
34
|
+
"http://localhost:2369, http://localhost:2379",
|
35
|
+
allow_reconnect: allow_reconnect
|
36
|
+
)
|
37
|
+
}
|
38
|
+
subject { modified_conn.get('boom') }
|
39
|
+
|
33
40
|
context 'without auth' do
|
34
41
|
# Set primary endpoint to a non-existing etcd endpoint
|
35
|
-
|
36
|
-
|
42
|
+
context 'with reconnect' do
|
43
|
+
it { is_expected.to be_an_instance_of(Etcdserverpb::RangeResponse) }
|
44
|
+
end
|
45
|
+
context 'without reconnect' do
|
46
|
+
let(:allow_reconnect) { false }
|
47
|
+
it { expect { subject }.to raise_error(GRPC::Unavailable) }
|
48
|
+
end
|
49
|
+
context 'without reconnect with single endpoint' do
|
50
|
+
let(:modified_conn) {
|
51
|
+
local_connection("http://localhost:2369",allow_reconnect: false)
|
52
|
+
}
|
53
|
+
it { expect { subject }.to raise_error(GRPC::Unavailable) }
|
54
|
+
end
|
37
55
|
end
|
38
56
|
context 'with auth' do
|
39
57
|
before do
|
@@ -50,12 +68,19 @@ describe Etcdv3::ConnectionWrapper do
|
|
50
68
|
modified_conn.auth_disable
|
51
69
|
modified_conn.user_delete('root')
|
52
70
|
end
|
53
|
-
|
54
|
-
|
71
|
+
context 'with reconnect' do
|
72
|
+
it { is_expected.to be_an_instance_of(Etcdserverpb::RangeResponse) }
|
73
|
+
end
|
74
|
+
context 'without reconnect' do
|
75
|
+
let(:allow_reconnect) { false }
|
76
|
+
it { expect { subject }.to raise_error(GRPC::Unavailable) }
|
77
|
+
end
|
55
78
|
end
|
56
79
|
end
|
57
80
|
|
58
81
|
describe "GRPC::Unauthenticated recovery" do
|
82
|
+
let(:allow_reconnect) { true }
|
83
|
+
let(:conn) { local_connection(allow_reconnect: allow_reconnect) }
|
59
84
|
let(:wrapper) { conn.send(:conn) }
|
60
85
|
let(:connection) { wrapper.connection }
|
61
86
|
before do
|
@@ -71,6 +96,12 @@ describe Etcdv3::ConnectionWrapper do
|
|
71
96
|
conn.user_delete('root')
|
72
97
|
end
|
73
98
|
subject { conn.user_get('root') }
|
74
|
-
|
99
|
+
context 'with reconnect' do
|
100
|
+
it { is_expected.to be_an_instance_of(Etcdserverpb::AuthUserGetResponse) }
|
101
|
+
end
|
102
|
+
context 'without reconnect' do
|
103
|
+
let(:allow_reconnect) { false }
|
104
|
+
it { expect { subject }.to raise_error(GRPC::Unauthenticated) }
|
105
|
+
end
|
75
106
|
end
|
76
107
|
end
|
data/spec/helpers/connections.rb
CHANGED
@@ -5,8 +5,8 @@ module Helpers
|
|
5
5
|
Etcdv3.new(endpoints: "http://#{local_url}", user: user, password: password)
|
6
6
|
end
|
7
7
|
|
8
|
-
def local_connection(endpoints="http://#{local_url}")
|
9
|
-
Etcdv3.new(endpoints: endpoints)
|
8
|
+
def local_connection(endpoints="http://#{local_url}", allow_reconnect: true)
|
9
|
+
Etcdv3.new(endpoints: endpoints, allow_reconnect: allow_reconnect)
|
10
10
|
end
|
11
11
|
|
12
12
|
def local_connection_with_timeout(timeout)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etcdv3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shaun Davis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grpc
|