etcdv3 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eea828b2c14cfeab2c0f9be8a84ea937131a5dc2
4
- data.tar.gz: a2e02f9d0155f35185994c07cd7abc5a6d23d5df
3
+ metadata.gz: db0142aa621e3ec4612d3d2051b06f208382001d
4
+ data.tar.gz: a1d300e69e53c41a9a3864d6d480011cc7ffc6a1
5
5
  SHA512:
6
- metadata.gz: bff96b426657924163a26df9ca1322b5600b33607453d4648affffe2e66bf7c7ef20e5fe2d0443435de71b74d9ceec637f968196315837426294d26dd1b84e78
7
- data.tar.gz: 1a10f332e633b1010aba3a355b05ef82e2546e37413222de7553bcdb2461d0d2b368573af75a33e927349c4f461c81564d80adbe149ea7f6e5ac8b478158cc1e
6
+ metadata.gz: 8cd28535b2f39b4b04d0d426b1bbf940997e512922ddc5da85a86d69cf0c24319b40a187d1cde576c5a01ad33f9ee470a33ea02f9fa2c442f6aaee0484b61d36
7
+ data.tar.gz: 3bb79400389240448d945e9b41b967cf4c4f65d1454bebdcaff4d8c60cbc82023b950e707f70c6bb87d89b0e3e13546eb64a05f1adcdf7356b0a75a35e0d3241
data/.gitignore CHANGED
@@ -1,9 +1,10 @@
1
- Gemfile.lock
2
- Guardfile
3
- *.sh
4
1
  *.gem
5
- /tmp/
2
+ *.sh
3
+ *.swp
4
+ /.bundle
6
5
  /.idea
7
6
  /coverage/*
8
7
  /doc/
9
- *.swp
8
+ /tmp/
9
+ Gemfile.lock
10
+ Guardfile
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
@@ -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(@timeout, *sanitized_endpoints)
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 => exception
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 handle(stub, method, method_args)
30
+ return retry_or_raise(stub, method, method_args)
22
31
  else
23
- return handle(stub, method, method_args)
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 handle(stub, method, method_args, retries: retries - 1)
39
+ return retry_or_raise(stub, method, method_args, retries: retries - 1)
31
40
  end
32
41
  end
33
42
  raise exception
@@ -1,3 +1,3 @@
1
1
  class Etcdv3
2
- VERSION = '0.10.1'.freeze
2
+ VERSION = '0.10.2'.freeze
3
3
  end
@@ -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(:modified_conn) { local_connection("http://localhost:2369, http://localhost:2379") }
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
- subject { modified_conn.get('boom') }
36
- it { is_expected.to be_an_instance_of(Etcdserverpb::RangeResponse) }
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
- subject { modified_conn.get('boom') }
54
- it { is_expected.to be_an_instance_of(Etcdserverpb::RangeResponse) }
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
- it { is_expected.to be_an_instance_of(Etcdserverpb::AuthUserGetResponse) }
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
@@ -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.1
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-01-29 00:00:00.000000000 Z
11
+ date: 2019-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc