etcd 0.2.0.alpha → 0.2.0.beta.1

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjEwNDYyYjk0OWMyNzU2M2NhMjk2N2QxYmVmYTFhMmI2NjhlNzdiOQ==
4
+ YjhkNjNmODJjMmU3YTg3NDliYTU4ODk3MjY0NDYyYjNjODg1Y2QwZg==
5
5
  data.tar.gz: !binary |-
6
- NDdkYzdhMzM4ZmFhZWU1YTkxZTM3ZWEwYTA1MDE1YjI5NWZmODgxZg==
6
+ NzEyZjMxMTcwYmFiOWY3ZWU0OTg0YzdiMDFlNTNlNGJiM2Q2NjAwNw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OGI3MTA1YmM5MjA4ZjUzYmE4Mjc0MTVmYWEzODU1NDI0ZjhiMzNlZDM3MWQ1
10
- Mjk1NTIxNmY2MzA4MGYyZTEyZTRiZjExOTFiZTRkNGI3MzAyZjFkOWY3Yjdm
11
- MGY5NGNmYjU5NDEwOTVjZDNjMzBiOWU5YTA5YzNmOTUwNGEzMDA=
9
+ YTM3YWI4NDQ1YWJhY2E1NjgwYmJlMjkyNGZiYmQ4YWNmYjQ3NDlmNDlmNGIy
10
+ ZjUwYTA0MWNjMGVkZWE1Y2Y3MTliNWNjYzMzODc5YzQwNjA2YzVhNzVhMDRh
11
+ MTk4MDYxYWI0NjAwYzEyYTVhYzc3YzI3ZDM2YmI3OWVkMWJlZjU=
12
12
  data.tar.gz: !binary |-
