diplomat 2.0.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,20 +6,17 @@ module Diplomat
6
6
 
7
7
  # Get all nodes
8
8
  # @deprecated Please use Diplomat::Node instead.
9
+ # @param options [Hash] options parameter hash
9
10
  # @return [OpenStruct] all data associated with the nodes in catalog
10
- def get
11
- ret = @conn.get '/v1/catalog/nodes'
11
+ def get(options = {})
12
+ ret = send_get_request(@conn, ['/v1/catalog/nodes'], options)
12
13
  JSON.parse(ret.body)
13
14
  end
14
15
 
15
- def get_all(options = nil)
16
- url = ['/v1/catalog/nodes']
17
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
18
-
19
- ret = @conn.get concat_url url
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)
20
19
  JSON.parse(ret.body).map { |service| OpenStruct.new service }
21
- rescue Faraday::ClientError
22
- raise Diplomat::PathNotFound
23
20
  end
24
21
  end
25
22
  end
@@ -7,44 +7,28 @@ module Diplomat
7
7
  # @param key [String] the prepared query ID
8
8
  # @param options [Hash] :dc string for dc specific query
9
9
  # @return [OpenStruct] all data associated with the prepared query
10
- def get(key, options = nil)
11
- url = ["/v1/query/#{key}"]
12
- url += check_acl_token
13
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
14
-
15
- ret = @conn.get concat_url url
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)
16
13
  JSON.parse(ret.body).map { |query| OpenStruct.new query }
17
- rescue Faraday::ClientError
18
- raise Diplomat::QueryNotFound
19
14
  end
20
15
 
21
16
  # Get all prepared queries
22
17
  # @param options [Hash] :dc Consul datacenter to query
23
18
  # @return [OpenStruct] the list of all prepared queries
24
- def get_all(options = nil)
25
- url = ['/v1/query']
26
- url += check_acl_token
27
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
28
-
29
- ret = @conn.get concat_url url
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)
30
22
  JSON.parse(ret.body).map { |query| OpenStruct.new query }
31
- rescue Faraday::ClientError
32
- raise Diplomat::PathNotFound
33
23
  end
34
24
 
35
25
  # Create a prepared query or prepared query template
36
26
  # @param definition [Hash] Hash containing definition of prepared query
37
27
  # @param options [Hash] :dc Consul datacenter to query
38
28
  # @return [String] the ID of the prepared query created
39
- def create(definition, options = nil)
40
- url = ['/v1/query']
41
- url += check_acl_token
42
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
43
- @raw = @conn.post do |req|
44
- req.url concat_url url
45
- req.body = JSON.dump(definition)
46
- end
47
-
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)
48
32
  parse_body
49
33
  rescue Faraday::ClientError
50
34
  raise Diplomat::QueryAlreadyExists
@@ -54,12 +38,9 @@ module Diplomat
54
38
  # @param key [String] the prepared query ID
55
39
  # @param options [Hash] :dc Consul datacenter to query
56
40
  # @return [Boolean]
57
- def delete(key, options = nil)
58
- url = ["/v1/query/#{key}"]
59
- url += check_acl_token
60
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
61
- ret = @conn.delete concat_url url
62
-
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)
63
44
  ret.status == 200
64
45
  end
65
46
 
@@ -68,16 +49,9 @@ module Diplomat
68
49
  # @param definition [Hash] Hash containing updated definition of prepared query
69
50
  # @param options [Hash] :dc Consul datacenter to query
70
51
  # @return [Boolean]
71
- def update(key, definition, options = nil)
72
- url = ["/v1/query/#{key}"]
73
- url += check_acl_token
74
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
75
- json_definition = JSON.dump(definition)
76
- ret = @conn.put do |req|
77
- req.url concat_url url
78
- req.body = json_definition
79
- end
80
-
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)
81
55
  ret.status == 200
82
56
  end
83
57
 
@@ -89,34 +63,25 @@ module Diplomat
89
63
  # estimated round trip time from that node
90
64
  # @option limit [Integer] to limit the size of the return list to the given number of results
91
65
  # @return [OpenStruct] the list of results from the prepared query or prepared query template
92
- # rubocop:disable PerceivedComplexity, CyclomaticComplexity, AbcSize
93
- def execute(key, options = nil)
94
- url = ["/v1/query/#{key}/execute"]
95
- url += check_acl_token
96
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
97
- url << use_named_parameter('near', options[:near]) if options && options[:near]
98
- url << use_named_parameter('limit', options[:limit]) if options && options[:limit]
99
-
100
- ret = @conn.get concat_url url
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)
101
73
  OpenStruct.new JSON.parse(ret.body)
