etcd 0.2.4 → 0.3.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 +4 -4
- data/.rspec +0 -1
- data/.rubocop.yml +4 -4
- data/.travis.yml +6 -4
- data/Gemfile +1 -0
- data/README.md +25 -0
- data/etcd.gemspec +3 -1
- data/lib/etcd/client.rb +25 -32
- data/lib/etcd/keys.rb +6 -2
- data/lib/etcd/node.rb +2 -2
- data/lib/etcd/version.rb +1 -1
- data/spec/etcd/basic_auth_client_spec.rb +0 -17
- data/spec/etcd/client_spec.rb +2 -28
- data/spec/etcd/keys_spec.rb +0 -35
- data/spec/etcd/node_spec.rb +0 -9
- data/spec/etcd/readme_spec.rb +1 -11
- data/spec/etcd/stats_spec.rb +5 -14
- data/spec/etcd/test_and_set_spec.rb +1 -10
- data/spec/etcd/watch_spec.rb +0 -10
- data/spec/spec_helper.rb +35 -51
- metadata +17 -12
- data/build_etcd +0 -8
- data/lib/etcd/mod/leader.rb +0 -28
- data/lib/etcd/mod/lock.rb +0 -61
- data/spec/etcd/leader_spec.rb +0 -39
- data/spec/etcd/lock_spec.rb +0 -55
- data/spec/etcd/read_only_client_spec.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22603e3722f2b94cc4b1b11b4b656328a43df33a
|
4
|
+
data.tar.gz: 13ecd4b92dc77af3540a61aa0237fbec51eb8b68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce218a334fd115475efb1e2aa4424de2a6c61c8b9d16ba3aceacecea6d2c4aa7fbeb980700cc6889e305f3297723a45837cdc022cd7e72fe4c880f25facb0033
|
7
|
+
data.tar.gz: ac82296d320989aa83c1852287a1b956709edb578e5215efbb9ad2318ad30e0641e37b3e7a70f7ea5efb127909cd404cbfe2fcee39c54ba4769d18795084706d
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
before_install:
|
2
|
-
-
|
3
|
-
-
|
2
|
+
- wget -c https://github.com/coreos/etcd/releases/download/v2.0.0-rc.1/etcd-v2.0.0-rc.1-linux-amd64.tar.gz
|
3
|
+
- tar -zxf etcd-v2.0.0-rc.1-linux-amd64.tar.gz
|
4
|
+
- bundle install
|
5
|
+
|
4
6
|
rvm:
|
5
7
|
- 1.9.3
|
6
|
-
- 2.0.0
|
7
8
|
- 2.1.0
|
9
|
+
- 2.2.0
|
8
10
|
branches:
|
9
11
|
only:
|
10
12
|
- master
|
11
|
-
script: "ETCD_BIN=./etcd/
|
13
|
+
script: "ETCD_BIN=./etcd-v2.0.0-rc.1-linux-amd64/etcd bundle exec rake spec"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -25,6 +25,31 @@ client = Etcd.client(host: '127.0.0.1', port: 4003)
|
|
25
25
|
client = Etcd.client(:user_name => 'test', :password => 'pwd') # populates the authentication header for basic HTTP auth with user name and password (useful for proxied connections)
|
26
26
|
client = Etcd.client(host: '127.0.0.1', port: 4003, allow_redirect: false) # wont let you run sensitive commands on non-leader machines, default is true
|
27
27
|
```
|
28
|
+
|
29
|
+
### Create a client object to connect to a SSL etcd instance
|
30
|
+
|
31
|
+
See [Etcd config](https://github.com/coreos/etcd/blob/master/Documentation/configuration.md) to setup `etcd` in SSL mode.
|
32
|
+
|
33
|
+
Assuming you have these:
|
34
|
+
* `myca.crt` - Your internal CAs certificate
|
35
|
+
* `my-cert.crt` - The "client" cert
|
36
|
+
* `my-cert.key` - The key corresponding to `my-cert.crt`
|
37
|
+
|
38
|
+
If you were using self signed Certs and have your own CA, You would have set `-ca-file` in your etcd config also to use `myca.crt`.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
client=Etcd.client(
|
42
|
+
:host => "your-etcd-host",
|
43
|
+
:port => 443,
|
44
|
+
:use_ssl => true,
|
45
|
+
:ca_file => "/pathto/myca.crt",
|
46
|
+
:ssl_cert => OpenSSL::X509::Certificate.new( File.read("/pathto/my-cert.crt") ),
|
47
|
+
:ssl_key => OpenSSL::PKey::RSA.new("/etc/ssl/my-cert.key",passphrase)
|
48
|
+
)
|
49
|
+
#Omit passphrase if not set on your key.
|
50
|
+
```
|
51
|
+
|
52
|
+
|
28
53
|
### Set a key
|
29
54
|
```ruby
|
30
55
|
client.set('/nodes/n1', value: 1)
|
data/etcd.gemspec
CHANGED
@@ -18,10 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.
|
21
|
+
spec.required_ruby_version = '>= 1.9'
|
22
22
|
|
23
|
+
spec.add_dependency "mixlib-log"
|
23
24
|
spec.add_development_dependency "uuid"
|
24
25
|
spec.add_development_dependency "bundler"
|
25
26
|
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rdoc"
|
26
28
|
spec.add_development_dependency "rspec"
|
27
29
|
end
|
data/lib/etcd/client.rb
CHANGED
@@ -16,7 +16,6 @@ module Etcd
|
|
16
16
|
# etcd api, like Etcd::Client#lock and Etcd::Client#eternal_watch, they
|
17
17
|
# are defined in separate modules and included in this class
|
18
18
|
class Client
|
19
|
-
|
20
19
|
extend Forwardable
|
21
20
|
|
22
21
|
HTTP_REDIRECT = ->(r) { r.is_a? Net::HTTPRedirection }
|
@@ -26,12 +25,19 @@ module Etcd
|
|
26
25
|
include Stats
|
27
26
|
include Keys
|
28
27
|
|
29
|
-
Config = Struct.new(
|
30
|
-
|
28
|
+
Config = Struct.new(
|
29
|
+
:use_ssl,
|
30
|
+
:verify_mode,
|
31
|
+
:read_timeout,
|
32
|
+
:ssl_key,
|
33
|
+
:ca_file,
|
34
|
+
:user_name,
|
35
|
+
:password,
|
36
|
+
:ssl_cert
|
37
|
+
)
|
31
38
|
|
32
39
|
def_delegators :@config, :use_ssl, :verify_mode, :read_timeout
|
33
|
-
def_delegators :@config, :user_name, :password
|
34
|
-
|
40
|
+
def_delegators :@config, :user_name, :password
|
35
41
|
|
36
42
|
attr_reader :host, :port, :http, :config
|
37
43
|
|
@@ -48,12 +54,15 @@ module Etcd
|
|
48
54
|
@port = opts[:port] || 4001
|
49
55
|
@config = Config.new
|
50
56
|
@config.read_timeout = opts[:read_timeout] || 60
|
51
|
-
@config.allow_redirect = opts.key?(:allow_redirect) ? opts[:allow_redirect] : true
|
52
57
|
@config.use_ssl = opts[:use_ssl] || false
|
53
58
|
@config.verify_mode = opts.key?(:verify_mode) ? opts[:verify_mode] : OpenSSL::SSL::VERIFY_PEER
|
54
59
|
@config.user_name = opts[:user_name] || nil
|
55
60
|
@config.password = opts[:password] || nil
|
56
|
-
@config.
|
61
|
+
@config.ca_file = opts.key?(:ca_file) ? opts[:ca_file] : nil
|
62
|
+
# Provide a OpenSSL X509 cert here and not the path. See README
|
63
|
+
@config.ssl_cert = opts.key?(:ssl_cert) ? opts[:ssl_cert] : nil
|
64
|
+
# Provide the key (content) and not just the filename here.
|
65
|
+
@config.ssl_key = opts.key?(:ssl_key) ? opts[:ssl_key] : nil
|
57
66
|
yield @config if block_given?
|
58
67
|
end
|
59
68
|
# rubocop:enable CyclomaticComplexity
|
@@ -68,14 +77,9 @@ module Etcd
|
|
68
77
|
api_execute('/version', :get).body
|
69
78
|
end
|
70
79
|
|
71
|
-
# Returns array of all machines in the cluster
|
72
|
-
def machines
|
73
|
-
api_execute(version_prefix + '/machines', :get).body.split(',').map(&:strip)
|
74
|
-
end
|
75
|
-
|
76
80
|
# Get the current leader
|
77
81
|
def leader
|
78
|
-
api_execute(version_prefix + '/leader', :get).body.strip
|
82
|
+
api_execute(version_prefix + '/stats/leader', :get).body.strip
|
79
83
|
end
|
80
84
|
|
81
85
|
# This method sends api request to etcd server.
|
@@ -99,51 +103,40 @@ module Etcd
|
|
99
103
|
else
|
100
104
|
fail "Unknown http action: #{method}"
|
101
105
|
end
|
102
|
-
timeout = options[:timeout] || @read_timeout
|
103
106
|
http = Net::HTTP.new(host, port)
|
104
|
-
http.read_timeout = timeout
|
107
|
+
http.read_timeout = options[:timeout] || read_timeout
|
105
108
|
setup_https(http)
|
106
109
|
req.basic_auth(user_name, password) if [user_name, password].all?
|
107
110
|
Log.debug("Invoking: '#{req.class}' against '#{path}")
|
108
111
|
res = http.request(req)
|
109
112
|
Log.debug("Response code: #{res.code}")
|
110
|
-
|
113
|
+
Log.debug("Response body: #{res.body}")
|
114
|
+
process_http_request(res)
|
111
115
|
end
|
112
116
|
|
113
117
|
def setup_https(http)
|
114
118
|
http.use_ssl = use_ssl
|
115
119
|
http.verify_mode = verify_mode
|
116
|
-
|
120
|
+
if config.ssl_cert
|
117
121
|
Log.debug('Setting up ssl cert')
|
118
122
|
http.cert = config.ssl_cert
|
119
123
|
end
|
120
|
-
|
124
|
+
if config.ssl_key
|
121
125
|
Log.debug('Setting up ssl key')
|
122
126
|
http.key = config.ssl_key
|
123
127
|
end
|
124
|
-
|
128
|
+
if config.ca_file
|
125
129
|
Log.debug('Setting up ssl ca file to :' + config.ca_file)
|
126
130
|
http.ca_file = config.ca_file
|
127
131
|
end
|
128
132
|
end
|
129
133
|
|
130
|
-
# need to
|
131
|
-
def process_http_request(res
|
134
|
+
# need to have original request to process the response when it redirects
|
135
|
+
def process_http_request(res)
|
132
136
|
case res
|
133
137
|
when HTTP_SUCCESS
|
134
138
|
Log.debug('Http success')
|
135
139
|
res
|
136
|
-
when HTTP_REDIRECT
|
137
|
-
if allow_redirect
|
138
|
-
uri = URI(res['location'])
|
139
|
-
@host = uri.host
|
140
|
-
@port = uri.port
|
141
|
-
Log.debug("Http redirect, setting new host to: #{@host}:#{@port}, and retrying")
|
142
|
-
api_execute(uri.path, req.method.downcase.to_sym, params: params)
|
143
|
-
else
|
144
|
-
Log.debug('Http redirect not allowed')
|
145
|
-
res.error!
|
146
|
-
end
|
147
140
|
when HTTP_CLIENT_ERROR
|
148
141
|
fail Error.from_http_response(res)
|
149
142
|
else
|
data/lib/etcd/keys.rb
CHANGED
@@ -78,8 +78,12 @@ module Etcd
|
|
78
78
|
params[:consistent] = opts[:consistent] if opts.key?(:consistent)
|
79
79
|
params[:recursive] = opts[:recursive] if opts.key?(:recursive)
|
80
80
|
|
81
|
-
response = api_execute(
|
82
|
-
|
81
|
+
response = api_execute(
|
82
|
+
key_endpoint + key,
|
83
|
+
:get,
|
84
|
+
timeout: timeout,
|
85
|
+
params: params
|
86
|
+
)
|
83
87
|
Response.from_http_response(response)
|
84
88
|
end
|
85
89
|
|
data/lib/etcd/node.rb
CHANGED
@@ -19,7 +19,7 @@ module Etcd
|
|
19
19
|
@expiration = opts['expiration']
|
20
20
|
@dir = opts['dir']
|
21
21
|
|
22
|
-
if opts['dir'] &&
|
22
|
+
if opts['dir'] && opts['nodes']
|
23
23
|
opts['nodes'].each do |data|
|
24
24
|
children << Node.new(data)
|
25
25
|
end
|
@@ -39,7 +39,7 @@ module Etcd
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def directory?
|
42
|
-
|
42
|
+
! @dir.nil?
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
data/lib/etcd/version.rb
CHANGED
@@ -3,14 +3,6 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe 'Etcd basic auth client' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon(2)
|
9
|
-
end
|
10
|
-
after(:all) do
|
11
|
-
stop_daemon
|
12
|
-
end
|
13
|
-
|
14
6
|
let(:client) do
|
15
7
|
Etcd.client(host: 'localhost') do |config|
|
16
8
|
config.user_name = 'test'
|
@@ -25,13 +17,4 @@ describe 'Etcd basic auth client' do
|
|
25
17
|
it '#password' do
|
26
18
|
expect(client.password).to eq('pwd')
|
27
19
|
end
|
28
|
-
|
29
|
-
it 'should set basic auth' do
|
30
|
-
Net::HTTPRequest.any_instance.should_receive(:basic_auth).with('test', 'pwd')
|
31
|
-
key = random_key
|
32
|
-
value = uuid.generate
|
33
|
-
client.set(key, value: value)
|
34
|
-
sleep 1
|
35
|
-
expect(read_only_client.get(key).value).to eq(value)
|
36
|
-
end
|
37
20
|
end
|
data/spec/etcd/client_spec.rb
CHANGED
@@ -1,29 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Etcd::Client do
|
4
|
-
|
5
|
-
before(:all) do
|
6
|
-
start_daemon(3)
|
7
|
-
end
|
8
|
-
|
9
|
-
after(:all) do
|
10
|
-
stop_daemon
|
11
|
-
end
|
12
|
-
|
13
4
|
let(:client) do
|
14
5
|
etcd_client
|
15
6
|
end
|
16
7
|
|
17
|
-
it '
|
18
|
-
expect(client.
|
19
|
-
end
|
20
|
-
|
21
|
-
it '#machines' do
|
22
|
-
expect(client.machines).to include('http://127.0.0.1:4001')
|
23
|
-
end
|
24
|
-
|
25
|
-
it '#version' do
|
26
|
-
expect(client.version).to match(/^etcd v?0\.\d+\.\d+(\+git)?/)
|
8
|
+
it '#version' do #etcd 2.0.0-rc.1
|
9
|
+
expect(client.version).to match(/^etcd v?\d+\.\d+\.\d+.*$/)
|
27
10
|
end
|
28
11
|
|
29
12
|
it '#version_prefix' do
|
@@ -36,15 +19,6 @@ describe Etcd::Client do
|
|
36
19
|
client.api_execute('/v2/keys/x', :do)
|
37
20
|
end.to raise_error
|
38
21
|
end
|
39
|
-
|
40
|
-
it 'should redirect api request when allow_redirect is set' do
|
41
|
-
key = random_key
|
42
|
-
value = uuid.generate
|
43
|
-
resp = client.set(key, value: value)
|
44
|
-
resp.node.key.should eql key
|
45
|
-
resp.node.value.should eql value
|
46
|
-
client.get(key).value.should eql resp.value
|
47
|
-
end
|
48
22
|
end
|
49
23
|
|
50
24
|
context '#http header based metadata' do
|
data/spec/etcd/keys_spec.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Etcd::Keys do
|
4
|
-
|
5
4
|
shared_examples 'basic key operation' do
|
6
|
-
|
7
5
|
it '#set/#get' do
|
8
6
|
key = random_key
|
9
7
|
value = uuid.generate
|
@@ -65,43 +63,10 @@ describe Etcd::Keys do
|
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
68
|
-
|
69
66
|
context 'without ssl' do
|
70
|
-
before(:all) do
|
71
|
-
start_daemon
|
72
|
-
end
|
73
|
-
after(:all) do
|
74
|
-
stop_daemon
|
75
|
-
end
|
76
67
|
let(:client) do
|
77
68
|
etcd_client
|
78
69
|
end
|
79
70
|
it_should_behave_like 'basic key operation'
|
80
71
|
end
|
81
|
-
|
82
|
-
context 'with ssl' do
|
83
|
-
before(:all) do
|
84
|
-
start_daemon(1, use_ssl: true)
|
85
|
-
end
|
86
|
-
after(:all) do
|
87
|
-
stop_daemon
|
88
|
-
end
|
89
|
-
let(:client) do
|
90
|
-
etcd_ssl_client
|
91
|
-
end
|
92
|
-
it_should_behave_like 'basic key operation'
|
93
|
-
end
|
94
|
-
|
95
|
-
context 'with ssl and client certificate' do
|
96
|
-
before(:all) do
|
97
|
-
start_daemon(1, use_ssl: true, check_client_cert: true )
|
98
|
-
end
|
99
|
-
after(:all) do
|
100
|
-
stop_daemon
|
101
|
-
end
|
102
|
-
let(:client) do
|
103
|
-
etcd_ssl_client_with_cert
|
104
|
-
end
|
105
|
-
it_should_behave_like 'basic key operation'
|
106
|
-
end
|
107
72
|
end
|
data/spec/etcd/node_spec.rb
CHANGED
data/spec/etcd/readme_spec.rb
CHANGED
@@ -3,17 +3,8 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe 'Etcd specs for the main etcd README examples' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon
|
9
|
-
end
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
stop_daemon
|
13
|
-
end
|
14
|
-
|
15
6
|
let(:client) do
|
16
|
-
|
7
|
+
etcd_client
|
17
8
|
end
|
18
9
|
|
19
10
|
shared_examples 'response with valid node data' do |action|
|
@@ -307,7 +298,6 @@ describe 'Etcd specs for the main etcd README examples' do
|
|
307
298
|
end
|
308
299
|
|
309
300
|
context 'hidden nodes' do
|
310
|
-
|
311
301
|
before(:all) do
|
312
302
|
etcd_client.set('/_message', value: 'Hello Hidden World')
|
313
303
|
etcd_client.set('/message', value: 'Hello World')
|
data/spec/etcd/stats_spec.rb
CHANGED
@@ -3,19 +3,14 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Etcd::Stats do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon(5)
|
9
|
-
end
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
stop_daemon
|
13
|
-
end
|
14
|
-
|
15
6
|
let(:client) do
|
16
7
|
etcd_client
|
17
8
|
end
|
18
9
|
|
10
|
+
let(:leader) do
|
11
|
+
etcd_leader
|
12
|
+
end
|
13
|
+
|
19
14
|
describe 'of leader' do
|
20
15
|
|
21
16
|
let(:stats) do
|
@@ -23,11 +18,7 @@ describe Etcd::Stats do
|
|
23
18
|
end
|
24
19
|
|
25
20
|
it 'should contain a key for leader' do
|
26
|
-
expect(stats
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should have 4 followers (since we spawn 5 node etcd cluster)' do
|
30
|
-
expect(stats['followers'].keys.size).to eq(4)
|
21
|
+
expect(leader.stats(:leader)).to_not be_nil
|
31
22
|
end
|
32
23
|
end
|
33
24
|
|
@@ -3,15 +3,6 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe 'Etcd test_and_set' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon
|
9
|
-
end
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
stop_daemon
|
13
|
-
end
|
14
|
-
|
15
6
|
let(:client) do
|
16
7
|
etcd_client
|
17
8
|
end
|
@@ -21,7 +12,7 @@ describe 'Etcd test_and_set' do
|
|
21
12
|
old_value = uuid.generate
|
22
13
|
new_value = uuid.generate
|
23
14
|
resp = client.set(key, value: old_value)
|
24
|
-
resp.node.value.
|
15
|
+
expect(resp.node.value).to eq(old_value)
|
25
16
|
client.test_and_set(key, value: new_value, prevValue: old_value)
|
26
17
|
expect(client.get(key).value).to eq(new_value)
|
27
18
|
end
|
data/spec/etcd/watch_spec.rb
CHANGED
@@ -3,19 +3,9 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe 'Etcd watch' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon
|
9
|
-
end
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
stop_daemon
|
13
|
-
end
|
14
|
-
|
15
6
|
let(:client) do
|
16
7
|
etcd_client
|
17
8
|
end
|
18
|
-
|
19
9
|
it 'without index, returns the value at a particular index' do
|
20
10
|
key = random_key(4)
|
21
11
|
value1 = uuid.generate
|
data/spec/spec_helper.rb
CHANGED
@@ -20,32 +20,31 @@ module Etcd
|
|
20
20
|
@ca_cert = File.expand_path('../data/ca.crt', __FILE__)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
@pids.size.times.inject([]){|servers, n| servers <<
|
23
|
+
def etcd_ports
|
24
|
+
@pids.size.times.inject([]){|servers, n| servers << 4000 + n + 1 }
|
25
25
|
end
|
26
26
|
|
27
|
-
def start(numbers = 1
|
27
|
+
def start(numbers = 1)
|
28
28
|
raise "Already running etcd servers(#{@pids.inspect})" unless @pids.empty?
|
29
29
|
@tmpdir = Dir.mktmpdir
|
30
|
-
|
31
|
-
|
32
|
-
ssl_args << " -ca-file=#{@ca_cert}" if opts[:check_client_cert]
|
33
|
-
@pids << daemonize(@tmpdir, ssl_args)
|
34
|
-
(numbers - 1).times do |n|
|
35
|
-
@pids << daemonize(@tmpdir, ssl_args)
|
30
|
+
(1..numbers).each do |n|
|
31
|
+
@pids << daemonize(n, @tmpdir + n.to_s , numbers)
|
36
32
|
end
|
33
|
+
sleep 5
|
37
34
|
end
|
38
35
|
|
39
|
-
def daemonize(dir,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
36
|
+
def daemonize(index, dir, total)
|
37
|
+
ad_url = "http://localhost:#{7000 + index}"
|
38
|
+
client_url = "http://localhost:#{4000 + index}"
|
39
|
+
cluster_urls = (1..total).map{|n| "node_#{n}=http://localhost:#{7000 + n}"}.join(",")
|
40
|
+
flags = " -name node_#{index} -initial-advertise-peer-urls #{ad_url}"
|
41
|
+
flags << " -listen-peer-urls #{ad_url}"
|
42
|
+
flags << " -listen-client-urls #{client_url}"
|
43
|
+
flags << " -initial-cluster #{cluster_urls}"
|
44
|
+
flags << " -data-dir #{dir} "
|
45
|
+
|
46
|
+
command = etcd_binary + flags
|
47
|
+
pid = spawn(command, out: '/dev/null', err: '/dev/null')
|
49
48
|
Process.detach(pid)
|
50
49
|
pid
|
51
50
|
end
|
@@ -70,13 +69,15 @@ module Etcd
|
|
70
69
|
end
|
71
70
|
|
72
71
|
module SpecHelper
|
73
|
-
|
72
|
+
def spawner
|
73
|
+
Spawner.instance
|
74
|
+
end
|
74
75
|
def start_daemon(numbers = 1, opts={})
|
75
|
-
|
76
|
+
spawner.start(numbers, opts)
|
76
77
|
end
|
77
78
|
|
78
79
|
def stop_daemon
|
79
|
-
|
80
|
+
spawner.stop
|
80
81
|
end
|
81
82
|
|
82
83
|
def uuid
|
@@ -91,41 +92,24 @@ module Etcd
|
|
91
92
|
key
|
92
93
|
end
|
93
94
|
|
94
|
-
def
|
95
|
-
Etcd.client(host: 'localhost'
|
96
|
-
config.use_ssl = true
|
97
|
-
config.ca_file = File.expand_path('../data/ca.crt', __FILE__)
|
98
|
-
end
|
95
|
+
def etcd_client(port = 4001)
|
96
|
+
Etcd.client(host: 'localhost', port: port)
|
99
97
|
end
|
100
98
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
config.ca_file = File.expand_path('../data/ca.crt', __FILE__)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def etcd_ssl_client_with_cert
|
109
|
-
client_cert = File.expand_path('../data/client.crt', __FILE__)
|
110
|
-
client_key = File.expand_path('../data/client.key', __FILE__)
|
111
|
-
Etcd.client(host: 'localhost') do |config|
|
112
|
-
config.use_ssl = true
|
113
|
-
config.ca_file = File.expand_path('../data/ca.crt', __FILE__)
|
114
|
-
config.ssl_cert = OpenSSL::X509::Certificate.new(File.read(client_cert))
|
115
|
-
config.ssl_key = OpenSSL::PKey::RSA.new(File.read(client_key))
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def etcd_client
|
120
|
-
Etcd.client
|
121
|
-
end
|
122
|
-
|
123
|
-
def read_only_client
|
124
|
-
Etcd.client(allow_redirect: false, port: 4002, host: 'localhost')
|
99
|
+
def etcd_leader
|
100
|
+
clients = spawner.etcd_ports.map{|port| etcd_client(port)}
|
101
|
+
clients.detect{|c|c.stats(:self)['state'] == 'StateLeader'}
|
125
102
|
end
|
126
103
|
end
|
127
104
|
end
|
128
105
|
|
129
106
|
RSpec.configure do |c|
|
130
107
|
c.include Etcd::SpecHelper
|
108
|
+
c.before(:suite) do
|
109
|
+
Etcd::Spawner.instance.start(3)
|
110
|
+
end
|
111
|
+
c.after(:suite) do
|
112
|
+
Etcd::Spawner.instance.stop
|
113
|
+
end
|
114
|
+
c.fail_fast = false
|
131
115
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etcd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ranjib Dey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mixlib-log
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rdoc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,15 +111,12 @@ files:
|
|
97
111
|
- LICENSE.txt
|
98
112
|
- README.md
|
99
113
|
- Rakefile
|
100
|
-
- build_etcd
|
101
114
|
- etcd.gemspec
|
102
115
|
- lib/etcd.rb
|
103
116
|
- lib/etcd/client.rb
|
104
117
|
- lib/etcd/exceptions.rb
|
105
118
|
- lib/etcd/keys.rb
|
106
119
|
- lib/etcd/log.rb
|
107
|
-
- lib/etcd/mod/leader.rb
|
108
|
-
- lib/etcd/mod/lock.rb
|
109
120
|
- lib/etcd/node.rb
|
110
121
|
- lib/etcd/response.rb
|
111
122
|
- lib/etcd/stats.rb
|
@@ -118,10 +129,7 @@ files:
|
|
118
129
|
- spec/etcd/basic_auth_client_spec.rb
|
119
130
|
- spec/etcd/client_spec.rb
|
120
131
|
- spec/etcd/keys_spec.rb
|
121
|
-
- spec/etcd/leader_spec.rb
|
122
|
-
- spec/etcd/lock_spec.rb
|
123
132
|
- spec/etcd/node_spec.rb
|
124
|
-
- spec/etcd/read_only_client_spec.rb
|
125
133
|
- spec/etcd/readme_spec.rb
|
126
134
|
- spec/etcd/stats_spec.rb
|
127
135
|
- spec/etcd/test_and_set_spec.rb
|
@@ -139,7 +147,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
147
|
requirements:
|
140
148
|
- - ">="
|
141
149
|
- !ruby/object:Gem::Version
|
142
|
-
version: '
|
150
|
+
version: '1.9'
|
143
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
152
|
requirements:
|
145
153
|
- - ">="
|
@@ -160,10 +168,7 @@ test_files:
|
|
160
168
|
- spec/etcd/basic_auth_client_spec.rb
|
161
169
|
- spec/etcd/client_spec.rb
|
162
170
|
- spec/etcd/keys_spec.rb
|
163
|
-
- spec/etcd/leader_spec.rb
|
164
|
-
- spec/etcd/lock_spec.rb
|
165
171
|
- spec/etcd/node_spec.rb
|
166
|
-
- spec/etcd/read_only_client_spec.rb
|
167
172
|
- spec/etcd/readme_spec.rb
|
168
173
|
- spec/etcd/stats_spec.rb
|
169
174
|
- spec/etcd/test_and_set_spec.rb
|
data/build_etcd
DELETED
data/lib/etcd/mod/leader.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
|
3
|
-
require 'timeout'
|
4
|
-
|
5
|
-
module Etcd
|
6
|
-
module Mod
|
7
|
-
# Implement Etcd's Leader module
|
8
|
-
module Leader
|
9
|
-
def mod_leader_endpoint
|
10
|
-
'/mod/v2/leader'
|
11
|
-
end
|
12
|
-
|
13
|
-
def set_leader(key, value, ttl)
|
14
|
-
path = mod_leader_endpoint + "#{key}?ttl=#{ttl}"
|
15
|
-
api_execute(path, :put, params: { name: value }).body
|
16
|
-
end
|
17
|
-
|
18
|
-
def get_leader(key)
|
19
|
-
api_execute(mod_leader_endpoint + key, :get).body
|
20
|
-
end
|
21
|
-
|
22
|
-
def delete_leader(key, value)
|
23
|
-
path = mod_leader_endpoint + key + '?' + URI.encode_www_form(name: value)
|
24
|
-
api_execute(path, :delete).body
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/lib/etcd/mod/lock.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
|
3
|
-
require 'timeout'
|
4
|
-
|
5
|
-
module Etcd
|
6
|
-
module Mod
|
7
|
-
# implement etcd lock module
|
8
|
-
module Lock
|
9
|
-
def mod_lock_endpoint
|
10
|
-
'/mod/v2/lock'
|
11
|
-
end
|
12
|
-
|
13
|
-
def acquire_lock(key, ttl, opts = {})
|
14
|
-
path = mod_lock_endpoint + key + "?ttl=#{ttl}"
|
15
|
-
timeout = opts[:timeout] || 60
|
16
|
-
Timeout.timeout(timeout) do
|
17
|
-
return api_execute(path, :post, params: opts).body
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def renew_lock(key, ttl, opts = {})
|
22
|
-
unless opts.key?(:index) || opts.key?(:value)
|
23
|
-
fail ArgumentError, 'You mast pass index or value'
|
24
|
-
end
|
25
|
-
path = mod_lock_endpoint + key + "?ttl=#{ttl}"
|
26
|
-
timeout = opts[:timeout] || 60
|
27
|
-
Timeout.timeout(timeout) do
|
28
|
-
api_execute(path, :put, params: opts).body
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def get_lock(key, opts = {})
|
33
|
-
api_execute(mod_lock_endpoint + key, :get, params: opts).body
|
34
|
-
end
|
35
|
-
|
36
|
-
def delete_lock(key, opts = {})
|
37
|
-
unless opts.key?(:index) || opts.key?(:value)
|
38
|
-
fail ArgumentError, 'You must pass index or value'
|
39
|
-
end
|
40
|
-
api_execute(mod_lock_endpoint + key, :delete, params: opts)
|
41
|
-
end
|
42
|
-
|
43
|
-
# rubocop:disable RescueException
|
44
|
-
def lock(key, ttl, opts = {})
|
45
|
-
key = "/" + key unless key.start_with? '/'
|
46
|
-
lock_index = acquire_lock(key, ttl, opts)
|
47
|
-
begin
|
48
|
-
yield key
|
49
|
-
rescue Exception => e
|
50
|
-
raise e
|
51
|
-
ensure
|
52
|
-
delete_lock(key, index: lock_index)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
# rubocop:enable RescueException
|
56
|
-
|
57
|
-
alias_method :retrive_lock, :get_lock
|
58
|
-
alias_method :release_lock, :delete_lock
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/spec/etcd/leader_spec.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
=begin
|
5
|
-
|
6
|
-
describe 'mod leader' do
|
7
|
-
|
8
|
-
before(:all) do
|
9
|
-
start_daemon
|
10
|
-
end
|
11
|
-
|
12
|
-
after(:all) do
|
13
|
-
stop_daemon
|
14
|
-
end
|
15
|
-
|
16
|
-
let(:client) do
|
17
|
-
etcd_client
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should allow setting a key value with ttl' do
|
21
|
-
client.set_leader('/db_master1', 'db01', 10)
|
22
|
-
expect(client.get_leader('/db_master1')).to eq('db01')
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should allow deleting key with value' do
|
26
|
-
client.set_leader('/db_master4', 'db04', 10)
|
27
|
-
expect do
|
28
|
-
client.delete_leader('/db_master4', 'db04')
|
29
|
-
end.to_not raise_error
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should not allow deleting key without value' do
|
33
|
-
client.set_leader('/db_master5', 'db05', 10)
|
34
|
-
expect do
|
35
|
-
client.delete_leader('/db_master5', 'db04')
|
36
|
-
end.to raise_error
|
37
|
-
end
|
38
|
-
end
|
39
|
-
=end
|
data/spec/etcd/lock_spec.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
=begin
|
5
|
-
describe 'lock' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon
|
9
|
-
end
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
stop_daemon
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:client) do
|
16
|
-
etcd_client
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should be able to acquire a lock' do
|
20
|
-
expect do
|
21
|
-
client.acquire_lock('/my_lock', 10)
|
22
|
-
end.to_not raise_error
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should be able to renew a lock based on value' do
|
26
|
-
client.acquire_lock('/my_lock1', 10, value: 123)
|
27
|
-
expect do
|
28
|
-
client.renew_lock('/my_lock1', 10, value: 123)
|
29
|
-
end.to_not raise_error
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should be able to renew a lock based on index' do
|
33
|
-
client.acquire_lock('/my_lock2', 10)
|
34
|
-
index = client.get_lock('/my_lock2', field: 'index')
|
35
|
-
expect do
|
36
|
-
client.renew_lock('/my_lock2', 10, index: index)
|
37
|
-
end.to_not raise_error
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should be able to delete a lock based on value' do
|
41
|
-
client.acquire_lock('/my_lock3', 10, value: 123)
|
42
|
-
expect do
|
43
|
-
client.delete_lock('/my_lock3', value: 123)
|
44
|
-
end.to_not raise_error
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should be able to delete a lock based on index' do
|
48
|
-
client.acquire_lock('/my_lock4', 10)
|
49
|
-
index = client.get_lock('/my_lock4', field: 'index')
|
50
|
-
expect do
|
51
|
-
client.delete_lock('/my_lock4', index: index)
|
52
|
-
end.to_not raise_error
|
53
|
-
end
|
54
|
-
end
|
55
|
-
=end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe 'Etcd read only client' do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
start_daemon(3)
|
9
|
-
end
|
10
|
-
after(:all) do
|
11
|
-
stop_daemon
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:client) do
|
15
|
-
etcd_client
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should not allow write' do
|
19
|
-
key = random_key
|
20
|
-
expect do
|
21
|
-
read_only_client.set(key, value: uuid.generate)
|
22
|
-
end.to raise_error(Net::HTTPRetriableError)
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should allow reads' do
|
26
|
-
key = random_key
|
27
|
-
value = uuid.generate
|
28
|
-
client.set(key, value: value)
|
29
|
-
sleep 1
|
30
|
-
expect(read_only_client.get(key).value).to eq(value)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should allow watch' do
|
34
|
-
key = random_key
|
35
|
-
value = uuid.generate
|
36
|
-
index = client.set(key, value: value).node.modified_index
|
37
|
-
expect(read_only_client.watch(key, index: index).value).to eq(value)
|
38
|
-
end
|
39
|
-
end
|