etcdv3 0.1.3 → 0.1.4

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: afad56a64c9b93a3438296356e13a9980625d193
4
- data.tar.gz: 6190434f69a1645f25f5336f3bebaf1efc8f3775
3
+ metadata.gz: 9275ec7e8408f87efd369493235bea9e7bd18a98
4
+ data.tar.gz: 9fcdd5d3199a60e6c0066758dc32e455e5125e8c
5
5
  SHA512:
6
- metadata.gz: 95d1672d8f0e0cd1843bf76d2998977c347711887ebacbae463d2d4aa86586b9c4ce663b9dd28e220c8a7cd87d55c94c7cb3381af98988c4ad232d2a733e9913
7
- data.tar.gz: 520c207ec53edc8a5ea840f138780c4b7a3e0f2a21180f135045dbb170e3bdaed9a2ebc2fb72b192e7de8295d67f83be9a5572cc9677196a4607b917c3a5f5e7
6
+ metadata.gz: f5755de875074e6268cd378568ba6633d141d71efeccffe197f59fa142c6fcaa553a4802d438b551f24808b524e07e68221d435f9cf20a434620850164bdf1e7
7
+ data.tar.gz: ee7cf3faf3e6694843a3c99ee553d3bbcf081c491fa463cf36223bc8e8eb6688c8fb2fe19a42c3d0737ed56d849504e9cea5215e65cc978380448502c4894a24
data/lib/etcdv3/auth.rb CHANGED
@@ -8,8 +8,8 @@ class Etcd
8
8
  'readwrite' => Authpb::Permission::Type::READWRITE
9
9
  }
10
10
 
11
- def initialize(hostname, port, credentials, metadata = {})
12
- @stub = Etcdserverpb::Auth::Stub.new("#{hostname}:#{port}", credentials)
11
+ def initialize(hostname, credentials, metadata = {})
12
+ @stub = Etcdserverpb::Auth::Stub.new(hostname, credentials)
13
13
  @metadata = metadata
14
14
  end
15
15
 
data/lib/etcdv3/kv.rb CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  class Etcd
3
3
  class KV
4
- def initialize(hostname, port, credentials, metadata={})
5
- @stub = Etcdserverpb::KV::Stub.new("#{hostname}:#{port}", credentials)
4
+ def initialize(hostname, credentials, metadata={})
5
+ @stub = Etcdserverpb::KV::Stub.new(hostname, credentials)
6
6
  @metadata = metadata
7
7
  end
8
8
 
data/lib/etcdv3/lease.rb CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  class Etcd
3
3
  class Lease
4
- def initialize(hostname, port, credentials, metadata={})
5
- @stub = Etcdserverpb::Lease::Stub.new("#{hostname}:#{port}", credentials)
4
+ def initialize(hostname, credentials, metadata={})
5
+ @stub = Etcdserverpb::Lease::Stub.new(hostname, credentials)
6
6
  @metadata = metadata
7
7
  end
8
8
 
@@ -14,8 +14,8 @@ class Etcd
14
14
  deactivate: 2
15
15
  }
16
16
 
17
- def initialize(hostname, port, credentials, metadata = {})
18
- @stub = Etcdserverpb::Maintenance::Stub.new("#{hostname}:#{port}", credentials)
17
+ def initialize(hostname, credentials, metadata = {})
18
+ @stub = Etcdserverpb::Maintenance::Stub.new(hostname, credentials)
19
19
  @metadata = metadata
20
20
  end
21
21
 
@@ -0,0 +1,41 @@
1
+ class Etcd
2
+ class Request
3
+
4
+ attr_reader :metacache
5
+
6
+ def initialize(hostname, credentials, metadata, metacache)
7
+ @hostname = hostname
8
+ @credentials = credentials
9
+ @metadata = metadata
10
+ @metacache = metacache
11
+ end
12
+
13
+ def handle(interface, method, method_args=[])
14
+ interface = resolve_interface(interface)
15
+ interface.send(method, *method_args)
16
+ end
17
+
18
+ private
19
+
20
+ def resolve_interface(interface)
21
+ self.send(interface)
22
+ end
23
+
24
+ def auth
25
+ @auth ||= Etcd::Auth.new(@hostname, @credentials, @metadata)
26
+ end
27
+
28
+ def kv
29
+ @kv ||= Etcd::KV.new(@hostname, @credentials, @metadata)
30
+ end
31
+
32
+ def maintenance
33
+ @maintenance ||= Etcd::Maintenance.new(@hostname, @credentials, @metadata)
34
+ end
35
+
36
+ def lease
37
+ @lease ||= Etcd::Lease.new(@hostname, @credentials, @metadata)
38
+ end
39
+
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  class Etcd
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'.freeze
3
3
  end