102
- rescue Faraday::ClientError
103
- raise Diplomat::QueryNotFound
104
74
  end
105
- # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize
75
+ # rubocop:enable PerceivedComplexity
106
76
 
107
77
  # Get the fully rendered query template
108
78
  # @param key [String] the prepared query ID or name
109
79
  # @param options [Hash] :dc Consul datacenter to query
110
80
  # @return [OpenStruct] the list of results from the prepared query or prepared query template
111
- def explain(key, options = nil)
112
- url = ["/v1/query/#{key}/explain"]
113
- url += check_acl_token
114
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
115
-
116
- ret = @conn.get concat_url url
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)
117
84
  OpenStruct.new JSON.parse(ret.body)
118
- rescue Faraday::ClientError
119
- raise Diplomat::QueryNotFound
120
85
  end
121
86
  end
122
87
  end
@@ -1,3 +1,5 @@
1
+ require 'deep_merge'
2
+
1
3
  module Diplomat
2
4
  # Base class for interacting with the Consul RESTful API
3
5
  class RestClient
@@ -30,6 +32,7 @@ module Diplomat
30
32
  # @param parts [Array] the url chunks to be assembled
31
33
  # @return [String] the resultant url string
32
34
  def concat_url(parts)
35
+ parts.reject!(&:empty?)
33
36
  if parts.length > 1
34
37
  parts.first + '?' + parts.drop(1).join('&')
35
38
  else
@@ -102,42 +105,10 @@ module Diplomat
102
105
  end
103
106
 
104
107
  # Converts k/v data into ruby hash
105
- # rubocop:disable MethodLength, AbcSize
106
108
  def convert_to_hash(data)
107
- collection = []
108
- master = {}
109
- data.each do |item|
110
- split_up = item[:key].split('/')
111
- sub_hash = {}
112
- temp = nil
113
- real_size = split_up.size - 1
114
- (0..real_size).each do |i|
115
- if i.zero?
116
- temp = {}
117
- sub_hash[split_up[i]] = temp
118
- next
119
- end
120
- if i == real_size
121
- temp[split_up[i]] = item[:value]
122
- else
123
- new_h = {}
124
- temp[split_up[i]] = new_h
125
- temp = new_h
126
- end
127
- end
128
- collection << sub_hash
129
- end
130
-
131
- collection.each do |h|
132
- master = deep_merge(master, h)
133
- end
134
- master
135
- end
136
- # rubocop:enable MethodLength, AbcSize
137
-
138
- def deep_merge(first, second)
139
- merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 }
140
- first.merge(second, &merger)
109
+ data.map do |item|
110
+ item[:key].split('/').reverse.reduce(item[:value]) { |h, v| { v => h } }
111
+ end.reduce(:deep_merge)
141
112
  end
142
113
 
143
114
  # Parse the body, apply it to the raw attribute
@@ -163,7 +134,7 @@ module Diplomat
163
134
  end
164
135
 
165
136
  # Get the key/value(s) from the raw output
166
- # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
137
+ # rubocop:disable PerceivedComplexity
167
138
  def return_value(nil_values = false, transformation = nil, return_hash = false)
168
139
  @value = decode_values
169
140
  return @value if @value.first.is_a? String
@@ -179,7 +150,7 @@ module Diplomat
179
150
  end.compact
180
151
  end
181
152
  end
182
- # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
153
+ # rubocop:enable PerceivedComplexity
183
154
 
184
155
  # Get the name and payload(s) from the raw output
185
156
  def return_payload
@@ -189,22 +160,88 @@ module Diplomat
189
160
  end
190
161
  end
191
162
 
192
- def check_acl_token
193
- use_named_parameter('token', configuration.acl_token)
194
- end
195
-
196
163
  def use_cas(options)
197
164
  options ? use_named_parameter('cas', options[:cas]) : []
198
165
  end
199
166
 
200
167
  def use_consistency(options)
