etcd 0.0.5 → 0.0.6

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b268d252f6591fe8015fcf257369ec0502d62b2
4
+ data.tar.gz: 0b2567328a06ca5f6433948c7431ee7c4bb4a2d8
5
+ SHA512:
6
+ metadata.gz: 9925238076f679e9983358c87f24d53e4f95726bfdea41f06aae831277f5126a99c956997848489c31ed0b228a8605a9f0b5c30fad323bbeca06e3564379f273
7
+ data.tar.gz: b65c505cbad680da0cf1967f750408986c69cf17c0d781b21a218a3706afaf069dd10b13b3c7a0d9bbf394cb3b163e5237d7a1c2b5424d549da809f17455586d
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  html/
19
+ etcd
@@ -1,4 +1,5 @@
1
1
  before_install:
2
+ - sudo apt-get update -y
2
3
  - sudo add-apt-repository ppa:duh/golang -y
3
4
  - sudo apt-get update -y
4
5
  - sudo apt-get install golang -y
@@ -17,7 +17,7 @@ module Etcd
17
17
  include Etcd::Helpers
18
18
  include Etcd::Lockable
19
19
 
20
- attr_reader :host, :port, :http, :allow_redirect
20
+ attr_reader :host, :port, :http, :allow_redirect, :use_ssl, :verify_mode
21
21
 
22
22
  ##
23
23
  # Creates a new instance of Etcd::Client. It accepts a hash +opts+ as argument
@@ -25,21 +25,20 @@ module Etcd
25
25
  # @param [Hash] opts The options for new Etcd::Client object
26
26
  # @opts [String] :host IP address of the etcd server (default is '127.0.0.1')
27
27
  # @opts [Fixnum] :port Port number of the etcd server (default is 4001)
28
+ # @opts [Fixnum] :read_timeout Set default HTTP read timeout for all api calls (default is 60)
28
29
 
29
30
  def initialize(opts={})
30
31
  @host = opts[:host] || '127.0.0.1'
31
32
  @port = opts[:port] || 4001
32
33
  @read_timeout = opts[:read_timeout] || 60
33
- if opts.has_key?(:allow_redirect)
34
- @allow_redirect = opts[:allow_redirect]
35
- else
36
- @allow_redirect = true
37
- end
34
+ @allow_redirect = opts.has_key?(:allow_redirect) ? opts[:allow_redirect] : true
35
+ @use_ssl = opts[:use_ssl] || false
36
+ @verify_mode = opts[:verify_mode] || OpenSSL::SSL::VERIFY_PEER
38
37
  end
39
38
 
40
- # Currently use 'v1' as version for etcd store
39
+ # Currently use 'v2' as version for etcd store
41
40
  def version_prefix
42
- '/v1'
41
+ '/v2'
43
42
  end
44
43
 
45
44
  # Lists all machines in the cluster
@@ -73,7 +72,24 @@ module Etcd
73
72
  path = key_endpoint + key
74
73
  payload = {'value' => value, 'prevValue' => prevValue }
75
74
  payload['ttl'] = ttl unless ttl.nil?
76
- response = api_execute(path, :post, payload)
75
+ response = api_execute(path, :put, params: payload)
76
+ json2obj(response)
77
+ end
78
+
79
+
80
+ def create(key, value, ttl = nil)
81
+ path = key_endpoint + key
82
+ payload = {value: value, prevExist: false }
83
+ payload['ttl'] = ttl unless ttl.nil?
84
+ response = api_execute(path, :put, params: payload)
85
+ json2obj(response)
86
+ end
87
+
88
+ def update(key, value, ttl = nil)
89
+ path = key_endpoint + key
90
+ payload = {value: value, prevExist: true }
91
+ payload['ttl'] = ttl unless ttl.nil?
92
+ response = api_execute(path, :put, params: payload)
77
93
  json2obj(response)
78
94
  end
79
95
 
@@ -87,7 +103,7 @@ module Etcd
87
103
  path = key_endpoint + key
88
104
  payload = {'value' => value}