data/lib/etcdv3.rb CHANGED
@@ -1,12 +1,14 @@
1
1
 
2
2
  require 'grpc'
3
3
  require 'uri'
4
+ require 'base64'
4
5
 
5
6
  require 'etcdv3/etcdrpc/rpc_services_pb'
6
7
  require 'etcdv3/auth'
7
8
  require 'etcdv3/kv'
8
9
  require 'etcdv3/maintenance'
9
10
  require 'etcdv3/lease'
11
+ require 'etcdv3/request'
10
12
 
11
13
  class Etcd
12
14
 
@@ -45,167 +47,165 @@ class Etcd
45
47
  @credentials = resolve_credentials
46
48
  @metadata = {}
47
49
  @metadata[:token] = auth.generate_token(user, password) unless user.nil?
50
+ @metacache = set_metacache
48
51
  end
49
52
 
50
53
  # Version of Etcd running on member
51
54
  def version
52
- maintenance.member_status.version
55
+ request.handle(:maintenance, 'member_status').version
53
56
  end
54
57
 
55
58
  # Store size in bytes.
56
59
  def db_size
57
- maintenance.member_status.dbSize
60
+ request.handle(:maintenance, 'member_status').dbSize
58
61
  end
59
62
 
60
63
  # Cluster leader id
61
64
  def leader_id
62
- maintenance.member_status.leader
65
+ request.handle(:maintenance, 'member_status').leader
63
66
  end
64
67
 
65
68
  # Inserts a new key.
66
69
  def put(key, value, lease_id: nil)
67
- kv.put(key, value, lease_id)
70
+ request.handle(:kv, 'put', [key, value, lease_id])
68
71
  end
69
72
 
70
73
  # Fetches key(s).
71
74
  def get(key, range_end='')
72
- kv.get(key, range_end)
75
+ request.handle(:get, 'get', [key, range_end])
73
76
  end
74
77
 
75
78
  # Grant a lease with a speified TTL
76
79
  def grant_lease(ttl)
77
- lease.grant_lease(ttl)
80
+ request.handle(:lease, 'grant_lease', [ttl])
78
81
  end
79
82
 
80
83
  # Revokes lease and delete all attached keys
81
84
  def revoke_lease(id)
82
- lease.revoke_lease(id)
85
+ request.handle(:lease, 'revoke_lease', [id])
83
86
  end
84
87
 
85
88
  # Returns information regarding the current state of the lease
86
89
  def lease_ttl(id)
87
- lease.lease_ttl(id)
90
+ request.handle(:lease, 'lease_ttl', [id])
88
91
  end
89
92
 
90
93
  # Creates new user.
91
94
  def add_user(user, password)
92
- auth.add_user(user, password)
95
+ request.handle(:auth, 'add_user', [user, password])
93
96
  end
94
97
 
95
98
  # Fetch specified user
96
99
  def get_user(user)
97
- auth.get_user(user)
100
+ request.handle(:auth, 'get_user', [user])
98
101
  end
99
102
 
100
103
  # Delete specified user.
101
104
  def delete_user(user)
102
- auth.delete_user(user)
105
+ request.handle(:auth, 'delete_user', [user])
103
106
  end
104
107
 
105
108
  # Changes the specified users password.
106
109
  def change_user_password(user, new_password)
107
- auth.change_user_password(user, new_password)
110
+ request.handle(:auth, 'change_user_password', [user, new_password])
108
111
  end
109
112
 
110
113
  # List all users.
111
114
  def user_list
112
- auth.user_list
113
- end
114
-
115
- # Authenticate using specified user and password.
116
- # On successful authentication, an auth token will be assigned to the instance.
117
- def authenticate(user, password)
118
- token = auth.generate_token(user, password)
119
- return false unless token
120
- @metadata[:token] = token
121
- @options[:user] = user
122
- @options[:password] = password
123
-
124
- true
115
+ request.handle(:auth, 'user_list')
125
116
  end
126
117
 
127
118
  # List all roles.
128
119
  def role_list
129
- auth.role_list
120
+ request.handle(:auth, 'role_list')
130
121
  end
131
122
 
132
123
  # Add role with specified name.
133
124
  def add_role(name)
134
- auth.add_role(name)
125
+ request.handle(:auth, 'add_role', [name])
135
126
  end
136
127
 
137
128
  # Fetches a specified role.
138
129
  def get_role(name)
139
- auth.get_role(name)
130
+ request.handle(:auth, 'get_role', [name])
140
131
  end
