diplomat-scalp42 0.224

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,112 @@
1
+ module Diplomat
2
+ # Methods for interacting with the Consul ACL Policy API endpoint
3
+ class Policy < Diplomat::RestClient
4
+ @access_methods = %i[list read create delete update]
5
+ attr_reader :id, :type, :acl
6
+
7
+ # Read ACL policy with the given UUID
8
+ # @param id [String] UUID of the ACL policy to read
9
+ # @param options [Hash] options parameter hash
10
+ # @return [Hash] existing ACL policy
11
+ # rubocop:disable PerceivedComplexity
12
+ def read(id, options = {}, not_found = :reject, found = :return)
13
+ @options = options
14
+ custom_params = []
15
+ custom_params << use_consistency(options)
16
+
17
+ @raw = send_get_request(@conn_no_err, ["/v1/acl/policy/#{id}"], options, custom_params)
18
+
19
+ if @raw.status == 200 && @raw.body.chomp != 'null'
20
+ case found
21
+ when :reject
22
+ raise Diplomat::PolicyNotFound, id
23
+ when :return
24
+ return parse_body
25
+ end
26
+ elsif @raw.status == 404
27
+ case not_found
28
+ when :reject
29
+ raise Diplomat::PolicyNotFound, id
30
+ when :return
31
+ return nil
32
+ end
33
+ elsif @raw.status == 403
34
+ case not_found
35
+ when :reject
36
+ raise Diplomat::AclNotFound, id
37
+ when :return
38
+ return nil
39
+ end
40
+ else
41
+ raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}"
42
+ end
43
+ end
44
+ # rubocop:enable PerceivedComplexity
45
+
46
+ # List all the ACL policies
47
+ # @param options [Hash] options parameter hash
48
+ # @return [List] list of [Hash] of ACL policies
49
+ def list(options = {})
50
+ @raw = send_get_request(@conn_no_err, ['/v1/acl/policies'], options)
51
+ raise Diplomat::AclNotFound if @raw.status == 403
52
+
53
+ parse_body
54
+ end
55
+
56
+ # Update an existing ACL policy
57
+ # @param value [Hash] ACL policy definition, ID and Name fields are mandatory
58
+ # @param options [Hash] options parameter hash
59
+ # @return [Hash] result ACL policy
60
+ def update(value, options = {})
61
+ id = value[:ID] || value['ID']
62
+ raise Diplomat::IdParameterRequired if id.nil?
63
+
64
+ policy_name = value[:Name] || value['Name']
65
+ raise Diplomat::NameParameterRequired if policy_name.nil?
66
+
67
+ custom_params = use_cas(@options)
68
+ @raw = send_put_request(@conn, ["/v1/acl/policy/#{id}"], options, value, custom_params)
69
+ if @raw.status == 200
70
+ parse_body
71
+ elsif @raw.status == 400
72
+ raise Diplomat::PolicyMalformed, @raw.body
73
+ else
74
+ raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}"
75
+ end
76
+ end
77
+
78
+ # Create a new ACL policy
79
+ # @param value [Hash] ACL policy definition, Name field is mandatory
80
+ # @param options [Hash] options parameter hash
81
+ # @return [Hash] new ACL policy
82
+ def create(value, options = {})
83
+ blacklist = ['ID', 'iD', 'Id', :ID, :iD, :Id] & value.keys
84
+ raise Diplomat::PolicyMalformed, 'ID should not be specified' unless blacklist.empty?
85
+
86
+ id = value[:Name] || value['Name']
87
+ raise Diplomat::NameParameterRequired if id.nil?
88
+
89
+ custom_params = use_cas(@options)
90
+ @raw = send_put_request(@conn, ['/v1/acl/policy'], options, value, custom_params)
91
+
92
+ # rubocop:disable GuardClause
93
+ if @raw.status == 200
94
+ return parse_body
95
+ elsif @raw.status == 500 && @raw.body.chomp.include?('already exists')
96
+ raise Diplomat::PolicyAlreadyExists, @raw.body
97
+ else
98
+ raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}"
99
+ end
100
+ end
101
+ # rubocop:enable GuardClause
102
+
103
+ # Delete an ACL policy by its UUID
104
+ # @param id [String] UUID of the ACL policy to delete
105
+ # @param options [Hash] options parameter hash
106
+ # @return [Bool]
107
+ def delete(id, options = {})
108
+ @raw = send_delete_request(@conn, ["/v1/acl/policy/#{id}"], options, nil)
109
+ @raw.body.chomp == 'true'
110
+ end
111
+ end
112
+ 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 consistency 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