89
105
  payload['ttl'] = ttl unless ttl.nil?
90
- response = api_execute(path, :post, payload)
106
+ response = api_execute(path, :put, params: payload)
91
107
  json2obj(response)
92
108
  end
93
109
 
@@ -95,8 +111,8 @@ module Etcd
95
111
  #
96
112
  # This method has following parameters as argument
97
113
  # * key - key to be deleted
98
- def delete(key)
99
- response = api_execute(key_endpoint + key, :delete)
114
+ def delete(key,opts={})
115
+ response = api_execute(key_endpoint + key, :delete, params:opts)
100
116
  json2obj(response)
101
117
  end
102
118
 
@@ -104,21 +120,25 @@ module Etcd
104
120
  #
105
121
  # This method has following parameters as argument
106
122
  # * key - whose data to be retrive
107
- def get(key)
108
- response = api_execute(key_endpoint + key, :get)
123
+ def get(key, opts={})
124
+ response = api_execute(key_endpoint + key, :get, params:opts)
109
125
  json2obj(response)
110
126
  end
111
127
 
112
128
  # Gives a notification when specified key changes
113
129
  #
114
130
  # This method has following parameters as argument
115
- # * key - key to be watched
116
- # * index - etcd server index of specified key (optional)
117
- def watch(key, index=nil)
131
+ # @ key - key to be watched
132
+ # @options [Hash] additional options for watching a key
133
+ # @options [Fixnum] :index watch the specified key from given index
134
+ # @options [Fixnum] :timeout specify http timeout (defaults to read_timeout value)
135
+ def watch(key, options={})
136
+ timeout = options[:timeout] || @read_timeout
137
+ index = options[:waitIndex] || options[:index]
118
138
  response = if index.nil?
119
- api_execute(watch_endpoint + key, :get)
139
+ api_execute(key_endpoint + key, :get, timeout: timeout, params:{wait: true})
120
140
  else
121
- api_execute(watch_endpoint + key, :post, {'index' => index})
141
+ api_execute(key_endpoint + key, :get, timeout: timeout, params: {wait: true, waitIndex: index})
122
142
  end
123
143
  json2obj(response)
124
144
  end
@@ -128,8 +148,11 @@ module Etcd
128
148
  # This method has following parameters as argument
129
149
  # * path - etcd server path (etcd server end point)
130
150
  # * method - the request method used
131
- # * params - any additional parameters used by request method (optional)
132
- def api_execute(path, method, params=nil)
151
+ # * options - any additional parameters used by request method (optional)
152
+ def api_execute(path, method, options={})
153
+
154
+ params = options[:params]
155
+ timeout = options[:timeout] || @read_timeout
133
156
 
134
157
  http = if path=~/^http/
135
158
  uri = URI.parse(path)
@@ -138,7 +161,9 @@ module Etcd
138
161
  else
139
162
  Net::HTTP.new(host, port)
140
163
  end
141
- http.read_timeout = @read_timeout
164
+ http.read_timeout = timeout
165
+ http.use_ssl = use_ssl
166
+ http.verify_mode = verify_mode
142
167
 
143
168
  case method
144
169
  when :get
@@ -152,12 +177,19 @@ module Etcd
152
177
  req = Net::HTTP::Post.new(path)
153
178
  req.body= encoded_params
154
179
  Log.debug("Setting body for post '#{encoded_params}'")
180
+ when :put
181
+ encoded_params = URI.encode_www_form(params)
182
+ req = Net::HTTP::Put.new(path)
183
+ req.body= encoded_params
184
+ Log.debug("Setting body for put '#{encoded_params}'")
155
185
  when :delete
156
186
  unless params.nil?
157
187
  encoded_params = URI.encode_www_form(params)
158
188
  path+= "?" + encoded_params
159
189
  end
160
190
  req = Net::HTTP::Delete.new(path)
191
+ else
192
+ raise "Unknown http action: #{method}"
161
193
  end
162
194
 
163
195
  Log.debug("Invoking: '#{req.class}' against '#{path}")
