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 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