201
- options && options[:consistency] ? [options[:consistency].to_s] : []
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.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
202
+ rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
203
+ req.options.timeout = options[:timeout] if options[:timeout]
204
+ end
205
+ rescue Faraday::ClientError => e
206
+ raise Diplomat::PathNotFound, e
207
+ end
208
+ end
209
+
210
+ def send_put_request(connection, url, options, data, custom_params = nil)
211
+ rest_options = parse_options(options)
212
+ url += rest_options[:query_params]
213
+ url += custom_params unless custom_params.nil?
214
+ connection.put do |req|
215
+ req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
216
+ rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
217
+ req.body = JSON.dump(data) unless data.nil?
218
+ end
219
+ end
220
+
221
+ def send_post_request(connection, url, options, data, custom_params = nil)
222
+ rest_options = parse_options(options)
223
+ url += rest_options[:query_params]
224
+ url += custom_params unless custom_params.nil?
225
+ connection.post do |req|
226
+ req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
227
+ rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
228
+ req.body = JSON.dump(data) unless data.nil?
229
+ end
230
+ end
231
+
232
+ def send_delete_request(connection, url, options, custom_params = nil)
233
+ rest_options = parse_options(options)
234
+ url += rest_options[:query_params]
235
+ url += custom_params unless custom_params.nil?
236
+ connection.delete do |req|
237
+ req.url rest_options[:url_prefix] ? rest_options[:url_prefix] + concat_url(url) : concat_url(url)
238
+ rest_options[:headers].map { |k, v| req.headers[k.to_sym] = v } unless rest_options[:headers].nil?
239
+ end
202
240
  end
203
241
 
204
242
  # Mapping for valid key/value store transaction verbs and required parameters
205
243
  #
206
244
  # @return [Hash] valid key/store transaction verbs and required parameters
207
- # rubocop:disable MethodLength
208
245
  def valid_transaction_verbs
209
246
  {
210
247
  'set' => %w[Key Value],
@@ -220,7 +257,6 @@ module Diplomat
220
257
  'delete-cas' => %w[Key Index]
221
258
  }
222
259
  end
223
- # rubocop:enable MethodLength
224
260
 
225
261
  # Key/value store transactions that require that a value be set
226
262
  #
@@ -1,5 +1,5 @@
1
1
  module Diplomat
2
- # Methods for interacting with the Consul serivce API endpoint.
2
+ # Methods for interacting with the Consul service API endpoint.
3
3
  class Service < Diplomat::RestClient
4
4
  @access_methods = %i[get get_all register deregister register_external deregister_external maintenance]
5
5
 
@@ -7,33 +7,21 @@ module Diplomat
7
7
  # @param key [String] the key
8
8
  # @param scope [Symbol] :first or :all results
9
9
  # @param options [Hash] options parameter hash
10
- # @option wait [Integer] :wait string for wait time
11
- # @option index [String] :index for index of last query
12
- # @option dc [String] :dc data center to make request for
13
- # @option tag [String] :tag service tag to get
14
10
  # @param meta [Hash] output structure containing header information about the request (index)
15
11
  # @return [OpenStruct] all data associated with the service
16
- # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
17
- def get(key, scope = :first, options = nil, meta = nil)
18
- url = ["/v1/catalog/service/#{key}"]
19
- url += check_acl_token
20
- url << use_named_parameter('wait', options[:wait]) if options && options[:wait]
21
- url << use_named_parameter('index', options[:index]) if options && options[:index]
22
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
23
- url << use_named_parameter('tag', options[:tag]) if options && options[:tag]
24
-
25
- # If the request fails, it's probably due to a bad path
26
- # so return a PathNotFound error.
27
- begin
28
- ret = @conn.get concat_url url
29
- rescue Faraday::ClientError => e
30
- raise Diplomat::PathNotFound, e
31
- end
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
+ custom_params << use_named_parameter('tag', options[:tag]) if options[:tag]
32
19
 
20
+ ret = send_get_request(@conn, ["/v1/catalog/service/#{key}"], options, custom_params)
33
21
  if meta && ret.headers
34
- meta[:index] = ret.headers['x-consul-index']
35
- meta[:knownleader] = ret.headers['x-consul-knownleader']
36
- meta[:lastcontact] = ret.headers['x-consul-lastcontact']
22
+ meta[:index] = ret.headers['x-consul-index'] if ret.headers['x-consul-index']
23
+ meta[:knownleader] = ret.headers['x-consul-knownleader'] if ret.headers['x-consul-knownleader']
24
+ meta[:lastcontact] = ret.headers['x-consul-lastcontact'] if ret.headers['x-consul-lastcontact']
37
25
  end
38
26
 
39
27
  if scope == :all
@@ -42,77 +30,67 @@ module Diplomat
42
30
  OpenStruct.new JSON.parse(ret.body).first
43
31
  end
44
32
  end
45
- # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
33
+ # rubocop:enable PerceivedComplexity
46
34
 
