diplomat-blsk 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.md +341 -0
- data/features/configuration.feature +9 -0
- data/features/step_definitions/setup_diplomat.rb +24 -0
- data/features/step_definitions/test_key_value.rb +9 -0
- data/lib/diplomat.rb +62 -0
- data/lib/diplomat/acl.rb +92 -0
- data/lib/diplomat/agent.rb +70 -0
- data/lib/diplomat/api_options.rb +46 -0
- data/lib/diplomat/check.rb +81 -0
- data/lib/diplomat/configuration.rb +28 -0
- data/lib/diplomat/datacenter.rb +22 -0
- data/lib/diplomat/error.rb +14 -0
- data/lib/diplomat/event.rb +177 -0
- data/lib/diplomat/health.rb +101 -0
- data/lib/diplomat/kv.rb +266 -0
- data/lib/diplomat/lock.rb +62 -0
- data/lib/diplomat/maintenance.rb +44 -0
- data/lib/diplomat/members.rb +13 -0
- data/lib/diplomat/node.rb +56 -0
- data/lib/diplomat/nodes.rb +25 -0
- data/lib/diplomat/query.rb +124 -0
- data/lib/diplomat/rest_client.rb +180 -0
- data/lib/diplomat/service.rb +118 -0
- data/lib/diplomat/session.rb +99 -0
- data/lib/diplomat/status.rb +22 -0
- data/lib/diplomat/version.rb +3 -0
- metadata +233 -0
data/lib/diplomat/acl.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul ACL API endpoint
|
3
|
+
class Acl < Diplomat::RestClient
|
4
|
+
include ApiOptions
|
5
|
+
|
6
|
+
@access_methods = %i[list info create destroy update]
|
7
|
+
attr_reader :id, :type, :acl
|
8
|
+
|
9
|
+
# Get Acl info by ID
|
10
|
+
# @param id [String] ID of the Acl to get
|
11
|
+
# @return [Hash]
|
12
|
+
# rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
|
13
|
+
def info(id, options = nil, not_found = :reject, found = :return)
|
14
|
+
@id = id
|
15
|
+
@options = options
|
16
|
+
url = ["/v1/acl/info/#{id}"]
|
17
|
+
url << check_acl_token
|
18
|
+
url << use_consistency(options)
|
19
|
+
|
20
|
+
raw = @conn_no_err.get concat_url url
|
21
|
+
if raw.status == 200 && raw.body.chomp != 'null'
|
22
|
+
case found
|
23
|
+
when :reject
|
24
|
+
raise Diplomat::AclAlreadyExists, id
|
25
|
+
when :return
|
26
|
+
@raw = raw
|
27
|
+
return parse_body
|
28
|
+
end
|
29
|
+
elsif raw.status == 200 && raw.body.chomp == 'null'
|
30
|
+
case not_found
|
31
|
+
when :reject
|
32
|
+
raise Diplomat::AclNotFound, id
|
33
|
+
when :return
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise Diplomat::UnknownStatus, "status #{raw.status}: #{raw.body}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
# rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
|
41
|
+
|
42
|
+
# List all Acls
|
43
|
+
# @return [List] list of [Hash] of Acls
|
44
|
+
def list
|
45
|
+
url = ['/v1/acl/list']
|
46
|
+
url += check_acl_token
|
47
|
+
@raw = @conn_no_err.get concat_url url
|
48
|
+
parse_body
|
49
|
+
end
|
50
|
+
|
51
|
+
# Update an Acl definition, create if not present
|
52
|
+
# @param value [Hash] Acl definition, ID field is mandatory
|
53
|
+
# @return [Hash] The result Acl
|
54
|
+
def update(value)
|
55
|
+
raise Diplomat::IdParameterRequired unless value['ID']
|
56
|
+
|
57
|
+
@raw = @conn.put do |req|
|
58
|
+
url = ['/v1/acl/update']
|
59
|
+
url += check_acl_token
|
60
|
+
url += use_cas(@options)
|
61
|
+
req.url concat_url url
|
62
|
+
req.body = value.to_json
|
63
|
+
end
|
64
|
+
parse_body
|
65
|
+
end
|
66
|
+
|
67
|
+
# Create an Acl definition
|
68
|
+
# @param value [Hash] Acl definition, ID field is mandatory
|
69
|
+
# @return [Hash] The result Acl
|
70
|
+
def create(value)
|
71
|
+
@raw = @conn.put do |req|
|
72
|
+
url = ['/v1/acl/create']
|
73
|
+
url += check_acl_token
|
74
|
+
url += use_cas(@options)
|
75
|
+
req.url concat_url url
|
76
|
+
req.body = value.to_json
|
77
|
+
end
|
78
|
+
parse_body
|
79
|
+
end
|
80
|
+
|
81
|
+
# Destroy an ACl token by its id
|
82
|
+
# @param ID [String] the Acl ID
|
83
|
+
# @return [Bool]
|
84
|
+
def destroy(id)
|
85
|
+
@id = id
|
86
|
+
url = ["/v1/acl/destroy/#{@id}"]
|
87
|
+
url << check_acl_token
|
88
|
+
@raw = @conn.put concat_url url
|
89
|
+
@raw.body.chomp == 'true'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
# Agent API endpoint methods
|
6
|
+
# @see https://www.consul.io/docs/agent/http/agent.html
|
7
|
+
class Agent < Diplomat::RestClient
|
8
|
+
@access_methods = %i[self checks services members]
|
9
|
+
|
10
|
+
# Get agent configuration
|
11
|
+
# @return [OpenStruct] all data associated with the node
|
12
|
+
def self
|
13
|
+
url = ['/v1/agent/self']
|
14
|
+
|
15
|
+
# If the request fails, it's probably due to a bad path
|
16
|
+
# so return a PathNotFound error.
|
17
|
+
begin
|
18
|
+
ret = @conn.get concat_url url
|
19
|
+
rescue Faraday::ClientError
|
20
|
+
raise Diplomat::PathNotFound
|
21
|
+
end
|
22
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get local agent checks
|
26
|
+
# @return [OpenStruct] all agent checks
|
27
|
+
def checks
|
28
|
+
url = ['/v1/agent/checks']
|
29
|
+
|
30
|
+
# If the request fails, it's probably due to a bad path
|
31
|
+
# so return a PathNotFound error.
|
32
|
+
begin
|
33
|
+
ret = @conn.get concat_url url
|
34
|
+
rescue Faraday::ClientError
|
35
|
+
raise Diplomat::PathNotFound
|
36
|
+
end
|
37
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get local agent services
|
41
|
+
# @return [OpenStruct] all agent services
|
42
|
+
def services
|
43
|
+
url = ['/v1/agent/services']
|
44
|
+
|
45
|
+
# If the request fails, it's probably due to a bad path
|
46
|
+
# so return a PathNotFound error.
|
47
|
+
begin
|
48
|
+
ret = @conn.get concat_url url
|
49
|
+
rescue Faraday::ClientError
|
50
|
+
raise Diplomat::PathNotFound
|
51
|
+
end
|
52
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get cluster members (as seen by the agent)
|
56
|
+
# @return [OpenStruct] all members
|
57
|
+
def members
|
58
|
+
url = ['/v1/agent/members']
|
59
|
+
|
60
|
+
# If the request fails, it's probably due to a bad path
|
61
|
+
# so return a PathNotFound error.
|
62
|
+
begin
|
63
|
+
ret = @conn.get concat_url url
|
64
|
+
rescue Faraday::ClientError
|
65
|
+
raise Diplomat::PathNotFound
|
66
|
+
end
|
67
|
+
JSON.parse(ret.body).map { |node| OpenStruct.new node }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Helper methods for interacting with the Consul RESTful API
|
3
|
+
module ApiOptions
|
4
|
+
def check_acl_token
|
5
|
+
use_named_parameter('token', Diplomat.configuration.acl_token)
|
6
|
+
end
|
7
|
+
|
8
|
+
def use_cas(options)
|
9
|
+
options ? use_named_parameter('cas', options[:cas]) : []
|
10
|
+
end
|
11
|
+
|
12
|
+
def use_consistency(options)
|
13
|
+
options && options[:consistency] ? [options[:consistency].to_s] : []
|
14
|
+
end
|
15
|
+
|
16
|
+
# Mapping for valid key/value store transaction verbs and required parameters
|
17
|
+
#
|
18
|
+
# @return [Hash] valid key/store transaction verbs and required parameters
|
19
|
+
# rubocop:disable MethodLength
|
20
|
+
def valid_transaction_verbs
|
21
|
+
{
|
22
|
+
'set' => %w[Key Value],
|
23
|
+
'cas' => %w[Key Value Index],
|
24
|
+
'lock' => %w[Key Value Session],
|
25
|
+
'unlock' => %w[Key Value Session],
|
26
|
+
'get' => %w[Key],
|
27
|
+
'get-tree' => %w[Key],
|
28
|
+
'check-index' => %w[Key Index],
|
29
|
+
'check-session' => %w[Key Session],
|
30
|
+
'delete' => %w[Key],
|
31
|
+
'delete-tree' => %w[Key],
|
32
|
+
'delete-cas' => %w[Key Index]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
# rubocop:enable MethodLength
|
36
|
+
|
37
|
+
# Key/value store transactions that require that a value be set
|
38
|
+
#
|
39
|
+
# @return [Array<String>] verbs that require a value be set
|
40
|
+
def valid_value_transactions
|
41
|
+
@valid_value_transactions ||= valid_transaction_verbs.select do |verb, requires|
|
42
|
+
verb if requires.include? 'Value'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul check API endpoint
|
3
|
+
class Check < Diplomat::RestClient
|
4
|
+
@access_methods = %i[checks register_script register_ttl
|
5
|
+
deregister pass warn fail]
|
6
|
+
|
7
|
+
# Get registered checks
|
8
|
+
# @return [OpenStruct] all data associated with the service
|
9
|
+
def checks
|
10
|
+
ret = @conn.get '/v1/agent/checks'
|
11
|
+
JSON.parse(ret.body)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Register a check
|
15
|
+
# @param check_id [String] the unique id of the check
|
16
|
+
# @param name [String] the name
|
17
|
+
# @param notes [String] notes about the check
|
18
|
+
# @param script [String] command to be run for check
|
19
|
+
# @param interval [String] frequency (with units) of the check execution
|
20
|
+
# @param ttl [String] time (with units) to mark a check down
|
21
|
+
# @return [Integer] Status code
|
22
|
+
#
|
23
|
+
def register_script(check_id, name, notes, script, interval)
|
24
|
+
ret = @conn.put do |req|
|
25
|
+
req.url '/v1/agent/check/register'
|
26
|
+
req.body = JSON.generate(
|
27
|
+
'ID' => check_id, 'Name' => name, 'Notes' => notes, 'Script' => script, 'Interval' => interval
|
28
|
+
)
|
29
|
+
end
|
30
|
+
ret.status == 200
|
31
|
+
end
|
32
|
+
|
33
|
+
# Register a TTL check
|
34
|
+
# @param check_id [String] the unique id of the check
|
35
|
+
# @param name [String] the name
|
36
|
+
# @param notes [String] notes about the check
|
37
|
+
# @param ttl [String] time (with units) to mark a check down
|
38
|
+
# @return [Boolean] Success
|
39
|
+
def register_ttl(check_id, name, notes, ttl)
|
40
|
+
ret = @conn.put do |req|
|
41
|
+
req.url '/v1/agent/check/register'
|
42
|
+
req.body = JSON.generate(
|
43
|
+
'ID' => check_id, 'Name' => name, 'Notes' => notes, 'TTL' => ttl
|
44
|
+
)
|
45
|
+
end
|
46
|
+
ret.status == 200
|
47
|
+
end
|
48
|
+
|
49
|
+
# Deregister a check
|
50
|
+
# @param check_id [String] the unique id of the check
|
51
|
+
# @return [Integer] Status code
|
52
|
+
def deregister(check_id)
|
53
|
+
ret = @conn.get "/v1/agent/check/deregister/#{check_id}"
|
54
|
+
ret.status == 200
|
55
|
+
end
|
56
|
+
|
57
|
+
# Pass a check
|
58
|
+
# @param check_id [String] the unique id of the check
|
59
|
+
# @return [Integer] Status code
|
60
|
+
def pass(check_id)
|
61
|
+
ret = @conn.get "/v1/agent/check/pass/#{check_id}"
|
62
|
+
ret.status == 200
|
63
|
+
end
|
64
|
+
|
65
|
+
# Warn a check
|
66
|
+
# @param check_id [String] the unique id of the check
|
67
|
+
# @return [Integer] Status code
|
68
|
+
def warn(check_id)
|
69
|
+
ret = @conn.get "/v1/agent/check/warn/#{check_id}"
|
70
|
+
ret.status == 200
|
71
|
+
end
|
72
|
+
|
73
|
+
# Warn a check
|
74
|
+
# @param check_id [String] the unique id of the check
|
75
|
+
# @return [Integer] Status code
|
76
|
+
def fail(check_id)
|
77
|
+
ret = @conn.get "/v1/agent/check/fail/#{check_id}"
|
78
|
+
ret.status == 200
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for configuring Diplomat
|
3
|
+
class Configuration
|
4
|
+
attr_reader :middleware
|
5
|
+
attr_accessor :url, :acl_token, :options
|
6
|
+
|
7
|
+
# Override defaults for configuration
|
8
|
+
# @param url [String] consul's connection URL
|
9
|
+
# @param acl_token [String] a connection token used when making requests to consul
|
10
|
+
# @param options [Hash] extra options to configure Faraday::Connection
|
11
|
+
def initialize(url = 'http://localhost:8500', acl_token = nil, options = {})
|
12
|
+
@middleware = []
|
13
|
+
@url = url
|
14
|
+
@acl_token = acl_token
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
18
|
+
# Define a middleware for Faraday
|
19
|
+
# @param middleware [Class] Faraday Middleware class
|
20
|
+
def middleware=(middleware)
|
21
|
+
if middleware.is_a? Array
|
22
|
+
@middleware = middleware
|
23
|
+
return
|
24
|
+
end
|
25
|
+
@middleware = [middleware]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul dataceneter API endpoint
|
3
|
+
class Datacenter < Diplomat::RestClient
|
4
|
+
@access_methods = [:get]
|
5
|
+
|
6
|
+
# Get an array of all avaliable datacenters accessible by the local consul agent
|
7
|
+
# @param meta [Hash] output structure containing header information about the request (index)
|
8
|
+
# @return [OpenStruct] all datacenters avaliable to this consul agent
|
9
|
+
def get(meta = nil)
|
10
|
+
url = ['/v1/catalog/datacenters']
|
11
|
+
|
12
|
+
ret = @conn.get concat_url url
|
13
|
+
|
14
|
+
if meta && ret.headers
|
15
|
+
meta[:index] = ret.headers['x-consul-index']
|
16
|
+
meta[:knownleader] = ret.headers['x-consul-knownleader']
|
17
|
+
meta[:lastcontact] = ret.headers['x-consul-lastcontact']
|
18
|
+
end
|
19
|
+
JSON.parse(ret.body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Diplomat
|
2
|
+
class KeyNotFound < StandardError; end
|
3
|
+
class PathNotFound < StandardError; end
|
4
|
+
class KeyAlreadyExists < StandardError; end
|
5
|
+
class AclNotFound < StandardError; end
|
6
|
+
class AclAlreadyExists < StandardError; end
|
7
|
+
class EventNotFound < StandardError; end
|
8
|
+
class EventAlreadyExists < StandardError; end
|
9
|
+
class QueryNotFound < StandardError; end
|
10
|
+
class QueryAlreadyExists < StandardError; end
|
11
|
+
class UnknownStatus < StandardError; end
|
12
|
+
class IdParameterRequired < StandardError; end
|
13
|
+
class InvalidTransaction < StandardError; end
|
14
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul event API endpoint
|
3
|
+
class Event < Diplomat::RestClient
|
4
|
+
include ApiOptions
|
5
|
+
|
6
|
+
@access_methods = %i[fire get_all get]
|
7
|
+
|
8
|
+
# Send an event
|
9
|
+
# @param name [String] the event name
|
10
|
+
# @param value [String] the payload of the event
|
11
|
+
# @param service [String] the target service name
|
12
|
+
# @param node [String] the target node name
|
13
|
+
# @param tag [String] the target tag name, must only be used with service
|
14
|
+
# @param dc [String] the dc to target
|
15
|
+
# @return [nil]
|
16
|
+
# rubocop:disable Metrics/ParameterLists
|
17
|
+
def fire(name, value = nil, service = nil, node = nil, tag = nil, dc = nil)
|
18
|
+
url = ["/v1/event/fire/#{name}"]
|
19
|
+
url += check_acl_token
|
20
|
+
url += use_named_parameter('service', service) if service
|
21
|
+
url += use_named_parameter('node', node) if node
|
22
|
+
url += use_named_parameter('tag', tag) if tag
|
23
|
+
url += use_named_parameter('dc', dc) if dc
|
24
|
+
|
25
|
+
@conn.put concat_url(url), value
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
# rubocop:enable Metrics/ParameterLists
|
29
|
+
|
30
|
+
# Get the list of events matching name
|
31
|
+
# @param name [String] the name of the event (regex)
|
32
|
+
# @param not_found [Symbol] behaviour if there are no events matching name;
|
33
|
+
# :reject with exception, :return degenerate value, or :wait for a non-empty list
|
34
|
+
# @param found [Symbol] behaviour if there are already events matching name;
|
35
|
+
# :reject with exception, :return its current value, or :wait for its next value
|
36
|
+
# @return [Array[hash]] The list of { :name, :payload } hashes
|
37
|
+
# @note
|
38
|
+
# Events are sent via the gossip protocol; there is no guarantee of delivery
|
39
|
+
# success or order, but the local agent will store up to 256 events that do
|
40
|
+
# arrive. This method lists those events.
|
41
|
+
# It has the same semantics as Kv::get, except the value returned is a list
|
42
|
+
# i.e. the current value is all events up until now, the next value is the
|
43
|
+
# current list plus the next event to arrive.
|
44
|
+
# To get a specific event in the sequence, @see #get
|
45
|
+
# When trying to get a list of events matching a name, there are two possibilities:
|
46
|
+
# - The list doesn't (yet) exist / is empty
|
47
|
+
# - The list exists / is non-empty
|
48
|
+
# The combination of not_found and found behaviour gives maximum possible
|
49
|
+
# flexibility. For X: reject, R: return, W: wait
|
50
|
+
# - X X - meaningless; never return a value
|
51
|
+
# - X R - "normal" non-blocking get operation. Default
|
52
|
+
# - X W - get the next value only (must have a current value)
|
53
|
+
# - R X - meaningless; never return a meaningful value
|
54
|
+
# - R R - "safe" non-blocking, non-throwing get-or-default operation
|
55
|
+
# - R W - get the next value or a default
|
56
|
+
# - W X - get the first value only (must not have a current value)
|
57
|
+
# - W R - get the first or current value; always return something, but
|
58
|
+
# block only when necessary
|
59
|
+
# - W W - get the first or next value; wait until there is an update
|
60
|
+
# rubocop:disable MethodLength, AbcSize
|
61
|
+
def get_all(name = nil, not_found = :reject, found = :return)
|
62
|
+
url = ['/v1/event/list']
|
63
|
+
url += check_acl_token
|
64
|
+
url += use_named_parameter('name', name)
|
65
|
+
url = concat_url url
|
66
|
+
|
67
|
+
# Event list never returns 404 or blocks, but may return an empty list
|
68
|
+
@raw = @conn.get url
|
69
|
+
if JSON.parse(@raw.body).count.zero?
|
70
|
+
case not_found
|
71
|
+
when :reject
|
72
|
+
raise Diplomat::EventNotFound, name
|
73
|
+
when :return
|
74
|
+
return []
|
75
|
+
end
|
76
|
+
else
|
77
|
+
case found
|
78
|
+
when :reject
|
79
|
+
raise Diplomat::EventAlreadyExists, name
|
80
|
+
when :return
|
81
|
+
# Always set the response to 200 so we always return
|
82
|
+
# the response body.
|
83
|
+
@raw.status = 200
|
84
|
+
@raw = parse_body
|
85
|
+
return return_payload
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
@raw = wait_for_next_event(url)
|
90
|
+
@raw = parse_body
|
91
|
+
return_payload
|
92
|
+
end
|
93
|
+
# rubocop:enable MethodLength, AbcSize
|
94
|
+
|
95
|
+
# Get a specific event in the sequence matching name
|
96
|
+
# @param name [String] the name of the event (regex)
|
97
|
+
# @param token [String|Symbol] the ordinate of the event in the sequence;
|
98
|
+
# String are tokens returned by previous calls to this function
|
99
|
+
# Symbols are the special tokens :first, :last, and :next
|
100
|
+
# @param not_found [Symbol] behaviour if there is no matching event;
|
101
|
+
# :reject with exception, :return degenerate value, or :wait for event
|
102
|
+
# @param found [Symbol] behaviour if there is a matching event;
|
103
|
+
# :reject with exception, or :return its current value
|
104
|
+
# @return [hash] A hash with keys :value and :token;
|
105
|
+
# :value is a further hash of the :name and :payload of the event,
|
106
|
+
# :token is the event's ordinate in the sequence and can be passed to future calls to get the subsequent event
|
107
|
+
# @note
|
108
|
+
# Whereas the consul API for events returns all past events that match
|
109
|
+
# name, this method allows retrieval of individual events from that
|
110
|
+
# sequence. However, because consul's API isn't conducive to this, we can
|
111
|
+
# offer first, last, next (last + 1) events, or arbitrary events in the
|
112
|
+
# middle, though these can only be identified relative to the preceding
|
113
|
+
# event. However, this is ideal for iterating through the sequence of
|
114
|
+
# events (while being sure that none are missed).
|
115
|
+
# rubocop:disable MethodLength, CyclomaticComplexity, AbcSize
|
116
|
+
def get(name = nil, token = :last, not_found = :wait, found = :return)
|
117
|
+
url = ['/v1/event/list']
|
118
|
+
url += check_acl_token
|
119
|
+
url += use_named_parameter('name', name)
|
120
|
+
@raw = @conn.get concat_url url
|
121
|
+
body = JSON.parse(@raw.body)
|
122
|
+
# TODO: deal with unknown symbols, invalid indices (find_index will return nil)
|
123
|
+
idx = case token
|
124
|
+
when :first then 0
|
125
|
+
when :last then body.length - 1
|
126
|
+
when :next then body.length
|
127
|
+
else body.find_index { |e| e['ID'] == token } + 1
|
128
|
+
end
|
129
|
+
if idx == body.length
|
130
|
+
case not_found
|
131
|
+
when :reject
|
132
|
+
raise Diplomat::EventNotFound, name
|
133
|
+
when :return
|
134
|
+
event_name = ''
|
135
|
+
event_payload = ''
|
136
|
+
event_token = :last
|
137
|
+
when :wait
|
138
|
+
@raw = wait_for_next_event(url)
|
139
|
+
@raw = parse_body
|
140
|
+
# If it's possible for two events to arrive at once,
|
141
|
+
# this needs to #find again:
|
142
|
+
event = @raw.last
|
143
|
+
event_name = event['Name']
|
144
|
+
event_payload = Base64.decode64(event['Payload'])
|
145
|
+
event_token = event['ID']
|
146
|
+
end
|
147
|
+
else
|
148
|
+
case found
|
149
|
+
when :reject
|
150
|
+
raise Diplomat::EventAlreadyExits, name
|
151
|
+
when :return
|
152
|
+
event = body[idx]
|
153
|
+
event_name = event['Name']
|
154
|
+
event_payload = Base64.decode64(event['Payload'])
|
155
|
+
event_token = event['ID']
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
{
|
160
|
+
value: { name: event_name, payload: event_payload },
|
161
|
+
token: event_token
|
162
|
+
}
|
163
|
+
end
|
164
|
+
# rubocop:enable MethodLength, CyclomaticComplexity, AbcSize
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def wait_for_next_event(url)
|
169
|
+
index = @raw.headers['x-consul-index']
|
170
|
+
url = [url, use_named_parameter('index', index)].join('&')
|
171
|
+
@conn.get do |req|
|
172
|
+
req.url concat_url url
|
173
|
+
req.options.timeout = 86_400
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|