@@ -168,7 +200,7 @@ module Etcd
168
200
  res.body
169
201
  elsif redirect?(res.code.to_i) and allow_redirect
170
202
  Log.debug("Http redirect, following")
171
- api_execute(res['location'], method, params)
203
+ api_execute(res['location'], method, params: params)
172
204
  else
173
205
  Log.debug("Http error")
174
206
  Log.debug(res.body)
@@ -183,11 +215,21 @@ module Etcd
183
215
 
184
216
  def json2obj(json)
185
217
  obj = JSON.parse(json)
186
- if obj.is_a?(Array)
187
- obj.map{|e| OpenStruct.new(e)}
218
+ if obj.has_key?('nodes')
219
+ obj.map do |e|
220
+ node2obj(e)
221
+ end
188
222
  else
189
- OpenStruct.new(obj)
223
+ node2obj(obj)
190
224
  end
191
225
  end
226
+
227
+ def node2obj(hash)
228
+ h = hash.dup
229
+ h[:value] = h['node']['value'] if h.has_key?('node') and h['node'].has_key?('value')
230
+ o = OpenStruct.new(h)
231
+ o.node = OpenStruct.new(o.node) if h.has_key?('node')
232
+ o
233
+ end
192
234
  end
193
235
  end
@@ -1,3 +1,3 @@
1
1
  module Etcd
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -19,6 +19,10 @@ describe "Functional Test Suite" do
19
19
  start_etcd_servers
20
20
  end
21
21
 
22
+ let(:etcd_servers) do
23
+ (1..5).map{|n| "http://127.0.0.1:700#{n}"}
24
+ end
25
+
22
26
  after(:all) do
23
27
  stop_etcd_servers
24
28
  end
@@ -46,7 +50,7 @@ describe "Functional Test Suite" do
46
50
 
47
51
 
48
52
  it "#leader" do
49
- expect(client.leader).to eq('http://127.0.0.1:7001')
53
+ expect(etcd_servers).to include(client.leader)
50
54
  end
51
55
 
52
56
  it "#machines" do
@@ -18,7 +18,7 @@ shared_examples "read only client" do
18
18
  key = random_key
19
19
  value = uuid.generate
20
20
  index = client.set(key, value).index
21
- expect(read_only_client.watch(key, index).value).to eq(value)
21
+ expect(read_only_client.watch(key, index: index).value).to eq(value)
22
22
  end
23
23
  end
24
24
 
@@ -14,5 +14,31 @@ shared_examples "test_and_set" do
14
14
  client.set(key, value)
15
15
  expect{ client.test_and_set(key, 10, 2)}.to raise_error(Net::HTTPServerException)
16
16
  end
17
+
18
+ it "#create should succeed when the key is absent and update should fail" do
19
+ key = random_key(2)
20
+ value = uuid.generate
21
+ expect {
22
+ client.update(key, value)
23
+ }.to raise_error
24
+ expect {
25
+ client.create(key, value)
26
+ }.to_not raise_error
27
+ expect(client.get(key).value).to eq(value)
28
+ end
29
+
30
+ it "#create should fail when the key is present and update should succeed" do
31
+ key = random_key(2)
32
+ value = uuid.generate
33
+ client.set(key, 1)
34
+
35
+ expect {
36
+ client.create(key, value)
37
+ }.to raise_error
38
+
39
+ expect {
40
+ client.update(key, value)
41
+ }.to_not raise_error
42
+ end
17
43
  end
18
44
 
@@ -4,11 +4,11 @@ shared_examples "watch" do
4
4
  value1 = uuid.generate
5
5
  value2 = uuid.generate
6
6
 
7
- index1 = client.set(key, value1).index
8
- index2 = client.set(key, value2).index
7
+ index1 = client.create(key, value1).node.modifiedIndex
8
+ index2 = client.test_and_set(key, value2, value1).node.modifiedIndex
9
9
 
10
- expect(client.watch(key, index1).value).to eq(value1)
11
- expect(client.watch(key, index2).value).to eq(value2)
10
+ expect(client.watch(key, index: index1).value).to eq(value1)
11
+ expect(client.watch(key, index: index2).value).to eq(value2)
12
12
  end