47
35
  # Get all the services
48
36
  # @param options [Hash] :dc Consul datacenter to query
49
37
  # @return [OpenStruct] the list of all services
50
- def get_all(options = nil)
51
- url = ['/v1/catalog/services']
52
- url += check_acl_token
53
- url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
54
- begin
55
- ret = @conn.get concat_url url
56
- rescue Faraday::ClientError
57
- raise Diplomat::PathNotFound
58
- end
59
-
38
+ def get_all(options = {})
39
+ custom_params = options[:dc] ? use_named_parameter('dc', options[:dc]) : nil
40
+ ret = send_get_request(@conn, ['/v1/catalog/services'], options, custom_params)
60
41
  OpenStruct.new JSON.parse(ret.body)
61
42
  end
62
43
 
63
44
  # Register a service
64
45
  # @param definition [Hash] Hash containing definition of service
46
+ # @param options [Hash] options parameter hash
65
47
  # @return [Boolean]
66
- def register(definition, path = '/v1/agent/service/register')
67
- url = [path]
68
- url += check_acl_token
69
- json_definition = JSON.dump(definition)
70
- register = @conn.put concat_url(url), json_definition
48
+ def register(definition, options = {})
49
+ url = options[:path] || ['/v1/agent/service/register']
50
+ register = send_put_request(@conn, url, options, definition)
71
51
  register.status == 200
72
52
  end
73
53
 
74
54
  # De-register a service
75
55
  # @param service_name [String] Service name to de-register
56
+ # @param options [Hash] options parameter hash
76
57
  # @return [Boolean]
77
- def deregister(service_name)
78
- url = ["/v1/agent/service/deregister/#{service_name}"]
79
- url += check_acl_token
80
- deregister = @conn.put concat_url(url)
58
+ def deregister(service_name, options = {})
59
+ deregister = send_put_request(@conn, ["/v1/agent/service/deregister/#{service_name}"], options, nil)
81
60
  deregister.status == 200
82
61
  end
83
62
 
84
63
  # Register an external service
85
64
  # @param definition [Hash] Hash containing definition of service
65
+ # @param options [Hash] options parameter hash
86
66
  # @return [Boolean]
87
- def register_external(definition)
88
- register(definition, '/v1/catalog/register')
67
+ def register_external(definition, options = {})
68
+ register = send_put_request(@conn, ['/v1/catalog/register'], options, definition)
69
+ register.status == 200
89
70
  end
90
71
 
91
72
  # Deregister an external service
92
73
  # @param definition [Hash] Hash containing definition of service
74
+ # @param options [Hash] options parameter hash
93
75
  # @return [Boolean]
94
- def deregister_external(definition)
95
- json_definition = JSON.dump(definition)
96
- deregister = @conn.put '/v1/catalog/deregister', json_definition
76
+ def deregister_external(definition, options = {})
77
+ deregister = send_put_request(@conn, ['/v1/catalog/deregister'], options, definition)
97
78
  deregister.status == 200
98
79
  end
99
80
 
100
81
  # Enable or disable maintenance for a service
101
- # @param [Hash] opts the options for enabling or disabling maintenance for a service
82
+ # @param service_id [String] id of the service
83
+ # @param options [Hash] opts the options for enabling or disabling maintenance for a service
102
84
  # @options opts [Boolean] :enable (true) whether to enable or disable maintenance
103
85
  # @options opts [String] :reason reason for the service maintenance
104
86
  # @raise [Diplomat::PathNotFound] if the request fails
105
87
  # @return [Boolean] if the request was successful or not
106
88
  def maintenance(service_id, options = { enable: true })
107
- url = ["/v1/agent/service/maintenance/#{service_id}"]
108
- url += check_acl_token
109
- url << ["enable=#{options[:enable]}"]
110
- url << ["reason=#{options[:reason].split(' ').join('+')}"] if options && options[:reason]
111
- begin
112
- maintenance = @conn.put concat_url(url)
113
- rescue Faraday::ClientError
114
- raise Diplomat::PathNotFound
115
- end
89
+ custom_params = []
90
+ custom_params << ["enable=#{options[:enable]}"]
91
+ custom_params << ["reason=#{options[:reason].split(' ').join('+')}"] if options[:reason]
92
+ maintenance = send_put_request(@conn, ["/v1/agent/service/maintenance/#{service_id}"],
93
+ options, nil, custom_params)
116
94
  maintenance.status == 200
117
95
  end
118
96
  end