141
132
 
142
133
  # Delete role.
143
134
  def delete_role(name)
144
- auth.delete_role(name)
135
+ request.handle(:auth, 'delete_role', [name])
145
136
  end
146
137
 
147
138
  # Grants role to an existing user.
148
139
  def grant_role_to_user(user, role)
149
- auth.grant_role_to_user(user, role)
140
+ request.handle(:auth, 'grant_role_to_user', [user, role])
150
141
  end
151
142
 
152
143
  # Revokes role from a specified user.
153
144
  def revoke_role_from_user(user, role)
154
- auth.revoke_role_from_user(user, role)
145
+ request.handle(:auth, 'revoke_role_from_user', [user, role])
155
146
  end
156
147
 
157
148
  # Grants a new permission to an existing role.
158
149
  def grant_permission_to_role(name, permission, key, range_end='')
159
- auth.grant_permission_to_role(name, permission, key, range_end)
150
+ request.handle(:auth, 'grant_permission_to_role', [name, permission, key, range_end])
160
151
  end
161
152
 
162
153
  def revoke_permission_from_role(name, permission, key, range_end='')
163
- auth.revoke_permission_from_role(name, permission, key, range_end)
154
+ request.handle(:auth, 'revoke_permission_from_role', [name, permission, key, range_end])
155
+ end
156
+
157
+ # List active alarms
158
+ def alarm_list
159
+ request.handle(:maintenance, 'alarms', [:get, leader_id])
160
+ end
161
+
162
+ # Disarm alarms on a specified member.
163
+ def deactivate_alarms
164
+ request.handle(:maintenance, 'alarms', [leader_id])
164
165
  end
165
166
 
166
167
  # Enables authentication.
167
168
  def enable_auth
168
- auth.enable_auth
169
+ request.handle(:auth, 'enable_auth')
169
170
  end
170
171
 
171
172
  # Disables authentication.
172
173
  # This will clear any active auth / token data.
173
174
  def disable_auth
174
- response = auth.disable_auth
175
+ response = request.handle(:auth, 'disable_auth')
175
176
  if response
176
177
  @metadata.delete(:token)
177
178
  @options[:user] = nil
178
179
  @options[:password] = nil
180
+ @metacache = set_metacache
179
181
  end
180
182
  response
181
183
  end
182
184
 
183
- # List active alarms
184
- def alarm_list
185
- maintenance.alarms(:get, leader_id)
186
- end
185
+ # Authenticate using specified user and password.
186
+ # On successful authentication, an auth token will be assigned to the instance.
187
+ def authenticate(user, password)
188
+ token = request.handle(:auth, 'generate_token', [user, password])
189
+ return false unless token
190
+ @metadata[:token] = token
191
+ @options[:user] = user
192
+ @options[:password] = password
193
+ @metacache = set_metacache
187
194
 
188
- # Disarm alarms on a specified member.
189
- def deactivate_alarms
190
- maintenance.alarms(:deactivate, leader_id)
195
+ true
191
196
  end
192
197
 
193
198
  private
194
199
 
195
- def auth
196
- Etcd::Auth.new(hostname, port, @credentials, @metadata)
197
- end
198
-
199
- def kv
200
- Etcd::KV.new(hostname, port, @credentials, @metadata)
201
- end
202
-
203
- def maintenance
204
- Etcd::Maintenance.new(hostname, port, @credentials, @metadata)
200
+ def request
201
+ # Only re-initialize when metadata changes.
202
+ return @request if @request && @request.metacache == @metacache
203
+ @request = Request.new("#{hostname}:#{port}", @credentials, @metadata, @metacache)
205
204
  end
206
205
 
207
- def lease
208
- Etcd::Lease.new(hostname, port, @credentials, @metadata)
206
+ # Generates a new hash using a base64 of the metadata.
207
+ def set_metacache
208
+ Base64.strict_encode64(@metadata.to_s)
209
209
  end
210
210
 
211
211
  def resolve_credentials
data/spec/etcd_spec.rb CHANGED
@@ -2,14 +2,13 @@ require 'spec_helper'
2
2
 
3
3
  describe Etcd do
4
4
  context 'Insecure connection without Auth' do
5
- let(:conn) do
6
- Etcd.new(url: 'http://127.0.0.1:2379')
7
- end
5
+
6
+ let(:conn) { local_connection }
7
+
8
8
  describe '#initialize' do
9
9
  subject { conn }
10
10
  it { is_expected.to have_attributes(scheme: 'http') }
11
11
  it { is_expected.to have_attributes(hostname: '127.0.0.1') }
