diplomat-blsk 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
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
+ # @return [OpenStruct] all data associated with the service
8
+ def get
9
+ ret = @conn.get '/v1/agent/members'
10
+ JSON.parse(ret.body)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ module Diplomat
2
+ # Methods for interacting with the Consul node API endpoint
3
+ class Node < Diplomat::RestClient
4
+ include ApiOptions
5
+
6
+ @access_methods = %i[get get_all register deregister]
7
+
8
+ # Get a node by it's key
9
+ # @param key [String] the key
10
+ # @param options [Hash] :dc string for dc specific query
11
+ # @return [OpenStruct] all data associated with the node
12
+ def get(key, options = nil)
13
+ url = ["/v1/catalog/node/#{key}"]
14
+ url += check_acl_token
15
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
16
+
17
+ # If the request fails, it's probably due to a bad path
18
+ # so return a PathNotFound error.
19
+ ret = @conn.get concat_url url
20
+ OpenStruct.new JSON.parse(ret.body)
21
+ rescue Faraday::ClientError
22
+ raise Diplomat::PathNotFound
23
+ end
24
+
25
+ # Get all the nodes
26
+ # @param options [Hash] :dc string for dc specific query
27
+ # @return [OpenStruct] the list of all nodes
28
+ def get_all(options = nil)
29
+ url = ['/v1/catalog/nodes']
30
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
31
+
32
+ ret = @conn.get concat_url url
33
+ JSON.parse(ret.body).map { |service| OpenStruct.new service }
34
+ rescue Faraday::ClientError
35
+ raise Diplomat::PathNotFound
36
+ end
37
+
38
+ # Register a node
39
+ # @param definition [Hash] Hash containing definition of a node to register
40
+ # @return [Boolean]
41
+ def register(definition, path = '/v1/catalog/register')
42
+ register = @conn.put path, JSON.dump(definition)
43
+
44
+ register.status == 200
45
+ end
46
+
47
+ # De-register a node (and all associated services and checks)
48
+ # @param definition [Hash] Hash containing definition of a node to de-register
49
+ # @return [Boolean]
50
+ def deregister(definition, path = '/v1/catalog/deregister')
51
+ deregister = @conn.put path, JSON.dump(definition)
52
+
53
+ deregister.status == 200
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
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
+ # @return [OpenStruct] all data associated with the nodes in catalog
10
+ def get
11
+ ret = @conn.get '/v1/catalog/nodes'
12
+ JSON.parse(ret.body)
13
+ end
14
+
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
20
+ JSON.parse(ret.body).map { |service| OpenStruct.new service }
21
+ rescue Faraday::ClientError
22
+ raise Diplomat::PathNotFound
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,124 @@
1
+ module Diplomat
2
+ # Methods for interacting with the Consul query API endpoint
3
+ class Query < Diplomat::RestClient
4
+ include ApiOptions
5
+
6
+ @access_methods = %i[get get_all create delete update execute explain]
7
+
8
+ # Get a prepared query by it's key
9
+ # @param key [String] the prepared query ID
10
+ # @param options [Hash] :dc string for dc specific query
11
+ # @return [OpenStruct] all data associated with the prepared query
12
+ def get(key, options = nil)
13
+ url = ["/v1/query/#{key}"]
14
+ url += check_acl_token
15
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
16
+
17
+ ret = @conn.get concat_url url
18
+ JSON.parse(ret.body).map { |query| OpenStruct.new query }
19
+ rescue Faraday::ClientError
20
+ raise Diplomat::QueryNotFound
21
+ end
22
+
23
+ # Get all prepared queries
24
+ # @param options [Hash] :dc Consul datacenter to query
25
+ # @return [OpenStruct] the list of all prepared queries
26
+ def get_all(options = nil)
27
+ url = ['/v1/query']
28
+ url += check_acl_token
29
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
30
+
31
+ ret = @conn.get concat_url url
32
+ JSON.parse(ret.body).map { |query| OpenStruct.new query }
33
+ rescue Faraday::ClientError
34
+ raise Diplomat::PathNotFound
35
+ end
36
+
37
+ # Create a prepared query or prepared query template
38
+ # @param definition [Hash] Hash containing definition of prepared query
39
+ # @param options [Hash] :dc Consul datacenter to query
40
+ # @return [String] the ID of the prepared query created
41
+ def create(definition, options = nil)
42
+ url = ['/v1/query']
43
+ url += check_acl_token
44
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
45
+ @raw = @conn.post do |req|
46
+ req.url concat_url url
47
+ req.body = JSON.dump(definition)
48
+ end
49
+
50
+ parse_body
51
+ rescue Faraday::ClientError
52
+ raise Diplomat::QueryAlreadyExists
53
+ end
54
+
55
+ # Delete a prepared query or prepared query template
56
+ # @param key [String] the prepared query ID
57
+ # @param options [Hash] :dc Consul datacenter to query
58
+ # @return [Boolean]
59
+ def delete(key, options = nil)
60
+ url = ["/v1/query/#{key}"]
61
+ url += check_acl_token
62
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
63
+ ret = @conn.delete concat_url url
64
+
65
+ ret.status == 200
66
+ end
67
+
68
+ # Update a prepared query or prepared query template
69
+ # @param key [String] the prepared query ID
70
+ # @param definition [Hash] Hash containing updated definition of prepared query
71
+ # @param options [Hash] :dc Consul datacenter to query
72
+ # @return [Boolean]
73
+ def update(key, definition, options = nil)
74
+ url = ["/v1/query/#{key}"]
75
+ url += check_acl_token
76
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
77
+ json_definition = JSON.dump(definition)
78
+ ret = @conn.put do |req|
79
+ req.url concat_url url
80
+ req.body = json_definition
81
+ end
82
+
83
+ ret.status == 200
84
+ end
85
+
86
+ # Execute a prepared query or prepared query template
87
+ # @param key [String] the prepared query ID or name
88
+ # @param options [Hash] prepared query execution options
89
+ # @option dc [String] :dc Consul datacenter to query
90
+ # @option near [String] node name to sort the resulting list in ascending order based on the
91
+ # estimated round trip time from that node
92
+ # @option limit [Integer] to limit the size of the return list to the given number of results
93
+ # @return [OpenStruct] the list of results from the prepared query or prepared query template
94
+ # rubocop:disable PerceivedComplexity, CyclomaticComplexity, AbcSize
95
+ def execute(key, options = nil)
96
+ url = ["/v1/query/#{key}/execute"]
97
+ url += check_acl_token
98
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
99
+ url << use_named_parameter('near', options[:near]) if options && options[:near]
100
+ url << use_named_parameter('limit', options[:limit]) if options && options[:limit]
101
+
102
+ ret = @conn.get concat_url url
103
+ OpenStruct.new JSON.parse(ret.body)
104
+ rescue Faraday::ClientError
105
+ raise Diplomat::QueryNotFound
106
+ end
107
+ # rubocop:enable PerceivedComplexity, CyclomaticComplexity, AbcSize
108
+
109
+ # Get the fully rendered query template
110
+ # @param key [String] the prepared query ID or name
111
+ # @param options [Hash] :dc Consul datacenter to query
112
+ # @return [OpenStruct] the list of results from the prepared query or prepared query template
113
+ def explain(key, options = nil)
114
+ url = ["/v1/query/#{key}/explain"]
115
+ url += check_acl_token
116
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
117
+
118
+ ret = @conn.get concat_url url
119
+ OpenStruct.new JSON.parse(ret.body)
120
+ rescue Faraday::ClientError
121
+ raise Diplomat::QueryNotFound
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,180 @@
1
+ module Diplomat
2
+ # Base class for interacting with the Consul RESTful API
3
+ class RestClient
4
+ @access_methods = []
5
+
6
+ # Initialize the fadaray connection
7
+ # @param api_connection [Faraday::Connection,nil] supply mock API Connection
8
+ def initialize(api_connection = nil)
9
+ start_connection api_connection
10
+ end
11
+
12
+ # Format url parameters into strings correctly
13
+ # @param name [String] the name of the parameter
14
+ # @param value [String] the value of the parameter
15
+ # @return [Array] the resultant parameter string inside an array.
16
+ def use_named_parameter(name, value)
17
+ value ? ["#{name}=#{value}"] : []
18
+ end
19
+
20
+ # Assemble a url from an array of parts.
21
+ # @param parts [Array] the url chunks to be assembled
22
+ # @return [String] the resultant url string
23
+ def concat_url(parts)
24
+ if parts.length > 1
25
+ parts.first + '?' + parts.drop(1).join('&')
26
+ else
27
+ parts.first
28
+ end
29
+ end
30
+
31
+ class << self
32
+ def access_method?(meth_id)
33
+ @access_methods.include? meth_id
34
+ end
35
+
36
+ # Allow certain methods to be accessed
37
+ # without defining "new".
38
+ # @param meth_id [Symbol] symbol defining method requested
39
+ # @param *args Arguments list
40
+ # @return [Boolean]
41
+ def method_missing(meth_id, *args)
42
+ if access_method?(meth_id)
43
+ new.send(meth_id, *args)
44
+ else
45
+
46
+ # See https://bugs.ruby-lang.org/issues/10969
47
+ begin
48
+ super
49
+ rescue NameError => err
50
+ raise NoMethodError, err
51
+ end
52
+ end
53
+ end
54
+
55
+ # Make `respond_to?` aware of method short-cuts.
56
+ #
57
+ # @param meth_id [Symbol] the tested method
58
+ # @oaram with_private if private methods should be tested too
59
+ def respond_to?(meth_id, with_private = false)
60
+ access_method?(meth_id) || super
61
+ end
62
+
63
+ # Make `respond_to_missing` aware of method short-cuts. This is needed for
64
+ # {#method} to work on these, which is helpful for testing purposes.
65
+ #
66
+ # @param meth_id [Symbol] the tested method
67
+ # @oaram with_private if private methods should be tested too
68
+ def respond_to_missing?(meth_id, with_private = false)
69
+ access_method?(meth_id) || super
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ # Build the API Client
76
+ # @param api_connection [Faraday::Connection,nil] supply mock API Connection
77
+ def start_connection(api_connection = nil)
78
+ @conn = build_connection(api_connection)
79
+ @conn_no_err = build_connection(api_connection, true)
80
+ end
81
+
82
+ def build_connection(api_connection, raise_error = false)
83
+ api_connection || Faraday.new(Diplomat.configuration.url, Diplomat.configuration.options) do |faraday|
84
+ Diplomat.configuration.middleware.each do |middleware|
85
+ faraday.use middleware
86
+ end
87
+
88
+ faraday.request :url_encoded
89
+ faraday.response :raise_error unless raise_error
90
+
91
+ faraday.adapter Faraday.default_adapter
92
+ end
93
+ end
94
+
95
+ # Converts k/v data into ruby hash
96
+ # rubocop:disable MethodLength, AbcSize
97
+ def convert_to_hash(data)
98
+ collection = []
99
+ master = {}
100
+ data.each do |item|
101
+ split_up = item[:key].split('/')
102
+ sub_hash = {}
103
+ temp = nil
104
+ real_size = split_up.size - 1
105
+ (0..real_size).each do |i|
106
+ if i.zero?
107
+ temp = {}
108
+ sub_hash[split_up[i]] = temp
109
+ next
110
+ end
111
+ if i == real_size
112
+ temp[split_up[i]] = item[:value]
113
+ else
114
+ new_h = {}
115
+ temp[split_up[i]] = new_h
116
+ temp = new_h
117
+ end
118
+ end
119
+ collection << sub_hash
120
+ end
121
+
122
+ collection.each do |h|
123
+ master = deep_merge(master, h)
124
+ end
125
+ master
126
+ end
127
+ # rubocop:enable MethodLength, AbcSize
128
+
129
+ def deep_merge(first, second)
130
+ merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 }
131
+ first.merge(second, &merger)
132
+ end
133
+
134
+ # Parse the body, apply it to the raw attribute
135
+ def parse_body
136
+ return JSON.parse(@raw.body) if @raw.status == 200
137
+ raise Diplomat::UnknownStatus, "status #{@raw.status}: #{@raw.body}"
138
+ end
139
+
140
+ # Return @raw with Value fields decoded
141
+ def decode_values
142
+ return @raw if @raw.first.is_a? String
143
+ @raw.each_with_object([]) do |acc, el|
144
+ begin
145
+ acc['Value'] = Base64.decode64(acc['Value'])
146
+ rescue # rubocop:disable RescueWithoutErrorClass
147
+ nil
148
+ end
149
+ el << acc
150
+ el
151
+ end
152
+ end
153
+
154
+ # Get the key/value(s) from the raw output
155
+ # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
156
+ def return_value(nil_values = false, transformation = nil, return_hash = false)
157
+ @value = decode_values
158
+ return @value if @value.first.is_a? String
159
+ if @value.count == 1 && !return_hash
160
+ @value = @value.first['Value']
161
+ @value = transformation.call(@value) if transformation && !@value.nil?
162
+ return @value
163
+ else
164
+ @value = @value.map do |el|
165
+ el['Value'] = transformation.call(el['Value']) if transformation && !el['Value'].nil?
166
+ { key: el['Key'], value: el['Value'] } if el['Value'] || nil_values
167
+ end.compact
168
+ end
169
+ end
170
+ # rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
171
+
172
+ # Get the name and payload(s) from the raw output
173
+ def return_payload
174
+ @value = @raw.map do |e|
175
+ { name: e['Name'],
176
+ payload: (Base64.decode64(e['Payload']) unless e['Payload'].nil?) }
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,118 @@
1
+ module Diplomat
2
+ # Methods for interacting with the Consul serivce API endpoint.
3
+ class Service < Diplomat::RestClient
4
+ include ApiOptions
5
+
6
+ @access_methods = %i[get get_all register deregister register_external deregister_external maintenance]
7
+
8
+ # Get a service by it's key
9
+ # @param key [String] the key
10
+ # @param scope [Symbol] :first or :all results
11
+ # @param options [Hash] options parameter hash
12
+ # @option wait [Integer] :wait string for wait time
13
+ # @option index [String] :index for index of last query
14
+ # @option dc [String] :dc data center to make request for
15
+ # @option tag [String] :tag service tag to get
16
+ # @param meta [Hash] output structure containing header information about the request (index)
17
+ # @return [OpenStruct] all data associated with the service
18
+ # rubocop:disable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize
19
+ def get(key, scope = :first, options = nil, meta = nil)
20
+ url = ["/v1/catalog/service/#{key}"]
21
+ url += check_acl_token
22
+ url << use_named_parameter('wait', options[:wait]) if options && options[:wait]
23
+ url << use_named_parameter('index', options[:index]) if options && options[:index]
24
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
25
+ url << use_named_parameter('tag', options[:tag]) if options && options[:tag]
26
+
27
+ # If the request fails, it's probably due to a bad path
28
+ # so return a PathNotFound error.
29
+ begin
30
+ ret = @conn.get concat_url url
31
+ rescue Faraday::ClientError => e
32
+ raise Diplomat::PathNotFound, e
33
+ end
34
+
35
+ if meta && ret.headers
36
+ meta[:index] = ret.headers['x-consul-index']
37
+ meta[:knownleader] = ret.headers['x-consul-knownleader']
38
+ meta[:lastcontact] = 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, MethodLength, CyclomaticComplexity, AbcSize
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 = nil)
53
+ url = ['/v1/catalog/services']
54
+ url += check_acl_token
55
+ url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
56
+ begin
57
+ ret = @conn.get concat_url url
58
+ rescue Faraday::ClientError
59
+ raise Diplomat::PathNotFound
60
+ end
61
+
62
+ OpenStruct.new JSON.parse(ret.body)
63
+ end
64
+
65
+ # Register a service
66
+ # @param definition [Hash] Hash containing definition of service
67
+ # @return [Boolean]
68
+ def register(definition, path = '/v1/agent/service/register')
69
+ json_definition = JSON.dump(definition)
70
+ register = @conn.put path, json_definition
71
+ register.status == 200
72
+ end
73
+
74
+ # De-register a service
75
+ # @param service_name [String] Service name to de-register
76
+ # @return [Boolean]
77
+ def deregister(service_name)
78
+ deregister = @conn.put "/v1/agent/service/deregister/#{service_name}"
79
+ deregister.status == 200
80
+ end
81
+
82
+ # Register an external service
83
+ # @param definition [Hash] Hash containing definition of service
84
+ # @return [Boolean]
85
+ def register_external(definition)
86
+ register(definition, '/v1/catalog/register')
87
+ end
88
+
89
+ # Deregister an external service
90
+ # @param definition [Hash] Hash containing definition of service
91
+ # @return [Boolean]
92
+ def deregister_external(definition)
93
+ json_definition = JSON.dump(definition)
94
+ deregister = @conn.put '/v1/catalog/deregister', json_definition
95
+ deregister.status == 200
96
+ end
97
+
98
+ # Enable or disable maintenance for a service
99
+ # @param [Hash] opts the options for enabling or disabling maintenance for a service
100
+ # @options opts [Boolean] :enable (true) whether to enable or disable maintenance
101
+ # @options opts [String] :reason reason for the service maintenance
102
+ # @raise [Diplomat::PathNotFound] if the request fails
103
+ # @return [Boolean] if the request was successful or not
104
+ def maintenance(service_id, options = { enable: true })
105
+ url = ["/v1/agent/service/maintenance/#{service_id}"]
106
+ url += check_acl_token
107
+ url << ["enable=#{options[:enable]}"]
108
+ url << ["reason=#{options[:reason].split(' ').join('+')}"] if options && options[:reason]
109
+ begin
110
+ maintenance = @conn.put concat_url(url)
111
+ rescue Faraday::ClientError
112
+ raise Diplomat::PathNotFound
113
+ end
114
+ maintenance.status == 200
115
+ end
116
+ # rubocop:enable AbcSize
117
+ end
118
+ end