13
13
 
14
14
  it "with index, waits and return when the key is updated" do
@@ -27,11 +27,11 @@ module Etcd
27
27
  end
28
28
 
29
29
  def spawn_etcd_server(dir, client_port=4001, server_port=7001, leader = nil)
30
- args = " -c 127.0.0.1:#{client_port} -s 127.0.0.1:#{server_port} -d #{dir} -n node_#{client_port}"
30
+ args = " -addr 127.0.0.1:#{client_port} -peer-addr 127.0.0.1:#{server_port} -data-dir #{dir} -name node_#{client_port}"
31
31
  command = if leader.nil?
32
32
  ETCD_BIN + args
33
33
  else
34
- ETCD_BIN + args + " -C #{leader}"
34
+ ETCD_BIN + args + " -peers #{leader}"
35
35
  end
36
36
  puts command
37
37
  pid = spawn(command)
@@ -12,54 +12,62 @@ describe Etcd::Client do
12
12
  expect(client.port).to eq(4001)
13
13
  end
14
14
 
15
- it "shlould follow redirection by default" do
15
+ it "should have SSL turned off by default" do
16
+ expect(client.use_ssl).to be_false
17
+ end
18
+
19
+ it "should have SSL verification turned on by default" do
20
+ expect(client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
21
+ end
22
+
23
+ it "should follow redirection by default" do
16
24
  expect(client.allow_redirect).to be_true
17
25
  end
18
26
 
19
27
  it "#machines should make /machines GET http request" do
20
- client.should_receive(:api_execute).with('/v1/machines', :get).and_return('foobar')
28
+ client.should_receive(:api_execute).with('/v2/machines', :get).and_return('foobar')
21
29
  expect(client.machines).to eq(['foobar'])
22
30
  end
23
31
 
24
32
  it "#leader should make /leader GET http request" do
25
- client.should_receive(:api_execute).with('/v1/leader', :get).and_return('foobar')
33
+ client.should_receive(:api_execute).with('/v2/leader', :get).and_return('foobar')
26
34
  expect(client.leader).to eq('foobar')
27
35
  end
28
36
 
29
- it "#get('/foo') should make /v1/keys/foo GET http request" do
30
- client.should_receive(:api_execute).with('/v1/keys/foo', :get).and_return('{"value":1}')
37
+ it "#get('/foo') should make /v2/keys/foo GET http request" do
38
+ client.should_receive(:api_execute).with('/v2/keys/foo', :get, {:params=>{}}).and_return('{"value":1}')
31
39
  expect(client.get('/foo').value).to eq(1)
32
40
  end
33
41
 
34
42
  describe "#set" do
35
- it "set('/foo', 1) should invoke /v1/keys/foo POST http request" do
36
- client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1}).and_return('{"value":1}')
43
+ it "set('/foo', 1) should invoke /v2/keys/foo PUT http request" do
44
+ client.should_receive(:api_execute).with('/v2/keys/foo', :put, params: {'value'=>1}).and_return('{"value":1}')
37
45
  expect(client.set('/foo', 1).value).to eq(1)
38
46
  end
39
- it "set('/foo', 1, 4) should invoke /v1/keys/foo POST http request and set the ttl to 4" do
40
- client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'ttl'=>4}).and_return('{"value":1}')
47
+ it "set('/foo', 1, 4) should invoke /v2/keys/foo PUT http request and set the ttl to 4" do
48
+ client.should_receive(:api_execute).with('/v2/keys/foo', :put, params: {'value'=>1, 'ttl'=>4}).and_return('{"value":1}')
41
49
  expect(client.set('/foo', 1, 4).value).to eq(1)
42
50
  end
43
51
  end
44
52
 
45
53
  describe "#test_and_set" do
