From 85628b43576fbfd37b3aa7bf15a3726b983a7f90 Mon Sep 17 00:00:00 2001 From: Nicolas BENOIT Date: Wed, 27 Feb 2019 18:56:25 +0100 Subject: [PATCH] Enable configuration override on each consul api call Using the configs hash target host or token can be different at each call --- diplomat.gemspec | 1 + lib/diplomat/acl.rb | 49 +++---- lib/diplomat/agent.rb | 52 ++----- lib/diplomat/check.rb | 77 +++++----- lib/diplomat/datacenter.rb | 15 +- lib/diplomat/error.rb | 1 + lib/diplomat/event.rb | 63 ++++----- lib/diplomat/health.rb | 53 +++---- lib/diplomat/kv.rb | 65 ++++----- lib/diplomat/lock.rb | 30 ++-- lib/diplomat/maintenance.rb | 18 +-- lib/diplomat/members.rb | 5 +- lib/diplomat/node.rb | 31 ++--- lib/diplomat/nodes.rb | 13 +- lib/diplomat/query.rb | 71 +++------- lib/diplomat/rest_client.rb | 87 +++++++++++- lib/diplomat/service.rb | 90 +++++------- lib/diplomat/session.rb | 64 +++------ lib/diplomat/status.rb | 12 +- lib/diplomat/version.rb | 2 +- spec/acl_spec.rb | 37 +++-- spec/check_spec.rb | 2 +- spec/configure_spec.rb | 4 +- spec/datacenter_spec.rb | 18 +-- spec/event_spec.rb | 49 ++++--- spec/kv_spec.rb | 15 +- spec/lock_spec.rb | 32 +++-- spec/maintenance_spec.rb | 34 ++--- spec/node_spec.rb | 49 +++---- spec/nodes_spec.rb | 7 +- spec/service_spec.rb | 271 ++++++++++++++++-------------------- 31 files changed, 612 insertions(+), 705 deletions(-) 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..a97cb29 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) @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 @@ -38,52 +39,42 @@ def info(id, options = nil, not_found = :reject, found = :return) # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize # 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 = nil) + @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 = nil) + 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 = nil) + 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 = nil) @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..df4c3d7 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 = nil) + 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 = nil) + 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 = nil) + 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 = nil) + 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..b6eed64 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 = nil) + 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 MethodLength, ParameterLists + def register_script(check_id, name, notes, args, interval, options = nil) + 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 MethodLength, 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 = nil) + 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 = nil) + 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 = nil) + 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 = nil) + 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 = nil) + 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 = nil) + update_ttl(check_id, 'critical', output, options) end end end diff --git a/lib/diplomat/datacenter.rb b/lib/diplomat/datacenter.rb index a4808c6..2d886c6 100644 --- a/lib/diplomat/datacenter.rb +++ b/lib/diplomat/datacenter.rb @@ -5,18 +5,19 @@ 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 + # rubocop:disable AbcSize, CyclomaticComplexity + def get(meta = nil, options = nil) + 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 + # rubocop:enable AbcSize, CyclomaticComplexity end 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..1769d63 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 = nil) + 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 @@ -56,14 +57,9 @@ def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil) # 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 = nil) # 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,15 +72,12 @@ 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 @@ -102,6 +95,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 +104,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 MethodLength, CyclomaticComplexity, AbcSize, PerceivedComplexity + def get(name = nil, token = :last, not_found = :wait, found = :return, options = nil) + @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 +115,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 +124,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 +140,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 +150,19 @@ def get(name = nil, token = :last, not_found = :wait, found = :return) token: event_token } end - # rubocop:enable MethodLength, CyclomaticComplexity, AbcSize + # rubocop:enable MethodLength, CyclomaticComplexity, AbcSize, 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 = nil, 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..ae10018 100644 --- a/lib/diplomat/health.rb +++ b/lib/diplomat/health.rb @@ -9,15 +9,11 @@ class Health < Diplomat::RestClient # @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] + custom_params = [] + custom_params << 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 + ret = send_get_request(@conn, ["/v1/health/node/#{n}"], options) JSON.parse(ret.body).map { |node| OpenStruct.new node } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Get service checks @@ -25,15 +21,11 @@ def node(n, options = nil) # @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] + custom_params = [] + custom_params << 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 + ret = send_get_request(@conn, ["/v1/health/checks/#{s}"], options) JSON.parse(ret.body).map { |check| OpenStruct.new check } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # Get service health @@ -41,23 +33,20 @@ def checks(s, options = nil) # @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 + # rubocop:disable PerceivedComplexity, CyclomaticComplexity, AbcSize, MethodLength 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] + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && options[:dc] + custom_params << ['passing'] if options && options[:passing] + custom_params << use_named_parameter('tag', options[:tag]) if options && options[:tag] + custom_params << use_named_parameter('near', options[:near]) if options && 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) JSON.parse(ret.body).map { |service| OpenStruct.new service } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end - # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize + # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize, MethodLength # Get service health # @param s [String] the state ("any", "passing", "warning", or "critical") @@ -65,16 +54,12 @@ def service(s, options = nil) # @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] + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && options[:dc] + custom_params << use_named_parameter('near', options[:near]) if options && 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) JSON.parse(ret.body).map { |status| OpenStruct.new status } - rescue Faraday::ClientError - raise Diplomat::PathNotFound end # rubocop:enable AbcSize diff --git a/lib/diplomat/kv.rb b/lib/diplomat/kv.rb index ed8b654..0f70e16 100644 --- a/lib/diplomat/kv.rb +++ b/lib/diplomat/kv.rb @@ -44,20 +44,17 @@ class Kv < Diplomat::RestClient def get(key, options = nil, 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,11 +85,13 @@ 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 @@ -109,15 +108,11 @@ def get(key, options = nil, not_found = :reject, found = :return) # rubocop:disable MethodLength, AbcSize def put(key, value, options = nil) @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 @@ -135,11 +130,10 @@ def put(key, value, options = nil) def delete(key, options = nil) @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,21 +157,18 @@ 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 + # rubocop:disable MethodLength, AbcSize def txn(value, options = nil) # 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 + # rubocop:enable MethodLength, AbcSize private diff --git a/lib/diplomat/lock.rb b/lib/diplomat/lock.rb index 328c1fe..bc390ba 100644 --- a/lib/diplomat/lock.rb +++ b/lib/diplomat/lock.rb @@ -7,19 +7,15 @@ 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 + custom_params = [] + custom_params << use_named_parameter('acquire', session) + custom_params << use_named_parameter('dc', options[:dc]) if options && 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 @@ -29,7 +25,7 @@ def acquire(key, session, value = nil, options = nil) # @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) acquired = false @@ -46,14 +42,10 @@ def wait_to_acquire(key, session, value = nil, check_interval = 10, options = ni # @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 + custom_params = [] + custom_params << use_named_parameter('release', session) + custom_params << use_named_parameter('dc', options[:dc]) if options && 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..805910b 100644 --- a/lib/diplomat/maintenance.rb +++ b/lib/diplomat/maintenance.rb @@ -7,6 +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' } + # rubocop:disable MethodLength def enabled(n, options = nil) health = Diplomat::Health.new(@conn) result = health.node(n, options) @@ -18,6 +19,7 @@ def enabled(n, options = nil) { enabled: true, reason: result.first['Notes'] } end end + # rubocop:enable MethodLength # Enable or disable maintenance mode. This endpoint only works # on the local agent. @@ -25,21 +27,19 @@ 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 + # rubocop:disable AbcSize, MethodLength 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 + 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 && 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 + # rubocop:enable AbcSize, MethodLength end end diff --git a/lib/diplomat/members.rb b/lib/diplomat/members.rb index 8decfea..078864d 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 = nil) + 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..6c8eb52 100644 --- a/lib/diplomat/node.rb +++ b/lib/diplomat/node.rb @@ -8,46 +8,35 @@ class Node < Diplomat::RestClient # @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 + custom_params = options && 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 + custom_params = options && 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 = nil) + 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 = nil) + 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..284ab77 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 = nil) + 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 + custom_params = options && 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..3d2c34a 100644 --- a/lib/diplomat/query.rb +++ b/lib/diplomat/query.rb @@ -8,58 +8,41 @@ class Query < Diplomat::RestClient # @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 + custom_params = options && 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 + custom_params = options && 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 + # rubocop:disable MethodLength 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 - + custom_params = options && 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 end + # rubocop:enable MethodLength # Delete a prepared query or prepared query template # @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 - + custom_params = options && options[:dc] ? use_named_parameter('dc', options[:dc]) : nil + ret = send_delete_request(@conn, ["/v1/query/#{key}"], options, custom_params) ret.status == 200 end @@ -69,15 +52,8 @@ def delete(key, options = nil) # @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 - + custom_params = options && 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 @@ -91,16 +67,12 @@ def update(key, definition, options = nil) # @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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && options[:dc] + custom_params << use_named_parameter('near', options[:near]) if options && options[:near] + custom_params << use_named_parameter('limit', options[:limit]) if options && 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 @@ -109,14 +81,9 @@ def execute(key, options = nil) # @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 + custom_params = options && 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..bd3df07 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 @@ -161,10 +162,6 @@ 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 @@ -173,6 +170,88 @@ def use_consistency(options) options && options[:consistency] ? [options[:consistency].to_s] : [] end + # rubocop:disable MethodLength, AbcSize, CyclomaticComplexity, PerceivedComplexity + # TODO: Migrate all custom params in options + def parse_options(options) + headers = nil + query_params = [] + url_prefix = nil + consistency = [] + + headers = { 'X-Consul-Token': configuration.acl_token } if configuration.acl_token + + unless options.nil? + # Parse options used as header + 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] + end + { query_params: query_params, headers: headers, url_prefix: url_prefix } + end + # rubocop:enable MethodLength, AbcSize, CyclomaticComplexity, PerceivedComplexity + + # rubocop:disable MethodLength, AbcSize, CyclomaticComplexity + 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 && options[:timeout] + end + rescue Faraday::ClientError => e + raise Diplomat::PathNotFound, e + end + end + # rubocop:enable MethodLength, AbcSize, CyclomaticComplexity + + # rubocop:disable MethodLength, AbcSize, CyclomaticComplexity + 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 + # rubocop:enable MethodLength, AbcSize, CyclomaticComplexity + + # rubocop:disable MethodLength, AbcSize, CyclomaticComplexity + 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 + # rubocop:enable MethodLength, AbcSize, CyclomaticComplexity + + # rubocop:disable MethodLength, AbcSize, CyclomaticComplexity + 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 + # rubocop:enable MethodLength, AbcSize, CyclomaticComplexity + # Mapping for valid key/value store transaction verbs and required parameters # # @return [Hash] valid key/store transaction verbs and required parameters diff --git a/lib/diplomat/service.rb b/lib/diplomat/service.rb index ae2d71c..87949f0 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 + custom_params = [] + custom_params << use_named_parameter('wait', options[:wait]) if options && options[:wait] + custom_params << use_named_parameter('index', options[:index]) if options && options[:index] + custom_params << use_named_parameter('dc', options[:dc]) if options && options[:dc] + custom_params << use_named_parameter('tag', options[:tag]) if options && 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 @@ -48,72 +36,64 @@ def get(key, scope = :first, options = nil, meta = nil) # @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 - + custom_params = options && 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 = nil) + url = options && options[:path] ? 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 = nil) + 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 = nil) + 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 = nil) + 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 + # rubocop:disable MethodLength, AbcSize 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 && options[:reason] + maintenance = send_put_request(@conn, ["/v1/agent/service/maintenance/#{service_id}"], + options, nil, custom_params) maintenance.status == 200 end + # rubocop:enable MethodLength, AbcSize end end diff --git a/lib/diplomat/session.rb b/lib/diplomat/session.rb index 8b053f3..7f0efde 100644 --- a/lib/diplomat/session.rb +++ b/lib/diplomat/session.rb @@ -6,93 +6,71 @@ 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 + # rubocop:disable AbcSize def create(value = nil, options = nil) # 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 && 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 + # rubocop:enable AbcSize # 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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && 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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && 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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && 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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && 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 + custom_params = [] + custom_params << use_named_parameter('dc', options[:dc]) if options && 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..a0d346b 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 = nil) + 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 = nil) + 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..9b4fa96 100644 --- a/lib/diplomat/version.rb +++ b/lib/diplomat/version.rb @@ -1,3 +1,3 @@ module Diplomat - VERSION = '2.0.5'.freeze + VERSION = '3.0.0'.freeze end diff --git a/spec/acl_spec.rb b/spec/acl_spec.rb index cc119e2..c0b4920 100644 --- a/spec/acl_spec.rb +++ b/spec/acl_spec.rb @@ -1,10 +1,9 @@ require 'spec_helper' +require 'webmock/rspec' 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 +48,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 +61,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 +74,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 +88,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 +107,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 +120,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..df4f416 100644 --- a/spec/datacenter_spec.rb +++ b/spec/datacenter_spec.rb @@ -1,12 +1,11 @@ require 'spec_helper' require 'json' require 'base64' +require 'webmock/rspec' 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 +19,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 +32,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 +45,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..76b7e9f 100644 --- a/spec/event_spec.rb +++ b/spec/event_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' require 'json' require 'base64' +require 'webmock/rspec' describe Diplomat::Event do let(:empty_json) { '[]' } @@ -196,61 +197,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..90f7ae7 100644 --- a/spec/kv_spec.rb +++ b/spec/kv_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'webmock/rspec' describe Diplomat::Kv do let(:faraday) { fake } @@ -14,10 +15,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 +417,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 diff --git a/spec/lock_spec.rb b/spec/lock_spec.rb index 2b41887..3a51ed1 100644 --- a/spec/lock_spec.rb +++ b/spec/lock_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' require 'json' require 'base64' +require 'webmock/rspec' describe Diplomat::Lock do let(:faraday) { fake } @@ -70,56 +71,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..fcc2ee8 100644 --- a/spec/maintenance_spec.rb +++ b/spec/maintenance_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'webmock/rspec' describe Diplomat::Maintenance do let(:faraday) { fake } @@ -61,41 +62,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..15f50c2 100644 --- a/spec/node_spec.rb +++ b/spec/node_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' +require 'webmock/rspec' describe Diplomat::Node do - let(:faraday) { fake } - context 'nodes' do let(:node_definition) do { @@ -12,14 +11,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 +27,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 +45,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 +83,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 +97,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 +117,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 +137,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..36b7d19 100644 --- a/spec/nodes_spec.rb +++ b/spec/nodes_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'webmock/rspec' describe Diplomat::Nodes do let(:faraday) { fake } @@ -12,7 +13,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 +40,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..5ca823f 100644 --- a/spec/service_spec.rb +++ b/spec/service_spec.rb @@ -1,17 +1,16 @@ require 'spec_helper' +require 'webmock/rspec' 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 +31,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 +38,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 +90,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 +100,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 +110,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 +138,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 +153,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 +163,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 +175,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 +190,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 +245,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 +264,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 +288,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 +299,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 +318,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