12
- it { is_expected.to have_attributes(port: 2379) }
13
12
  it { is_expected.to have_attributes(credentials: :this_channel_is_insecure) }
14
13
  it { is_expected.to have_attributes(token: nil) }
15
14
  it { is_expected.to have_attributes(user: nil) }
@@ -82,5 +81,32 @@ describe Etcd do
82
81
  end
83
82
  end
84
83
  end
84
+
85
+ describe '#metacache' do
86
+ context 'uses cached request object' do
87
+ let!(:object_id) { conn.send(:request).object_id }
88
+ before { conn.add_user('root', 'test') }
89
+ after { conn.delete_user('root') }
90
+ subject { conn.send(:request).object_id }
91
+ it { is_expected.to eq(object_id) }
92
+ end
93
+ context 'resets cache on auth' do
94
+ let!(:object_id) { conn.send(:request).object_id }
95
+ before do
96
+ conn.add_user('root', 'test')
97
+ conn.grant_role_to_user('root', 'root')
98
+ conn.enable_auth
99
+ conn.authenticate('root', 'test')
100
+ conn.add_user('boom', 'password')
101
+ end
102
+ after do
103
+ conn.disable_auth
104
+ conn.delete_user('root')
105
+ conn.delete_user('boom')
106
+ end
107
+ subject { conn.send(:request).object_id }
108
+ it { is_expected.to_not eq(object_id) }
109
+ end
110
+ end
85
111
  end
86
112
  end
@@ -2,9 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Etcd::Auth do
4
4
 
5
- let(:stub) do
6
- Etcd::Auth.new("127.0.0.1", 2379, :this_channel_is_insecure, {})
7
- end
5
+ let(:stub) { local_stub(Etcd::Auth) }
8
6
 
9
7
  describe '#add_user' do
10
8
  after { stub.delete_user('boom') }
@@ -1,14 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Etcd::KV do
4
-
5
- let(:stub) do
6
- Etcd::KV.new("127.0.0.1", 2379, :this_channel_is_insecure, {})
7
- end
8
-
9
- let(:lease_stub) do
10
- Etcd::Lease.new("127.0.0.1", 2379, :this_channel_is_insecure, {})
11
- end
4
+ let(:stub) { local_stub(Etcd::KV) }
5
+ let(:lease_stub) { local_stub(Etcd::Lease) }
12
6
 
13
7
  describe '#put' do
14
8
  context 'without lease' do
@@ -2,9 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Etcd::Lease do
4
4
 
5
- let(:stub) do
6
- Etcd::Lease.new("127.0.0.1", 2379, :this_channel_is_insecure, {})
7
- end
5
+ let(:stub) { local_stub(Etcd::Lease) }
8
6
 
9
7
  describe '#grant_lease' do
10
8
  subject { stub.grant_lease(10) }
@@ -2,9 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Etcd::Maintenance do
4
4
 
5
- let(:stub) do
6
- Etcd::Maintenance.new("127.0.0.1", 2379, :this_channel_is_insecure, {})
7
- end
5
+ let(:stub) { local_stub(Etcd::Maintenance) }
8
6
 
9
7
  describe "#member_status" do
10
8
  subject { stub.member_status }
@@ -0,0 +1,21 @@
1
+ module Helpers
2
+ module Connections
3
+
4
+ def local_connection
5
+ Etcd.new(url: "http://#{local_url}")
6
+ end
7
+
8
+ def local_stub(interface)
9
+ interface.new(local_url, :this_channel_is_insecure, {})
10
+ end
11
+
12
+ def local_url
13
+ "127.0.0.1:#{port}"
14
+ end
15
+
16
+ def port
17
+ ENV.fetch('ETCD_TEST_PORT', 2379).to_i
18
+ end
19
+
20
+ end
21
+ end
@@ -1,8 +1,16 @@
1
1
  require 'fileutils'
2
2
  require 'tmpdir'
3
+ require 'socket'
4
+ require 'timeout'
5
+ require 'helpers/connections'
3
6
 
4
7
  module Helpers
5
8
  class TestInstance
9
+ include Helpers::Connections
10
+
11
+ class InvalidVersionException < StandardError; end
12
+ class PortInUseException < StandardError; end
13
+
6
14
  MINIMUM_VERSION = Gem::Version.new('3.0.0')
7
15
 
8
16
  def initialize
@@ -11,21 +19,28 @@ module Helpers
11
19
  @bin = discover_binary_path
12
20
  @version = discover_binary_version
13
21
 