46
- it "test_and_set('/foo', 1, 4) should invoke /v1/keys/foo POST http request" do
47
- client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'prevValue'=>4}).and_return('{"value":1}')
54
+ it "test_and_set('/foo', 1, 4) should invoke /v2/keys/foo PUT http request" do
55
+ client.should_receive(:api_execute).with('/v2/keys/foo', :put, params: {'value'=>1, 'prevValue'=>4}).and_return('{"value":1}')
48
56
  expect(client.test_and_set('/foo', 1, 4).value).to eq(1)
49
57
  end
50
- it "test_and_set('/foo', 1, 4, 10) should invoke /v1/keys/foo POST http request and set the ttl to 10" do
51
- client.should_receive(:api_execute).with('/v1/keys/foo', :post, {'value'=>1, 'prevValue'=>4, 'ttl'=>10}).and_return('{"value":1}')
58
+ it "test_and_set('/foo', 1, 4, 10) should invoke /v2/keys/foo PUT http request and set the ttl to 10" do
59
+ client.should_receive(:api_execute).with('/v2/keys/foo', :put, params: {'value'=>1, 'prevValue'=>4, 'ttl'=>10}).and_return('{"value":1}')
52
60
  expect(client.test_and_set('/foo', 1, 4, 10).value).to eq(1)
53
61
  end
54
62
  end
55
63
 
56
- it "#watch('/foo') should make /v1/watch/foo GET http request" do
57
- client.should_receive(:api_execute).with('/v1/watch/foo', :get).and_return('{"value":1}')
64
+ it "#watch('/foo') should make /v2/watch/foo GET http request" do
65
+ client.should_receive(:api_execute).with('/v2/keys/foo', :get, {:timeout=>60, :params=>{:wait=>true}}).and_return('{"value":1}')
58
66
  expect(client.watch('/foo').value).to eq(1)
59
67
  end
60
68
 
61
- it "#delete('/foo') should make /v1/keys/foo DELETE http request" do
62
- client.should_receive(:api_execute).with('/v1/keys/foo', :delete).and_return('{"index":"1"}')
69
+ it "#delete('/foo') should make /v2/keys/foo DELETE http request" do
70
+ client.should_receive(:api_execute).with('/v2/keys/foo', :delete, {:params=>{}}).and_return('{"index":"1"}')
63
71
  client.delete('/foo')
64
72
  end
65
73
 
metadata CHANGED
@@ -1,126 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: etcd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
5
- prerelease:
4
+ version: 0.0.6
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ranjib Dey
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-09-10 00:00:00.000000000 Z
11
+ date: 2013-12-10 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: mixlib-cli
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: mixlib-log
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: uuid
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bundler
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - '>='
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - '>='
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: simplecov
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - '>='
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - '>='
124
109
  - !ruby/object:Gem::Version
125
110
  version: '0'
126
111
  description: Ruby client library for etcd
@@ -159,33 +144,26 @@ files:
159
144
  homepage: https://github.com/ranjib/etcd-ruby
160
145
  licenses:
161
146
  - MIT
147
+ metadata: {}
162
148
  post_install_message:
163
149
  rdoc_options: []
164
150
  require_paths:
165
151
  - lib
166
152
  required_ruby_version: !ruby/object:Gem::Requirement
167
- none: false
168
153
  requirements:
169
- - - ! '>='
154
+ - - '>='
170
155
  - !ruby/object:Gem::Version
171
156
  version: '0'
172
- segments:
173
- - 0
174
- hash: -924240572325429270
175
157
  required_rubygems_version: !ruby/object:Gem::Requirement
176
- none: false
177
158
  requirements:
178
- - - ! '>='
159
+ - - '>='
179
160
  - !ruby/object:Gem::Version
180
161
  version: '0'
181
- segments:
182
- - 0
183
- hash: -924240572325429270
184
162
  requirements: []
185
163
  rubyforge_project:
186
- rubygems_version: 1.8.23
164
+ rubygems_version: 2.0.3
187
165
  signing_key:
188
- specification_version: 3
166
+ specification_version: 4
189
167
  summary: Ruby client library for etcd
190
168
  test_files:
191
169
  - spec/functional/client_spec.rb