etcd 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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