14
- raise "Invalid Etcd Version: #{@version}. Must be running 3.0+" \
15
- if @version < MINIMUM_VERSION
22
+ raise InvalidVersionException if @version < MINIMUM_VERSION
23
+ raise PortInUseException if port_open?
24
+
25
+ rescue InvalidVersionException
26
+ puts "Invalid Etcd Version: #{@version}. Must be running 3.0+"
27
+ exit(1)
28
+ rescue PortInUseException
29
+ puts "Port #{port} is already in use. To choose a new port: `export ETCD_TEST_PORT=new_port`"
30
+ exit(1)
16
31
  end
17
32
 
18
33
  def start
19
34
  raise "Already running etcd servers(#{@pids.inspect})" unless @pids.empty?
20
- puts 'Starting up testing environment...'
35
+ puts "Starting up testing environment on port #{port}..."
21
36
  @pids << spawn_etcd_instance
22
37
  sleep(5)
23
38
  end
24
39
 
25
40
  def spawn_etcd_instance
26
- peer_url = 'http://127.0.0.1:2380'
27
- client_url = 'http://127.0.0.1:2379'
28
- cluster_url = 'node=http://127.0.0.1:2380'
41
+ peer_url = "http://127.0.0.1:#{port+1}"
42
+ client_url = "http://127.0.0.1:#{port}"
43
+ cluster_url = "node=http://127.0.0.1:#{port+1}"
29
44
  flags = ' --name=node'
30
45
  flags << " --initial-advertise-peer-urls=#{peer_url}"
31
46
  flags << " --listen-peer-urls=#{peer_url}"
@@ -47,6 +62,8 @@ module Helpers
47
62
  @pids.clear
48
63
  end
49
64
 
65
+ private
66
+
50
67
  def discover_binary_path
51
68
  'etcd'
52
69
  end
@@ -54,6 +71,23 @@ module Helpers
54
71
  def discover_binary_version
55
72
  result = `#{@bin} --version | grep "etcd Version"`
56
73
  Gem::Version.new(result.split(':').last.strip)
74
+ rescue
75
+ puts "The etcd binary is not in $PATH. Export it, and try again."
76
+ exit(1)
57
77
  end
78
+
79
+ def port_open?(seconds=1)
80
+ Timeout::timeout(seconds) do
81
+ begin
82
+ TCPSocket.new('127.0.0.1', port).close
83
+ true
84
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
85
+ false
86
+ end
87
+ end
88
+ rescue Timeout::Error
89
+ false
90
+ end
91
+
58
92
  end
59
93
  end
data/spec/spec_helper.rb CHANGED
@@ -3,8 +3,11 @@ $LOAD_PATH.unshift File.expand_path('./helpers', __FILE__)
3
3
 
4
4
  require 'etcdv3'
5
5
  require 'helpers/test_instance'
6
+ require 'helpers/connections'
6
7
 
7
8
  RSpec.configure do |config|
9
+ config.include(Helpers::Connections)
10
+
8
11
  config.expect_with :rspec do |expectations|
9
12
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
10
13
  end
@@ -12,6 +15,7 @@ RSpec.configure do |config|
12
15
  mocks.verify_partial_doubles = true
13
16
  end
14
17
  config.shared_context_metadata_behavior = :apply_to_host_groups
18
+
15
19
  instance = Helpers::TestInstance.new
16
20
  config.before(:suite) do
17
21
  instance.start
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.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shaun Davis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-06 00:00:00.000000000 Z
11
+ date: 2017-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc
@@ -66,12 +66,14 @@ files:
66
66
  - lib/etcdv3/protos/http.proto
67
67
  - lib/etcdv3/protos/kv.proto
68
68
  - lib/etcdv3/protos/rpc.proto
69
+ - lib/etcdv3/request.rb
69
70
  - lib/etcdv3/version.rb
70
71
  - spec/etcd_spec.rb
71
72
  - spec/etcdv3/auth_spec.rb
72
73
  - spec/etcdv3/kv_spec.rb
73
74
  - spec/etcdv3/lease_spec.rb
74
75
  - spec/etcdv3/maintenance_spec.rb
76
+ - spec/helpers/connections.rb
75
77
  - spec/helpers/test_instance.rb
76
78
  - spec/spec_helper.rb
77
79
  homepage: https://github.com/davissp14/etcdv3-ruby
@@ -104,5 +106,6 @@ test_files:
104
106
  - spec/etcdv3/kv_spec.rb
105
107
  - spec/etcdv3/lease_spec.rb
106
108
  - spec/etcdv3/maintenance_spec.rb
109
+ - spec/helpers/connections.rb
107
110
  - spec/helpers/test_instance.rb
108
111
  - spec/spec_helper.rb