13
- OGYwZThkZjFmMDcxNzUyZTBjODBhMTgwZWYwMWVmZjU1NzAyZmVjNTg5YmY5
14
- ZGQ0ODgxYmMzNjBlMTFmMDZhOTI3MmI2MTgzMGE0NDQ3ODkxYWIzYWI0NDc0
15
- YzAzNzNjYzc3YzIwYzZiMGI5ZjEzN2ZjMWI5NmFlMDkzNDNlOWM=
13
+ YWUwNGJkYWIwOWZkOGVkMDRlNDg5NmQ1MzY5NWI1OGI1MGI3MjNjODc3ODNh
14
+ NzBhNjc2YzI2ZGI1ZDAzMGU1MDYzMmNjNDAxZTFkYjkzZTZlYmNiYjJlNDkz
15
+ N2ZkNDk5NTcyMGIyZDM0OTlkNDMxZDJkOGFiNzc1OGI5ZThlNmI=
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  -c
2
- -fs
2
+ -fd
3
+ --fail-fast
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+ AllCops:
2
+ Includes:
3
+ - Gemfile
4
+ - lib/**
5
+ Excludes:
6
+ - spec/**
7
+
8
+ Encoding:
9
+ Enabled: false
10
+
11
+ LineLength:
12
+ Max: 100
data/.travis.yml CHANGED
@@ -8,4 +8,4 @@ rvm:
8
8
  branches:
9
9
  only:
10
10
  - master
11
- script: "bundle exec rake spec"
11
+ script: "ETCD_BIN=./etcd/bin/etcd bundle exec rake spec"
data/Gemfile CHANGED
@@ -2,5 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in etcd.gemspec
4
4
  gemspec
5
+
5
6
  gem 'coco'
6
7
  gem 'rubocop'
8
+ gem 'guard'
9
+ gem 'guard-rake'
10
+ # uuid gem isn't pulling in systemu
11
+ gem 'systemu'
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # vim: set ft=ruby:
2
+ require 'guard/guard'
3
+ require 'guard/rake'
4
+
5
+ guard 'rake', :task => 'test:quick' do
6
+ watch(%r{^spec/.+_spec\.rb$})
7
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
+ end
data/README.md CHANGED
@@ -22,6 +22,7 @@ Or install it yourself as:
22
22
  client = Etcd.client # this will create a client against etcd server running on localhost on port 4001
23
23
  client = Etcd.client(port: 4002)
24
24
  client = Etcd.client(host: '127.0.0.1', port: 4003)
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)
25
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
26
27
  ```
27
28
  ### Set a key
@@ -66,11 +67,14 @@ client.machines
66
67
  ```ruby
67
68
  client.leader
68
69
  ```
70
+ More examples and api details can be found in the [wiki](https://github.com/ranjib/etcd-ruby/wiki)
69
71
 
70
72
  ## Contributors
71
73
  * Ranjib Dey
72
- * Jesse Nelson
73
-
74
+ * [Jesse Nelson](https://github.com/spheromak)
75
+ * [Nilesh Bairagi](https://github.com/Bairagi)
76
+ * [Dr Nic Williams](https://github.com/drnic)
77
+ * [Eric Buth] (https://github.com/buth)
74
78
 
75
79
 
76
80
  ## Contributing
data/Rakefile CHANGED
@@ -1,10 +1,23 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
  require "rdoc/task"
4
+ require "rubocop/rake_task"
4
5
 
5
6
  RSpec::Core::RakeTask.new("spec")
6
7
 
8
+ Rubocop::RakeTask.new do |task|
9
+ task.fail_on_error = true
10
+ end
11
+
7
12
  RDoc::Task.new do |rdoc|
8
13
  rdoc.main = "README.rdoc"
9
14
  rdoc.rdoc_files.include("lib /*.rb")
10
15
  end
16
+
17
+ namespace :test do
18
+ desc 'Run all of the quick tests.'
19
+ task :quick do
20
+ Rake::Task['rubocop'].invoke
21
+ Rake::Task['spec'].invoke
22
+ end
23
+ end
data/lib/etcd.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'etcd/client'
4
4
  ##
5
- # This module provides the Etcd:: name space for the gem and few
5
+ # This module provides the Etcd:: name space for the gem and few
6
6
  # factory methods for Etcd domain objects
7
7
  module Etcd
8
8
  ##
@@ -10,7 +10,7 @@ module Etcd
10
10
  # as an argument which gets passed to the Etcd::Client.new method
11
11
  # directly
12
12
  # If +opts+ is not passed default options are used, defined by Etcd::Client.new
13
- def self.client(opts={})
13
+ def self.client(opts = {})
14
14
  Etcd::Client.new(opts)
15
15
  end
16
16
  end
data/lib/etcd/client.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # Encoding: utf-8
2
2
 
3
+ require 'openssl'
3
4
  require 'net/http'
4
5
  require 'json'
5
6
  require 'etcd/log'
@@ -16,10 +17,9 @@ module Etcd
16
17
  # etcd api, like Etcd::Client#lock and Etcd::Client#eternal_watch, they
17
18
  # are defined in separate modules and included in this class
18
19
  class Client
19
-
20
- HTTP_REDIRECT = ->(r){ r.is_a? Net::HTTPRedirection }
21
- HTTP_SUCCESS = ->(r){ r.is_a? Net::HTTPSuccess }
22
- HTTP_CLIENT_ERROR = ->(r){ r.is_a? Net::HTTPClientError }
20
+ HTTP_REDIRECT = ->(r) { r.is_a? Net::HTTPRedirection }
21
+ HTTP_SUCCESS = ->(r) { r.is_a? Net::HTTPSuccess }
22
+ HTTP_CLIENT_ERROR = ->(r) { r.is_a? Net::HTTPClientError }
23
23
 
24
24
  include Stats
25
25
  include Keys
@@ -28,6 +28,7 @@ module Etcd
28
28
 
29
29
  attr_reader :host, :port, :http, :allow_redirect
30
30
  attr_reader :use_ssl, :verify_mode, :read_timeout
31
+ attr_reader :user_name, :password
31
32
 
32
33
  ##
33
34
  # Creates an Etcd::Client object. It accepts a hash +opts+ as argument
@@ -36,6 +37,7 @@ module Etcd
36
37
  # @opts [String] :host IP address of the etcd server (default 127.0.0.1)
37
38
  # @opts [Fixnum] :port Port number of the etcd server (default 4001)
38
39
  # @opts [Fixnum] :read_timeout set HTTP read timeouts (default 60)
40
+ # rubocop:disable CyclomaticComplexity
39
41
  def initialize(opts = {})
40
42
  @host = opts[:host] || '127.0.0.1'
41
43
  @port = opts[:port] || 4001
@@ -43,7 +45,10 @@ module Etcd
43
45
  @allow_redirect = opts.key?(:allow_redirect) ? opts[:allow_redirect] : true
44
46
  @use_ssl = opts[:use_ssl] || false
45
47
  @verify_mode = opts.key?(:verify_mode) ? opts[:verify_mode] : OpenSSL::SSL::VERIFY_PEER
48
+ @user_name = opts[:user_name] || nil
49
+ @password = opts[:password] || nil
46
50
  end
51
+ # rubocop:enable CyclomaticComplexity
47
52
 
48
53
  # Returns the etcd api version that will be used for across API methods
49
54
  def version_prefix
@@ -71,6 +76,7 @@ module Etcd
71
76
  # * path - etcd server path (etcd server end point)
72
77
  # * method - the request method used
73
78
  # * options - any additional parameters used by request method (optional)
79
+ # rubocop:disable MethodLength, CyclomaticComplexity
74
80
  def api_execute(path, method, options = {})
75
81
  params = options[:params]
76
82
  case method
@@ -90,21 +96,26 @@ module Etcd
90
96
  http.read_timeout = timeout
91
97
  http.use_ssl = use_ssl
92
98
  http.verify_mode = verify_mode
99
+ req.basic_auth(user_name, password) if [user_name, password].all?
93
100
  Log.debug("Invoking: '#{req.class}' against '#{path}")
94
101
  res = http.request(req)
95
102
  Log.debug("Response code: #{res.code}")
96
- process_http_request(res)
103
+ process_http_request(res, req, params)
97
104
  end
98
105
 
99
- def process_http_request(res)
106
+ # need to ahve original request to process the response when it redirects
107
+ def process_http_request(res, req = nil, params = nil)
100
108
  case res
101
109
  when HTTP_SUCCESS
102
110
  Log.debug('Http success')
103
111
  res
104
112
  when HTTP_REDIRECT
105
113
  if allow_redirect
106
- Log.debug('Http redirect, following')
107
- api_execute(res['location'], method, params: params)
114
+ uri = URI(res['location'])
115
+ @host = uri.host
116
+ @port = uri.port
117
+ Log.debug("Http redirect, setting new host to: #{@host}:#{@port}, and retrying")
118
+ api_execute(uri.path, req.method.downcase.to_sym, params: params)
108
119
  else
109
120
  Log.debug('Http redirect not allowed')
110
121
  res.error!
@@ -117,6 +128,7 @@ module Etcd
117
128
  res.error!
118
129
  end
119
130
  end
131
+ # rubocop:enable MethodLength
120
132
 
121
133
  def build_http_request(klass, path, params = nil, body = nil)
122
134
  path += '?' + URI.encode_www_form(params) unless params.nil?
@@ -36,6 +36,7 @@ module Etcd
36
36
  class NotDir < Error; end
37
37
  class NodeExist < Error; end
38
38
  class KeyIsPreserved < Error; end
39
+ class DirNotEmpty < Error; end
39
40
 
40
41
  # Post form related error
41
42
  class ValueRequired < Error; end
@@ -60,6 +61,7 @@ module Etcd
60
61
  104 => NotDir,
61
62
  105 => NodeExist,
62
63
  106 => KeyIsPreserved,
64
+ 108 => DirNotEmpty,
63
65
 
64
66
  # Post form related error
65
67
  200 => ValueRequired,
data/lib/etcd/keys.rb CHANGED
@@ -16,8 +16,8 @@ module Etcd
16
16
  # Retrives a key with its associated data, if key is not present it will
17
17
  # return with message "Key Not Found"
18
18
  #
19
- # This method has following parameters as argument
20
- # * key - whose data to be retrive
19
+ # This method takes the following parameters as arguments
20
+ # * key - whose data is to be retrieved
21
21
  def get(key, opts = {})
22
22
  response = api_execute(key_endpoint + key, :get, params: opts)
23
23
  Response.from_http_response(response)
@@ -25,30 +25,16 @@ module Etcd
25
25
 
26
26
  # Create or update a new key
27
27
  #
28
- # This method has following parameters as argument
28
+ # This method takes the following parameters as arguments
29
29
  # * key - whose value to be set
30
30
  # * value - value to be set for specified key
31
- # * ttl - shelf life of a key (in secsonds) (optional)
32
- def set(key, value, opts = nil)
31
+ # * ttl - shelf life of a key (in seconds) (optional)
32
+ def set(key, opts = nil)
33
+ fail ArgumentError, 'Second argument must be a hash' unless opts.is_a?(Hash)
33
34
  path = key_endpoint + key
34
35
  payload = {}
35
- if value.is_a?(Hash) # directory
36
- opts = value.dup
37
- else
38
- payload['value'] = value
39
- end
40
- if opts.is_a? Fixnum
41
- warn '[DEPRECATION] Passing ttl as raw argument is deprecated \
42
- please use :ttl => value, this will be removed in next minor release'
43
- payload['ttl'] = opts
44
- elsif opts.is_a? Hash
45
- [:ttl, :dir, :prevExist, :prevValue, :prevIndex].each do |k|
46
- payload[k] = opts[k] if opts.key?(k)
47
- end
48
- elsif opts.nil?
49
- # do nothing
50
- else
51
- fail ArgumentError, "Dont know how to parse #{opts}"
36
+ [:ttl, :value, :dir, :prevExist, :prevValue, :prevIndex].each do |k|
37
+ payload[k] = opts[k] if opts.key?(k)
52
38
  end
53
39
  response = api_execute(path, :put, params: payload)
54
40
  Response.from_http_response(response)
@@ -56,7 +42,7 @@ module Etcd
56
42
 
57
43
  # Deletes a key (and its content)
58
44
  #
59
- # This method has following parameters as argument
45
+ # This method takes the following parameters as arguments
60
46
  # * key - key to be deleted
61
47
  def delete(key, opts = {})
62
48
  response = api_execute(key_endpoint + key, :delete, params: opts)
@@ -65,71 +51,63 @@ module Etcd
65
51
 
66
52
  # Set a new value for key if previous value of key is matched
67
53
  #
68
- # This method takes following parameters as argument
54
+ # This method takes the following parameters as arguments
69
55
  # * key - whose value is going to change if previous value is matched
70
56
  # * value - new value to be set for specified key
71
57
  # * prevValue - value of a key to compare with existing value of key
72
58
  # * ttl - shelf life of a key (in secsonds) (optional)
73
- def compare_and_swap(key, value, prevValue, ttl = nil)
74
- path = key_endpoint + key
75
- payload = { 'value' => value, 'prevValue' => prevValue }
76
- payload['ttl'] = ttl unless ttl.nil?
77
- response = api_execute(path, :put, params: payload)
78
- Response.from_http_response(response)
59
+ def compare_and_swap(key, opts = {})
60
+ fail ArgumentError, 'Second argument must be a hash' unless opts.is_a?(Hash)
61
+ fail ArgumentError, 'You must pass prevValue' unless opts.key?(:prevValue)
62
+ set(key, opts)
79
63
  end
80
64
 
81
65
  # Gives a notification when specified key changes
82
66
  #
83
- # This method has following parameters as argument
67
+ # This method takes the following parameters as arguments
84
68
  # @ key - key to be watched
85
69
  # @options [Hash] additional options for watching a key
86
70
  # @options [Fixnum] :index watch the specified key from given index
87
71
  # @options [Fixnum] :timeout specify http timeout
88
- def watch(key, options = {})
72
+ def watch(key, opts = {})
89
73
  params = { wait: true }
90
- timeout = options[:timeout] || @read_timeout
91
- index = options[:waitIndex] || options[:index]
74
+ fail ArgumentError, 'Second argument must be a hash' unless opts.is_a?(Hash)
75
+ timeout = opts[:timeout] || @read_timeout
76
+ index = opts[:waitIndex] || opts[:index]
92
77
  params[:waitIndex] = index unless index.nil?
93
- params[:consistent] = options[:consistent] if options.key?(:consistent)
78
+ params[:consistent] = opts[:consistent] if opts.key?(:consistent)
94
79
 
95
80
  response = api_execute(key_endpoint + key, :get,
96
81
  timeout: timeout, params: params)
97
82
  Response.from_http_response(response)
98
83
  end
99
84
 
100
- def create_in_order(dir, value, opts = {})
85
+ def create_in_order(dir, opts = {})
101
86
  path = key_endpoint + dir
102
- payload = { 'value' => value }
103
- payload['ttl'] = opts[:ttl] if opts[:ttl]
87
+ fail ArgumentError, 'Second argument must be a hash' unless opts.is_a?(Hash)
88
+ payload = {}
89
+ [:ttl, :value].each do |k|
90
+ payload[k] = opts[k] if opts.key?(k)
91
+ end
104
92
  response = api_execute(path, :post, params: payload)
105
93
  Response.from_http_response(response)
106
94
  end
107
95
 
108
96
  def exists?(key)
109
- begin
110
- Etcd::Log.debug("Checking if key:' #{key}' exists")
111
- get(key)
112
- true
113
- rescue KeyNotFound => e
114
- Etcd::Log.debug("Key does not exist #{e}")
115
- false
116
- end
97
+ Etcd::Log.debug("Checking if key:' #{key}' exists")
98
+ get(key)
99
+ true
100
+ rescue KeyNotFound => e
101
+ Etcd::Log.debug("Key does not exist #{e}")
102
+ false
117
103
  end
118
104
 
119
- def create(key, value, ttl = nil)
120
- path = key_endpoint + key
121
- payload = { value: value, prevExist: false }
122
- payload['ttl'] = ttl unless ttl.nil?
123
- response = api_execute(path, :put, params: payload)
124
- Response.from_http_response(response)
105
+ def create(key, opts = {})
106
+ set(key, opts.merge(prevExist: false))
125
107
  end
126
108
 
127
- def update(key, value, ttl = nil)
128
- path = key_endpoint + key
129
- payload = { value: value, prevExist: true }
130
- payload['ttl'] = ttl unless ttl.nil?
131
- response = api_execute(path, :put, params: payload)
132
- Response.from_http_response(response)
109
+ def update(key, opts = {})
110
+ set(key, opts.merge(prevExist: true))
133
111
  end
134
112
 
135
113
  def eternal_watch(key, index = nil)
@@ -4,15 +4,15 @@ require 'timeout'
4
4
 
5
5
  module Etcd
6
6
  module Mod
7
+ # Implemetn Etcd's Leader module
7
8
  module Leader
8
-
9
9
  def mod_leader_endpoint
10
10
  '/mod/v2/leader'
11
11
  end
12
12
 
13
13
  def set_leader(key, value, ttl)
14
14
  path = mod_leader_endpoint + "#{key}?ttl=#{ttl}"
15
- api_execute(path, :put, params:{name: value}).body
15
+ api_execute(path, :put, params: { name: value }).body
16
16
  end
17
17
 
18
18
  def get_leader(key)
data/lib/etcd/mod/lock.rb CHANGED
@@ -4,45 +4,46 @@ require 'timeout'
4
4
 
5
5
  module Etcd
6
6
  module Mod
7
+ # implement etcd lock module
7
8
  module Lock
8
-
9
9
  def mod_lock_endpoint
10
10
  '/mod/v2/lock'
11
11
  end
12
12
 
13
- def acquire_lock(key, ttl, opts={})
13
+ def acquire_lock(key, ttl, opts = {})
14
14
  path = mod_lock_endpoint + key + "?ttl=#{ttl}"
15
15
  timeout = opts[:timeout] || 60
16
- Timeout::timeout(timeout) do
17
- api_execute(path, :post, params:opts)
16
+ Timeout.timeout(timeout) do
17
+ api_execute(path, :post, params: opts)
18
18
  end
19
19
  end
20
20
 
21
- def renew_lock(key, ttl, opts={})
22
- unless opts.has_key?(:index) or opts.has_key?(:value)
23
- raise ArgumentError, 'You mast pass index or value'
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
24
  end
25
25
  path = mod_lock_endpoint + key + "?ttl=#{ttl}"
26
26
  timeout = opts[:timeout] || 60
27
- Timeout::timeout(timeout) do
28
- api_execute(path, :put, params:opts).body
27
+ Timeout.timeout(timeout) do
28
+ api_execute(path, :put, params: opts).body
29
29
  end
30
30
  end
31
31
 
32
- def get_lock(key, opts={})
33
- api_execute(mod_lock_endpoint + key, :get, params:opts).body
32
+ def get_lock(key, opts = {})
33
+ api_execute(mod_lock_endpoint + key, :get, params: opts).body
34
34
  end
35
35
 
36
- def delete_lock(key, opts={})
37
- unless opts.has_key?(:index) or opts.has_key?(:value)
38
- raise ArgumentError, 'You must pass index or value'
36
+ def delete_lock(key, opts = {})
37
+ unless opts.key?(:index) || opts.key?(:value)
38
+ fail ArgumentError, 'You must pass index or value'
39
39
  end
40
- api_execute(mod_lock_endpoint + key, :delete, params:opts)
40
+ api_execute(mod_lock_endpoint + key, :delete, params: opts)
41
41
  end
42
42
 
43
- def lock(key, ttl, opts={})
44
- acquire_lock('/'+key, ttl, opts)
45
- index= get_lock('/'+key, field: index)
43
+ # rubocop:disable RescueException
44
+ def lock(key, ttl, opts = {})
45
+ acquire_lock('/' + key, ttl, opts)
46
+ index = get_lock('/' + key, field: index)
46
47
  begin
47
48
  yield key
48
49
  rescue Exception => e
@@ -51,6 +52,7 @@ module Etcd
51
52
  delete_lock(key, index: index)
52
53
  end
53
54
  end
55
+ # rubocop:enable RescueException
54
56
 
55
57
  alias_method :retrive_lock, :get_lock
56
58
  alias_method :release_lock, :delete_lock