diplomat 2.0.5 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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