From bdd5cd52fa008a217e62c034f3ab6076e314e3ba Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Wed, 4 Oct 2017 13:00:37 +0300 Subject: [PATCH 01/45] Add HTTP check type --- lib/diplomat/check.rb | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index b19d40e..e9477c8 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -11,7 +11,26 @@ def checks JSON.parse(ret.body) end - # Register a check + # Register a HTTP check + # @param check_id [String] the unique id of the check + # @param name [String] the name + # @param notes [String] notes about the check + # @param script [String] command to be run for check + # @param interval [String] frequency (with units) of the check execution + # @param ttl [String] time (with units) to mark a check down + # @return [Integer] Status code + # + def register_http(check_id, name, notes, url, method, header, interval) + ret = @conn.put do |req| + req.url '/v1/agent/check/register' + req.body = JSON.generate( + 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'HTTP' => url, 'Method' => method, 'Header' => header, 'Interval' => interval + ) + end + ret.status == 200 + end + + # Register a script check # @param check_id [String] the unique id of the check # @param name [String] the name # @param notes [String] notes about the check From 94bb8c6ace80619db082acafa115d1376701c6f1 Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Wed, 4 Oct 2017 13:15:42 +0300 Subject: [PATCH 02/45] Add register_http to access methods --- lib/diplomat/check.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index e9477c8..54d3bc0 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -1,7 +1,7 @@ module Diplomat # Methods for interacting with the Consul check API endpoint class Check < Diplomat::RestClient - @access_methods = %i[checks register_script register_ttl + @access_methods = %i[checks register_http register_script register_ttl deregister pass warn fail] # Get registered checks From 37046f687317358110c817bee27cc5909c78681d Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Fri, 6 Oct 2017 08:42:05 +0300 Subject: [PATCH 03/45] Fix travis errors where applicable --- lib/diplomat/check.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index 54d3bc0..1e6b46b 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -24,12 +24,13 @@ def register_http(check_id, name, notes, url, method, header, interval) ret = @conn.put do |req| req.url '/v1/agent/check/register' req.body = JSON.generate( - 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'HTTP' => url, 'Method' => method, 'Header' => header, 'Interval' => interval + 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'HTTP' => url, 'Method' => method, + 'Header' => header, 'Interval' => interval ) end ret.status == 200 end - + # Register a script check # @param check_id [String] the unique id of the check # @param name [String] the name From aa8bbb705e645c155674226e08c1ad70f2695812 Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Fri, 6 Oct 2017 09:07:40 +0300 Subject: [PATCH 04/45] Updated README and Changelog --- CHANGELOG.md | 4 ++++ README.md | 8 ++++++++ spec/check_spec.rb | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3d830..312307d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.0.3 + +- 2017-10-06 Lars Remes [lars.remes@lawly.fi][1] Support HTTP service checks + ## 2.0.2 - 2017-08-23 Trevor Wood [trevor.g.wood@gmail.com][1] Revert the change to single values diff --git a/README.md b/README.md index ede8962..56f1ec5 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,14 @@ services = Diplomat::Service.get_all({ :dc => 'My_Datacenter' }) # => # ``` +#### Checks + +Register a check: +```ruby +headers = { "Authorization" => [ "Basic ZGlwbG9tYXQ6cGFzc3dvcmQ=" ] } +Diplomat::Check.register_http('health-check-1', 'Health check', 'Node level HTTP health check', "http://#{addr}:#{port}/health_check", 'GET', headers, '10s') +``` + ### Datacenters Getting a list of datacenters is quite simple and gives you the option to extract all services out of diff --git a/spec/check_spec.rb b/spec/check_spec.rb index e348c00..7e49bc3 100644 --- a/spec/check_spec.rb +++ b/spec/check_spec.rb @@ -32,6 +32,12 @@ expect(check.register_script('foobar-1', 'Foobar', 'Foobar test', '/script/test', '10s')).to eq(true) end + it 'register_http' do + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) + check = Diplomat::Check.new(faraday) + expect(check.register_http('foobar-1', 'Foobar', 'Foobar test', 'localhost', 'GET', {}, '10s')).to eq(true) + end + it 'register_ttl' do faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) From 08b339fbc5202df1efcecc61fb3fdf4f71b75df1 Mon Sep 17 00:00:00 2001 From: "Josep M. Blanquer" Date: Fri, 10 Nov 2017 21:23:35 -0800 Subject: [PATCH 05/45] Use `PUT` as the verb for deregistering a service. (#158) * Use `PUT` as the verb for deregistering a service. Consul 1.0 has started to enforce the verbs used: *https://www.consul.io/docs/upgrade-specific.html#http-verbs-are-enforced-in-many-http-apis * Appease rubocop errors --- CHANGELOG.md | 5 +++++ diplomat.gemspec | 12 ++++++------ lib/diplomat/configuration.rb | 7 +++++-- lib/diplomat/kv.rb | 9 ++++++--- lib/diplomat/rest_client.rb | 6 +++++- lib/diplomat/service.rb | 2 +- spec/agent_spec.rb | 16 ++++++++-------- spec/service_spec.rb | 2 +- 8 files changed, 37 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3d830..55bdd59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +# Next + +- 2017-11-09 Josep M. Blanquer (@blanquer) Fix service deregister to use the proper verb (`PUT` instead of `GET`). Consul 1.x seems to +have started enforcing [it](https://www.consul.io/docs/upgrade-specific.html#http-verbs-are-enforced-in-many-http-apis). + ## 2.0.2 - 2017-08-23 Trevor Wood [trevor.g.wood@gmail.com][1] Revert the change to single values diff --git a/diplomat.gemspec b/diplomat.gemspec index 73ae792..14fb050 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -10,16 +10,16 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.files = `git ls-files lib README.md LICENSE features`.split("\n") spec.add_development_dependency 'bundler', '~> 1.3' - spec.add_development_dependency 'rake', '~> 12.0' - spec.add_development_dependency 'pry', '~> 0.9' - spec.add_development_dependency 'rspec', '~> 3.2' - spec.add_development_dependency 'fakes-rspec', '~> 2.1' spec.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.0' + spec.add_development_dependency 'cucumber', '~> 2.0' + spec.add_development_dependency 'fakes-rspec', '~> 2.1' spec.add_development_dependency 'fivemat', '~> 1.3' spec.add_development_dependency 'gem-release', '~> 0.7' - spec.add_development_dependency 'cucumber', '~> 2.0' + spec.add_development_dependency 'pry', '~> 0.9' + spec.add_development_dependency 'rake', '~> 12.0' + spec.add_development_dependency 'rspec', '~> 3.2' spec.add_development_dependency 'rubocop', '~> 0.47', '>= 0.47.1' - spec.add_runtime_dependency 'json' if RUBY_VERSION < '1.9.3' spec.add_runtime_dependency 'faraday', '~> 0.9' + spec.add_runtime_dependency 'json' if RUBY_VERSION < '1.9.3' end diff --git a/lib/diplomat/configuration.rb b/lib/diplomat/configuration.rb index 8370a35..f3a450c 100644 --- a/lib/diplomat/configuration.rb +++ b/lib/diplomat/configuration.rb @@ -1,7 +1,7 @@ module Diplomat # Methods for configuring Diplomat class Configuration - attr_accessor :middleware + attr_reader :middleware attr_accessor :url, :acl_token, :options # Override defaults for configuration @@ -18,7 +18,10 @@ def initialize(url = 'http://localhost:8500', acl_token = nil, options = {}) # Define a middleware for Faraday # @param middleware [Class] Faraday Middleware class def middleware=(middleware) - return @middleware = middleware if middleware.is_a? Array + if middleware.is_a? Array + @middleware = middleware + return + end @middleware = [middleware] end end diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index a42dc3c..64c070b 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -248,14 +248,17 @@ def transaction_return(raw_return, options) OpenStruct.new decoded_return end - def decode_transaction(transaction) + def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength return transaction if transaction['Results'].nil? || transaction['Results'].empty? transaction.tap do |txn| txn['Results'].each do |resp| next unless resp['KV']['Value'] - value = resp['KV']['Value'] - resp['KV']['Value'] = Base64.decode64(value) rescue nil # rubocop:disable RescueModifier + begin + resp['KV']['Value'] = Base64.decode64(resp['KV']['Value']) + rescue # rubocop:disable RescueWithoutErrorClass + nil + end end end end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index cc67f57..efbee4a 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -141,7 +141,11 @@ def parse_body def decode_values return @raw if @raw.first.is_a? String @raw.each_with_object([]) do |acc, el| - acc['Value'] = Base64.decode64(acc['Value']) rescue nil # rubocop:disable RescueModifier + begin + acc['Value'] = Base64.decode64(acc['Value']) + rescue # rubocop:disable RescueWithoutErrorClass + nil + end el << acc el end diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index e3715a8..463607c 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -75,7 +75,7 @@ def register(definition, path = '/v1/agent/service/register') # @param service_name [String] Service name to de-register # @return [Boolean] def deregister(service_name) - deregister = @conn.get "/v1/agent/service/deregister/#{service_name}" + deregister = @conn.put "/v1/agent/service/deregister/#{service_name}" deregister.status == 200 end diff --git a/spec/agent_spec.rb b/spec/agent_spec.rb index faf5b0b..09f233d 100644 --- a/spec/agent_spec.rb +++ b/spec/agent_spec.rb @@ -7,7 +7,7 @@ context 'agent' do it 'self' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-EOF)) + faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) { "Config": { "Bootstrap": true, @@ -73,7 +73,7 @@ "DelegateCur": 4 } } - EOF + JSON agent = Diplomat::Agent.new(faraday) @@ -81,7 +81,7 @@ end it 'checks' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-EOF)) + faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) { "service:redis": { "Node": "foobar", @@ -94,7 +94,7 @@ "ServiceName": "redis" } } - EOF + JSON agent = Diplomat::Agent.new(faraday) @@ -102,7 +102,7 @@ end it 'services' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-EOF)) + faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) { "redis": { "ID": "redis", @@ -112,7 +112,7 @@ "Port": 8000 } } - EOF + JSON agent = Diplomat::Agent.new(faraday) @@ -120,7 +120,7 @@ end it 'members' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-EOF)) + faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) [ { "Name": "foobar", @@ -141,7 +141,7 @@ "DelegateCur": 3 } ] - EOF + JSON agent = Diplomat::Agent.new(faraday) diff --git a/spec/service_spec.rb b/spec/service_spec.rb index bcf7797..52ee33d 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -231,7 +231,7 @@ it 'can deregister a service' do url = "#{deregister_service_url}/#{service_definition[:name]}" - expect(faraday).to receive(:get).with(url) do + expect(faraday).to receive(:put).with(url) do OpenStruct.new(body: '', status: 200) end service = Diplomat::Service.new(faraday) From 78c8ab88cf22069c2465f9297b2adb1e4a3feb3a Mon Sep 17 00:00:00 2001 From: Jeff Fraser Date: Thu, 28 Dec 2017 14:02:45 -0500 Subject: [PATCH 06/45] Suggest using X-Consul-Token for ACLs Concerning ACL tokens, the Consul documentation (https://www.consul.io/api/index.html#authentication) says: > Previously this was provided via a ?token= query parameter. This functionality exists on many endpoints for backwards compatibility, but its use is highly discouraged, since it can show up in access logs as part of the URL. The `config.acl_token` setting in Diplomat sets the `token` query string parameter rather than the header. Additionally, it does not set it for all API endpoints (e.g., Services). Setting the header instead fixes both issues. --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ede8962..767e80f 100644 --- a/README.md +++ b/README.md @@ -310,10 +310,8 @@ Diplomat.configure do |config| config.url = "http://localhost:8888" # Set up a custom Faraday Middleware config.middleware = MyCustomMiddleware - # Connect into consul with custom access token (ACL) - config.acl_token = "xxxxxxxx-yyyy-zzzz-1111-222222222222" - # Set extra Faraday configuration options - config.options = {ssl: { version: :TLSv1_2 }} + # Set extra Faraday configuration options and custom access token (ACL) + config.options = {ssl: {version: :TLSv1_2}, headers: {"X-Consul-Token" => "xxxxxxxx-yyyy-zzzz-1111-222222222222"}} end ``` From 575c866e662beb2bdf819972ad00cf334dd16c58 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 3 Mar 2018 16:08:42 +0100 Subject: [PATCH 07/45] Move ApiOptions methods into Restclient There is no need for a separate module, all these methods are only used within the rest client. --- lib/diplomat.rb | 4 ++-- lib/diplomat/acl.rb | 2 -- lib/diplomat/api_options.rb | 46 ------------------------------------- lib/diplomat/event.rb | 2 -- lib/diplomat/kv.rb | 2 -- lib/diplomat/lock.rb | 2 -- lib/diplomat/node.rb | 2 -- lib/diplomat/query.rb | 2 -- lib/diplomat/rest_client.rb | 42 +++++++++++++++++++++++++++++++++ lib/diplomat/service.rb | 2 -- 10 files changed, 44 insertions(+), 62 deletions(-) delete mode 100644 lib/diplomat/api_options.rb diff --git a/lib/diplomat.rb b/lib/diplomat.rb index e18f451..59680f7 100644 --- a/lib/diplomat.rb +++ b/lib/diplomat.rb @@ -26,8 +26,8 @@ def require_libs(*libs) self.root_path = File.expand_path '..', __FILE__ self.lib_path = File.expand_path '../diplomat', __FILE__ - require_libs 'configuration', 'rest_client', 'api_options', 'kv', 'datacenter', - 'service', 'members', 'node', 'nodes', 'check', 'health', 'session', 'lock', + require_libs 'configuration', 'rest_client', 'kv', 'datacenter', 'service', + 'members', 'node', 'nodes', 'check', 'health', 'session', 'lock', 'error', 'event', 'acl', 'maintenance', 'query', 'agent', 'status' self.configuration ||= Diplomat::Configuration.new diff --git a/lib/diplomat/acl.rb b/lib/diplomat/acl.rb index 8c0f599..3c69871 100644 --- a/lib/diplomat/acl.rb +++ b/lib/diplomat/acl.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul ACL API endpoint class Acl < Diplomat::RestClient - include ApiOptions - @access_methods = %i[list info create destroy update] attr_reader :id, :type, :acl diff --git a/lib/diplomat/api_options.rb b/lib/diplomat/api_options.rb deleted file mode 100644 index 03ce558..0000000 --- a/lib/diplomat/api_options.rb +++ /dev/null @@ -1,46 +0,0 @@ -module Diplomat - # Helper methods for interacting with the Consul RESTful API - module ApiOptions - def check_acl_token - use_named_parameter('token', Diplomat.configuration.acl_token) - end - - def use_cas(options) - options ? use_named_parameter('cas', options[:cas]) : [] - end - - def use_consistency(options) - options && options[:consistency] ? [options[:consistency].to_s] : [] - end - - # Mapping for valid key/value store transaction verbs and required parameters - # - # @return [Hash] valid key/store transaction verbs and required parameters - # rubocop:disable MethodLength - def valid_transaction_verbs - { - 'set' => %w[Key Value], - 'cas' => %w[Key Value Index], - 'lock' => %w[Key Value Session], - 'unlock' => %w[Key Value Session], - 'get' => %w[Key], - 'get-tree' => %w[Key], - 'check-index' => %w[Key Index], - 'check-session' => %w[Key Session], - 'delete' => %w[Key], - 'delete-tree' => %w[Key], - 'delete-cas' => %w[Key Index] - } - end - # rubocop:enable MethodLength - - # Key/value store transactions that require that a value be set - # - # @return [Array] verbs that require a value be set - def valid_value_transactions - @valid_value_transactions ||= valid_transaction_verbs.select do |verb, requires| - verb if requires.include? 'Value' - end - end - end -end diff --git a/lib/diplomat/event.rb b/lib/diplomat/event.rb index d6aac2a..c607b32 100644 --- a/lib/diplomat/event.rb +++ b/lib/diplomat/event.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul event API endpoint class Event < Diplomat::RestClient - include ApiOptions - @access_methods = %i[fire get_all get] # Send an event diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index 64c070b..5b4e170 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul KV API endpoint class Kv < Diplomat::RestClient - include ApiOptions - @access_methods = %i[get put delete txn] attr_reader :key, :value, :raw diff --git a/lib/diplomat/lock.rb b/lib/diplomat/lock.rb index da70a9c..328c1fe 100644 --- a/lib/diplomat/lock.rb +++ b/lib/diplomat/lock.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul lock API endpoint class Lock < Diplomat::RestClient - include ApiOptions - @access_methods = %i[acquire wait_to_acquire release] # Acquire a lock diff --git a/lib/diplomat/node.rb b/lib/diplomat/node.rb index f29af90..c12bb4e 100644 --- a/lib/diplomat/node.rb +++ b/lib/diplomat/node.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul node API endpoint class Node < Diplomat::RestClient - include ApiOptions - @access_methods = %i[get get_all register deregister] # Get a node by it's key diff --git a/lib/diplomat/query.rb b/lib/diplomat/query.rb index da239ac..25d4334 100644 --- a/lib/diplomat/query.rb +++ b/lib/diplomat/query.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul query API endpoint class Query < Diplomat::RestClient - include ApiOptions - @access_methods = %i[get get_all create delete update execute explain] # Get a prepared query by it's key diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index efbee4a..1a0b71f 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -176,5 +176,47 @@ def return_payload payload: (Base64.decode64(e['Payload']) unless e['Payload'].nil?) } end end + + def check_acl_token + use_named_parameter('token', Diplomat.configuration.acl_token) + end + + def use_cas(options) + options ? use_named_parameter('cas', options[:cas]) : [] + end + + def use_consistency(options) + options && options[:consistency] ? [options[:consistency].to_s] : [] + end + + # Mapping for valid key/value store transaction verbs and required parameters + # + # @return [Hash] valid key/store transaction verbs and required parameters + # rubocop:disable MethodLength + def valid_transaction_verbs + { + 'set' => %w[Key Value], + 'cas' => %w[Key Value Index], + 'lock' => %w[Key Value Session], + 'unlock' => %w[Key Value Session], + 'get' => %w[Key], + 'get-tree' => %w[Key], + 'check-index' => %w[Key Index], + 'check-session' => %w[Key Session], + 'delete' => %w[Key], + 'delete-tree' => %w[Key], + 'delete-cas' => %w[Key Index] + } + end + # rubocop:enable MethodLength + + # Key/value store transactions that require that a value be set + # + # @return [Array] verbs that require a value be set + def valid_value_transactions + @valid_value_transactions ||= valid_transaction_verbs.select do |verb, requires| + verb if requires.include? 'Value' + end + end end end diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index 463607c..cfde3f6 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -1,8 +1,6 @@ module Diplomat # Methods for interacting with the Consul serivce API endpoint. class Service < Diplomat::RestClient - include ApiOptions - @access_methods = %i[get get_all register deregister register_external deregister_external maintenance] # Get a service by it's key From ec3be3aa2ab47b1ca5531c92dfc5a267d045a253 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 3 Mar 2018 16:41:08 +0100 Subject: [PATCH 08/45] Allow to pass ::Diplomat::Configuration object to the Rest Client In some cases you might want to have multiple ::Diplomat::RestClient at the same time but with different configurations. Using a static config forbid this kind of uses. Possible use cases: - Multiple clients with different Tokens - Multiple clients pointing to different Consul cluster This commit should fix #159 --- lib/diplomat/rest_client.rb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index 1a0b71f..db8721d 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -2,13 +2,22 @@ module Diplomat # Base class for interacting with the Consul RESTful API class RestClient @access_methods = [] + @configuration = nil # Initialize the fadaray connection # @param api_connection [Faraday::Connection,nil] supply mock API Connection - def initialize(api_connection = nil) + # @param configuration [Diplomat::Configuration] a dedicated config to use + def initialize(api_connection = nil, configuration: nil) + @configuration = configuration start_connection api_connection end + # Get client configuration or global one if not specified via initialize. + # @return [Diplomat::Configuration] used by this client + def configuration + @configuration || ::Diplomat.configuration + end + # Format url parameters into strings correctly # @param name [String] the name of the parameter # @param value [String] the value of the parameter @@ -80,8 +89,8 @@ def start_connection(api_connection = nil) end def build_connection(api_connection, raise_error = false) - api_connection || Faraday.new(Diplomat.configuration.url, Diplomat.configuration.options) do |faraday| - Diplomat.configuration.middleware.each do |middleware| + api_connection || Faraday.new(configuration.url, configuration.options) do |faraday| + configuration.middleware.each do |middleware| faraday.use middleware end @@ -178,7 +187,7 @@ def return_payload end def check_acl_token - use_named_parameter('token', Diplomat.configuration.acl_token) + use_named_parameter('token', configuration.acl_token) end def use_cas(options) From 243b9af6710df4c69c8e671b54775ecf1428bef5 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 3 Mar 2018 17:09:36 +0100 Subject: [PATCH 09/45] Specify StandardError on few rescue statements to make rubocop happy --- lib/diplomat/kv.rb | 2 +- lib/diplomat/rest_client.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index 5b4e170..2c7d7b0 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -254,7 +254,7 @@ def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength next unless resp['KV']['Value'] begin resp['KV']['Value'] = Base64.decode64(resp['KV']['Value']) - rescue # rubocop:disable RescueWithoutErrorClass + rescue StandardError nil end end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index db8721d..e947e6c 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -152,7 +152,7 @@ def decode_values @raw.each_with_object([]) do |acc, el| begin acc['Value'] = Base64.decode64(acc['Value']) - rescue # rubocop:disable RescueWithoutErrorClass + rescue StandardError nil end el << acc From d6b297568af2ff4b8ba57dc633ae7754f3c7f124 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Thu, 6 Sep 2018 19:44:18 +0200 Subject: [PATCH 10/45] Support for tokens when registering/unregistering entities on Agent --- lib/diplomat/service.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index 463607c..30e1f80 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -66,8 +66,10 @@ def get_all(options = nil) # @param definition [Hash] Hash containing definition of service # @return [Boolean] def register(definition, path = '/v1/agent/service/register') + url = [path] + url += check_acl_token json_definition = JSON.dump(definition) - register = @conn.put path, json_definition + register = @conn.put concat_url(url), json_definition register.status == 200 end @@ -75,7 +77,9 @@ def register(definition, path = '/v1/agent/service/register') # @param service_name [String] Service name to de-register # @return [Boolean] def deregister(service_name) - deregister = @conn.put "/v1/agent/service/deregister/#{service_name}" + url = ["/v1/agent/service/deregister/#{service_name}"] + url += check_acl_token + deregister = @conn.put concat_url(url) deregister.status == 200 end From 70a71b0a76a44ba610e80e8fa991782334d7152f Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Thu, 6 Sep 2018 21:58:24 +0200 Subject: [PATCH 11/45] Fixed rubocop warnings + Fixed rubocop version --- .rubocop.yml | 9 +++++++++ diplomat.gemspec | 2 +- lib/diplomat.rb | 4 ++-- lib/diplomat/kv.rb | 2 +- lib/diplomat/rest_client.rb | 2 +- lib/diplomat/service.rb | 1 - spec/agent_spec.rb | 23 ++++++++++++++--------- 7 files changed, 28 insertions(+), 15 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 7681dd0..da005a9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,3 +11,12 @@ Metrics/LineLength: # Allow classes longer than 100 lines of code ClassLength: Max: 250 + +Naming/UncommunicativeMethodParamName: + Enabled: false + +Lint/UnneededCopDisableDirective: + Enabled: false + +Layout/ClosingHeredocIndentation: + Enabled: false diff --git a/diplomat.gemspec b/diplomat.gemspec index 14fb050..fdf2e6d 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.add_development_dependency 'pry', '~> 0.9' spec.add_development_dependency 'rake', '~> 12.0' spec.add_development_dependency 'rspec', '~> 3.2' - spec.add_development_dependency 'rubocop', '~> 0.47', '>= 0.47.1' + spec.add_development_dependency 'rubocop', '~> 0.49' spec.add_runtime_dependency 'faraday', '~> 0.9' spec.add_runtime_dependency 'json' if RUBY_VERSION < '1.9.3' diff --git a/lib/diplomat.rb b/lib/diplomat.rb index e18f451..30ad53f 100644 --- a/lib/diplomat.rb +++ b/lib/diplomat.rb @@ -23,8 +23,8 @@ def require_libs(*libs) raise 'Diplomat only supports ruby >= 2.0.0' unless RUBY_VERSION.to_f >= 2.0 - self.root_path = File.expand_path '..', __FILE__ - self.lib_path = File.expand_path '../diplomat', __FILE__ + self.root_path = File.expand_path __dir__ + self.lib_path = File.expand_path 'diplomat', __dir__ require_libs 'configuration', 'rest_client', 'api_options', 'kv', 'datacenter', 'service', 'members', 'node', 'nodes', 'check', 'health', 'session', 'lock', diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index 64c070b..9db65d6 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -256,7 +256,7 @@ def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength next unless resp['KV']['Value'] begin resp['KV']['Value'] = Base64.decode64(resp['KV']['Value']) - rescue # rubocop:disable RescueWithoutErrorClass + rescue StandardError nil end end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index efbee4a..414983c 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -143,7 +143,7 @@ def decode_values @raw.each_with_object([]) do |acc, el| begin acc['Value'] = Base64.decode64(acc['Value']) - rescue # rubocop:disable RescueWithoutErrorClass + rescue StandardError nil end el << acc diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index 30e1f80..fc2704a 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -117,6 +117,5 @@ def maintenance(service_id, options = { enable: true }) end maintenance.status == 200 end - # rubocop:enable AbcSize end end diff --git a/spec/agent_spec.rb b/spec/agent_spec.rb index 09f233d..e9a8052 100644 --- a/spec/agent_spec.rb +++ b/spec/agent_spec.rb @@ -1,13 +1,14 @@ require 'spec_helper' require 'json' require 'base64' - +# rubocop:disable describe Diplomat::Agent do let(:faraday) { fake } context 'agent' do it 'self' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) + faraday.stub(:get) + .and_return(OpenStruct.new(body: <<-JSON)) { "Config": { "Bootstrap": true, @@ -73,7 +74,7 @@ "DelegateCur": 4 } } - JSON + JSON agent = Diplomat::Agent.new(faraday) @@ -81,7 +82,8 @@ end it 'checks' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) + faraday.stub(:get) + .and_return(OpenStruct.new(body: <<-JSON)) { "service:redis": { "Node": "foobar", @@ -94,7 +96,7 @@ "ServiceName": "redis" } } - JSON + JSON agent = Diplomat::Agent.new(faraday) @@ -102,7 +104,8 @@ end it 'services' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) + faraday.stub(:get) + .and_return(OpenStruct.new(body: <<-JSON)) { "redis": { "ID": "redis", @@ -112,7 +115,7 @@ "Port": 8000 } } - JSON + JSON agent = Diplomat::Agent.new(faraday) @@ -120,7 +123,8 @@ end it 'members' do - faraday.stub(:get).and_return(OpenStruct.new(body: <<-JSON)) + faraday.stub(:get) + .and_return(OpenStruct.new(body: <<-JSON)) [ { "Name": "foobar", @@ -141,7 +145,7 @@ "DelegateCur": 3 } ] - JSON + JSON agent = Diplomat::Agent.new(faraday) @@ -150,3 +154,4 @@ end end end +# rubocop:enable From 0b70f6290495982031c340fe217a7c73cbe0b2a2 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Thu, 6 Sep 2018 22:28:31 +0200 Subject: [PATCH 12/45] Depreciate Ruby < 2.3 in travis tests --- .rubocop.yml | 3 --- .travis.yml | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index da005a9..aea50c2 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,6 +17,3 @@ Naming/UncommunicativeMethodParamName: Lint/UnneededCopDisableDirective: Enabled: false - -Layout/ClosingHeredocIndentation: - Enabled: false diff --git a/.travis.yml b/.travis.yml index 06e8161..6cd47b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,10 @@ language: ruby before_install: - gem install bundler rvm: - - "2.0.0" - - "2.1.0" - - "2.2.1" - - "2.2.2" + - "2.2.10" + - "2.3.7" + - "2.4.4" + - "2.5.1" addons: code_climate: repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b From d753006671bdb11b144e426f86618d26fce3c294 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Thu, 6 Sep 2018 22:52:27 +0200 Subject: [PATCH 13/45] Added new unit test for service registration with token --- spec/service_spec.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/service_spec.rb b/spec/service_spec.rb index 52ee33d..916ad48 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -207,6 +207,7 @@ describe 'Register service' do let(:register_service_url) { '/v1/agent/service/register' } let(:deregister_service_url) { '/v1/agent/service/deregister' } + let(:token) { '80a6200c-6ec9-42e1-816a-e40007e732a6' } let(:service_definition) do { name: 'test_service_definition', @@ -229,6 +230,20 @@ expect(s).to eq(true) end + it 'can register a service with a token' do + json_request = JSON.dump(service_definition) + + expect(faraday).to receive(:put).with("#{register_service_url}?token=#{token}", json_request) do + OpenStruct.new(body: '', status: 200) + end + Diplomat.configure do |config| + config.acl_token = token + end + service = Diplomat::Service.new(faraday) + s = service.register(service_definition) + expect(s).to eq(true) + end + it 'can deregister a service' do url = "#{deregister_service_url}/#{service_definition[:name]}" expect(faraday).to receive(:put).with(url) do From 4f39bfb35967e6d71dba9bd8eda2e3a75d3583fd Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Thu, 6 Sep 2018 22:55:15 +0200 Subject: [PATCH 14/45] New version 2.0.3 with token support for agent registration --- CHANGELOG.md | 5 +++++ lib/diplomat/version.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55bdd59..68ba6a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # Next +Resume development + +# 2.0.3 + +- 2018-09-06 Allow to register/deregister entities using tokens - 2017-11-09 Josep M. Blanquer (@blanquer) Fix service deregister to use the proper verb (`PUT` instead of `GET`). Consul 1.x seems to have started enforcing [it](https://www.consul.io/docs/upgrade-specific.html#http-verbs-are-enforced-in-many-http-apis). diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index 2ba2df7..8ad9589 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.0.2'.freeze + VERSION = '2.0.3'.freeze end From a2b418029eeeeeead44dd353a40878478827cc2e Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Wed, 31 Oct 2018 21:55:02 +0100 Subject: [PATCH 15/45] Fixed minor rubocop style warnings after last PR #163 --- lib/diplomat/kv.rb | 6 ++++++ lib/diplomat/maintenance.rb | 1 + lib/diplomat/rest_client.rb | 3 +++ spec/datacenter_spec.rb | 6 +++--- spec/kv_spec.rb | 26 +++++++++++++------------- spec/node_spec.rb | 4 ++-- spec/service_spec.rb | 18 +++++++++--------- 7 files changed, 37 insertions(+), 27 deletions(-) diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index 2c7d7b0..ed8b654 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -78,6 +78,7 @@ def get(key, options = nil, not_found = :reject, found = :return) return @raw.first['Session'] if @options && @options[:session] return decode_values if @options && @options[:decode_values] return convert_to_hash(return_value(return_nil_values, transformation, true)) if @options && @options[:convert_to_hash] + return return_value(return_nil_values, transformation) when :wait index = raw.headers['x-consul-index'] @@ -202,6 +203,7 @@ def separator(options) def transaction_consistency(options) return [] unless options + if options[:consistency] && options[:consistency] == 'stale' ['stale'] elsif options[:consistency] && options[:consistency] == 'consistent' @@ -213,6 +215,7 @@ def transaction_consistency(options) def transaction_verification(transaction) raise Diplomat::InvalidTransaction unless transaction.is_a?(Array) + transaction.each do |req| raise Diplomat::InvalidTransaction unless transaction_type_verification(req) raise Diplomat::InvalidTransaction unless transaction_verb_verification(req['KV']) @@ -228,6 +231,7 @@ def transaction_type_verification(txn) def transaction_verb_verification(txn) transaction_verb = txn['Verb'] raise Diplomat::InvalidTransaction unless valid_transaction_verbs.include? transaction_verb + test_requirements = valid_transaction_verbs[transaction_verb] - txn.keys test_requirements.empty? end @@ -235,6 +239,7 @@ def transaction_verb_verification(txn) def encode_transaction(transaction) transaction.each do |txn| next unless valid_value_transactions.include? txn['KV']['Verb'] + value = txn['KV']['Value'] txn['KV']['Value'] = Base64.encode64(value).chomp end @@ -252,6 +257,7 @@ def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength transaction.tap do |txn| txn['Results'].each do |resp| next unless resp['KV']['Value'] + begin resp['KV']['Value'] = Base64.decode64(resp['KV']['Value']) rescue StandardError diff --git a/lib/diplomat/maintenance.rb b/lib/diplomat/maintenance.rb index 0c32202..eebfe04 100644 --- a/lib/diplomat/maintenance.rb +++ b/lib/diplomat/maintenance.rb @@ -37,6 +37,7 @@ def enable(enable = true, reason = nil, options = nil) return_status = raw.status == 200 raise Diplomat::UnknownStatus, "status #{raw.status}: #{raw.body}" unless return_status + return_status end # rubocop:enable AbcSize diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index e947e6c..8c688f5 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -143,12 +143,14 @@ def deep_merge(first, second) # Parse the body, apply it to the raw attribute def parse_body return JSON.parse(@raw.body) if @raw.status == 200 + raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}" end # Return @raw with Value fields decoded def decode_values return @raw if @raw.first.is_a? String + @raw.each_with_object([]) do |acc, el| begin acc['Value'] = Base64.decode64(acc['Value']) @@ -165,6 +167,7 @@ def decode_values def return_value(nil_values = false, transformation = nil, return_hash = false) @value = decode_values return @value if @value.first.is_a? String + if @value.count == 1 && !return_hash @value = @value.first['Value'] @value = transformation.call(@value) if transformation && !@value.nil? diff --git a/spec/datacenter_spec.rb b/spec/datacenter_spec.rb index 65dca7c..83f8308 100644 --- a/spec/datacenter_spec.rb +++ b/spec/datacenter_spec.rb @@ -10,9 +10,9 @@ let(:body) { %w[dc1 dc2] } let(:headers) do { - 'x-consul-index' => '8', - 'x-consul-knownleader' => 'true', - 'x-consul-lastcontact' => '0' + 'x-consul-index' => '8', + 'x-consul-knownleader' => 'true', + 'x-consul-lastcontact' => '0' } end diff --git a/spec/kv_spec.rb b/spec/kv_spec.rb index c5bcbb0..81a13f9 100644 --- a/spec/kv_spec.rb +++ b/spec/kv_spec.rb @@ -27,17 +27,17 @@ JSON.generate( [ { - 'Key' => key + 'dewfr', + 'Key' => key + 'dewfr', 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key + 'iamnil', + 'Key' => key + 'iamnil', 'Value' => nil, 'Flags' => 0 } @@ -74,17 +74,17 @@ JSON.generate( [ { - 'Key' => key + 'dewfr', + 'Key' => key + 'dewfr', 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key + 'iamnil', + 'Key' => key + 'iamnil', 'Value' => nil, 'Flags' => 0 } @@ -124,17 +124,17 @@ JSON.generate( [ { - 'Key' => key + '/dewfr', + 'Key' => key + '/dewfr', 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64(key_params), 'Flags' => 0 }, { - 'Key' => key + '/iamnil', + 'Key' => key + '/iamnil', 'Value' => nil, 'Flags' => 0 } @@ -165,7 +165,7 @@ JSON.generate( [ { - 'Key' => key + '/dewfr', + 'Key' => key + '/dewfr', 'Value' => Base64.encode64(key_params), 'Flags' => 0 } @@ -267,7 +267,7 @@ JSON.generate( [ { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64(key_params), 'Flags' => 0 } @@ -294,7 +294,7 @@ JSON.generate( [ { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64('Faraday::ResourceNotFound: the server responded with status 404'), 'Flags' => 0 } @@ -323,7 +323,7 @@ JSON.generate( [ { - 'Key' => key, + 'Key' => key, 'Value' => Base64.encode64(key_params), 'Flags' => 0 } diff --git a/spec/node_spec.rb b/spec/node_spec.rb index dbd4470..748d9cc 100644 --- a/spec/node_spec.rb +++ b/spec/node_spec.rb @@ -86,8 +86,8 @@ let(:body_all_with_dc) do [ { - 'Address' => '10.1.10.14', - 'Node' => 'foo' + 'Address' => '10.1.10.14', + 'Node' => 'foo' } ] end diff --git a/spec/service_spec.rb b/spec/service_spec.rb index 916ad48..d8d74f0 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -15,17 +15,17 @@ let(:body) do [ { - 'Node' => 'foo', - 'Address' => '10.1.10.12', - 'ServiceID' => key, + 'Node' => 'foo', + 'Address' => '10.1.10.12', + 'ServiceID' => key, 'ServiceName' => key, 'ServiceTags' => ['sometag'], 'ServicePort' => '70457' }, { - 'Node' => 'bar', - 'Address' => '10.1.10.13', - 'ServiceID' => key, + 'Node' => 'bar', + 'Address' => '10.1.10.13', + 'ServiceID' => key, 'ServiceName' => key, 'ServiceTags' => %w[sometag anothertag], 'ServicePort' => '70457' @@ -40,9 +40,9 @@ end let(:headers) do { - 'x-consul-index' => '8', - 'x-consul-knownleader' => 'true', - 'x-consul-lastcontact' => '0' + 'x-consul-index' => '8', + 'x-consul-knownleader' => 'true', + 'x-consul-lastcontact' => '0' } end From 71c921b3b13a1387e65cd36a8a042831667f4f43 Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Sat, 15 Dec 2018 11:14:57 +0100 Subject: [PATCH 16/45] README: Drop defunct badge, use SVG --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ede8962..125f0b6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Diplomat -[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](http://badge.fury.io/rb/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.png)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Dependency Status](https://gemnasium.com/WeAreFarmGeek/diplomat.svg)](https://gemnasium.com/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat) +[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](http://badge.fury.io/rb/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.svg)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat) ### A HTTP Ruby API for [Consul](http://www.consul.io/) ![Diplomacy Boad Game](http://i.imgur.com/Nkuy4b7.jpg) From 985f4b8d8d5c6ffa989d2c8b88b0aaac3f8f5ad3 Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Sat, 15 Dec 2018 11:38:19 +0100 Subject: [PATCH 17/45] CI: Update to current set of Rubies --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6cd47b1..fd12abf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,10 @@ before_install: - gem install bundler rvm: - "2.2.10" - - "2.3.7" - - "2.4.4" - - "2.5.1" + - "2.3.8" + - "2.4.5" + - "2.5.3" + - "2.6.0-rc1" addons: code_climate: repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b From 19d9813b3af83534f8fa11a858c433cd091ebaa8 Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Wed, 19 Dec 2018 21:25:08 +0100 Subject: [PATCH 18/45] Travis: Exempt 2.6.0-rc2 from matrix --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd12abf..f833833 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,10 @@ rvm: - "2.3.8" - "2.4.5" - "2.5.3" - - "2.6.0-rc1" + - "2.6.0-rc2" +matrix: + allow_failures: + - rvm: 2.6.0-rc2 addons: code_climate: repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b From 55b7db7b94ee95917cb4fc0abef6618a68dbec62 Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Wed, 19 Dec 2018 21:28:45 +0100 Subject: [PATCH 19/45] CI: Drop matrix allow_failures - 2.6.0-rc2 passes --- .travis.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index f833833..26385aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,11 @@ language: ruby before_install: - gem install bundler rvm: - - "2.2.10" - - "2.3.8" - - "2.4.5" - - "2.5.3" - - "2.6.0-rc2" -matrix: - allow_failures: - - rvm: 2.6.0-rc2 + - 2.2.10 + - 2.3.8 + - 2.4.5 + - 2.5.3 + - 2.6.0-rc2 addons: code_climate: repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b From e327f8164fb77a7bb86f63810fc2c8e05ece79d9 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 13:01:33 +0100 Subject: [PATCH 20/45] Added automatic publication of GEM on a branch --- .travis.yml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 26385aa..8217774 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,18 @@ language: ruby -before_install: - - gem install bundler +before_install: +- gem install bundler rvm: - - 2.2.10 - - 2.3.8 - - 2.4.5 - - 2.5.3 - - 2.6.0-rc2 +- 2.2.10 +- 2.3.8 +- 2.4.5 +- 2.5.3 +- 2.6.0-rc2 addons: - code_climate: - repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b + code_climate: + repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b +deploy: + provider: rubygems + api_key: + secure: RbB9Va0vmEY3hyCDuvDxj6G/cmgD8ZQ3Wwg2Xx+oi64AWOckmTa4e4nVR6231kkgF63fG2swpkRhyHU+pfRSy+m/Ng8qAK4IIDgce6FTMPbzY45TlzPDq9OKsLyChYtkCnRTjXI16cS9+t1OBAXtwEDgQnXG7VDU4cRi3NMyFCk= + on: + tags: true From 13dacc02914fbb9bc65fd41b888ff21734c6b029 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 13:25:34 +0100 Subject: [PATCH 21/45] Use bundle v2.0+ --- diplomat.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diplomat.gemspec b/diplomat.gemspec index fdf2e6d..5203cbe 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.files = `git ls-files lib README.md LICENSE features`.split("\n") - spec.add_development_dependency 'bundler', '~> 1.3' + spec.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.1' spec.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.0' spec.add_development_dependency 'cucumber', '~> 2.0' spec.add_development_dependency 'fakes-rspec', '~> 2.1' From acd356e02f8ab565694da01d515ff68579e9e502 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 13:43:44 +0100 Subject: [PATCH 22/45] Do not build with ruby 2.2.x in travis build --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8217774..ea58b69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: ruby before_install: - gem install bundler rvm: -- 2.2.10 - 2.3.8 - 2.4.5 - 2.5.3 From e67773f1bd8d93a920aa10abf46df1966cc8f398 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 13:52:23 +0100 Subject: [PATCH 23/45] Bump version to 2.0.4 --- lib/diplomat/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index 8ad9589..2200de0 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.0.3'.freeze + VERSION = '2.0.4'.freeze end From 688a6c9b3ff3863ef4a58ff5af8868e068ddb395 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 14:45:09 +0100 Subject: [PATCH 24/45] Use correct verbs for Check methods. Some of the verbs were get instead of put. Will fix https://github.com/WeAreFarmGeek/diplomat/issues/173 --- lib/diplomat/check.rb | 8 ++++---- spec/check_spec.rb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index b19d40e..33f68c8 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -50,7 +50,7 @@ def register_ttl(check_id, name, notes, ttl) # @param check_id [String] the unique id of the check # @return [Integer] Status code def deregister(check_id) - ret = @conn.get "/v1/agent/check/deregister/#{check_id}" + ret = @conn.put "/v1/agent/check/deregister/#{check_id}" ret.status == 200 end @@ -58,7 +58,7 @@ def deregister(check_id) # @param check_id [String] the unique id of the check # @return [Integer] Status code def pass(check_id) - ret = @conn.get "/v1/agent/check/pass/#{check_id}" + ret = @conn.put "/v1/agent/check/pass/#{check_id}" ret.status == 200 end @@ -66,7 +66,7 @@ def pass(check_id) # @param check_id [String] the unique id of the check # @return [Integer] Status code def warn(check_id) - ret = @conn.get "/v1/agent/check/warn/#{check_id}" + ret = @conn.put "/v1/agent/check/warn/#{check_id}" ret.status == 200 end @@ -74,7 +74,7 @@ def warn(check_id) # @param check_id [String] the unique id of the check # @return [Integer] Status code def fail(check_id) - ret = @conn.get "/v1/agent/check/fail/#{check_id}" + ret = @conn.put "/v1/agent/check/fail/#{check_id}" ret.status == 200 end end diff --git a/spec/check_spec.rb b/spec/check_spec.rb index e348c00..b74ce77 100644 --- a/spec/check_spec.rb +++ b/spec/check_spec.rb @@ -39,25 +39,25 @@ end it 'deregister' do - faraday.stub(:get).and_return(OpenStruct.new(body: '', status: 200)) + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) expect(check.deregister('foobar-1')).to eq(true) end it 'pass' do - faraday.stub(:get).and_return(OpenStruct.new(body: '', status: 200)) + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) expect(check.pass('foobar-1')).to eq(true) end it 'warn' do - faraday.stub(:get).and_return(OpenStruct.new(body: '', status: 200)) + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) expect(check.warn('foobar-1')).to eq(true) end it 'fail' do - faraday.stub(:get).and_return(OpenStruct.new(body: '', status: 200)) + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) expect(check.fail('foobar-1')).to eq(true) end From e388ef0e9d52b67b5d5a6a6905eb6f4beb3b989e Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 14:54:31 +0100 Subject: [PATCH 25/45] Updated changelog --- CHANGELOG.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68ba6a7..6768b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ # Changelog -# Next +## Next -Resume development +- Fix incorrect verbs for checks Fix https://github.com/WeAreFarmGeek/diplomat/issues/173 -# 2.0.3 + +## 2.0.4 + +- automatic GEM publication from Travis when a tag is pushed +- Depreciate old Ruby version 2.2.x +- Bump bundler to version 2.0.x + +## 2.0.3 - 2018-09-06 Allow to register/deregister entities using tokens - 2017-11-09 Josep M. Blanquer (@blanquer) Fix service deregister to use the proper verb (`PUT` instead of `GET`). Consul 1.x seems to From 1617f676e31cbc5556d6bb5da8520234bd719c48 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 15:16:33 +0100 Subject: [PATCH 26/45] Added new link to https://rubygems.org/gems/diplomat --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 896fd8c..5971b1a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Diplomat -[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](http://badge.fury.io/rb/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.svg)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat) +[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](https://rubygems.org/gems/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.svg)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat) ### A HTTP Ruby API for [Consul](http://www.consul.io/) ![Diplomacy Boad Game](http://i.imgur.com/Nkuy4b7.jpg) From f45b152f6b44674b6f17b17c78107a88758de82d Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 20:58:09 +0100 Subject: [PATCH 27/45] Use json_pure if ruby < 1.9.3 to avoid using a compiler It will solve https://github.com/WeAreFarmGeek/diplomat/issues/177 --- diplomat.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diplomat.gemspec b/diplomat.gemspec index 5203cbe..3adbdbc 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -21,5 +21,5 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.add_development_dependency 'rubocop', '~> 0.49' spec.add_runtime_dependency 'faraday', '~> 0.9' - spec.add_runtime_dependency 'json' if RUBY_VERSION < '1.9.3' + spec.add_runtime_dependency 'json_pure' if RUBY_VERSION < '1.9.3' end From 1fb4560ed4b64acadd205da66bd6dc3a2acdb919 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 25 Feb 2019 21:01:11 +0100 Subject: [PATCH 28/45] Updated CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6768b45..a0b068b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Next - Fix incorrect verbs for checks Fix https://github.com/WeAreFarmGeek/diplomat/issues/173 - +- Use json_pure to avoid the need for installing a compiler. Fix https://github.com/WeAreFarmGeek/diplomat/issues/177 ## 2.0.4 From 9e90b9317b0572c881342599024b18aec67e5c29 Mon Sep 17 00:00:00 2001 From: Samoilenko Yuri Date: Tue, 26 Feb 2019 10:26:34 +0300 Subject: [PATCH 29/45] Support for Output in TTL checks --- lib/diplomat/check.rb | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index 33f68c8..c08b67c 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -54,28 +54,41 @@ def deregister(check_id) ret.status == 200 end - # Pass a check + # Update a TTL check # @param check_id [String] the unique id of the check + # @param status [String] status of the check. Valid values are "passing", "warning", and "critical" + # @param output [String] human-readable message will be passed through to the check's Output field # @return [Integer] Status code - def pass(check_id) - ret = @conn.put "/v1/agent/check/pass/#{check_id}" + def update_ttl(check_id, status, output = nil) + ret = @conn.put do |req| + req.url "/v1/agent/check/update/#{check_id}" + req.body = JSON.generate('Status' => status, 'Output' => output) + end ret.status == 200 end - # Warn a check + # Pass a check # @param check_id [String] the unique id of the check + # @param output [String] human-readable message will be passed through to the check's Output field # @return [Integer] Status code - def warn(check_id) - ret = @conn.put "/v1/agent/check/warn/#{check_id}" - ret.status == 200 + def pass(check_id, output = nil) + update_ttl(check_id, 'passing', output) end # Warn a check # @param check_id [String] the unique id of the check + # @param output [String] human-readable message will be passed through to the check's Output field # @return [Integer] Status code - def fail(check_id) - ret = @conn.put "/v1/agent/check/fail/#{check_id}" - ret.status == 200 + def warn(check_id, output = nil) + update_ttl(check_id, 'warning', output) + end + + # Fail a check + # @param check_id [String] the unique id of the check + # @param output [String] human-readable message will be passed through to the check's Output field + # @return [Integer] Status code + def fail(check_id, output = nil) + update_ttl(check_id, 'critical', output) end end end From 2412de1a7383b145c4f380743d536fee187218f3 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 26 Feb 2019 15:08:46 +0100 Subject: [PATCH 30/45] Diplomat release 2.0.5 Bugfix release - Fix incorrect verbs for checks Fix https://github.com/WeAreFarmGeek/diplomat/issues/173 - Use json_pure to avoid the need for installing a compiler. Fix https://github.com/WeAreFarmGeek/diplomat/issues/177 - Allow updating Output with TTL checks https://github.com/WeAreFarmGeek/diplomat/pull/178 --- CHANGELOG.md | 3 +++ lib/diplomat/version.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b068b..9e34242 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,11 @@ ## Next +## 2.0.5 + - Fix incorrect verbs for checks Fix https://github.com/WeAreFarmGeek/diplomat/issues/173 - Use json_pure to avoid the need for installing a compiler. Fix https://github.com/WeAreFarmGeek/diplomat/issues/177 +- Allow updating Output with TTL checks https://github.com/WeAreFarmGeek/diplomat/pull/178 ## 2.0.4 diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index 2200de0..c2ccb6f 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.0.4'.freeze + VERSION = '2.0.5'.freeze end From 95bee472f994f42078503a4ae9f9fcc8a0f23c53 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 26 Feb 2019 15:14:24 +0100 Subject: [PATCH 31/45] Updated travis versions of Ruby to use stable 2.6.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ea58b69..6d83226 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ rvm: - 2.3.8 - 2.4.5 - 2.5.3 -- 2.6.0-rc2 +- 2.6.1 addons: code_climate: repo_token: 0c910d8f8af55cc2d2f38170d5362be4e16be8ce232df9c565057985af264b7b From 322966916388bb29856a4ff85bfadbb1890de0a4 Mon Sep 17 00:00:00 2001 From: Robert Brooks Date: Mon, 11 Feb 2019 14:08:15 -0800 Subject: [PATCH 32/45] simpler convert_to_hash function --- diplomat.gemspec | 1 + lib/diplomat/rest_client.rb | 38 +++++-------------------------------- spec/kv_spec.rb | 7 +++++++ 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/diplomat.gemspec b/diplomat.gemspec index 3adbdbc..8db2d66 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.add_development_dependency 'rspec', '~> 3.2' spec.add_development_dependency 'rubocop', '~> 0.49' + spec.add_runtime_dependency 'deep_merge', '~> 1.0', '>= 1.0.1' spec.add_runtime_dependency 'faraday', '~> 0.9' spec.add_runtime_dependency 'json_pure' if RUBY_VERSION < '1.9.3' end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index 8c688f5..2c2e15d 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -1,3 +1,5 @@ +require 'deep_merge' + module Diplomat # Base class for interacting with the Consul RESTful API class RestClient @@ -104,42 +106,12 @@ def build_connection(api_connection, raise_error = false) # Converts k/v data into ruby hash # rubocop:disable MethodLength, AbcSize def convert_to_hash(data) - collection = [] - master = {} - data.each do |item| - split_up = item[:key].split('/') - sub_hash = {} - temp = nil - real_size = split_up.size - 1 - (0..real_size).each do |i| - if i.zero? - temp = {} - sub_hash[split_up[i]] = temp - next - end - if i == real_size - temp[split_up[i]] = item[:value] - else - new_h = {} - temp[split_up[i]] = new_h - temp = new_h - end - end - collection << sub_hash - end - - collection.each do |h| - master = deep_merge(master, h) - end - master + data.map do |item| + item[:key].split('/').reverse.reduce(item[:value]) { |h, v| { v => h } } + end.reduce(:deep_merge) end # rubocop:enable MethodLength, AbcSize - def deep_merge(first, second) - merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 } - first.merge(second, &merger) - end - # Parse the body, apply it to the raw attribute def parse_body return JSON.parse(@raw.body) if @raw.status == 200 diff --git a/spec/kv_spec.rb b/spec/kv_spec.rb index 81a13f9..24dfcbb 100644 --- a/spec/kv_spec.rb +++ b/spec/kv_spec.rb @@ -137,6 +137,11 @@ 'Key' => key + '/iamnil', 'Value' => nil, 'Flags' => 0 + }, + { + 'Key' => 'foo', + 'Value' => Base64.encode64('bar'), + 'Flags' => 0 } ] ) @@ -148,6 +153,7 @@ answer = {} answer[key] = {} answer[key]['dewfr'] = 'toast' + answer['foo'] = 'bar' expect(kv.get(key, recurse: true, convert_to_hash: true)).to eql(answer) end it 'GET with nil values' do @@ -157,6 +163,7 @@ answer[key] = {} answer[key]['dewfr'] = 'toast' answer[key]['iamnil'] = nil + answer['foo'] = 'bar' expect(kv.get(key, recurse: true, convert_to_hash: true, nil_values: true)).to eql(answer) end From 0f8078181fdc7a8cc07b29b3e39554e2b676796f Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Wed, 27 Feb 2019 14:34:09 +0100 Subject: [PATCH 33/45] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e34242..2e18cd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Next +- use dedup for safer/simpler conversion of results to hash https://github.com/WeAreFarmGeek/diplomat/pull/176 + ## 2.0.5 - Fix incorrect verbs for checks Fix https://github.com/WeAreFarmGeek/diplomat/issues/173 From 35c369f845ccbaf7aec160b91f3c169c79c8f44e Mon Sep 17 00:00:00 2001 From: Nicolas BENOIT Date: Wed, 27 Feb 2019 18:56:25 +0100 Subject: [PATCH 34/45] Enable configuration override on each consul api call Using the configs hash target host or token can be different at each call --- .rubocop.yml | 12 ++ README.md | 10 +- diplomat.gemspec | 1 + lib/diplomat/acl.rb | 55 +++----- lib/diplomat/agent.rb | 52 ++----- lib/diplomat/check.rb | 77 +++++----- lib/diplomat/datacenter.rb | 13 +- lib/diplomat/error.rb | 1 + lib/diplomat/event.rb | 65 ++++----- lib/diplomat/health.rb | 66 +++------ lib/diplomat/kv.rb | 91 ++++++------ lib/diplomat/lock.rb | 38 ++--- lib/diplomat/maintenance.rb | 18 +-- lib/diplomat/members.rb | 5 +- lib/diplomat/node.rb | 35 ++--- lib/diplomat/nodes.rb | 15 +- lib/diplomat/query.rb | 87 ++++-------- lib/diplomat/rest_client.rb | 86 ++++++++++-- lib/diplomat/service.rb | 96 +++++-------- lib/diplomat/session.rb | 74 ++++------ lib/diplomat/status.rb | 12 +- lib/diplomat/version.rb | 2 +- spec/acl_spec.rb | 36 +++-- spec/check_spec.rb | 2 +- spec/configure_spec.rb | 4 +- spec/datacenter_spec.rb | 17 ++- spec/event_spec.rb | 48 ++++--- spec/kv_spec.rb | 22 ++- spec/lock_spec.rb | 31 +++-- spec/maintenance_spec.rb | 33 ++--- spec/node_spec.rb | 48 +++---- spec/nodes_spec.rb | 6 +- spec/service_spec.rb | 270 ++++++++++++++++-------------------- spec/spec_helper.rb | 1 + 34 files changed, 654 insertions(+), 775 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index aea50c2..2d19666 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,12 +2,24 @@ AllCops: DisplayCopNames: true +Metrics/AbcSize: + Max: 60 + +Metrics/CyclomaticComplexity: + Max: 15 + Metrics/LineLength: # This will disable the rule completely, regardless what other options you put Enabled: true # Change the default 80 chars limit value Max: 120 +Metrics/MethodLength: + # This cop checks if the length of a method exceeds some maximum value + Enabled: true + # Change the default 10 lines limit value + Max: 50 + # Allow classes longer than 100 lines of code ClassLength: Max: 250 diff --git a/README.md b/README.md index 5971b1a..ac31a9d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Gem Version](https://badge.fury.io/rb/diplomat.svg)](https://rubygems.org/gems/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.svg)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat) ### A HTTP Ruby API for [Consul](http://www.consul.io/) -![Diplomacy Boad Game](http://i.imgur.com/Nkuy4b7.jpg) +![Diplomacy Board Game](http://i.imgur.com/Nkuy4b7.jpg) ## FAQ @@ -317,6 +317,14 @@ end This is traditionally kept inside the `config/initializers` directory if you're using rails. The middleware allows you to customise what happens when faraday sends and receives data. This can be useful if you want to instrument your use of diplomat, for example. You can read more about Faraday's custom middleware [here](http://stackoverflow.com/a/20973008). +Alternatively, configuration settings can be overriden at each method call allowing for instance to address different consul agents, with some other token. + +```ruby +Diplomat::Service.get('foo', { http_addr: 'http://consu01:8500' }) +Diplomat::Service.get('foo', { http_addr: 'http://consu02:8500' }) +Diplomat::Kv.put('key/path', 'value', { http_addr: 'http://localhost:8500', dc: 'dc1', token: '111-222-333-444-555' }) +``` + ### Todo - [ ] Updating Docs with latest changes diff --git a/diplomat.gemspec b/diplomat.gemspec index 8db2d66..ffa9ec7 100644 --- a/diplomat.gemspec +++ b/diplomat.gemspec @@ -19,6 +19,7 @@ Gem::Specification.new 'diplomat', Diplomat::VERSION do |spec| spec.add_development_dependency 'rake', '~> 12.0' spec.add_development_dependency 'rspec', '~> 3.2' spec.add_development_dependency 'rubocop', '~> 0.49' + spec.add_development_dependency 'webmock' spec.add_runtime_dependency 'deep_merge', '~> 1.0', '>= 1.0.1' spec.add_runtime_dependency 'faraday', '~> 0.9' diff --git a/lib/diplomat/acl.rb b/lib/diplomat/acl.rb index 3c69871..ddd25fc 100644 --- a/lib/diplomat/acl.rb +++ b/lib/diplomat/acl.rb @@ -6,16 +6,17 @@ class Acl < Diplomat::RestClient # Get Acl info by ID # @param id [String] ID of the Acl to get + # @param options [Hash] options parameter hash # @return [Hash] - # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize - def info(id, options = nil, not_found = :reject, found = :return) + # rubocop:disable PerceivedComplexity + def info(id, options = {}, not_found = :reject, found = :return) @id = id @options = options - url = ["/v1/acl/info/#{id}"] - url << check_acl_token - url << use_consistency(options) + custom_params = [] + custom_params << use_consistency(options) + + raw = send_get_request(@conn_no_err, ["/v1/acl/info/#{id}"], options, custom_params) - raw = @conn_no_err.get concat_url url if raw.status == 200 && raw.body.chomp != 'null' case found when :reject @@ -35,55 +36,45 @@ def info(id, options = nil, not_found = :reject, found = :return) raise Diplomat::UnknownStatus, "status #{raw.status}: #{raw.body}" end end - # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity # List all Acls + # @param options [Hash] options parameter hash # @return [List] list of [Hash] of Acls - def list - url = ['/v1/acl/list'] - url += check_acl_token - @raw = @conn_no_err.get concat_url url + def list(options = {}) + @raw = send_get_request(@conn_no_err, ['/v1/acl/list'], options) parse_body end # Update an Acl definition, create if not present # @param value [Hash] Acl definition, ID field is mandatory + # @param options [Hash] options parameter hash # @return [Hash] The result Acl - def update(value) - raise Diplomat::IdParameterRequired unless value['ID'] + def update(value, options = {}) + raise Diplomat::IdParameterRequired unless value['ID'] || value[:ID] - @raw = @conn.put do |req| - url = ['/v1/acl/update'] - url += check_acl_token - url += use_cas(@options) - req.url concat_url url - req.body = value.to_json - end + custom_params = use_cas(@options) + @raw = send_put_request(@conn, ['/v1/acl/update'], options, value, custom_params) parse_body end # Create an Acl definition # @param value [Hash] Acl definition, ID field is mandatory + # @param options [Hash] options parameter hash # @return [Hash] The result Acl - def create(value) - @raw = @conn.put do |req| - url = ['/v1/acl/create'] - url += check_acl_token - url += use_cas(@options) - req.url concat_url url - req.body = value.to_json - end + def create(value, options = {}) + custom_params = use_cas(@options) + @raw = send_put_request(@conn, ['/v1/acl/create'], options, value, custom_params) parse_body end # Destroy an ACl token by its id # @param ID [String] the Acl ID + # @param options [Hash] options parameter hash # @return [Bool] - def destroy(id) + def destroy(id, options = {}) @id = id - url = ["/v1/acl/destroy/#{@id}"] - url << check_acl_token - @raw = @conn.put concat_url url + @raw = send_put_request(@conn, ["/v1/acl/destroy/#{@id}"], options, nil) @raw.body.chomp == 'true' end end diff --git a/lib/diplomat/agent.rb b/lib/diplomat/agent.rb index 27a56e3..d9ecceb 100644 --- a/lib/diplomat/agent.rb +++ b/lib/diplomat/agent.rb @@ -8,62 +8,34 @@ class Agent < Diplomat::RestClient @access_methods = %i[self checks services members] # Get agent configuration + # @param options [Hash] options parameter hash # @return [OpenStruct] all data associated with the node - def self - url = ['/v1/agent/self'] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end + def self(options = {}) + ret = send_get_request(@conn, ['/v1/agent/self'], options) JSON.parse(ret.body).tap { |node| OpenStruct.new node } end # Get local agent checks + # @param options [Hash] options parameter hash # @return [OpenStruct] all agent checks - def checks - url = ['/v1/agent/checks'] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end + def checks(options = {}) + ret = send_get_request(@conn, ['/v1/agent/checks'], options) JSON.parse(ret.body).tap { |node| OpenStruct.new node } end # Get local agent services + # @param options [Hash] options parameter hash # @return [OpenStruct] all agent services - def services - url = ['/v1/agent/services'] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end + def services(options = {}) + ret = send_get_request(@conn, ['/v1/agent/services'], options) JSON.parse(ret.body).tap { |node| OpenStruct.new node } end # Get cluster members (as seen by the agent) + # @param options [Hash] options parameter hash # @return [OpenStruct] all members - def members - url = ['/v1/agent/members'] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end + def members(options = {}) + ret = send_get_request(@conn, ['/v1/agent/members'], options) JSON.parse(ret.body).map { |node| OpenStruct.new node } end end diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index c08b67c..26cf072 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -6,8 +6,8 @@ class Check < Diplomat::RestClient # Get registered checks # @return [OpenStruct] all data associated with the service - def checks - ret = @conn.get '/v1/agent/checks' + def checks(options = {}) + ret = send_get_request(@conn, ['/v1/agent/checks'], options) JSON.parse(ret.body) end @@ -15,42 +15,52 @@ def checks # @param check_id [String] the unique id of the check # @param name [String] the name # @param notes [String] notes about the check - # @param script [String] command to be run for check + # @param args [String[]] command to be run for check # @param interval [String] frequency (with units) of the check execution - # @param ttl [String] time (with units) to mark a check down + # @param options [Hash] options parameter hash # @return [Integer] Status code - # - def register_script(check_id, name, notes, script, interval) - ret = @conn.put do |req| - req.url '/v1/agent/check/register' - req.body = JSON.generate( - 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'Script' => script, 'Interval' => interval - ) + # rubocop:disable ParameterLists + def register_script(check_id, name, notes, args, interval, options = {}) + unless args.is_a?(Array) + raise(Diplomat::DeprecatedArgument, 'Script usage is deprecated, replace by an array of args') end + + definition = { + 'ID' => check_id, + 'Name' => name, + 'Notes' => notes, + 'Args' => args, + 'Interval' => interval + } + ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition) ret.status == 200 end + # rubocop:enable ParameterLists # Register a TTL check # @param check_id [String] the unique id of the check # @param name [String] the name # @param notes [String] notes about the check # @param ttl [String] time (with units) to mark a check down + # @param options [Hash] options parameter hash # @return [Boolean] Success - def register_ttl(check_id, name, notes, ttl) - ret = @conn.put do |req| - req.url '/v1/agent/check/register' - req.body = JSON.generate( - 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'TTL' => ttl - ) - end + def register_ttl(check_id, name, notes, ttl, options = {}) + definition = { + 'ID' => check_id, + 'Name' => name, + 'Notes' => notes, + 'TTL' => ttl + } + ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition) ret.status == 200 end # Deregister a check # @param check_id [String] the unique id of the check + # @param options [Hash] options parameter hash # @return [Integer] Status code - def deregister(check_id) - ret = @conn.put "/v1/agent/check/deregister/#{check_id}" + def deregister(check_id, options = {}) + ret = send_put_request(@conn, ["/v1/agent/check/deregister/#{check_id}"], options, nil) ret.status == 200 end @@ -58,37 +68,42 @@ def deregister(check_id) # @param check_id [String] the unique id of the check # @param status [String] status of the check. Valid values are "passing", "warning", and "critical" # @param output [String] human-readable message will be passed through to the check's Output field + # @param options [Hash] options parameter hash # @return [Integer] Status code - def update_ttl(check_id, status, output = nil) - ret = @conn.put do |req| - req.url "/v1/agent/check/update/#{check_id}" - req.body = JSON.generate('Status' => status, 'Output' => output) - end + def update_ttl(check_id, status, output = nil, options = {}) + definition = { + 'Status' => status, + 'Output' => output + } + ret = send_put_request(@conn, ["/v1/agent/check/update/#{check_id}"], options, definition) ret.status == 200 end # Pass a check # @param check_id [String] the unique id of the check # @param output [String] human-readable message will be passed through to the check's Output field + # @param options [Hash] options parameter hash # @return [Integer] Status code - def pass(check_id, output = nil) - update_ttl(check_id, 'passing', output) + def pass(check_id, output = nil, options = {}) + update_ttl(check_id, 'passing', output, options) end # Warn a check # @param check_id [String] the unique id of the check # @param output [String] human-readable message will be passed through to the check's Output field + # @param options [Hash] options parameter hash # @return [Integer] Status code - def warn(check_id, output = nil) - update_ttl(check_id, 'warning', output) + def warn(check_id, output = nil, options = {}) + update_ttl(check_id, 'warning', output, options) end # Fail a check # @param check_id [String] the unique id of the check # @param output [String] human-readable message will be passed through to the check's Output field + # @param options [Hash] options parameter hash # @return [Integer] Status code - def fail(check_id, output = nil) - update_ttl(check_id, 'critical', output) + def fail(check_id, output = nil, options = {}) + update_ttl(check_id, 'critical', output, options) end end end diff --git a/lib/diplomat/datacenter.rb b/lib/diplomat/datacenter.rb index a4808c6..2c5aeca 100644 --- a/lib/diplomat/datacenter.rb +++ b/lib/diplomat/datacenter.rb @@ -5,16 +5,15 @@ class Datacenter < Diplomat::RestClient # Get an array of all avaliable datacenters accessible by the local consul agent # @param meta [Hash] output structure containing header information about the request (index) + # @param options [Hash] options parameter hash # @return [OpenStruct] all datacenters avaliable to this consul agent - def get(meta = nil) - url = ['/v1/catalog/datacenters'] - - ret = @conn.get concat_url url + def get(meta = nil, options = {}) + ret = send_get_request(@conn, ['/v1/catalog/datacenters'], options) if meta && ret.headers - meta[:index] = ret.headers['x-consul-index'] - meta[:knownleader] = ret.headers['x-consul-knownleader'] - meta[:lastcontact] = ret.headers['x-consul-lastcontact'] + meta[:index] = ret.headers['x-consul-index'] if ret.headers['x-consul-index'] + meta[:knownleader] = ret.headers['x-consul-knownleader'] if ret.headers['x-consul-knownleader'] + meta[:lastcontact] = ret.headers['x-consul-lastcontact'] if ret.headers['x-consul-lastcontact'] end JSON.parse(ret.body) end diff --git a/lib/diplomat/error.rb b/lib/diplomat/error.rb index a80acb3..044c731 100644 --- a/lib/diplomat/error.rb +++ b/lib/diplomat/error.rb @@ -11,4 +11,5 @@ class QueryAlreadyExists < StandardError; end class UnknownStatus < StandardError; end class IdParameterRequired < StandardError; end class InvalidTransaction < StandardError; end + class DeprecatedArgument < StandardError; end end diff --git a/lib/diplomat/event.rb b/lib/diplomat/event.rb index c607b32..39c61ea 100644 --- a/lib/diplomat/event.rb +++ b/lib/diplomat/event.rb @@ -10,17 +10,17 @@ class Event < Diplomat::RestClient # @param node [String] the target node name # @param tag [String] the target tag name, must only be used with service # @param dc [String] the dc to target + # @param options [Hash] options parameter hash # @return [nil] # rubocop:disable Metrics/ParameterLists - def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil) - url = ["/v1/event/fire/#{name}"] - url += check_acl_token - url += use_named_parameter('service', service) if service - url += use_named_parameter('node', node) if node - url += use_named_parameter('tag', tag) if tag - url += use_named_parameter('dc', dc) if dc + def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil, options = {}) + custom_params = [] + custom_params << use_named_parameter('service', service) if service + custom_params << use_named_parameter('node', node) if node + custom_params << use_named_parameter('tag', tag) if tag + custom_params << use_named_parameter('dc', dc) if dc - @conn.put concat_url(url), value + send_put_request(@conn, ["/v1/event/fire/#{name}"], options, value, custom_params) nil end # rubocop:enable Metrics/ParameterLists @@ -32,6 +32,7 @@ def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil) # @param found [Symbol] behaviour if there are already events matching name; # :reject with exception, :return its current value, or :wait for its next value # @return [Array[hash]] The list of { :name, :payload } hashes + # @param options [Hash] options parameter hash # @note # Events are sent via the gossip protocol; there is no guarantee of delivery # success or order, but the local agent will store up to 256 events that do @@ -55,15 +56,9 @@ def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil) # - W R - get the first or current value; always return something, but # block only when necessary # - W W - get the first or next value; wait until there is an update - # rubocop:disable MethodLength, AbcSize - def get_all(name = nil, not_found = :reject, found = :return) - url = ['/v1/event/list'] - url += check_acl_token - url += use_named_parameter('name', name) - url = concat_url url - + def get_all(name = nil, not_found = :reject, found = :return, options = {}) # Event list never returns 404 or blocks, but may return an empty list - @raw = @conn.get url + @raw = send_get_request(@conn, ['/v1/event/list'], options, use_named_parameter('name', name)) if JSON.parse(@raw.body).count.zero? case not_found when :reject @@ -76,19 +71,15 @@ def get_all(name = nil, not_found = :reject, found = :return) when :reject raise Diplomat::EventAlreadyExists, name when :return - # Always set the response to 200 so we always return - # the response body. - @raw.status = 200 @raw = parse_body return return_payload end end - @raw = wait_for_next_event(url) + @raw = wait_for_next_event(['/v1/event/list'], options, use_named_parameter('name', name)) @raw = parse_body return_payload end - # rubocop:enable MethodLength, AbcSize # Get a specific event in the sequence matching name # @param name [String] the name of the event (regex) @@ -102,6 +93,7 @@ def get_all(name = nil, not_found = :reject, found = :return) # @return [hash] A hash with keys :value and :token; # :value is a further hash of the :name and :payload of the event, # :token is the event's ordinate in the sequence and can be passed to future calls to get the subsequent event + # @param options [Hash] options parameter hash # @note # Whereas the consul API for events returns all past events that match # name, this method allows retrieval of individual events from that @@ -110,12 +102,9 @@ def get_all(name = nil, not_found = :reject, found = :return) # middle, though these can only be identified relative to the preceding # event. However, this is ideal for iterating through the sequence of # events (while being sure that none are missed). - # rubocop:disable MethodLength, CyclomaticComplexity, AbcSize - def get(name = nil, token = :last, not_found = :wait, found = :return) - url = ['/v1/event/list'] - url += check_acl_token - url += use_named_parameter('name', name) - @raw = @conn.get concat_url url + # rubocop:disable PerceivedComplexity + def get(name = nil, token = :last, not_found = :wait, found = :return, options = {}) + @raw = send_get_request(@conn, ['/v1/event/list'], options, use_named_parameter('name', name)) body = JSON.parse(@raw.body) # TODO: deal with unknown symbols, invalid indices (find_index will return nil) idx = case token @@ -124,7 +113,7 @@ def get(name = nil, token = :last, not_found = :wait, found = :return) when :next then body.length else body.find_index { |e| e['ID'] == token } + 1 end - if idx == body.length + if JSON.parse(@raw.body).count.zero? || idx == body.length case not_found when :reject raise Diplomat::EventNotFound, name @@ -133,7 +122,7 @@ def get(name = nil, token = :last, not_found = :wait, found = :return) event_payload = '' event_token = :last when :wait - @raw = wait_for_next_event(url) + @raw = wait_for_next_event(['/v1/event/list'], options, use_named_parameter('name', name)) @raw = parse_body # If it's possible for two events to arrive at once, # this needs to #find again: @@ -149,7 +138,7 @@ def get(name = nil, token = :last, not_found = :wait, found = :return) when :return event = body[idx] event_name = event['Name'] - event_payload = Base64.decode64(event['Payload']) + event_payload = event['Payload'].nil? ? nil : Base64.decode64(event['Payload']) event_token = event['ID'] end end @@ -159,17 +148,19 @@ def get(name = nil, token = :last, not_found = :wait, found = :return) token: event_token } end - # rubocop:enable MethodLength, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity private - def wait_for_next_event(url) - index = @raw.headers['x-consul-index'] - url = [url, use_named_parameter('index', index)].join('&') - @conn.get do |req| - req.url concat_url url - req.options.timeout = 86_400 + def wait_for_next_event(url, options = {}, param = nil) + if options.nil? + options = { timeout: 86_400 } + else + options[:timeout] = 86_400 end + index = @raw.headers['x-consul-index'] + param += use_named_parameter('index', index) + send_get_request(@conn, url, options, param) end end end diff --git a/lib/diplomat/health.rb b/lib/diplomat/health.rb index 2dd18f2..d511a0e 100644 --- a/lib/diplomat/health.rb +++ b/lib/diplomat/health.rb @@ -8,75 +8,55 @@ class Health < Diplomat::RestClient # @param n [String] the node # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] all data associated with the node - def node(n, options = nil) - url = ["/v1/health/node/#{n}"] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] + def node(n, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - ret = @conn.get concat_url url + ret = send_get_request(@conn, ["/v1/health/node/#{n}"], options, custom_params) JSON.parse(ret.body).map { |node| OpenStruct.new node } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Get service checks # @param s [String] the service # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] all data associated with the node - def checks(s, options = nil) - url = ["/v1/health/checks/#{s}"] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] + def checks(s, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - ret = @conn.get concat_url url + ret = send_get_request(@conn, ["/v1/health/checks/#{s}"], options, custom_params) JSON.parse(ret.body).map { |check| OpenStruct.new check } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Get service health # @param s [String] the service - # @param options [Hash] :dc string for dc specific query - # @param options [Hash] :passing boolean to return only checks in passing state - # @param options [Hash] :tag string for specific tag + # @param options [Hash] options parameter hash # @return [OpenStruct] all data associated with the node - # rubocop:disable PerceivedComplexity, CyclomaticComplexity, AbcSize - def service(s, options = nil) - url = ["/v1/health/service/#{s}"] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - url << 'passing' if options && options[:passing] - url << use_named_parameter('tag', options[:tag]) if options && options[:tag] - url << use_named_parameter('near', options[:near]) if options && options[:near] + # rubocop:disable PerceivedComplexity + def service(s, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << ['passing'] if options[:passing] + custom_params << use_named_parameter('tag', options[:tag]) if options[:tag] + custom_params << use_named_parameter('near', options[:near]) if options[:near] - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - ret = @conn.get concat_url url + ret = send_get_request(@conn, ["/v1/health/service/#{s}"], options, custom_params) JSON.parse(ret.body).map { |service| OpenStruct.new service } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end - # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity # Get service health # @param s [String] the state ("any", "passing", "warning", or "critical") # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] all data associated with the node - # rubocop:disable AbcSize - def state(s, options = nil) - url = ["/v1/health/state/#{s}"] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - url << use_named_parameter('near', options[:near]) if options && options[:near] + def state(s, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << use_named_parameter('near', options[:near]) if options[:near] - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - ret = @conn.get concat_url url + ret = send_get_request(@conn, ["/v1/health/state/#{s}"], options, custom_params) JSON.parse(ret.body).map { |status| OpenStruct.new status } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end - # rubocop:enable AbcSize # Convenience method to get services in any state def any diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index ed8b654..cd982d5 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -40,24 +40,21 @@ class Kv < Diplomat::RestClient # - W R - get the first or current value; always return something, but # block only when necessary # - W W - get the first or next value; wait until there is an update - # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize, LineLength - def get(key, options = nil, not_found = :reject, found = :return) + # rubocop:disable PerceivedComplexity, LineLength, CyclomaticComplexity + def get(key, options = {}, not_found = :reject, found = :return) @key = key @options = options - - url = ["/v1/kv/#{@key}"] - url += recurse_get(@options) - url += check_acl_token - url += use_consistency(@options) - url += dc(@options) - url += keys(@options) - url += separator(@options) + custom_params = [] + custom_params << recurse_get(@options) + custom_params << use_consistency(options) + custom_params << dc(@options) + custom_params << keys(@options) + custom_params << separator(@options) return_nil_values = @options && @options[:nil_values] transformation = @options && @options[:transformation] && @options[:transformation].methods.find_index(:call) ? @options[:transformation] : nil - # 404s OK using this connection - raw = @conn_no_err.get concat_url url + raw = send_get_request(@conn_no_err, ["/v1/kv/#{@key}"], options, custom_params) if raw.status == 404 case not_found when :reject @@ -88,15 +85,17 @@ def get(key, options = nil, not_found = :reject, found = :return) end # Wait for first/next value - url += use_named_parameter('index', index) - @raw = @conn.get do |req| - req.url concat_url url - req.options.timeout = 86_400 + custom_params << use_named_parameter('index', index) + if options.nil? + options = { timeout: 86_400 } + else + options[:timeout] = 86_400 end + @raw = send_get_request(@conn, ["/v1/kv/#{@key}"], options, custom_params) @raw = parse_body return_value(return_nil_values, transformation) end - # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize, LineLength + # rubocop:enable PerceivedComplexity, LineLength, CyclomaticComplexity # Associate a value with a key # @param key [String] the key @@ -106,25 +105,19 @@ def get(key, options = nil, not_found = :reject, found = :return) # @option options [String] :dc Target datacenter # @option options [String] :acquire Session to attach to key # @return [Bool] Success or failure of the write (can fail in c-a-s mode) - # rubocop:disable MethodLength, AbcSize - def put(key, value, options = nil) + def put(key, value, options = {}) @options = options - @raw = @conn.put do |req| - url = ["/v1/kv/#{key}"] - url += check_acl_token - url += use_cas(@options) - url += dc(@options) - url += acquire(@options) - req.url concat_url url - req.body = value - end + custom_params = [] + custom_params << use_cas(@options) + custom_params << dc(@options) + custom_params << acquire(@options) + @raw = send_put_request(@conn, ["/v1/kv/#{key}"], options, value, custom_params) if @raw.body.chomp == 'true' @key = key @value = value end @raw.body.chomp == 'true' end - # rubocop:enable MethodLength, AbcSize # Delete a value by its key # @param key [String] the key @@ -132,14 +125,13 @@ def put(key, value, options = nil) # @option options [String] :dc Target datacenter # @option options [Boolean] :recurse If to make recursive get or not # @return [OpenStruct] - def delete(key, options = nil) + def delete(key, options = {}) @key = key @options = options - url = ["/v1/kv/#{@key}"] - url += recurse_get(@options) - url += check_acl_token - url += dc(@options) - @raw = @conn.delete concat_url url + custom_params = [] + custom_params << recurse_get(@options) + custom_params << dc(@options) + @raw = send_delete_request(@conn, ["/v1/kv/#{@key}"], options, custom_params) end # Perform a key/value store transaction. @@ -163,42 +155,37 @@ def delete(key, options = nil) # @option options [String] :consistency the accepted staleness level of the transaction. # Can be 'stale' or 'consistent' # @return [OpenStruct] result of the transaction - def txn(value, options = nil) + def txn(value, options = {}) # Verify the given value for the transaction transaction_verification(value) # Will return 409 if transaction was rolled back - raw = @conn_no_err.put do |req| - url = ['/v1/txn'] - url += check_acl_token - url += dc(options) - url += transaction_consistency(options) - - req.url concat_url url - req.body = JSON.generate(value) - end + custom_params = [] + custom_params << dc(options) + custom_params << transaction_consistency(options) + raw = send_put_request(@conn_no_err, ['/v1/txn'], options, value, custom_params) transaction_return JSON.parse(raw.body), options end private def recurse_get(options) - options && options[:recurse] ? ['recurse'] : [] + options[:recurse] ? ['recurse'] : [] end def dc(options) - options && options[:dc] ? use_named_parameter('dc', options[:dc]) : [] + options[:dc] ? use_named_parameter('dc', options[:dc]) : [] end def acquire(options) - options && options[:acquire] ? use_named_parameter('acquire', options[:acquire]) : [] + options[:acquire] ? use_named_parameter('acquire', options[:acquire]) : [] end def keys(options) - options && options[:keys] ? ['keys'] : [] + options[:keys] ? ['keys'] : [] end def separator(options) - options && options[:separator] ? use_named_parameter('separator', options[:separator]) : [] + options[:separator] ? use_named_parameter('separator', options[:separator]) : [] end def transaction_consistency(options) @@ -247,11 +234,11 @@ def encode_transaction(transaction) def transaction_return(raw_return, options) decoded_return = - options && options[:decode_values] == false ? raw_return : decode_transaction(raw_return) + options[:decode_values] == false ? raw_return : decode_transaction(raw_return) OpenStruct.new decoded_return end - def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength + def decode_transaction(transaction) return transaction if transaction['Results'].nil? || transaction['Results'].empty? transaction.tap do |txn| diff --git a/lib/diplomat/lock.rb b/lib/diplomat/lock.rb index 328c1fe..2b168b1 100644 --- a/lib/diplomat/lock.rb +++ b/lib/diplomat/lock.rb @@ -7,31 +7,25 @@ class Lock < Diplomat::RestClient # @param key [String] the key # @param session [String] the session, generated from Diplomat::Session.create # @param value [String] the value for the key - # @param options [Hash] :dc string for dc specific query + # @param options [Hash] options parameter hash # @return [Boolean] If the lock was acquired - # rubocop:disable AbcSize - def acquire(key, session, value = nil, options = nil) - raw = @conn.put do |req| - url = ["/v1/kv/#{key}"] - url += use_named_parameter('acquire', session) - url += check_acl_token - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - req.body = value unless value.nil? - end + def acquire(key, session, value = nil, options = {}) + custom_params = [] + custom_params << use_named_parameter('acquire', session) + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + data = value unless value.nil? + raw = send_put_request(@conn, ["/v1/kv/#{key}"], options, data, custom_params) raw.body.chomp == 'true' end - # rubocop:enable AbcSize # wait to aquire a lock # @param key [String] the key # @param session [String] the session, generated from Diplomat::Session.create # @param value [String] the value for the key # @param check_interval [Integer] number of seconds to wait between retries - # @param options [Hash] :dc string for dc specific query + # @param options [Hash] options parameter hash # @return [Boolean] If the lock was acquired - def wait_to_acquire(key, session, value = nil, check_interval = 10, options = nil) + def wait_to_acquire(key, session, value = nil, check_interval = 10, options = {}) acquired = false until acquired acquired = acquire(key, session, value, options) @@ -45,15 +39,11 @@ def wait_to_acquire(key, session, value = nil, check_interval = 10, options = ni # @param session [String] the session, generated from Diplomat::Session.create # @param options [Hash] :dc string for dc specific query # @return [nil] - def release(key, session, options = nil) - raw = @conn.put do |req| - url = ["/v1/kv/#{key}"] - url += use_named_parameter('release', session) - url += check_acl_token - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def release(key, session, options = {}) + custom_params = [] + custom_params << use_named_parameter('release', session) + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_put_request(@conn, ["/v1/kv/#{key}"], options, nil, custom_params) raw.body end end diff --git a/lib/diplomat/maintenance.rb b/lib/diplomat/maintenance.rb index eebfe04..ab03987 100644 --- a/lib/diplomat/maintenance.rb +++ b/lib/diplomat/maintenance.rb @@ -7,7 +7,7 @@ class Maintenance < Diplomat::RestClient # @param n [String] the node # @param options [Hash] :dc string for dc specific query # @return [Hash] { :enabled => true, :reason => 'foo' } - def enabled(n, options = nil) + def enabled(n, options = {}) health = Diplomat::Health.new(@conn) result = health.node(n, options) .select { |check| check['CheckID'] == '_node_maintenance' } @@ -25,21 +25,17 @@ def enabled(n, options = nil) # @param reason [String] the reason for enabling maintenance mode # @param options [Hash] :dc string for dc specific query # @return true if call is successful - # rubocop:disable AbcSize - def enable(enable = true, reason = nil, options = nil) - raw = @conn.put do |req| - url = ['/v1/agent/maintenance'] - url << use_named_parameter('enable', enable.to_s) - url << use_named_parameter('reason', reason) if reason - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - req.url concat_url url - end + def enable(enable = true, reason = nil, options = {}) + custom_params = [] + custom_params << use_named_parameter('enable', enable.to_s) + custom_params << use_named_parameter('reason', reason) if reason + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_put_request(@conn, ['/v1/agent/maintenance'], options, nil, custom_params) return_status = raw.status == 200 raise Diplomat::UnknownStatus, "status #{raw.status}: #{raw.body}" unless return_status return_status end - # rubocop:enable AbcSize end end diff --git a/lib/diplomat/members.rb b/lib/diplomat/members.rb index 8decfea..7546995 100644 --- a/lib/diplomat/members.rb +++ b/lib/diplomat/members.rb @@ -4,9 +4,10 @@ class Members < Diplomat::RestClient @access_methods = [:get] # Get all members + # @param options [Hash] options parameter hash # @return [OpenStruct] all data associated with the service - def get - ret = @conn.get '/v1/agent/members' + def get(options = {}) + ret = send_get_request(@conn, ['/v1/agent/members'], options) JSON.parse(ret.body) end end diff --git a/lib/diplomat/node.rb b/lib/diplomat/node.rb index c12bb4e..720c19c 100644 --- a/lib/diplomat/node.rb +++ b/lib/diplomat/node.rb @@ -7,47 +7,36 @@ class Node < Diplomat::RestClient # @param key [String] the key # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] all data associated with the node - def get(key, options = nil) - url = ["/v1/catalog/node/#{key}"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - ret = @conn.get concat_url url + def get(key, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ["/v1/catalog/node/#{key}"], options, custom_params) OpenStruct.new JSON.parse(ret.body) - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Get all the nodes # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] the list of all nodes - def get_all(options = nil) - url = ['/v1/catalog/nodes'] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - ret = @conn.get concat_url url + def get_all(options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ['/v1/catalog/nodes'], options, custom_params) JSON.parse(ret.body).map { |service| OpenStruct.new service } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Register a node # @param definition [Hash] Hash containing definition of a node to register + # @param options [Hash] options parameter hash # @return [Boolean] - def register(definition, path = '/v1/catalog/register') - register = @conn.put path, JSON.dump(definition) - + def register(definition, options = {}) + register = send_put_request(@conn, ['/v1/catalog/register'], options, definition) register.status == 200 end # De-register a node (and all associated services and checks) # @param definition [Hash] Hash containing definition of a node to de-register + # @param options [Hash] options parameter hash # @return [Boolean] - def deregister(definition, path = '/v1/catalog/deregister') - deregister = @conn.put path, JSON.dump(definition) - + def deregister(definition, options = {}) + deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition) deregister.status == 200 end end diff --git a/lib/diplomat/nodes.rb b/lib/diplomat/nodes.rb index 62cee13..5d4108f 100644 --- a/lib/diplomat/nodes.rb +++ b/lib/diplomat/nodes.rb @@ -6,20 +6,17 @@ class Nodes < Diplomat::RestClient # Get all nodes # @deprecated Please use Diplomat::Node instead. + # @param options [Hash] options parameter hash # @return [OpenStruct] all data associated with the nodes in catalog - def get - ret = @conn.get '/v1/catalog/nodes' + def get(options = {}) + ret = send_get_request(@conn, ['/v1/catalog/nodes'], options) JSON.parse(ret.body) end - def get_all(options = nil) - url = ['/v1/catalog/nodes'] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - ret = @conn.get concat_url url + def get_all(options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ['/v1/catalog/nodes'], options, custom_params) JSON.parse(ret.body).map { |service| OpenStruct.new service } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end end end diff --git a/lib/diplomat/query.rb b/lib/diplomat/query.rb index 25d4334..fba2d0c 100644 --- a/lib/diplomat/query.rb +++ b/lib/diplomat/query.rb @@ -7,44 +7,28 @@ class Query < Diplomat::RestClient # @param key [String] the prepared query ID # @param options [Hash] :dc string for dc specific query # @return [OpenStruct] all data associated with the prepared query - def get(key, options = nil) - url = ["/v1/query/#{key}"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - ret = @conn.get concat_url url + def get(key, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ["/v1/query/#{key}"], options, custom_params) JSON.parse(ret.body).map { |query| OpenStruct.new query } - rescue Faraday::ClientError - raise Diplomat::QueryNotFound end # Get all prepared queries # @param options [Hash] :dc Consul datacenter to query # @return [OpenStruct] the list of all prepared queries - def get_all(options = nil) - url = ['/v1/query'] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - ret = @conn.get concat_url url + def get_all(options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ['/v1/query'], options, custom_params) JSON.parse(ret.body).map { |query| OpenStruct.new query } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Create a prepared query or prepared query template # @param definition [Hash] Hash containing definition of prepared query # @param options [Hash] :dc Consul datacenter to query # @return [String] the ID of the prepared query created - def create(definition, options = nil) - url = ['/v1/query'] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - @raw = @conn.post do |req| - req.url concat_url url - req.body = JSON.dump(definition) - end - + def create(definition, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + @raw = send_post_request(@conn, ['/v1/query'], options, definition, custom_params) parse_body rescue Faraday::ClientError raise Diplomat::QueryAlreadyExists @@ -54,12 +38,9 @@ def create(definition, options = nil) # @param key [String] the prepared query ID # @param options [Hash] :dc Consul datacenter to query # @return [Boolean] - def delete(key, options = nil) - url = ["/v1/query/#{key}"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - ret = @conn.delete concat_url url - + def delete(key, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_delete_request(@conn, ["/v1/query/#{key}"], options, custom_params) ret.status == 200 end @@ -68,16 +49,9 @@ def delete(key, options = nil) # @param definition [Hash] Hash containing updated definition of prepared query # @param options [Hash] :dc Consul datacenter to query # @return [Boolean] - def update(key, definition, options = nil) - url = ["/v1/query/#{key}"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - json_definition = JSON.dump(definition) - ret = @conn.put do |req| - req.url concat_url url - req.body = json_definition - end - + def update(key, definition, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_put_request(@conn, ["/v1/query/#{key}"], options, definition, custom_params) ret.status == 200 end @@ -89,34 +63,25 @@ def update(key, definition, options = nil) # estimated round trip time from that node # @option limit [Integer] to limit the size of the return list to the given number of results # @return [OpenStruct] the list of results from the prepared query or prepared query template - # rubocop:disable PerceivedComplexity, CyclomaticComplexity, AbcSize - def execute(key, options = nil) - url = ["/v1/query/#{key}/execute"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - url << use_named_parameter('near', options[:near]) if options && options[:near] - url << use_named_parameter('limit', options[:limit]) if options && options[:limit] - - ret = @conn.get concat_url url + # rubocop:disable PerceivedComplexity + def execute(key, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << use_named_parameter('near', options[:near]) if options[:near] + custom_params << use_named_parameter('limit', options[:limit]) if options[:limit] + ret = send_get_request(@conn, ["/v1/query/#{key}/execute"], options, custom_params) OpenStruct.new JSON.parse(ret.body) - rescue Faraday::ClientError - raise Diplomat::QueryNotFound end - # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity # Get the fully rendered query template # @param key [String] the prepared query ID or name # @param options [Hash] :dc Consul datacenter to query # @return [OpenStruct] the list of results from the prepared query or prepared query template - def explain(key, options = nil) - url = ["/v1/query/#{key}/explain"] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - - ret = @conn.get concat_url url + def explain(key, options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ["/v1/query/#{key}/explain"], options, custom_params) OpenStruct.new JSON.parse(ret.body) - rescue Faraday::ClientError - raise Diplomat::QueryNotFound end end end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index 2c2e15d..8795de9 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -32,6 +32,7 @@ def use_named_parameter(name, value) # @param parts [Array] the url chunks to be assembled # @return [String] the resultant url string def concat_url(parts) + parts.reject!(&:empty?) if parts.length > 1 parts.first + '?' + parts.drop(1).join('&') else @@ -104,13 +105,11 @@ def build_connection(api_connection, raise_error = false) end # Converts k/v data into ruby hash - # rubocop:disable MethodLength, AbcSize def convert_to_hash(data) data.map do |item| item[:key].split('/').reverse.reduce(item[:value]) { |h, v| { v => h } } end.reduce(:deep_merge) end - # rubocop:enable MethodLength, AbcSize # Parse the body, apply it to the raw attribute def parse_body @@ -135,7 +134,7 @@ def decode_values end # Get the key/value(s) from the raw output - # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize + # rubocop:disable PerceivedComplexity def return_value(nil_values = false, transformation = nil, return_hash = false) @value = decode_values return @value if @value.first.is_a? String @@ -151,7 +150,7 @@ def return_value(nil_values = false, transformation = nil, return_hash = false) end.compact end end - # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity # Get the name and payload(s) from the raw output def return_payload @@ -161,22 +160,88 @@ def return_payload end end - def check_acl_token - use_named_parameter('token', configuration.acl_token) - end - def use_cas(options) options ? use_named_parameter('cas', options[:cas]) : [] end def use_consistency(options) - options && options[:consistency] ? [options[:consistency].to_s] : [] + options[:consistency] ? [options[:consistency].to_s] : [] + end + + # rubocop:disable PerceivedComplexity + # TODO: Migrate all custom params in options + def parse_options(options) + headers = nil + query_params = [] + url_prefix = nil + consistency = [] + + # Parse options used as header + headers = { 'X-Consul-Token': configuration.acl_token } if configuration.acl_token + headers = { 'X-Consul-Token': options[:token] } if options[:token] + + # Parse options used as query params + consistency = 'stale' if options[:stale] + consistency = 'leader' if options[:leader] + consistency = 'consistent' if options[:consistent] + query_params << consistency + + # Parse url host + url_prefix = options[:http_addr] if options[:http_addr] + { query_params: query_params, headers: headers, url_prefix: url_prefix } + end + # rubocop:enable PerceivedComplexity + + def send_get_request(connection, url, options, custom_params = nil) + rest_options = parse_options(options) + url += rest_options[:query_params] + url += custom_params unless custom_params.nil? + begin + connection.get do |req| + req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url) + rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil? + req.options.timeout = options[:timeout] if options[:timeout] + end + rescue Faraday::ClientError => e + raise Diplomat::PathNotFound, e + end + end + + def send_put_request(connection, url, options, data, custom_params = nil) + rest_options = parse_options(options) + url += rest_options[:query_params] + url += custom_params unless custom_params.nil? + connection.put do |req| + req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url) + rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil? + req.body = JSON.dump(data) unless data.nil? + end + end + + def send_post_request(connection, url, options, data, custom_params = nil) + rest_options = parse_options(options) + url += rest_options[:query_params] + url += custom_params unless custom_params.nil? + connection.post do |req| + req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url) + rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil? + req.body = JSON.dump(data) unless data.nil? + end + end + + def send_delete_request(connection, url, options, custom_params = nil) + rest_options = parse_options(options) + url += rest_options[:query_params] + url += custom_params unless custom_params.nil? + connection.delete do |req| + req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url) + rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil? + end end # Mapping for valid key/value store transaction verbs and required parameters # # @return [Hash] valid key/store transaction verbs and required parameters - # rubocop:disable MethodLength def valid_transaction_verbs { 'set' => %w[Key Value], @@ -192,7 +257,6 @@ def valid_transaction_verbs 'delete-cas' => %w[Key Index] } end - # rubocop:enable MethodLength # Key/value store transactions that require that a value be set # diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index ae2d71c..5407bae 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -1,5 +1,5 @@ module Diplomat - # Methods for interacting with the Consul serivce API endpoint. + # Methods for interacting with the Consul service API endpoint. class Service < Diplomat::RestClient @access_methods = %i[get get_all register deregister register_external deregister_external maintenance] @@ -7,33 +7,21 @@ class Service < Diplomat::RestClient # @param key [String] the key # @param scope [Symbol] :first or :all results # @param options [Hash] options parameter hash - # @option wait [Integer] :wait string for wait time - # @option index [String] :index for index of last query - # @option dc [String] :dc data center to make request for - # @option tag [String] :tag service tag to get # @param meta [Hash] output structure containing header information about the request (index) # @return [OpenStruct] all data associated with the service - # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize - def get(key, scope = :first, options = nil, meta = nil) - url = ["/v1/catalog/service/#{key}"] - url += check_acl_token - url << use_named_parameter('wait', options[:wait]) if options && options[:wait] - url << use_named_parameter('index', options[:index]) if options && options[:index] - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - url << use_named_parameter('tag', options[:tag]) if options && options[:tag] - - # If the request fails, it's probably due to a bad path - # so return a PathNotFound error. - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError => e - raise Diplomat::PathNotFound, e - end + # rubocop:disable PerceivedComplexity + def get(key, scope = :first, options = {}, meta = nil) + custom_params = [] + custom_params << use_named_parameter('wait', options[:wait]) if options[:wait] + custom_params << use_named_parameter('index', options[:index]) if options[:index] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << use_named_parameter('tag', options[:tag]) if options[:tag] + ret = send_get_request(@conn, ["/v1/catalog/service/#{key}"], options, custom_params) if meta && ret.headers - meta[:index] = ret.headers['x-consul-index'] - meta[:knownleader] = ret.headers['x-consul-knownleader'] - meta[:lastcontact] = ret.headers['x-consul-lastcontact'] + meta[:index] = ret.headers['x-consul-index'] if ret.headers['x-consul-index'] + meta[:knownleader] = ret.headers['x-consul-knownleader'] if ret.headers['x-consul-knownleader'] + meta[:lastcontact] = ret.headers['x-consul-lastcontact'] if ret.headers['x-consul-lastcontact'] end if scope == :all @@ -42,77 +30,67 @@ def get(key, scope = :first, options = nil, meta = nil) OpenStruct.new JSON.parse(ret.body).first end end - # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity # Get all the services # @param options [Hash] :dc Consul datacenter to query # @return [OpenStruct] the list of all services - def get_all(options = nil) - url = ['/v1/catalog/services'] - url += check_acl_token - url << use_named_parameter('dc', options[:dc]) if options && options[:dc] - begin - ret = @conn.get concat_url url - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end - + def get_all(options = {}) + custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_get_request(@conn, ['/v1/catalog/services'], options, custom_params) OpenStruct.new JSON.parse(ret.body) end # Register a service # @param definition [Hash] Hash containing definition of service + # @param options [Hash] options parameter hash # @return [Boolean] - def register(definition, path = '/v1/agent/service/register') - url = [path] - url += check_acl_token - json_definition = JSON.dump(definition) - register = @conn.put concat_url(url), json_definition + def register(definition, options = {}) + url = options[:path] || ['/v1/agent/service/register'] + register = send_put_request(@conn, url, options, definition) register.status == 200 end # De-register a service # @param service_name [String] Service name to de-register + # @param options [Hash] options parameter hash # @return [Boolean] - def deregister(service_name) - url = ["/v1/agent/service/deregister/#{service_name}"] - url += check_acl_token - deregister = @conn.put concat_url(url) + def deregister(service_name, options = {}) + deregister = send_put_request(@conn, ["/v1/agent/service/deregister/#{service_name}"], options, nil) deregister.status == 200 end # Register an external service # @param definition [Hash] Hash containing definition of service + # @param options [Hash] options parameter hash # @return [Boolean] - def register_external(definition) - register(definition, '/v1/catalog/register') + def register_external(definition, options = {}) + register = send_put_request(@conn, ['/v1/catalog/register'], options, definition) + register.status == 200 end # Deregister an external service # @param definition [Hash] Hash containing definition of service + # @param options [Hash] options parameter hash # @return [Boolean] - def deregister_external(definition) - json_definition = JSON.dump(definition) - deregister = @conn.put '/v1/catalog/deregister', json_definition + def deregister_external(definition, options = {}) + deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition) deregister.status == 200 end # Enable or disable maintenance for a service - # @param [Hash] opts the options for enabling or disabling maintenance for a service + # @param service_id [String] id of the service + # @param options [Hash] opts the options for enabling or disabling maintenance for a service # @options opts [Boolean] :enable (true) whether to enable or disable maintenance # @options opts [String] :reason reason for the service maintenance # @raise [Diplomat::PathNotFound] if the request fails # @return [Boolean] if the request was successful or not def maintenance(service_id, options = { enable: true }) - url = ["/v1/agent/service/maintenance/#{service_id}"] - url += check_acl_token - url << ["enable=#{options[:enable]}"] - url << ["reason=#{options[:reason].split(' ').join('+')}"] if options && options[:reason] - begin - maintenance = @conn.put concat_url(url) - rescue Faraday::ClientError - raise Diplomat::PathNotFound - end + custom_params = [] + custom_params << ["enable=#{options[:enable]}"] + custom_params << ["reason=#{options[:reason].split(' ').join('+')}"] if options[:reason] + maintenance = send_put_request(@conn, ["/v1/agent/service/maintenance/#{service_id}"], + options, nil, custom_params) maintenance.status == 200 end end diff --git a/lib/diplomat/session.rb b/lib/diplomat/session.rb index 8b053f3..a252647 100644 --- a/lib/diplomat/session.rb +++ b/lib/diplomat/session.rb @@ -6,18 +6,14 @@ class Session < Diplomat::RestClient # Create a new session # @param value [Object] hash or json representation of the session arguments # @param options [Hash] session options - # @param options [String] :dc datacenter to create session for # @return [String] The sesssion id - def create(value = nil, options = nil) + def create(value = nil, options = {}) # TODO: only certain keys are recognised in a session create request, # should raise an error on others. - raw = @conn.put do |req| - url = ['/v1/session/create'] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - req.body = (value.is_a?(String) ? value : JSON.generate(value)) unless value.nil? - end + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + data = value.is_a?(String) ? value : JSON.generate(value) unless value.nil? + raw = send_put_request(@conn, ['/v1/session/create'], options, data, custom_params) body = JSON.parse(raw.body) body['ID'] end @@ -25,74 +21,54 @@ def create(value = nil, options = nil) # Destroy a session # @param id [String] session id # @param options [Hash] session options - # @param options [String] :dc datacenter to destroy session for # @return [String] Success or failure of the session destruction - def destroy(id, options = nil) - raw = @conn.put do |req| - url = ["/v1/session/destroy/#{id}"] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def destroy(id, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_put_request(@conn, ["/v1/session/destroy/#{id}"], options, nil, custom_params) raw.body end # List sessions # @param options [Hash] session options - # @param options [String] :dc datacenter to list sessions # @return [OpenStruct] - def list(options = nil) - raw = @conn.get do |req| - url = ['/v1/session/list'] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def list(options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_get_request(@conn, ['/v1/session/list'], options, custom_params) JSON.parse(raw.body).map { |session| OpenStruct.new session } end # Renew session # @param id [String] session id # @param options [Hash] session options - # @param options [String] :dc datacenter to renew session for # @return [OpenStruct] - def renew(id, options = nil) - raw = @conn.put do |req| - url = ["/v1/session/renew/#{id}"] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def renew(id, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_put_request(@conn, ["/v1/session/renew/#{id}"], options, nil, custom_params) JSON.parse(raw.body).map { |session| OpenStruct.new session } end # Session information # @param id [String] session id # @param options [Hash] session options - # @param options [String] :dc datacenter to renew session for # @return [OpenStruct] - def info(id, options = nil) - raw = @conn.get do |req| - url = ["/v1/session/info/#{id}"] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def info(id, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_get_request(@conn, ["/v1/session/info/#{id}"], options, custom_params) JSON.parse(raw.body).map { |session| OpenStruct.new session } end # Session information for a given node # @param name [String] node name # @param options [Hash] session options - # @param options [String] :dc datacenter to renew session for # @return [OpenStruct] - def node(name, options = nil) - raw = @conn.get do |req| - url = ["/v1/session/node/#{name}"] - url += use_named_parameter('dc', options[:dc]) if options && options[:dc] - - req.url concat_url url - end + def node(name, options = {}) + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + raw = send_get_request(@conn, ["/v1/session/node/#{name}"], options, custom_params) JSON.parse(raw.body).map { |session| OpenStruct.new session } end end diff --git a/lib/diplomat/status.rb b/lib/diplomat/status.rb index 9ab0c66..40cf9eb 100644 --- a/lib/diplomat/status.rb +++ b/lib/diplomat/status.rb @@ -4,18 +4,18 @@ class Status < Diplomat::RestClient @access_methods = %i[leader peers] # Get the raft leader for the datacenter in which the local consul agent is running + # @param options [Hash] options parameter hash # @return [OpenStruct] the address of the leader - def leader - url = ['/v1/status/leader'] - ret = @conn.get concat_url url + def leader(options = {}) + ret = send_get_request(@conn, ['/v1/status/leader'], options) JSON.parse(ret.body) end # Get an array of Raft peers for the datacenter in which the agent is running + # @param options [Hash] options parameter hash # @return [OpenStruct] an array of peers - def peers - url = ['/v1/status/peers'] - ret = @conn.get concat_url url + def peers(options = {}) + ret = send_get_request(@conn, ['/v1/status/peers'], options) JSON.parse(ret.body) end end diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index c2ccb6f..0a862d5 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.0.5'.freeze + VERSION = '2.1.0'.freeze end diff --git a/spec/acl_spec.rb b/spec/acl_spec.rb index cc119e2..998a742 100644 --- a/spec/acl_spec.rb +++ b/spec/acl_spec.rb @@ -1,10 +1,8 @@ require 'spec_helper' describe Diplomat::Acl do - let(:faraday) { fake } - context 'acls' do - let(:key_url) { '/v1/acl' } + let(:key_url) { 'http://localhost:8500/v1/acl' } let(:id) { '8f246b77-f3e1-ff88-5b48-8ec93abf3e05' } let(:info_body) do [ @@ -49,9 +47,9 @@ json = JSON.generate(info_body) url = key_url + '/info/' + id - expect(faraday).to receive(:get).with(/#{url}/).and_return(OpenStruct.new(body: json, status: 200)) + stub_request(:get, url).to_return(OpenStruct.new(body: json, status: 200)) - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new info = acl.info(id) expect(info.size).to eq(1) @@ -62,9 +60,9 @@ json = 'null' url = key_url + '/info/' + 'none' - expect(faraday).to receive(:get).with(/#{url}/).and_return(OpenStruct.new(body: json, status: 200)) + stub_request(:get, url).to_return(OpenStruct.new(body: json, status: 200)) - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new expect { acl.info('none') }.to raise_error(Diplomat::AclNotFound) end @@ -75,9 +73,9 @@ json = JSON.generate(list_body) url = key_url + '/list' - expect(faraday).to receive(:get).with(/#{url}/).and_return(OpenStruct.new(body: json, status: 200)) + stub_request(:get, url).to_return(OpenStruct.new(body: json, status: 200)) - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new list = acl.list expect(list.size).to eq(2) @@ -89,18 +87,16 @@ json = JSON.generate(info_body.first) url = key_url + '/update' - req = fake - expect(faraday).to receive(:put).and_yield(req).and_return(OpenStruct.new(body: json, status: 200)) - expect(req).to receive(:url).with(/#{url}/) + stub_request(:put, url).to_return(OpenStruct.new(body: json, status: 200)) - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new response = acl.update(info_body.first) expect(response['ID']).to eq(info_body.first['ID']) end it 'fails if no ID is provided ' do - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new expect { acl.update(Name: 'test') }.to raise_error(Diplomat::IdParameterRequired) end end @@ -110,11 +106,10 @@ json = JSON.generate(info_body.first) url = key_url + '/create' - req = fake - expect(faraday).to receive(:put).and_yield(req).and_return(OpenStruct.new(body: json, status: 200)) - expect(req).to receive(:url).with(/#{url}/) + stub_request(:put, url) + .with(body: json).to_return(OpenStruct.new(body: json, status: 200)) - acl = Diplomat::Acl.new(faraday) + acl = Diplomat::Acl.new response = acl.create(info_body.first) expect(response['ID']).to eq(info_body.first['ID']) @@ -124,8 +119,9 @@ describe 'destroy' do it 'return the ID' do url = key_url + '/destroy/' + id - expect(faraday).to receive(:put).with(/#{url}/).and_return(OpenStruct.new(body: "true\n", status: 200)) - acl = Diplomat::Acl.new(faraday) + stub_request(:put, url).to_return(OpenStruct.new(body: "true\n", status: 200)) + + acl = Diplomat::Acl.new response = acl.destroy(id) expect(response).to be true diff --git a/spec/check_spec.rb b/spec/check_spec.rb index b74ce77..ee40a04 100644 --- a/spec/check_spec.rb +++ b/spec/check_spec.rb @@ -29,7 +29,7 @@ it 'register_script' do faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) - expect(check.register_script('foobar-1', 'Foobar', 'Foobar test', '/script/test', '10s')).to eq(true) + expect(check.register_script('foobar-1', 'Foobar', 'Foobar test', ['/script/test'], '10s')).to eq(true) end it 'register_ttl' do diff --git a/spec/configure_spec.rb b/spec/configure_spec.rb index 589e4aa..0bab5eb 100644 --- a/spec/configure_spec.rb +++ b/spec/configure_spec.rb @@ -49,13 +49,13 @@ def call(env) it 'Sets the correct configuration' do Diplomat.configure do |config| - config.url = 'http://google.com' + config.url = 'http://localhost:8500' config.acl_token = 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f1' config.middleware = StubMiddleware config.options = { ssl: { verify: true } } end - expect(Diplomat.configuration.url).to eq('http://google.com') + expect(Diplomat.configuration.url).to eq('http://localhost:8500') expect(Diplomat.configuration.acl_token).to eq('f45cbd0b-5022-47ab-8640-4eaa7c1f40f1') expect(Diplomat.configuration.middleware).to be_a(Array) expect(Diplomat.configuration.middleware.first).to eq(StubMiddleware) diff --git a/spec/datacenter_spec.rb b/spec/datacenter_spec.rb index 83f8308..1d9b7ba 100644 --- a/spec/datacenter_spec.rb +++ b/spec/datacenter_spec.rb @@ -3,10 +3,8 @@ require 'base64' describe Diplomat::Datacenter do - let(:faraday) { fake } - context 'datacenters' do - let(:key_url) { '/v1/catalog/datacenters' } + let(:key_url) { 'http://localhost:8500/v1/catalog/datacenters' } let(:body) { %w[dc1 dc2] } let(:headers) do { @@ -20,9 +18,9 @@ it 'returns dcs' do json = JSON.generate(body) - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json)) + stub_request(:get, key_url).to_return(OpenStruct.new(body: json)) - datacenters = Diplomat::Datacenter.new(faraday) + datacenters = Diplomat::Datacenter expect(datacenters.get.size).to eq(2) expect(datacenters.get.first).to eq('dc1') @@ -33,9 +31,9 @@ it 'empty headers' do json = JSON.generate(body) - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json, headers: nil)) + stub_request(:get, key_url).to_return(OpenStruct.new(body: json, headers: nil)) - datacenters = Diplomat::Datacenter.new(faraday) + datacenters = Diplomat::Datacenter.new meta = {} expect(datacenters.get(meta).size).to eq(2) @@ -46,9 +44,10 @@ it 'filled headers' do json = JSON.generate(body) - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json, headers: headers)) + stub_request(:get, key_url) + .to_return(OpenStruct.new(body: json, headers: headers)) - datacenters = Diplomat::Datacenter.new(faraday) + datacenters = Diplomat::Datacenter.new meta = {} s = datacenters.get(meta) diff --git a/spec/event_spec.rb b/spec/event_spec.rb index 8dc17f4..7b2a2c2 100644 --- a/spec/event_spec.rb +++ b/spec/event_spec.rb @@ -196,61 +196,69 @@ describe 'FIRE' do it 'token empty' do - expect(faraday).to receive(:put).with("/v1/event/fire/#{event_name}", nil) + stub_request(:put, "http://localhost:8500/v1/event/fire/#{event_name}") Diplomat.configuration.acl_token = nil - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.fire(event_name) end it 'token specified' do - expect(faraday).to receive(:put).with("/v1/event/fire/#{event_name}?token=#{acl_token}", nil) + stub_request(:put, "http://localhost:8500/v1/event/fire/#{event_name}") + .with(headers: { 'X-Consul-Token' => acl_token }) Diplomat.configuration.acl_token = acl_token - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.fire(event_name) end end describe 'GET_ALL' do - before do - allow(faraday).to receive(:get).and_return(OpenStruct.new(body: events_json)) - end - it 'token empty' do - expect(faraday).to receive(:get).with('/v1/event/list') + stub_without_token = stub_request(:get, 'http://localhost:8500/v1/event/list') + .to_return(OpenStruct.new(body: events_json)) + stub_with_token = stub_request(:get, 'http://localhost:8500/v1/event/list') + .with(headers: { 'X-Consul-Token' => acl_token }) + .to_return(OpenStruct.new(body: events_json)) + Diplomat.configuration.acl_token = nil - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.get_all + expect(stub_without_token).to have_been_requested + expect(stub_with_token).not_to have_been_requested end it 'token specified' do - expect(faraday).to receive(:get).with("/v1/event/list?token=#{acl_token}") + stub_request(:get, 'http://localhost:8500/v1/event/list') + .with(headers: { 'X-Consul-Token' => acl_token }).to_return(OpenStruct.new(body: events_json)) Diplomat.configuration.acl_token = acl_token - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.get_all end end describe 'GET' do - before do - allow(faraday).to receive(:get).and_return(OpenStruct.new(body: events_json)) - end - it 'token empty' do - expect(faraday).to receive(:get).with('/v1/event/list') + stub_without_token = stub_request(:get, 'http://localhost:8500/v1/event/list') + .to_return(OpenStruct.new(body: events_json)) + stub_with_token = stub_request(:get, 'http://localhost:8500/v1/event/list') + .with(headers: { 'X-Consul-Token' => acl_token }) + .to_return(OpenStruct.new(body: events_json)) Diplomat.configuration.acl_token = nil - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.get + expect(stub_without_token).to have_been_requested + expect(stub_with_token).not_to have_been_requested end it 'token specified' do - expect(faraday).to receive(:get).with("/v1/event/list?token=#{acl_token}") + stub_request(:get, 'http://localhost:8500/v1/event/list') + .with(headers: { 'X-Consul-Token' => acl_token }).to_return(OpenStruct.new(body: events_json)) Diplomat.configuration.acl_token = acl_token - ev = Diplomat::Event.new(faraday) + ev = Diplomat::Event.new ev.get end diff --git a/spec/kv_spec.rb b/spec/kv_spec.rb index 24dfcbb..f23337f 100644 --- a/spec/kv_spec.rb +++ b/spec/kv_spec.rb @@ -14,10 +14,9 @@ describe '#get' do context 'Datacenter filter' do it 'GET' do - faraday.double - kv = Diplomat::Kv.new(faraday) - expect(faraday).to receive(:get).with(/dc=bar/) - .and_return(OpenStruct.new(status: 200, body: JSON.generate([]))) + kv = Diplomat::Kv.new + stub_request(:get, 'http://localhost:8500/v1/kv/foo?dc=bar') + .to_return(OpenStruct.new(status: 200, body: JSON.generate([]))) kv.get('foo', dc: 'bar') end end @@ -417,10 +416,9 @@ context 'ACLs NOT enabled, recurse option ON' do it 'DELETE' do - faraday.double - expect(faraday).to receive(:delete).with(/recurse/).and_return(OpenStruct.new(status: 200)) - - kv = Diplomat::Kv.new(faraday) + stub_request(:delete, 'http://localhost:8500/v1/kv/key?recurse') + .to_return(OpenStruct.new(status: 200)) + kv = Diplomat::Kv.new expect(kv.delete(key, recurse: true).status).to eq(200) end end @@ -577,18 +575,18 @@ end it 'returns a Hash' do - expect(kv.call(valid_transaction, nil)).to be_a_kind_of(OpenStruct) + expect(kv.call(valid_transaction, {})).to be_a_kind_of(OpenStruct) end it 'returns arrays as the values' do - return_values = kv.call(valid_transaction, nil) + return_values = kv.call(valid_transaction, {}) return_values.each_pair do |_, values| expect(values).to be_a_kind_of(Array) end end it 'returns arrays of Hash objects' do - return_values = kv.call(valid_transaction, nil) + return_values = kv.call(valid_transaction, {}) return_values.each_pair do |_, values| values.each do |value| expect(value).to be_a_kind_of(Hash) @@ -627,7 +625,7 @@ end it 'handles a rollback with missing results section' do - expect(rollback_kv.call(valid_transaction, nil).Errors).to eq(rollback_return['Errors']) + expect(rollback_kv.call(valid_transaction, {}).Errors).to eq(rollback_return['Errors']) end end diff --git a/spec/lock_spec.rb b/spec/lock_spec.rb index 2b41887..14560dd 100644 --- a/spec/lock_spec.rb +++ b/spec/lock_spec.rb @@ -70,56 +70,61 @@ context 'with an ACL token configured' do before do - expect(faraday).to receive(:put).and_yield(req).and_return(OpenStruct.new(body: "true\n", status: 200)) Diplomat.configure do |c| c.acl_token = acl_token end end it 'acquire' do - expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&token=#{acl_token}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.acquire('lock/key', session)).to eq(true) end it 'wait_to_acquire' do - expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&token=#{acl_token}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.wait_to_acquire('lock/key', session, 2)).to eq(true) end it 'release' do - expect(req).to receive(:url).with("/v1/kv/lock/key?release=#{session}&token=#{acl_token}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?release=#{session}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.release('lock/key', session).chomp).to eq('true') end it 'acquires with dc option' do - expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&token=#{acl_token}&dc=#{dc}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}&dc=#{dc}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.acquire('lock/key', session, nil, options)).to eq(true) end it 'waits to acquire with dc option' do - expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&token=#{acl_token}&dc=#{dc}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}&dc=#{dc}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.wait_to_acquire('lock/key', session, nil, 2, options)).to eq(true) end it 'releases with dc option' do - expect(req).to receive(:url).with("/v1/kv/lock/key?release=#{session}&token=#{acl_token}&dc=#{dc}") + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?release=#{session}&dc=#{dc}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) - lock = Diplomat::Lock.new(faraday) + lock = Diplomat::Lock.new expect(lock.release('lock/key', session, options).chomp).to eq('true') end diff --git a/spec/maintenance_spec.rb b/spec/maintenance_spec.rb index 04b00c3..ff5dc93 100644 --- a/spec/maintenance_spec.rb +++ b/spec/maintenance_spec.rb @@ -61,41 +61,32 @@ end context 'enable' do - before do - expect(faraday).to receive(:put).and_yield(req).and_return(OpenStruct.new(body: '', status: 200)) - end - it 'enables' do - maintenance = Diplomat::Maintenance.new(faraday) - expect(req).to receive(:url).with('/v1/agent/maintenance?enable=true') + maintenance = Diplomat::Maintenance.new + stub_request(:put, 'http://localhost:8500/v1/agent/maintenance?enable=true') + .to_return(OpenStruct.new(body: '', status: 200)) expect(maintenance.enable(true)).to eq(true) end it 'disables' do - maintenance = Diplomat::Maintenance.new(faraday) - expect(req).to receive(:url).with('/v1/agent/maintenance?enable=false') + maintenance = Diplomat::Maintenance.new + stub_request(:put, 'http://localhost:8500/v1/agent/maintenance?enable=false') + .to_return(OpenStruct.new(body: '', status: 200)) expect(maintenance.enable(false)).to eq(true) end it 'with reason' do - maintenance = Diplomat::Maintenance.new(faraday) - expect(req).to receive(:url).with('/v1/agent/maintenance?enable=true&reason=foobar') + maintenance = Diplomat::Maintenance.new + stub_request(:put, 'http://localhost:8500/v1/agent/maintenance?enable=true&reason=foobar') + .to_return(OpenStruct.new(body: '', status: 200)) expect(maintenance.enable(true, 'foobar')).to eq(true) end it 'with dc' do - maintenance = Diplomat::Maintenance.new(faraday) - expect(req).to receive(:url).with('/v1/agent/maintenance?enable=true&reason=foobar&dc=abc') + maintenance = Diplomat::Maintenance.new + stub_request(:put, 'http://localhost:8500/v1/agent/maintenance?enable=true&reason=foobar&dc=abc') + .to_return(OpenStruct.new(body: '', status: 200)) expect(maintenance.enable(true, 'foobar', dc: 'abc')).to eq(true) end end - - context 'enable raises errors' do - it 'throw error unless 200' do - expect(faraday).to receive(:put).and_yield(req).and_return(OpenStruct.new(body: '', status: 500)) - maintenance = Diplomat::Maintenance.new(faraday) - expect(req).to receive(:url).with('/v1/agent/maintenance?enable=true') - expect { maintenance.enable(true) }.to raise_error(Diplomat::UnknownStatus, 'status 500: ') - end - end end diff --git a/spec/node_spec.rb b/spec/node_spec.rb index 748d9cc..9657ed0 100644 --- a/spec/node_spec.rb +++ b/spec/node_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Diplomat::Node do - let(:faraday) { fake } - context 'nodes' do let(:node_definition) do { @@ -12,14 +10,15 @@ end describe '#register' do - let(:path) { '/v1/catalog/register' } + let(:path) { 'http://localhost:8500/v1/catalog/register' } it 'registers a node' do json = JSON.generate(node_definition) - faraday.stub(:put).with(path, json).and_return(OpenStruct.new(body: '', status: 200)) + stub_request(:put, path) + .with(body: json).and_return(OpenStruct.new(body: '', status: 200)) - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new n = node.register(node_definition) expect(n).to eq(true) @@ -27,14 +26,15 @@ end describe '#deregister' do - let(:path) { '/v1/catalog/deregister' } + let(:path) { 'http://localhost:8500/v1/catalog/deregister' } it 'de-registers a node' do json = JSON.generate(node_definition) - faraday.stub(:put).with(path, json).and_return(OpenStruct.new(body: '', status: 200)) + stub_request(:put, path) + .with(body: json).and_return(OpenStruct.new(body: '', status: 200)) - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new n = node.deregister(node_definition) expect(n).to eq(true) @@ -44,8 +44,8 @@ context 'services' do let(:key) { 'foobar' } - let(:key_url) { "/v1/catalog/node/#{key}" } - let(:all_url) { '/v1/catalog/nodes' } + let(:key_url) { "http://localhost:8500/v1/catalog/node/#{key}" } + let(:all_url) { 'http://localhost:8500/v1/catalog/nodes' } let(:body_all) do [ { @@ -82,7 +82,7 @@ } } end - let(:all_with_dc_url) { '/v1/catalog/nodes?dc=dc1' } + let(:all_with_dc_url) { 'http://localhost:8500/v1/catalog/nodes?dc=dc1' } let(:body_all_with_dc) do [ { @@ -96,18 +96,18 @@ it 'lists all the nodes' do json = JSON.generate(body_all) - faraday.stub(:get).with(all_url).and_return(OpenStruct.new(body: json)) + stub_request(:get, all_url).and_return(OpenStruct.new(body: json)) - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new expect(node.get_all.size).to eq(2) end it 'lists all the nodes' do json = JSON.generate(body_all_with_dc) - faraday.stub(:get).with(all_with_dc_url).and_return(OpenStruct.new(body: json)) + stub_request(:get, all_with_dc_url).and_return(OpenStruct.new(body: json)) - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new expect(node.get_all(dc: 'dc1').size).to eq(1) end end @@ -116,8 +116,8 @@ let(:cn) do json = JSON.generate(body) Diplomat.configuration.acl_token = nil - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json)) - node = Diplomat::Node.new(faraday) + stub_request(:get, key_url).and_return(OpenStruct.new(body: json)) + node = Diplomat::Node.new node.get('foobar') end @@ -136,27 +136,23 @@ let(:acl_token) { 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f1' } describe 'GET' do - # Stub Faraday's get method and return valid '{}' empty json for each parameter - before do - allow(faraday).to receive(:get).and_return(OpenStruct.new(body: '{}')) - end - # Verify that URL passed to Faraday is without token it 'token empty' do - expect(faraday).to receive(:get).with("/v1/catalog/node/#{node_name}") + stub_request(:get, "http://localhost:8500/v1/catalog/node/#{node_name}").and_return(OpenStruct.new(body: '{}')) Diplomat.configuration.acl_token = nil - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new node.get(node_name) end # Verify that URL passed to Faraday has token from Diplomat.configuration.acl_token it 'token specified' do - expect(faraday).to receive(:get).with("/v1/catalog/node/#{node_name}?token=#{acl_token}") + stub_request(:get, "http://localhost:8500/v1/catalog/node/#{node_name}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: '{}')) Diplomat.configuration.acl_token = acl_token - node = Diplomat::Node.new(faraday) + node = Diplomat::Node.new node.get(node_name) end diff --git a/spec/nodes_spec.rb b/spec/nodes_spec.rb index 156bf5c..3ecac23 100644 --- a/spec/nodes_spec.rb +++ b/spec/nodes_spec.rb @@ -12,7 +12,7 @@ } ] end - let(:all_datacenter_url) { "/v1/catalog/nodes?dc=#{datacenter}" } + let(:all_datacenter_url) { "http://localhost:8500/v1/catalog/nodes?dc=#{datacenter}" } context 'nodes' do it 'GET' do @@ -39,9 +39,9 @@ it 'GET ALL' do json = JSON.generate(datacenter_body_all) - faraday.stub(:get).with(all_datacenter_url).and_return(OpenStruct.new(body: json)) + stub_request(:get, all_datacenter_url).and_return(OpenStruct.new(body: json)) - nodes = Diplomat::Nodes.new(faraday) + nodes = Diplomat::Nodes.new options = { dc: 'us-west2' } expect(nodes.get_all(options).size).to eq(1) end diff --git a/spec/service_spec.rb b/spec/service_spec.rb index d8d74f0..596a77b 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -1,17 +1,15 @@ require 'spec_helper' describe Diplomat::Service do - let(:faraday) { fake } - context 'services' do let(:key) { 'toast' } - let(:key_url) { "/v1/catalog/service/#{key}" } - let(:key_url_with_alloptions) { "/v1/catalog/service/#{key}?wait=5m&index=3&dc=somedc" } - let(:key_url_with_indexoption) { "/v1/catalog/service/#{key}?index=5" } - let(:key_url_with_waitoption) { "/v1/catalog/service/#{key}?wait=6s" } - let(:key_url_with_datacenteroption) { "/v1/catalog/service/#{key}?dc=somedc" } - let(:key_url_with_tagoption) { "/v1/catalog/service/#{key}?tag=sometag" } - let(:services_url_with_datacenteroption) { '/v1/catalog/services?dc=somedc' } + let(:key_url) { "http://localhost:8500/v1/catalog/service/#{key}" } + let(:key_url_with_indexoption) { "http://localhost:8500/v1/catalog/service/#{key}?index=5" } + let(:key_url_with_waitoption) { "http://localhost:8500/v1/catalog/service/#{key}?wait=6s" } + let(:key_url_with_alloptions) { "http://localhost:8500/v1/catalog/service/#{key}?wait=5m&index=3&dc=somedc" } + let(:key_url_with_datacenteroption) { "http://localhost:8500/v1/catalog/service/#{key}?dc=somedc" } + let(:key_url_with_tagoption) { "http://localhost:8500/v1/catalog/service/#{key}?tag=sometag" } + let(:services_url_with_datacenteroption) { 'http://localhost:8500/v1/catalog/services?dc=somedc' } let(:body) do [ { @@ -32,12 +30,6 @@ } ] end - let(:body_all) do - { - service1: ['tag one', 'tag two', 'tag three'], - service2: ['tag four'] - } - end let(:headers) do { 'x-consul-index' => '8', @@ -45,56 +37,48 @@ 'x-consul-lastcontact' => '0' } end - - # Do not use ACL tokens for basic service tests + let(:body_all) do + { + service1: ['tag one', 'tag two', 'tag three'], + service2: ['tag four'] + } + end before do Diplomat.configuration.acl_token = nil end - describe 'GET' do it ':first' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url) + .to_return(OpenStruct.new(body: json)) + service = Diplomat::Service.new expect(service.get('toast').Node).to eq('foo') end - it ':all' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url) + .to_return(OpenStruct.new(body: json)) + service = Diplomat::Service.new expect(service.get('toast', :all).size).to eq(2) expect(service.get('toast', :all).first.Node).to eq('foo') end end - describe 'GET With Options' do it 'empty headers' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json, headers: nil)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url) + .to_return(OpenStruct.new(body: json, headers: nil)) + service = Diplomat::Service.new meta = {} s = service.get('toast', :first, {}, meta) expect(s.Node).to eq('foo') expect(meta.length).to eq(0) end - it 'filled headers' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new meta = {} s = service.get('toast', :first, {}, meta) expect(s.Node).to eq('foo') @@ -105,11 +89,9 @@ it 'index option' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url_with_indexoption).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url_with_indexoption) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new options = { index: '5' } s = service.get('toast', :first, options) expect(s.Node).to eq('foo') @@ -117,11 +99,9 @@ it 'wait option' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url_with_waitoption).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url_with_waitoption) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new options = { wait: '6s' } s = service.get('toast', :first, options) expect(s.Node).to eq('foo') @@ -129,34 +109,27 @@ it 'datacenter option' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url_with_datacenteroption).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url_with_datacenteroption) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new options = { dc: 'somedc' } s = service.get('toast', :first, options) expect(s.Node).to eq('foo') end it 'bad datacenter option' do - faraday = double - - allow(faraday).to receive(:get) - .with(key_url_with_datacenteroption) - .and_raise(Faraday::ClientError.new({}, 500)) - - service = Diplomat::Service.new(faraday) + stub_request(:get, key_url_with_datacenteroption) + .to_return(status: [500, 'Internal Server Error']) + service = Diplomat::Service.new options = { dc: 'somedc' } expect { service.get('toast', :first, options) }.to raise_error(Diplomat::PathNotFound) end it 'tag option' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url_with_tagoption).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) + stub_request(:get, key_url_with_tagoption) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new options = { tag: 'sometag' } s = service.get('toast', :first, options) expect(s.Node).to eq('foo') @@ -164,11 +137,9 @@ it 'all options' do json = JSON.generate(body) - - faraday.stub(:get).with(key_url_with_alloptions).and_return(OpenStruct.new(body: json, headers: headers)) - - service = Diplomat::Service.new(faraday) - + stub_request(:get, key_url_with_alloptions) + .to_return(OpenStruct.new(body: json, headers: headers)) + service = Diplomat::Service.new options = { wait: '5m', index: '3', dc: 'somedc' } s = service.get('toast', :first, options) expect(s.Node).to eq('foo') @@ -181,10 +152,9 @@ it 'lists all the services for the default datacenter' do json = JSON.generate(body_all) - - faraday.stub(:get).and_return(OpenStruct.new(body: json)) - - service = Diplomat::Service.new(faraday) + stub_request(:get, 'http://localhost:8500/v1/catalog/services') + .to_return(OpenStruct.new(body: json)) + service = Diplomat::Service.new expect(service.get_all.service1).to be_an(Array) expect(service.get_all.service2).to be_an(Array) expect(service.get_all.service1.first).to eq(service_one_tag) @@ -192,11 +162,10 @@ end it 'lists all the services for the specified datacenter' do json = JSON.generate(body_all) - - faraday.stub(:get).with(services_url_with_datacenteroption).and_return(OpenStruct.new(body: json)) - + stub_request(:get, services_url_with_datacenteroption) + .to_return(OpenStruct.new(body: json)) options = { dc: 'somedc' } - service = Diplomat::Service.new(faraday) + service = Diplomat::Service.new expect(service.get_all(options).service1).to be_an(Array) expect(service.get_all(options).service2).to be_an(Array) expect(service.get_all(options).service1.first).to eq(service_one_tag) @@ -205,8 +174,8 @@ end describe 'Register service' do - let(:register_service_url) { '/v1/agent/service/register' } - let(:deregister_service_url) { '/v1/agent/service/deregister' } + let(:register_service_url) { 'http://localhost:8500/v1/agent/service/register' } + let(:deregister_service_url) { 'http://localhost:8500/v1/agent/service/deregister' } let(:token) { '80a6200c-6ec9-42e1-816a-e40007e732a6' } let(:service_definition) do { @@ -220,44 +189,39 @@ it 'can register a service' do json_request = JSON.dump(service_definition) - - expect(faraday).to receive(:put).with(register_service_url, json_request) do - OpenStruct.new(body: '', status: 200) - end - - service = Diplomat::Service.new(faraday) + stub_request(:put, register_service_url) + .with(body: json_request).to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new s = service.register(service_definition) expect(s).to eq(true) end it 'can register a service with a token' do json_request = JSON.dump(service_definition) - - expect(faraday).to receive(:put).with("#{register_service_url}?token=#{token}", json_request) do - OpenStruct.new(body: '', status: 200) - end + stub_request(:put, register_service_url) + .with(body: json_request, headers: { 'X-Consul-Token' => token }) + .to_return(OpenStruct.new(body: '', status: 200)) Diplomat.configure do |config| config.acl_token = token end - service = Diplomat::Service.new(faraday) + service = Diplomat::Service.new s = service.register(service_definition) expect(s).to eq(true) end it 'can deregister a service' do url = "#{deregister_service_url}/#{service_definition[:name]}" - expect(faraday).to receive(:put).with(url) do - OpenStruct.new(body: '', status: 200) - end - service = Diplomat::Service.new(faraday) + stub_request(:put, url) + .to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new s = service.deregister(service_definition[:name]) expect(s).to eq(true) end end describe 'Register external service' do - let(:register_service_url) { '/v1/catalog/register' } - let(:deregister_service_url) { '/v1/catalog/deregister' } + let(:register_service_url) { 'http://localhost:8500/v1/catalog/register' } + let(:deregister_service_url) { 'http://localhost:8500/v1/catalog/deregister' } let(:service_definition) do { @@ -280,23 +244,18 @@ it 'can register a service' do json_request = JSON.dump(service_definition) - - expect(faraday).to receive(:put).with(register_service_url, json_request) do - OpenStruct.new(body: '', status: 200) - end - - service = Diplomat::Service.new(faraday) + stub_request(:put, register_service_url) + .with(body: json_request).to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new s = service.register_external(service_definition) expect(s).to eq(true) end it 'can deregister a service' do json_request = JSON.dump(deregister_definition) - expect(faraday).to receive(:put).with(deregister_service_url, json_request) do - OpenStruct.new(body: '', status: 200) - end - - service = Diplomat::Service.new(faraday) + stub_request(:put, deregister_service_url) + .with(body: json_request).to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new s = service.deregister_external(deregister_definition) expect(s).to eq(true) end @@ -304,15 +263,16 @@ describe '#maintenance' do let(:service_id) { 'TEST1' } - let(:enable_url) { '/v1/agent/service/maintenance/TEST1?enable=true' } - let(:disable_url) { '/v1/agent/service/maintenance/TEST1?enable=false' } + let(:enable_url) { 'http://localhost:8500/v1/agent/service/maintenance/TEST1?enable=true' } + let(:disable_url) { 'http://localhost:8500/v1/agent/service/maintenance/TEST1?enable=false' } let(:message_url) { enable_url + '&reason=My+Maintenance+Reason' } context 'when enabling maintenance' do let(:s) do proc do |reason| - expect(faraday).to receive(:put).with(enable_url).and_return(OpenStruct.new(body: '', status: 200)) - service = Diplomat::Service.new(faraday) + stub_request(:put, enable_url) + .to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new service.maintenance(service_id, enable: 'true', reason: reason) end end @@ -327,8 +287,9 @@ it 'adds a reason' do reason = 'My Maintenance Reason' - expect(faraday).to receive(:put).with(message_url).and_return(OpenStruct.new(body: '', status: 200)) - service = Diplomat::Service.new(faraday) + stub_request(:put, message_url) + .to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new s_message = service.maintenance(service_id, enable: 'true', reason: reason) expect(s_message).to eq(true) end @@ -337,8 +298,9 @@ context 'when disabling maintenance' do let(:s) do proc do - expect(faraday).to receive(:put).with(disable_url).and_return(OpenStruct.new(body: '', status: 200)) - service = Diplomat::Service.new(faraday) + stub_request(:put, disable_url) + .to_return(OpenStruct.new(body: '', status: 200)) + service = Diplomat::Service.new service.maintenance(service_id, enable: 'false') end end @@ -355,53 +317,63 @@ end context 'acl' do - let(:acl_token) { 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f1' } - + let(:acl_token_1) { 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f1' } + let(:acl_token_2) { 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f2' } describe 'GET' do let(:service_name) { 'toast' } - - before do - allow(faraday).to receive(:get).and_return(OpenStruct.new(body: '{}')) - end - it 'token empty' do - expect(faraday).to receive(:get).with("/v1/catalog/service/#{service_name}") + stub_without_token = stub_request(:get, "http://localhost:8500/v1/catalog/service/#{service_name}") + .to_return(OpenStruct.new(body: '{}')) + stub_with_token = stub_request(:get, "http://localhost:8500/v1/catalog/service/#{service_name}") + .with(headers: { 'X-Consul-Token' => acl_token_1 }).to_return(OpenStruct.new(body: '{}')) Diplomat.configuration.acl_token = nil - service = Diplomat::Service.new(faraday) - + service = Diplomat::Service.new service.get(service_name) + expect(stub_without_token).to have_been_requested + expect(stub_with_token).not_to have_been_requested end - - it 'token specified' do - expect(faraday).to receive(:get).with("/v1/catalog/service/#{service_name}?token=#{acl_token}") - Diplomat.configuration.acl_token = acl_token - service = Diplomat::Service.new(faraday) - + it 'token specified in configuration' do + stub_request(:get, "http://localhost:8500/v1/catalog/service/#{service_name}") + .with(headers: { 'X-Consul-Token' => acl_token_1 }).to_return(OpenStruct.new(body: '{}')) + Diplomat.configuration.acl_token = acl_token_1 + service = Diplomat::Service.new service.get(service_name) end + it 'token specified in method call' do + stub_request(:get, "http://localhost:8500/v1/catalog/service/#{service_name}") + .with(headers: { 'X-Consul-Token' => acl_token_2 }).to_return(OpenStruct.new(body: '{}')) + Diplomat.configuration.acl_token = acl_token_1 + service = Diplomat::Service.new + service.get(service_name, :first, token: acl_token_2) + end end - describe 'GET_ALL' do - before do - allow(faraday).to receive(:get).and_return(OpenStruct.new(body: '{}')) - end - + let(:service_name) { 'toast' } it 'token empty' do - expect(faraday).to receive(:get).with('/v1/catalog/services') + stub_without_token = stub_request(:get, 'http://localhost:8500/v1/catalog/services') + .to_return(OpenStruct.new(body: '{}')) + stub_with_token = stub_request(:get, 'http://localhost:8500/v1/catalog/services') + .with(headers: { 'X-Consul-Token' => acl_token_1 }).to_return(OpenStruct.new(body: '{}')) Diplomat.configuration.acl_token = nil - service = Diplomat::Service.new(faraday) - + service = Diplomat::Service.new service.get_all + expect(stub_without_token).to have_been_requested + expect(stub_with_token).not_to have_been_requested end - - it 'token specified' do - expect(faraday).to receive(:get).with("/v1/catalog/services?token=#{acl_token}") - - Diplomat.configuration.acl_token = acl_token - service = Diplomat::Service.new(faraday) - + it 'token specified in configuration' do + stub_request(:get, 'http://localhost:8500/v1/catalog/services') + .with(headers: { 'X-Consul-Token' => acl_token_1 }).to_return(OpenStruct.new(body: '{}')) + Diplomat.configuration.acl_token = acl_token_1 + service = Diplomat::Service.new service.get_all end + it 'token specified in method call' do + stub_request(:get, 'http://localhost:8500/v1/catalog/services') + .with(headers: { 'X-Consul-Token' => acl_token_2 }).to_return(OpenStruct.new(body: '{}')) + Diplomat.configuration.acl_token = acl_token_1 + service = Diplomat::Service.new + service.get_all(token: acl_token_2) + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 16c8ec0..346c4e2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,6 +11,7 @@ require 'diplomat' require 'fakes-rspec' +require 'webmock/rspec' RSpec.configure do |config| config.run_all_when_everything_filtered = true From 588eaf04d29ab8cecf25dd16401b1fdf63d26c08 Mon Sep 17 00:00:00 2001 From: Brandon Burnett Date: Wed, 6 Mar 2019 20:40:04 +0000 Subject: [PATCH 35/45] Adding support for KV flags during lock acquisition. --- lib/diplomat/lock.rb | 4 ++++ spec/lock_spec.rb | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/lib/diplomat/lock.rb b/lib/diplomat/lock.rb index 2b168b1..c9f0ad8 100644 --- a/lib/diplomat/lock.rb +++ b/lib/diplomat/lock.rb @@ -13,6 +13,7 @@ def acquire(key, session, value = nil, options = {}) custom_params = [] custom_params << use_named_parameter('acquire', session) custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << use_named_parameter('flags', options[:flags]) if options && options[:flags] data = value unless value.nil? raw = send_put_request(@conn, ["/v1/kv/#{key}"], options, data, custom_params) raw.body.chomp == 'true' @@ -39,12 +40,15 @@ def wait_to_acquire(key, session, value = nil, check_interval = 10, options = {} # @param session [String] the session, generated from Diplomat::Session.create # @param options [Hash] :dc string for dc specific query # @return [nil] + # rubocop:disable AbcSize def release(key, session, options = {}) custom_params = [] custom_params << use_named_parameter('release', session) custom_params << use_named_parameter('dc', options[:dc]) if options[:dc] + custom_params << use_named_parameter('flags', options[:flags]) if options && options[:flags] raw = send_put_request(@conn, ["/v1/kv/#{key}"], options, nil, custom_params) raw.body end + # rubocop:enable AbcSize end end diff --git a/spec/lock_spec.rb b/spec/lock_spec.rb index 14560dd..4519115 100644 --- a/spec/lock_spec.rb +++ b/spec/lock_spec.rb @@ -8,7 +8,9 @@ let(:session) { 'fc5ca01a-c317-39ea-05e8-221da00d3a12' } let(:acl_token) { 'f45cbd0b-5022-47ab-8640-4eaa7c1f40f1' } let(:dc) { 'some-dc' } + let(:flags) { 123 } let(:options) { { dc: dc } } + let(:options_flags) { { flags: 123 } } context 'lock' do context 'without an ACL token configured' do @@ -66,6 +68,30 @@ expect(lock.release('lock/key', session, options).chomp).to eq('true') end + + it 'acquires with flags option' do + expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&flags=#{flags}") + + lock = Diplomat::Lock.new(faraday) + + expect(lock.acquire('lock/key', session, nil, options_flags)).to eq(true) + end + + it 'waits to acquire with flags option' do + expect(req).to receive(:url).with("/v1/kv/lock/key?acquire=#{session}&flags=#{flags}") + + lock = Diplomat::Lock.new(faraday) + + expect(lock.wait_to_acquire('lock/key', session, nil, 2, options_flags)).to eq(true) + end + + it 'releases with flags option' do + expect(req).to receive(:url).with("/v1/kv/lock/key?release=#{session}&flags=#{flags}") + + lock = Diplomat::Lock.new(faraday) + + expect(lock.release('lock/key', session, options_flags).chomp).to eq('true') + end end context 'with an ACL token configured' do @@ -128,6 +154,34 @@ expect(lock.release('lock/key', session, options).chomp).to eq('true') end + + it 'acquires with flags option' do + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}&flags=#{flags}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) + puts "/v1/kv/lock/key?acquire=#{session}&flags=#{flags}" + + lock = Diplomat::Lock.new + + expect(lock.acquire('lock/key', session, nil, options_flags)).to eq(true) + end + + it 'waits to acquire with flags option' do + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}&flags=#{flags}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) + + lock = Diplomat::Lock.new + + expect(lock.wait_to_acquire('lock/key', session, nil, 2, options_flags)).to eq(true) + end + + it 'releases with flags option' do + stub_request(:put, "http://localhost:8500/v1/kv/lock/key?release=#{session}&flags=#{flags}") + .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) + + lock = Diplomat::Lock.new + + expect(lock.release('lock/key', session, options_flags).chomp).to eq('true') + end end end end From 0880966f000622ea56483fcb75bd9fe4c20bbc15 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Fri, 15 Mar 2019 20:00:27 +0100 Subject: [PATCH 36/45] Avoid having a HTTP 302 if key requested starts with '/' (#181) * Avoid having a HTTP 302 if key requested starts with '/' This might fix: https://github.com/WeAreFarmGeek/diplomat/issues/171 * Fixed rubocop warning --- lib/diplomat/kv.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index cd982d5..31cc80e 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -40,9 +40,14 @@ class Kv < Diplomat::RestClient # - W R - get the first or current value; always return something, but # block only when necessary # - W W - get the first or next value; wait until there is an update - # rubocop:disable PerceivedComplexity, LineLength, CyclomaticComplexity + # rubocop:disable PerceivedComplexity, MethodLength, LineLength, CyclomaticComplexity def get(key, options = {}, not_found = :reject, found = :return) - @key = key + key_subst = if key.start_with? '/' + key[1..-1] + else + key.freeze + end + @key = key_subst @options = options custom_params = [] custom_params << recurse_get(@options) @@ -95,7 +100,7 @@ def get(key, options = {}, not_found = :reject, found = :return) @raw = parse_body return_value(return_nil_values, transformation) end - # rubocop:enable PerceivedComplexity, LineLength, CyclomaticComplexity + # rubocop:enable PerceivedComplexity, LineLength, MethodLength, CyclomaticComplexity # Associate a value with a key # @param key [String] the key From f9317281bda4cd157e750c3d5e5606a4cee963c5 Mon Sep 17 00:00:00 2001 From: Nicolas BENOIT Date: Fri, 15 Mar 2019 18:59:00 +0100 Subject: [PATCH 37/45] Add some options example in the documentation --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index ac31a9d..d592442 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,14 @@ foo = Diplomat::Kv.get('foo') ``` Or retrieve a value from another datacenter: + ```ruby foo = Diplomat::Kv.get('foo', :dc => 'dc-west') # => "baz" ``` You can also retrieve values recursively: + ```ruby Diplomat::Kv.put('foo/a', 'lorem') Diplomat::Kv.put('foo/b', 'ipsum') @@ -94,6 +96,7 @@ Or list all available keys: Diplomat::Kv.get('/', :keys => true) # => ['foo/a', 'foo/b'] ``` You can convert the consul data to a ruby hash + ```ruby Diplomat::Kv.put('foo/a', 'lorem') Diplomat::Kv.put('foo/b', 'ipsum') @@ -325,6 +328,12 @@ Diplomat::Service.get('foo', { http_addr: 'http://consu02:8500' }) Diplomat::Kv.put('key/path', 'value', { http_addr: 'http://localhost:8500', dc: 'dc1', token: '111-222-333-444-555' }) ``` +Most common options are: +* dc: target datacenter +* token: identity used to perform the corresponding action +* http_addr: to target a remote consul node +* stale: use consistency mode that allows any server to service the read regardless of whether it is the leader + ### Todo - [ ] Updating Docs with latest changes From bf5a26b9e9823b72b9bd4cb47ceba4fc1526e210 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Mon, 18 Mar 2019 11:25:20 +0100 Subject: [PATCH 38/45] Changelog for release 2.1.0 This release cleanup a lot the existing APIs while preserving ascending compatibility. It will avoid relying on side effects to configure diplomat and allow to override most configuration options per API call as implemented in https://github.com/WeAreFarmGeek/diplomat/pull/179. It is now easy to use one instance of the lib and to perform several calls with different tokens and/or consistency options for instance. --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e18cd5..8855244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,20 @@ ## Next -- use dedup for safer/simpler conversion of results to hash https://github.com/WeAreFarmGeek/diplomat/pull/176 +## 2.1.0 + +This release cleanup a lot the existing APIs while preserving ascending compatibility. +It will avoid relying on side effects to configure diplomat and allow to override most +configuration options per API call as implemented in https://github.com/WeAreFarmGeek/diplomat/pull/179. +It is now easy to use one instance of the lib and to perform several calls with different tokens and/or +consistency options for instance. + +Full changelog: + +- Fix behavior of HTTP 302 on some 2.5 ruby releases (#181 fix #171) +- Set flags attribute on KVPair during lock acquisition and release (#180) +- Now allow to override most parameters per request (#179) +- use dedup for safer/simpler conversion of results to hash #176 ## 2.0.5 From 5297bb9ec245774f750ba9accf4b5904bf0c1479 Mon Sep 17 00:00:00 2001 From: ori bracha Date: Tue, 19 Mar 2019 10:57:26 +0200 Subject: [PATCH 39/45] fix syntax error colon instead of => --- lib/diplomat/rest_client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index 8795de9..cc54014 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -177,8 +177,8 @@ def parse_options(options) consistency = [] # Parse options used as header - headers = { 'X-Consul-Token': configuration.acl_token } if configuration.acl_token - headers = { 'X-Consul-Token': options[:token] } if options[:token] + headers = { 'X-Consul-Token' => configuration.acl_token } if configuration.acl_token + headers = { 'X-Consul-Token' => options[:token] } if options[:token] # Parse options used as query params consistency = 'stale' if options[:stale] From d415447fd9590156cb76a5081327052be31a5543 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 19 Mar 2019 12:03:12 +0100 Subject: [PATCH 40/45] BUGFIX release 2.1.1, fixes #186 using #185 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8855244..526295b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Next +## 2.1.1 + +Bugfix release. + +- Fix for #186 + ## 2.1.0 This release cleanup a lot the existing APIs while preserving ascending compatibility. From 8458296533efc7dab0aa00bed827d22ad86628b2 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 19 Mar 2019 13:10:17 +0100 Subject: [PATCH 41/45] Bump version number to 2.1.1 --- lib/diplomat/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index 0a862d5..22a9b47 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.1.0'.freeze + VERSION = '2.1.1'.freeze end From fc22b27c2d0d13ae95cde79f4f9520676f71f754 Mon Sep 17 00:00:00 2001 From: Nicolas BENOIT Date: Tue, 19 Mar 2019 17:37:09 +0100 Subject: [PATCH 42/45] Fix raw data usage in kv As every data was converted to json, raw data usage was impossible Reverting all json conversion to source function and remove systematic conversion. Fixes: #187 --- lib/diplomat/acl.rb | 4 ++-- lib/diplomat/check.rb | 12 ++++++------ lib/diplomat/kv.rb | 2 +- lib/diplomat/node.rb | 4 ++-- lib/diplomat/query.rb | 2 +- lib/diplomat/rest_client.rb | 2 +- lib/diplomat/service.rb | 4 ++-- spec/lock_spec.rb | 7 +++++-- spec/service_spec.rb | 2 +- 9 files changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/diplomat/acl.rb b/lib/diplomat/acl.rb index ddd25fc..f9b15aa 100644 --- a/lib/diplomat/acl.rb +++ b/lib/diplomat/acl.rb @@ -54,7 +54,7 @@ def update(value, options = {}) raise Diplomat::IdParameterRequired unless value['ID'] || value[:ID] custom_params = use_cas(@options) - @raw = send_put_request(@conn, ['/v1/acl/update'], options, value, custom_params) + @raw = send_put_request(@conn, ['/v1/acl/update'], options, value.to_json, custom_params) parse_body end @@ -64,7 +64,7 @@ def update(value, options = {}) # @return [Hash] The result Acl def create(value, options = {}) custom_params = use_cas(@options) - @raw = send_put_request(@conn, ['/v1/acl/create'], options, value, custom_params) + @raw = send_put_request(@conn, ['/v1/acl/create'], options, value.to_json, custom_params) parse_body end diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index 26cf072..dc2653f 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -25,13 +25,13 @@ def register_script(check_id, name, notes, args, interval, options = {}) raise(Diplomat::DeprecatedArgument, 'Script usage is deprecated, replace by an array of args') end - definition = { + definition = JSON.generate( 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'Args' => args, 'Interval' => interval - } + ) ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition) ret.status == 200 end @@ -45,12 +45,12 @@ def register_script(check_id, name, notes, args, interval, options = {}) # @param options [Hash] options parameter hash # @return [Boolean] Success def register_ttl(check_id, name, notes, ttl, options = {}) - definition = { + definition = JSON.generate( 'ID' => check_id, 'Name' => name, 'Notes' => notes, 'TTL' => ttl - } + ) ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition) ret.status == 200 end @@ -71,10 +71,10 @@ def deregister(check_id, options = {}) # @param options [Hash] options parameter hash # @return [Integer] Status code def update_ttl(check_id, status, output = nil, options = {}) - definition = { + definition = JSON.generate( 'Status' => status, 'Output' => output - } + ) ret = send_put_request(@conn, ["/v1/agent/check/update/#{check_id}"], options, definition) ret.status == 200 end diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index 31cc80e..5500562 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -167,7 +167,7 @@ def txn(value, options = {}) custom_params = [] custom_params << dc(options) custom_params << transaction_consistency(options) - raw = send_put_request(@conn_no_err, ['/v1/txn'], options, value, custom_params) + raw = send_put_request(@conn_no_err, ['/v1/txn'], options, JSON.generate(value), custom_params) transaction_return JSON.parse(raw.body), options end diff --git a/lib/diplomat/node.rb b/lib/diplomat/node.rb index 720c19c..9fb153a 100644 --- a/lib/diplomat/node.rb +++ b/lib/diplomat/node.rb @@ -27,7 +27,7 @@ def get_all(options = {}) # @param options [Hash] options parameter hash # @return [Boolean] def register(definition, options = {}) - register = send_put_request(@conn, ['/v1/catalog/register'], options, definition) + register = send_put_request(@conn, ['/v1/catalog/register'], options, JSON.dump(definition)) register.status == 200 end @@ -36,7 +36,7 @@ def register(definition, options = {}) # @param options [Hash] options parameter hash # @return [Boolean] def deregister(definition, options = {}) - deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition) + deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, JSON.dump(definition)) deregister.status == 200 end end diff --git a/lib/diplomat/query.rb b/lib/diplomat/query.rb index fba2d0c..a643645 100644 --- a/lib/diplomat/query.rb +++ b/lib/diplomat/query.rb @@ -51,7 +51,7 @@ def delete(key, options = {}) # @return [Boolean] def update(key, definition, options = {}) custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil - ret = send_put_request(@conn, ["/v1/query/#{key}"], options, definition, custom_params) + ret = send_put_request(@conn, ["/v1/query/#{key}"], options, JSON.dump(definition), custom_params) ret.status == 200 end diff --git a/lib/diplomat/rest_client.rb b/lib/diplomat/rest_client.rb index cc54014..087fcc7 100644 --- a/lib/diplomat/rest_client.rb +++ b/lib/diplomat/rest_client.rb @@ -214,7 +214,7 @@ def send_put_request(connection, url, options, data, custom_params = nil) connection.put do |req| req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url) rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil? - req.body = JSON.dump(data) unless data.nil? + req.body = data unless data.nil? end end diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index 5407bae..9d2dbb3 100644 --- a/lib/diplomat/service.rb +++ b/lib/diplomat/service.rb @@ -47,7 +47,7 @@ def get_all(options = {}) # @return [Boolean] def register(definition, options = {}) url = options[:path] || ['/v1/agent/service/register'] - register = send_put_request(@conn, url, options, definition) + register = send_put_request(@conn, url, options, JSON.dump(definition)) register.status == 200 end @@ -74,7 +74,7 @@ def register_external(definition, options = {}) # @param options [Hash] options parameter hash # @return [Boolean] def deregister_external(definition, options = {}) - deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition) + deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, JSON.dump(definition)) deregister.status == 200 end diff --git a/spec/lock_spec.rb b/spec/lock_spec.rb index 4519115..28e582f 100644 --- a/spec/lock_spec.rb +++ b/spec/lock_spec.rb @@ -112,11 +112,14 @@ it 'wait_to_acquire' do stub_request(:put, "http://localhost:8500/v1/kv/lock/key?acquire=#{session}") - .with(headers: { 'X-Consul-Token' => acl_token }).and_return(OpenStruct.new(body: "true\n", status: 200)) + .with( + headers: { 'X-Consul-Token' => acl_token }, + body: '2' + ).and_return(OpenStruct.new(body: "true\n", status: 200)) lock = Diplomat::Lock.new - expect(lock.wait_to_acquire('lock/key', session, 2)).to eq(true) + expect(lock.wait_to_acquire('lock/key', session, '2')).to eq(true) end it 'release' do diff --git a/spec/service_spec.rb b/spec/service_spec.rb index 596a77b..f5968fc 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -247,7 +247,7 @@ stub_request(:put, register_service_url) .with(body: json_request).to_return(OpenStruct.new(body: '', status: 200)) service = Diplomat::Service.new - s = service.register_external(service_definition) + s = service.register_external(json_request) expect(s).to eq(true) end From 5f57ca91bea69371968bdf426a34b9909869f696 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 19 Mar 2019 18:19:04 +0100 Subject: [PATCH 43/45] BUGFIX release 2.1.2 --- CHANGELOG.md | 6 ++++++ lib/diplomat/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 526295b..c9218a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Next +## 2.1.2 + +Bugfix relase: fix #188 + +Release 2.1.0 did break a few things. Ensure more compatibility with 2.0.x + ## 2.1.1 Bugfix release. diff --git a/lib/diplomat/version.rb b/lib/diplomat/version.rb index 22a9b47..301d64a 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.1.1'.freeze + VERSION = '2.1.2'.freeze end From 34c045f096c8b2bd3f7d2a48327d83c8561505aa Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Wed, 4 Oct 2017 13:00:37 +0300 Subject: [PATCH 44/45] Add HTTP check type Adds register_http to access methods and Updated README and Changelog --- CHANGELOG.md | 4 ++++ README.md | 8 ++++++++ lib/diplomat/check.rb | 32 ++++++++++++++++++++++++++++++-- spec/check_spec.rb | 8 ++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9218a3..e880cd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Next +## 2.1.3 + +- 2019-03-20 Lars Remes [lars.remes@ramboll.fi][1] Support HTTP service checks + ## 2.1.2 Bugfix relase: fix #188 diff --git a/README.md b/README.md index d592442..e2350e4 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,14 @@ services = Diplomat::Service.get_all({ :dc => 'My_Datacenter' }) # => # ``` +#### Checks + +Register a check: +```ruby +headers = { "Authorization" => [ "Basic ZGlwbG9tYXQ6cGFzc3dvcmQ=" ] } +Diplomat::Check.register_http("http://#{addr}:#{port}/health_check", '10s', id: 'health-check-1', name: 'Health check', notes: 'Node level HTTP health check', method: 'GET', headers: {}, timeout: '1s') +``` + ### Datacenters Getting a list of datacenters is quite simple and gives you the option to extract all services out of diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index dc2653f..aff3d85 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -1,7 +1,7 @@ module Diplomat # Methods for interacting with the Consul check API endpoint class Check < Diplomat::RestClient - @access_methods = %i[checks register_script register_ttl + @access_methods = %i[checks register_http register_script register_ttl deregister pass warn fail] # Get registered checks @@ -11,7 +11,35 @@ def checks(options = {}) JSON.parse(ret.body) end - # Register a check + # Register a HTTP check + # @param url [string] URL to check + # @param interval [String] frequency (with units) of the check execution, for example, "10s" + # @param id [String] the unique id of the check + # @param name [String] the name + # @param notes [String] notes about the check + # @param method [String] HTTP method to use when checking the url. Default is GET. + # @param headers [Hash] HTTP headers to add to the check call + # @param timeout [String] Timeout for check as string, for example, "1s" + # @return [Integer] Status code + # + def register_http(url, interval, id: nil, name: nil, notes: nil, method: 'GET', headers: nil, timeout: nil) + ret = @conn.put do |req| + req.url '/v1/agent/check/register' + req.body = JSON.generate( + 'ID' => check_id, + 'Name' => name, + 'Notes' => notes, + 'HTTP' => url, + 'Method' => method, + 'Header' => headers, + 'Interval' => interval, + 'Timeout' => timeout + ) + end + ret.status == 200 + end + + # Register a script check # @param check_id [String] the unique id of the check # @param name [String] the name # @param notes [String] notes about the check diff --git a/spec/check_spec.rb b/spec/check_spec.rb index ee40a04..8f63bd2 100644 --- a/spec/check_spec.rb +++ b/spec/check_spec.rb @@ -32,6 +32,14 @@ expect(check.register_script('foobar-1', 'Foobar', 'Foobar test', ['/script/test'], '10s')).to eq(true) end + it 'register_http' do + faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) + check = Diplomat::Check.new(faraday) + expect(check.register_http('localhost', '10s', id: 'foobar-1', name: 'Foobar', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(true) + + expect(check.register_http('localhost', '10x', id: 'foobar-1', name: 'Foobar', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(false) + end + it 'register_ttl' do faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) From 6c3fc6bb562f507072827af4f5059ee42464a6f1 Mon Sep 17 00:00:00 2001 From: Lars Remes Date: Wed, 20 Mar 2019 09:46:26 +0200 Subject: [PATCH 45/45] register_http check name parameter is mandatory --- lib/diplomat/check.rb | 4 ++-- spec/check_spec.rb | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/diplomat/check.rb b/lib/diplomat/check.rb index aff3d85..b7c74fa 100644 --- a/lib/diplomat/check.rb +++ b/lib/diplomat/check.rb @@ -12,17 +12,17 @@ def checks(options = {}) end # Register a HTTP check + # @param name [String] the name of the check # @param url [string] URL to check # @param interval [String] frequency (with units) of the check execution, for example, "10s" # @param id [String] the unique id of the check - # @param name [String] the name # @param notes [String] notes about the check # @param method [String] HTTP method to use when checking the url. Default is GET. # @param headers [Hash] HTTP headers to add to the check call # @param timeout [String] Timeout for check as string, for example, "1s" # @return [Integer] Status code # - def register_http(url, interval, id: nil, name: nil, notes: nil, method: 'GET', headers: nil, timeout: nil) + def register_http(name, url, interval, id: nil, notes: nil, method: 'GET', headers: nil, timeout: nil) ret = @conn.put do |req| req.url '/v1/agent/check/register' req.body = JSON.generate( diff --git a/spec/check_spec.rb b/spec/check_spec.rb index 8f63bd2..ab3d5f4 100644 --- a/spec/check_spec.rb +++ b/spec/check_spec.rb @@ -35,9 +35,13 @@ it 'register_http' do faraday.stub(:put).and_return(OpenStruct.new(body: '', status: 200)) check = Diplomat::Check.new(faraday) - expect(check.register_http('localhost', '10s', id: 'foobar-1', name: 'Foobar', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(true) + expect(check.register_http('Foobar', 'localhost', '10s', id: 'foobar-1', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(true) + end - expect(check.register_http('localhost', '10x', id: 'foobar-1', name: 'Foobar', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(false) + it 'register_http_invalid_params' do + faraday.stub(:put).and_return(OpenStruct.new(body: 'Request decode failed: invalid "interval": time: unknown unit x in duration 10x', status: 400)) + check = Diplomat::Check.new(faraday) + expect(check.register_http('Foobar', 'localhost', '10x', id: 'foobar-1', notes: 'Foobar test' , method: 'GET', headers: {}, timeout: '1s')).to eq(false) end it 'register_ttl' do