diplomatic_bag 2.2.1
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 +356 -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/acl.rb +81 -0
- data/lib/diplomat/agent.rb +42 -0
- data/lib/diplomat/check.rb +109 -0
- data/lib/diplomat/configuration.rb +28 -0
- data/lib/diplomat/datacenter.rb +21 -0
- data/lib/diplomat/error.rb +15 -0
- data/lib/diplomat/event.rb +166 -0
- data/lib/diplomat/health.rb +81 -0
- data/lib/diplomat/kv.rb +263 -0
- data/lib/diplomat/lock.rb +54 -0
- data/lib/diplomat/maintenance.rb +41 -0
- data/lib/diplomat/members.rb +14 -0
- data/lib/diplomat/node.rb +43 -0
- data/lib/diplomat/nodes.rb +22 -0
- data/lib/diplomat/query.rb +87 -0
- data/lib/diplomat/rest_client.rb +278 -0
- data/lib/diplomat/service.rb +111 -0
- data/lib/diplomat/session.rb +75 -0
- data/lib/diplomat/status.rb +22 -0
- data/lib/diplomat/version.rb +3 -0
- data/lib/diplomat.rb +62 -0
- data/lib/diplomatic_bag/datacenters.rb +11 -0
- data/lib/diplomatic_bag/info.rb +32 -0
- data/lib/diplomatic_bag/nodes.rb +28 -0
- data/lib/diplomatic_bag/service.rb +20 -0
- data/lib/diplomatic_bag/services.rb +38 -0
- data/lib/diplomatic_bag.rb +7 -0
- metadata +89 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul members API endpoint
|
3
|
+
class Members < Diplomat::RestClient
|
4
|
+
@access_methods = [:get]
|
5
|
+
|
6
|
+
# Get all members
|
7
|
+
# @param options [Hash] options parameter hash
|
8
|
+
# @return [OpenStruct] all data associated with the service
|
9
|
+
def get(options = {})
|
10
|
+
ret = send_get_request(@conn, ['/v1/agent/members'], options)
|
11
|
+
JSON.parse(ret.body)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul node API endpoint
|
3
|
+
class Node < Diplomat::RestClient
|
4
|
+
@access_methods = %i[get get_all register deregister]
|
5
|
+
|
6
|
+
# Get a node by it's key
|
7
|
+
# @param key [String] the key
|
8
|
+
# @param options [Hash] :dc string for dc specific query
|
9
|
+
# @return [OpenStruct] all data associated with the node
|
10
|
+
def get(key, options = {})
|
11
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
12
|
+
ret = send_get_request(@conn, ["/v1/catalog/node/#{key}"], options, custom_params)
|
13
|
+
OpenStruct.new JSON.parse(ret.body)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get all the nodes
|
17
|
+
# @param options [Hash] :dc string for dc specific query
|
18
|
+
# @return [OpenStruct] the list of all nodes
|
19
|
+
def get_all(options = {})
|
20
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
21
|
+
ret = send_get_request(@conn, ['/v1/catalog/nodes'], options, custom_params)
|
22
|
+
JSON.parse(ret.body).map { |service| OpenStruct.new service }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Register a node
|
26
|
+
# @param definition [Hash] Hash containing definition of a node to register
|
27
|
+
# @param options [Hash] options parameter hash
|
28
|
+
# @return [Boolean]
|
29
|
+
def register(definition, options = {})
|
30
|
+
register = send_put_request(@conn, ['/v1/catalog/register'], options, definition)
|
31
|
+
register.status == 200
|
32
|
+
end
|
33
|
+
|
34
|
+
# De-register a node (and all associated services and checks)
|
35
|
+
# @param definition [Hash] Hash containing definition of a node to de-register
|
36
|
+
# @param options [Hash] options parameter hash
|
37
|
+
# @return [Boolean]
|
38
|
+
def deregister(definition, options = {})
|
39
|
+
deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition)
|
40
|
+
deregister.status == 200
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# @depreciated
|
3
|
+
# Methods for interacting with the Consul nodes API endpoint
|
4
|
+
class Nodes < Diplomat::RestClient
|
5
|
+
@access_methods = %i[get get_all]
|
6
|
+
|
7
|
+
# Get all nodes
|
8
|
+
# @deprecated Please use Diplomat::Node instead.
|
9
|
+
# @param options [Hash] options parameter hash
|
10
|
+
# @return [OpenStruct] all data associated with the nodes in catalog
|
11
|
+
def get(options = {})
|
12
|
+
ret = send_get_request(@conn, ['/v1/catalog/nodes'], options)
|
13
|
+
JSON.parse(ret.body)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_all(options = {})
|
17
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
18
|
+
ret = send_get_request(@conn, ['/v1/catalog/nodes'], options, custom_params)
|
19
|
+
JSON.parse(ret.body).map { |service| OpenStruct.new service }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul query API endpoint
|
3
|
+
class Query < Diplomat::RestClient
|
4
|
+
@access_methods = %i[get get_all create delete update execute explain]
|
5
|
+
|
6
|
+
# Get a prepared query by it's key
|
7
|
+
# @param key [String] the prepared query ID
|
8
|
+
# @param options [Hash] :dc string for dc specific query
|
9
|
+
# @return [OpenStruct] all data associated with the prepared query
|
10
|
+
def get(key, options = {})
|
11
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
12
|
+
ret = send_get_request(@conn, ["/v1/query/#{key}"], options, custom_params)
|
13
|
+
JSON.parse(ret.body).map { |query| OpenStruct.new query }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get all prepared queries
|
17
|
+
# @param options [Hash] :dc Consul datacenter to query
|
18
|
+
# @return [OpenStruct] the list of all prepared queries
|
19
|
+
def get_all(options = {})
|
20
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
21
|
+
ret = send_get_request(@conn, ['/v1/query'], options, custom_params)
|
22
|
+
JSON.parse(ret.body).map { |query| OpenStruct.new query }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a prepared query or prepared query template
|
26
|
+
# @param definition [Hash] Hash containing definition of prepared query
|
27
|
+
# @param options [Hash] :dc Consul datacenter to query
|
28
|
+
# @return [String] the ID of the prepared query created
|
29
|
+
def create(definition, options = {})
|
30
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
31
|
+
@raw = send_post_request(@conn, ['/v1/query'], options, definition, custom_params)
|
32
|
+
parse_body
|
33
|
+
rescue Faraday::ClientError
|
34
|
+
raise Diplomat::QueryAlreadyExists
|
35
|
+
end
|
36
|
+
|
37
|
+
# Delete a prepared query or prepared query template
|
38
|
+
# @param key [String] the prepared query ID
|
39
|
+
# @param options [Hash] :dc Consul datacenter to query
|
40
|
+
# @return [Boolean]
|
41
|
+
def delete(key, options = {})
|
42
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
43
|
+
ret = send_delete_request(@conn, ["/v1/query/#{key}"], options, custom_params)
|
44
|
+
ret.status == 200
|
45
|
+
end
|
46
|
+
|
47
|
+
# Update a prepared query or prepared query template
|
48
|
+
# @param key [String] the prepared query ID
|
49
|
+
# @param definition [Hash] Hash containing updated definition of prepared query
|
50
|
+
# @param options [Hash] :dc Consul datacenter to query
|
51
|
+
# @return [Boolean]
|
52
|
+
def update(key, definition, options = {})
|
53
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
54
|
+
ret = send_put_request(@conn, ["/v1/query/#{key}"], options, definition, custom_params)
|
55
|
+
ret.status == 200
|
56
|
+
end
|
57
|
+
|
58
|
+
# Execute a prepared query or prepared query template
|
59
|
+
# @param key [String] the prepared query ID or name
|
60
|
+
# @param options [Hash] prepared query execution options
|
61
|
+
# @option dc [String] :dc Consul datacenter to query
|
62
|
+
# @option near [String] node name to sort the resulting list in ascending order based on the
|
63
|
+
# estimated round trip time from that node
|
64
|
+
# @option limit [Integer] to limit the size of the return list to the given number of results
|
65
|
+
# @return [OpenStruct] the list of results from the prepared query or prepared query template
|
66
|
+
# rubocop:disable PerceivedComplexity
|
67
|
+
def execute(key, options = {})
|
68
|
+
custom_params = []
|
69
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
70
|
+
custom_params << use_named_parameter('near', options[:near]) if options[:near]
|
71
|
+
custom_params << use_named_parameter('limit', options[:limit]) if options[:limit]
|
72
|
+
ret = send_get_request(@conn, ["/v1/query/#{key}/execute"], options, custom_params)
|
73
|
+
OpenStruct.new JSON.parse(ret.body)
|
74
|
+
end
|
75
|
+
# rubocop:enable PerceivedComplexity
|
76
|
+
|
77
|
+
# Get the fully rendered query template
|
78
|
+
# @param key [String] the prepared query ID or name
|
79
|
+
# @param options [Hash] :dc Consul datacenter to query
|
80
|
+
# @return [OpenStruct] the list of results from the prepared query or prepared query template
|
81
|
+
def explain(key, options = {})
|
82
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
83
|
+
ret = send_get_request(@conn, ["/v1/query/#{key}/explain"], options, custom_params)
|
84
|
+
OpenStruct.new JSON.parse(ret.body)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'deep_merge'
|
2
|
+
|
3
|
+
module Diplomat
|
4
|
+
# Base class for interacting with the Consul RESTful API
|
5
|
+
class RestClient
|
6
|
+
@access_methods = []
|
7
|
+
@configuration = nil
|
8
|
+
|
9
|
+
# Initialize the fadaray connection
|
10
|
+
# @param api_connection [Faraday::Connection,nil] supply mock API Connection
|
11
|
+
# @param configuration [Diplomat::Configuration] a dedicated config to use
|
12
|
+
def initialize(api_connection = nil, configuration: nil)
|
13
|
+
@configuration = configuration
|
14
|
+
start_connection api_connection
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get client configuration or global one if not specified via initialize.
|
18
|
+
# @return [Diplomat::Configuration] used by this client
|
19
|
+
def configuration
|
20
|
+
@configuration || ::Diplomat.configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
# Format url parameters into strings correctly
|
24
|
+
# @param name [String] the name of the parameter
|
25
|
+
# @param value [String] the value of the parameter
|
26
|
+
# @return [Array] the resultant parameter string inside an array.
|
27
|
+
def use_named_parameter(name, value)
|
28
|
+
value ? ["#{name}=#{value}"] : []
|
29
|
+
end
|
30
|
+
|
31
|
+
# Assemble a url from an array of parts.
|
32
|
+
# @param parts [Array] the url chunks to be assembled
|
33
|
+
# @return [String] the resultant url string
|
34
|
+
def concat_url(parts)
|
35
|
+
parts.reject!(&:empty?)
|
36
|
+
if parts.length > 1
|
37
|
+
parts.first + '?' + parts.drop(1).join('&')
|
38
|
+
else
|
39
|
+
parts.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def access_method?(meth_id)
|
45
|
+
@access_methods.include? meth_id
|
46
|
+
end
|
47
|
+
|
48
|
+
# Allow certain methods to be accessed
|
49
|
+
# without defining "new".
|
50
|
+
# @param meth_id [Symbol] symbol defining method requested
|
51
|
+
# @param *args Arguments list
|
52
|
+
# @return [Boolean]
|
53
|
+
def method_missing(meth_id, *args)
|
54
|
+
if access_method?(meth_id)
|
55
|
+
new.send(meth_id, *args)
|
56
|
+
else
|
57
|
+
|
58
|
+
# See https://bugs.ruby-lang.org/issues/10969
|
59
|
+
begin
|
60
|
+
super
|
61
|
+
rescue NameError => e
|
62
|
+
raise NoMethodError, e
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Make `respond_to?` aware of method short-cuts.
|
68
|
+
#
|
69
|
+
# @param meth_id [Symbol] the tested method
|
70
|
+
# @oaram with_private if private methods should be tested too
|
71
|
+
def respond_to?(meth_id, with_private = false)
|
72
|
+
access_method?(meth_id) || super
|
73
|
+
end
|
74
|
+
|
75
|
+
# Make `respond_to_missing` aware of method short-cuts. This is needed for
|
76
|
+
# {#method} to work on these, which is helpful for testing purposes.
|
77
|
+
#
|
78
|
+
# @param meth_id [Symbol] the tested method
|
79
|
+
# @oaram with_private if private methods should be tested too
|
80
|
+
def respond_to_missing?(meth_id, with_private = false)
|
81
|
+
access_method?(meth_id) || super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Build the API Client
|
88
|
+
# @param api_connection [Faraday::Connection,nil] supply mock API Connection
|
89
|
+
def start_connection(api_connection = nil)
|
90
|
+
@conn = build_connection(api_connection)
|
91
|
+
@conn_no_err = build_connection(api_connection, true)
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_connection(api_connection, raise_error = false)
|
95
|
+
api_connection || Faraday.new(configuration.url, configuration.options) do |faraday|
|
96
|
+
configuration.middleware.each do |middleware|
|
97
|
+
faraday.use middleware
|
98
|
+
end
|
99
|
+
|
100
|
+
faraday.request :url_encoded
|
101
|
+
faraday.response :raise_error unless raise_error
|
102
|
+
|
103
|
+
faraday.adapter Faraday.default_adapter
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Converts k/v data into ruby hash
|
108
|
+
def convert_to_hash(data)
|
109
|
+
data.map do |item|
|
110
|
+
item[:key].split('/').reverse.reduce(item[:value]) { |h, v| { v => h } }
|
111
|
+
end.reduce(:deep_merge)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Parse the body, apply it to the raw attribute
|
115
|
+
def parse_body
|
116
|
+
return JSON.parse(@raw.body) if @raw.status == 200
|
117
|
+
|
118
|
+
raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return @raw with Value fields decoded
|
122
|
+
def decode_values
|
123
|
+
return @raw if @raw.first.is_a? String
|
124
|
+
|
125
|
+
@raw.each_with_object([]) do |acc, el|
|
126
|
+
begin
|
127
|
+
acc['Value'] = Base64.decode64(acc['Value'])
|
128
|
+
rescue StandardError
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
el << acc
|
132
|
+
el
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Get the key/value(s) from the raw output
|
137
|
+
# rubocop:disable PerceivedComplexity
|
138
|
+
def return_value(nil_values = false, transformation = nil, return_hash = false)
|
139
|
+
@value = decode_values
|
140
|
+
return @value if @value.first.is_a? String
|
141
|
+
|
142
|
+
if @value.count == 1 && !return_hash
|
143
|
+
@value = @value.first['Value']
|
144
|
+
@value = transformation.call(@value) if transformation && !@value.nil?
|
145
|
+
return @value
|
146
|
+
else
|
147
|
+
@value = @value.map do |el|
|
148
|
+
el['Value'] = transformation.call(el['Value']) if transformation && !el['Value'].nil?
|
149
|
+
{ key: el['Key'], value: el['Value'] } if el['Value'] || nil_values
|
150
|
+
end.compact
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# rubocop:enable PerceivedComplexity
|
154
|
+
|
155
|
+
# Get the name and payload(s) from the raw output
|
156
|
+
def return_payload
|
157
|
+
@value = @raw.map do |e|
|
158
|
+
{ name: e['Name'],
|
159
|
+
payload: (Base64.decode64(e['Payload']) unless e['Payload'].nil?) }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def use_cas(options)
|
164
|
+
options ? use_named_parameter('cas', options[:cas]) : []
|
165
|
+
end
|
166
|
+
|
167
|
+
def use_consistency(options)
|
168
|
+
options[:consistency] ? [options[:consistency].to_s] : []
|
169
|
+
end
|
170
|
+
|
171
|
+
# rubocop:disable PerceivedComplexity
|
172
|
+
# TODO: Migrate all custom params in options
|
173
|
+
def parse_options(options)
|
174
|
+
headers = nil
|
175
|
+
query_params = []
|
176
|
+
url_prefix = nil
|
177
|
+
consistency = []
|
178
|
+
|
179
|
+
# Parse options used as header
|
180
|
+
headers = { 'X-Consul-Token' => configuration.acl_token } if configuration.acl_token
|
181
|
+
headers = { 'X-Consul-Token' => options[:token] } if options[:token]
|
182
|
+
|
183
|
+
# Parse options used as query params
|
184
|
+
consistency = 'stale' if options[:stale]
|
185
|
+
consistency = 'leader' if options[:leader]
|
186
|
+
consistency = 'consistent' if options[:consistent]
|
187
|
+
query_params << consistency
|
188
|
+
|
189
|
+
# Parse url host
|
190
|
+
url_prefix = options[:http_addr] if options[:http_addr]
|
191
|
+
{ query_params: query_params, headers: headers, url_prefix: url_prefix }
|
192
|
+
end
|
193
|
+
# rubocop:enable PerceivedComplexity
|
194
|
+
|
195
|
+
def send_get_request(connection, url, options, custom_params = nil)
|
196
|
+
rest_options = parse_options(options)
|
197
|
+
url += rest_options[:query_params]
|
198
|
+
url += custom_params unless custom_params.nil?
|
199
|
+
begin
|
200
|
+
connection.get do |req|
|
201
|
+
req.options[:params_encoder] = options[:params_encoder] if options[:params_encoder]
|
202
|
+
req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
|
203
|
+
rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
|
204
|
+
req.options.timeout = options[:timeout] if options[:timeout]
|
205
|
+
end
|
206
|
+
rescue Faraday::ClientError => e
|
207
|
+
raise Diplomat::PathNotFound, e
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def send_put_request(connection, url, options, data, custom_params = nil, mime = 'application/json')
|
212
|
+
rest_options = parse_options(options)
|
213
|
+
url += rest_options[:query_params]
|
214
|
+
url += custom_params unless custom_params.nil?
|
215
|
+
connection.put do |req|
|
216
|
+
req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
|
217
|
+
rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
|
218
|
+
unless data.nil?
|
219
|
+
(req.headers || {})['Content-Type'] = mime
|
220
|
+
req.body = if mime == 'application/json' && !data.is_a?(String)
|
221
|
+
data.to_json
|
222
|
+
else
|
223
|
+
data
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def send_post_request(connection, url, options, data, custom_params = nil)
|
230
|
+
rest_options = parse_options(options)
|
231
|
+
url += rest_options[:query_params]
|
232
|
+
url += custom_params unless custom_params.nil?
|
233
|
+
connection.post do |req|
|
234
|
+
req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
|
235
|
+
rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
|
236
|
+
req.body = JSON.dump(data) unless data.nil?
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def send_delete_request(connection, url, options, custom_params = nil)
|
241
|
+
rest_options = parse_options(options)
|
242
|
+
url += rest_options[:query_params]
|
243
|
+
url += custom_params unless custom_params.nil?
|
244
|
+
connection.delete do |req|
|
245
|
+
req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
|
246
|
+
rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Mapping for valid key/value store transaction verbs and required parameters
|
251
|
+
#
|
252
|
+
# @return [Hash] valid key/store transaction verbs and required parameters
|
253
|
+
def valid_transaction_verbs
|
254
|
+
{
|
255
|
+
'set' => %w[Key Value],
|
256
|
+
'cas' => %w[Key Value Index],
|
257
|
+
'lock' => %w[Key Value Session],
|
258
|
+
'unlock' => %w[Key Value Session],
|
259
|
+
'get' => %w[Key],
|
260
|
+
'get-tree' => %w[Key],
|
261
|
+
'check-index' => %w[Key Index],
|
262
|
+
'check-session' => %w[Key Session],
|
263
|
+
'delete' => %w[Key],
|
264
|
+
'delete-tree' => %w[Key],
|
265
|
+
'delete-cas' => %w[Key Index]
|
266
|
+
}
|
267
|
+
end
|
268
|
+
|
269
|
+
# Key/value store transactions that require that a value be set
|
270
|
+
#
|
271
|
+
# @return [Array<String>] verbs that require a value be set
|
272
|
+
def valid_value_transactions
|
273
|
+
@valid_value_transactions ||= valid_transaction_verbs.select do |verb, requires|
|
274
|
+
verb if requires.include? 'Value'
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul service API endpoint.
|
3
|
+
class Service < Diplomat::RestClient
|
4
|
+
@access_methods = %i[get get_all register deregister register_external deregister_external maintenance]
|
5
|
+
|
6
|
+
# Get a service by it's key
|
7
|
+
# @param key [String] the key
|
8
|
+
# @param scope [Symbol] :first or :all results
|
9
|
+
# @param options [Hash] options parameter hash
|
10
|
+
# @param meta [Hash] output structure containing header information about the request (index)
|
11
|
+
# @return [OpenStruct] all data associated with the service
|
12
|
+
# rubocop:disable PerceivedComplexity
|
13
|
+
def get(key, scope = :first, options = {}, meta = nil)
|
14
|
+
custom_params = []
|
15
|
+
custom_params << use_named_parameter('wait', options[:wait]) if options[:wait]
|
16
|
+
custom_params << use_named_parameter('index', options[:index]) if options[:index]
|
17
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
18
|
+
if options[:tag]
|
19
|
+
# tag can be either a String, or an array of strings
|
20
|
+
# by splatting it is guaranteed to be an array of strings
|
21
|
+
[*options[:tag]].each do |value|
|
22
|
+
custom_params << use_named_parameter('tag', value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# We have to provide a custom params encoder here because Faraday - by default - assumes that
|
27
|
+
# list keys have [] as part of their name. This is however not the case for consul tags, which
|
28
|
+
# just use repeated occurences of the same key.
|
29
|
+
#
|
30
|
+
# So faraday reduces this: http://localhost:8500?a=1&a=2 to http://localhost:8500?a=2 unless you
|
31
|
+
# explicitly tell it not to.
|
32
|
+
options[:params_encoder] = Faraday::FlatParamsEncoder
|
33
|
+
|
34
|
+
ret = send_get_request(@conn, ["/v1/catalog/service/#{key}"], options, custom_params)
|
35
|
+
if meta && ret.headers
|
36
|
+
meta[:index] = ret.headers['x-consul-index'] if ret.headers['x-consul-index']
|
37
|
+
meta[:knownleader] = ret.headers['x-consul-knownleader'] if ret.headers['x-consul-knownleader']
|
38
|
+
meta[:lastcontact] = ret.headers['x-consul-lastcontact'] if ret.headers['x-consul-lastcontact']
|
39
|
+
end
|
40
|
+
|
41
|
+
if scope == :all
|
42
|
+
JSON.parse(ret.body).map { |service| OpenStruct.new service }
|
43
|
+
else
|
44
|
+
OpenStruct.new JSON.parse(ret.body).first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# rubocop:enable PerceivedComplexity
|
48
|
+
|
49
|
+
# Get all the services
|
50
|
+
# @param options [Hash] :dc Consul datacenter to query
|
51
|
+
# @return [OpenStruct] the list of all services
|
52
|
+
def get_all(options = {})
|
53
|
+
custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
|
54
|
+
ret = send_get_request(@conn, ['/v1/catalog/services'], options, custom_params)
|
55
|
+
OpenStruct.new JSON.parse(ret.body)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Register a service
|
59
|
+
# @param definition [Hash] Hash containing definition of service
|
60
|
+
# @param options [Hash] options parameter hash
|
61
|
+
# @return [Boolean]
|
62
|
+
def register(definition, options = {})
|
63
|
+
url = options[:path] || ['/v1/agent/service/register']
|
64
|
+
register = send_put_request(@conn, url, options, definition)
|
65
|
+
register.status == 200
|
66
|
+
end
|
67
|
+
|
68
|
+
# De-register a service
|
69
|
+
# @param service_name [String] Service name to de-register
|
70
|
+
# @param options [Hash] options parameter hash
|
71
|
+
# @return [Boolean]
|
72
|
+
def deregister(service_name, options = {})
|
73
|
+
deregister = send_put_request(@conn, ["/v1/agent/service/deregister/#{service_name}"], options, nil)
|
74
|
+
deregister.status == 200
|
75
|
+
end
|
76
|
+
|
77
|
+
# Register an external service
|
78
|
+
# @param definition [Hash] Hash containing definition of service
|
79
|
+
# @param options [Hash] options parameter hash
|
80
|
+
# @return [Boolean]
|
81
|
+
def register_external(definition, options = {})
|
82
|
+
register = send_put_request(@conn, ['/v1/catalog/register'], options, definition)
|
83
|
+
register.status == 200
|
84
|
+
end
|
85
|
+
|
86
|
+
# Deregister an external service
|
87
|
+
# @param definition [Hash] Hash containing definition of service
|
88
|
+
# @param options [Hash] options parameter hash
|
89
|
+
# @return [Boolean]
|
90
|
+
def deregister_external(definition, options = {})
|
91
|
+
deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition)
|
92
|
+
deregister.status == 200
|
93
|
+
end
|
94
|
+
|
95
|
+
# Enable or disable maintenance for a service
|
96
|
+
# @param service_id [String] id of the service
|
97
|
+
# @param options [Hash] opts the options for enabling or disabling maintenance for a service
|
98
|
+
# @options opts [Boolean] :enable (true) whether to enable or disable maintenance
|
99
|
+
# @options opts [String] :reason reason for the service maintenance
|
100
|
+
# @raise [Diplomat::PathNotFound] if the request fails
|
101
|
+
# @return [Boolean] if the request was successful or not
|
102
|
+
def maintenance(service_id, options = { enable: true })
|
103
|
+
custom_params = []
|
104
|
+
custom_params << ["enable=#{options[:enable]}"]
|
105
|
+
custom_params << ["reason=#{options[:reason].split(' ').join('+')}"] if options[:reason]
|
106
|
+
maintenance = send_put_request(@conn, ["/v1/agent/service/maintenance/#{service_id}"],
|
107
|
+
options, nil, custom_params)
|
108
|
+
maintenance.status == 200
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul session API endpoint
|
3
|
+
class Session < Diplomat::RestClient
|
4
|
+
@access_methods = %i[create destroy list renew info node]
|
5
|
+
|
6
|
+
# Create a new session
|
7
|
+
# @param value [Object] hash or json representation of the session arguments
|
8
|
+
# @param options [Hash] session options
|
9
|
+
# @return [String] The sesssion id
|
10
|
+
def create(value = nil, options = {})
|
11
|
+
# TODO: only certain keys are recognised in a session create request,
|
12
|
+
# should raise an error on others.
|
13
|
+
custom_params = []
|
14
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
15
|
+
data = value.is_a?(String) ? value : JSON.generate(value) unless value.nil?
|
16
|
+
raw = send_put_request(@conn, ['/v1/session/create'], options, data, custom_params)
|
17
|
+
body = JSON.parse(raw.body)
|
18
|
+
body['ID']
|
19
|
+
end
|
20
|
+
|
21
|
+
# Destroy a session
|
22
|
+
# @param id [String] session id
|
23
|
+
# @param options [Hash] session options
|
24
|
+
# @return [String] Success or failure of the session destruction
|
25
|
+
def destroy(id, options = {})
|
26
|
+
custom_params = []
|
27
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
28
|
+
raw = send_put_request(@conn, ["/v1/session/destroy/#{id}"], options, nil, custom_params)
|
29
|
+
raw.body
|
30
|
+
end
|
31
|
+
|
32
|
+
# List sessions
|
33
|
+
# @param options [Hash] session options
|
34
|
+
# @return [OpenStruct]
|
35
|
+
def list(options = {})
|
36
|
+
custom_params = []
|
37
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
38
|
+
raw = send_get_request(@conn, ['/v1/session/list'], options, custom_params)
|
39
|
+
JSON.parse(raw.body).map { |session| OpenStruct.new session }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Renew session
|
43
|
+
# @param id [String] session id
|
44
|
+
# @param options [Hash] session options
|
45
|
+
# @return [OpenStruct]
|
46
|
+
def renew(id, options = {})
|
47
|
+
custom_params = []
|
48
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
49
|
+
raw = send_put_request(@conn, ["/v1/session/renew/#{id}"], options, nil, custom_params)
|
50
|
+
JSON.parse(raw.body).map { |session| OpenStruct.new session }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Session information
|
54
|
+
# @param id [String] session id
|
55
|
+
# @param options [Hash] session options
|
56
|
+
# @return [OpenStruct]
|
57
|
+
def info(id, options = {})
|
58
|
+
custom_params = []
|
59
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
60
|
+
raw = send_get_request(@conn, ["/v1/session/info/#{id}"], options, custom_params)
|
61
|
+
JSON.parse(raw.body).map { |session| OpenStruct.new session }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Session information for a given node
|
65
|
+
# @param name [String] node name
|
66
|
+
# @param options [Hash] session options
|
67
|
+
# @return [OpenStruct]
|
68
|
+
def node(name, options = {})
|
69
|
+
custom_params = []
|
70
|
+
custom_params << use_named_parameter('dc', options[:dc]) if options[:dc]
|
71
|
+
raw = send_get_request(@conn, ["/v1/session/node/#{name}"], options, custom_params)
|
72
|
+
JSON.parse(raw.body).map { |session| OpenStruct.new session }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul status API endpoints, leader and peers
|
3
|
+
class Status < Diplomat::RestClient
|
4
|
+
@access_methods = %i[leader peers]
|
5
|
+
|
6
|
+
# Get the raft leader for the datacenter in which the local consul agent is running
|
7
|
+
# @param options [Hash] options parameter hash
|
8
|
+
# @return [OpenStruct] the address of the leader
|
9
|
+
def leader(options = {})
|
10
|
+
ret = send_get_request(@conn, ['/v1/status/leader'], options)
|
11
|
+
JSON.parse(ret.body)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get an array of Raft peers for the datacenter in which the agent is running
|
15
|
+
# @param options [Hash] options parameter hash
|
16
|
+
# @return [OpenStruct] an array of peers
|
17
|
+
def peers(options = {})
|
18
|
+
ret = send_get_request(@conn, ['/v1/status/peers'], options)
|
19
|
+
JSON.parse(ret.body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|