hawkular-client 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/CHANGES.rdoc +8 -0
  4. data/README.rdoc +12 -5
  5. data/hawkularclient.gemspec +2 -2
  6. data/lib/alerts/alerts_api.rb +193 -0
  7. data/lib/{hawkularclient.rb → hawkular.rb} +93 -52
  8. data/lib/hawkular_all.rb +7 -0
  9. data/lib/inventory/inventory_api.rb +378 -0
  10. data/lib/metrics/metric_api.rb +20 -10
  11. data/lib/metrics/metrics_client.rb +52 -0
  12. data/lib/metrics/tenant_api.rb +1 -1
  13. data/lib/metrics/version.rb +3 -1
  14. data/lib/version.rb +8 -0
  15. data/spec/integration/alerts_spec.rb +143 -0
  16. data/spec/integration/inventory_spec.rb +191 -0
  17. data/spec/integration/metric_spec.rb +33 -0
  18. data/spec/spec_helper.rb +14 -1
  19. data/spec/unit/base_spec.rb +57 -0
  20. data/spec/vcr_cassettes/Alert/Alerts/Should_acknowledge_an_alert.yml +183 -0
  21. data/spec/vcr_cassettes/Alert/Alerts/Should_fetch_single_alert.yml +69 -0
  22. data/spec/vcr_cassettes/Alert/Alerts/Should_list_alerts.yml +85 -0
  23. data/spec/vcr_cassettes/Alert/Alerts/Should_list_alerts_for_trigger.yml +142 -0
  24. data/spec/vcr_cassettes/Alert/Alerts/Should_list_alerts_for_unknown_trigger.yml +46 -0
  25. data/spec/vcr_cassettes/Alert/Alerts/Should_resolve_an_alert.yml +181 -0
  26. data/spec/vcr_cassettes/Alert/Alerts/Should_resolve_an_alert2.yml +49 -0
  27. data/spec/vcr_cassettes/Alert/Triggers/Should_List_Triggers.yml +62 -0
  28. data/spec/vcr_cassettes/Alert/Triggers/Should_List_Triggers_for_ID.yml +55 -0
  29. data/spec/vcr_cassettes/Alert/Triggers/Should_List_Triggers_for_Tag.yml +68 -0
  30. data/spec/vcr_cassettes/Alert/Triggers/Should_List_Triggers_for_Tags.yml +68 -0
  31. data/spec/vcr_cassettes/Alert/Triggers/Should_get_a_single_Trigger_with_conditions.yml +138 -0
  32. data/spec/vcr_cassettes/Alert/Triggers/Should_get_a_single_metric_Trigger.yml +50 -0
  33. data/spec/vcr_cassettes/Gauge_metrics/Platform_mem.yml +44 -0
  34. data/spec/vcr_cassettes/Gauge_metrics/Platform_mem_def.yml +45 -0
  35. data/spec/vcr_cassettes/Inventory/Should_List_datasources_with_no_props.yml +228 -0
  36. data/spec/vcr_cassettes/Inventory/Should_list_URLs.yml +105 -0
  37. data/spec/vcr_cassettes/Inventory/Should_list_WildFlys.yml +104 -0
  38. data/spec/vcr_cassettes/Inventory/Should_list_WildFlys_with_props.yml +162 -0
  39. data/spec/vcr_cassettes/Inventory/Should_list_children_of_WildFly.yml +180 -0
  40. data/spec/vcr_cassettes/Inventory/Should_list_feeds.yml +102 -0
  41. data/spec/vcr_cassettes/Inventory/Should_list_heap_metrics_for_WildFlys.yml +308 -0
  42. data/spec/vcr_cassettes/Inventory/Should_list_metrics_for_WildFlys.yml +172 -0
  43. data/spec/vcr_cassettes/Inventory/Should_list_types_with_bad_feed.yml +101 -0
  44. data/spec/vcr_cassettes/Inventory/Should_list_types_with_feed.yml +109 -0
  45. data/spec/vcr_cassettes/Inventory/Should_list_types_without_feed.yml +110 -0
  46. data/spec/vcr_cassettes/Metrics/Status.yml +44 -0
  47. data/spec/vcr_cassettes/No_Tenant/Should_fail.yml +42 -0
  48. data/spec/vcr_cassettes/Tenants/Should_Get_Tenant_For_Explicit_Credentials.yml +50 -0
  49. data/spec/vcr_cassettes/Tenants/Should_Get_Tenant_For_Implicit_Credentials.yml +50 -0
  50. metadata +74 -3
@@ -0,0 +1,7 @@
1
+ require 'inventory/inventory_api'
2
+ require 'metrics/metrics_client.rb'
3
+ require 'alerts/alerts_api'
4
+ require 'hawkular'
5
+
6
+ module Hawkular
7
+ end
@@ -0,0 +1,378 @@
1
+ require 'hawkular'
2
+
3
+ # Inventory module provides access to the Hawkular Inventory REST API.
4
+ # @see http://www.hawkular.org/docs/rest/rest-inventory.html
5
+ #
6
+ # @note While Inventory supports 'environments', they are not used currently
7
+ # and thus set to 'test' as default value.
8
+ module Hawkular::Inventory
9
+ # Client class to interact with Hawkular Inventory
10
+ class InventoryClient < Hawkular::BaseClient
11
+ # Create a new Inventory Client
12
+ # @param entrypoint [String] base url of Hawkular-inventory - e.g
13
+ # http://localhost:8080/hawkular/inventory
14
+ # @param credentials [Hash{String=>String}] Hash of username, password, token(optional)
15
+ def initialize(entrypoint = nil, credentials = {})
16
+ @entrypoint = entrypoint
17
+
18
+ super(entrypoint, credentials)
19
+ end
20
+
21
+ # Retrieve the tenant id for the passed credentials.
22
+ # If no credentials are passed, the ones from the constructor are used
23
+ # @param credentials [Hash{String=>String}] Hash of username, password, token(optional)
24
+ # @return [String] tenant id
25
+ def get_tenant(credentials = {})
26
+ creds = credentials.empty? ? @credentials : credentials
27
+ auth_header = { Authorization: base_64_credentials(creds) }
28
+
29
+ ret = http_get('/tenant', auth_header)
30
+
31
+ ret['id']
32
+ end
33
+
34
+ # TODO: revisit and potentially move to Base ?
35
+ def impersonate(credentials = {})
36
+ @tenant = get_tenant(credentials)
37
+ @options[:tenant] = @tenant
38
+ end
39
+
40
+ # List feeds in the system
41
+ # @return [Array<String>] List of feed ids
42
+ def list_feeds(_environment = 'test')
43
+ ret = http_get('feeds')
44
+ val = []
45
+ ret.each { |f| val.push(f['id']) }
46
+ val
47
+ end
48
+
49
+ # List resource types. If no need is given all types are listed
50
+ # @param [String] feed The id of the feed the type lives under. Can be nil for feedless types
51
+ # @return [Array<ResourceType>] List of types, that can be empty
52
+ def list_resource_types(feed = nil)
53
+ if feed.nil?
54
+ ret = http_get('/resourceTypes')
55
+ else
56
+ the_feed = hawk_escape feed
57
+ ret = http_get('/feeds/' + the_feed + '/resourceTypes')
58
+ end
59
+ val = []
60
+ ret.each { |rt| val.push(ResourceType.new(rt)) }
61
+ val
62
+ end
63
+
64
+ # List the resources for the passed feed and resource type. The representation for
65
+ # resources under a feed are sparse and additional data must be retrived separately.
66
+ # It is possible though to also obtain runtime properties by setting #fetch_properties to true.
67
+ # @param [String] feed The id of the feed the type lives under. Can be nil for feedless types
68
+ # @param [String] type Name of the type to look for. Can be obtained from {ResourceType}.id.
69
+ # Must not be nil
70
+ # @param [Boolean] fetch_properties Shall additional runtime properties be fetched?
71
+ # @return [Array<Resource>] List of resources. Can be empty
72
+ def list_resources_for_type(feed, type, fetch_properties = false)
73
+ fail 'Type must not be nil' unless type
74
+ the_type = hawk_escape type
75
+ if feed.nil?
76
+ ret = http_get('resourceTypes/' + the_type + '/resources')
77
+ else
78
+
79
+ the_feed = hawk_escape feed
80
+ ret = http_get('/feeds/' + the_feed + '/resourceTypes/' + the_type + '/resources')
81
+ end
82
+ val = []
83
+ ret.each do |r|
84
+ if fetch_properties && !feed.nil?
85
+ p = get_config_data_for_resource(r['id'], feed)
86
+ r['properties'] = p['value']
87
+ end
88
+ val.push(Resource.new(r))
89
+ end
90
+ val
91
+ end
92
+
93
+ # Retrieve runtime properties for the passed resource
94
+ # @param [String] resource_id Id of the resource to read properties from
95
+ # @param [String] feed Feed of the resource
96
+ # @return [Hash<String,Object] Hash with additional data
97
+ def get_config_data_for_resource(resource_id, feed)
98
+ the_id = hawk_escape resource_id
99
+ the_feed = hawk_escape feed
100
+ http_get('feeds/' + the_feed + '/resources/' + the_id + '/data?dataType=configuration')
101
+ rescue
102
+ {}
103
+ end
104
+
105
+ # Obtain the child resources of the passed resource. In case of a WildFly server,
106
+ # those would be Datasources, Deployments and so on.
107
+ # @param [Resource] parent_resource Resource to obtain children from
108
+ # @return [Array<Resource>] List of resources that are children of the given parent resource.
109
+ # Can be empty
110
+ def list_child_resources(parent_resource)
111
+ the_feed = hawk_escape parent_resource.feed
112
+ the_id = hawk_escape parent_resource.id
113
+
114
+ ret = http_get('/feeds/' + the_feed +
115
+ '/resources/' + the_id + '/children')
116
+ val = []
117
+ ret.each { |r| val.push(Resource.new(r)) }
118
+ val
119
+ end
120
+
121
+ # Obtain a list of relationships starting at the passed resource
122
+ # @param [Resource] resource One end of the relationship
123
+ # @return [Array<Relationship>] List of relationships
124
+ def list_relationships(resource)
125
+ the_feed = hawk_escape resource.feed
126
+ the_id = hawk_escape resource.id
127
+
128
+ ret = http_get('/feeds/' + the_feed + '/resources/' + the_id + '/relationships')
129
+ val = []
130
+ ret.each { |r| val.push(Relationship.new(r)) }
131
+ val
132
+ rescue
133
+ []
134
+ end
135
+
136
+ # Obtain a list of relationships for the passed feed
137
+ # @param [String] feed_id Id of the feed
138
+ # @return [Array<Relationship>] List of relationships
139
+ def list_relationships_for_feed(feed_id)
140
+ the_feed = hawk_escape feed_id
141
+ ret = http_get('/feeds/' + the_feed + '/relationships')
142
+ val = []
143
+ ret.each { |r| val.push(Relationship.new(r)) }
144
+ val
145
+ rescue
146
+ []
147
+ end
148
+
149
+ # [15:01:51] <jkremser> pilhuhn, this works for me curl -XPOST
150
+ # -H "Content-Type: application/json"
151
+ # -u jdoe:password -d
152
+ # '{"id" : "foo", "source": "/t;28026b36-8fe4-4332-84c8-524e173a68bf/f;localhost",
153
+ # "target": "/t;28026b36-8fe4-4332-84c8-524e173a68bf/f;localhost/r;localhost~Local~~/
154
+ # r;localhost~Local~%2Fsubsystem=hawkular-bus-broker",
155
+ # "name": "isRelatedTo"}'
156
+ # 'http://localhost:8080/hawkular/inventory/feeds/localhost/relationships'
157
+ #
158
+ # def create_relationship(source_resource, target_resource, name, properties = {})
159
+ # rel = Relationship.new
160
+ # rel.source_id = source_resource.path
161
+ # rel.target_id = target_resource.path
162
+ # rel.name = name
163
+ # rel.properties = properties
164
+ #
165
+ # http_post('/feeds/' + source_resource.feed + '/relationships',
166
+ # rel.to_h)
167
+ # end
168
+
169
+ # def list_metrics_for_resource_type
170
+ # # TODO implement me
171
+ # end
172
+
173
+ # List metric (definitions) for the passed resource. It is possible to filter down the
174
+ # result by a filter to only return a subset. The
175
+ # @param [Resource] resource
176
+ # @param [Hash{Symbol=>String}] filter for 'type' and 'match'
177
+ # Metric type can be one of 'GAUGE', 'COUNTER', 'AVAILABILITY'. If a key is missing
178
+ # it will not be used for filtering
179
+ # @return [Aray<Metric>] List of metrics that can be empty.
180
+ # @example
181
+ # # Filter by type and match on metrics id
182
+ # client.list_metrics_for_resource(wild_fly, type: 'GAUGE', match: 'Metrics~Heap')
183
+ # # Filter by type only
184
+ # client.list_metrics_for_resource(wild_fly, type: 'COUNTER')
185
+ # # Don't filter, return all metric definitions
186
+ # client.list_metrics_for_resource(wild_fly)
187
+ def list_metrics_for_resource(resource, filter = {})
188
+ the_feed = hawk_escape resource.feed
189
+ the_id = hawk_escape resource.id
190
+
191
+ ret = http_get('/feeds/' +
192
+ the_feed + '/resources/' +
193
+ the_id + '/metrics')
194
+ val = []
195
+ ret.each do |m|
196
+ metric_new = Metric.new(m)
197
+ found = should_include?(metric_new, filter)
198
+ val.push(metric_new) if found
199
+ end
200
+ val
201
+ end
202
+
203
+ private
204
+
205
+ def should_include?(metric_new, filter)
206
+ found = true
207
+ if filter.empty?
208
+ found = true
209
+ else
210
+ found = false unless filter[:type] == (metric_new.type) || filter[:type].nil?
211
+ found = false unless filter[:match].nil? || metric_new.id.include?(filter[:match])
212
+ end
213
+ found
214
+ end
215
+ end
216
+
217
+ # A ResourceType is like a class definition for {Resource}s
218
+ # ResourceTypes are currently unique per feed, but one can assume
219
+ # that a two types with the same name of two different feeds are
220
+ # (more or less) the same.
221
+ class ResourceType
222
+ # @return [String] Full path of the type
223
+ attr_reader :path
224
+ # @return [String] Name of the type
225
+ attr_reader :name
226
+ # @return [String] Name of the type
227
+ attr_reader :id
228
+ # @return [String] Feed this type belongs to
229
+ attr_reader :feed
230
+ # @return [String] Environment this Type belongs to - currently unused
231
+ attr_reader :env
232
+ # @return [String] Properties of this type
233
+ attr_reader :properties
234
+
235
+ def initialize(rt_hash)
236
+ @id = rt_hash['id']
237
+ @path = rt_hash['path']
238
+ @name = rt_hash['name'] || rt_hash['id']
239
+ @properties = rt_hash['properties']
240
+ @_hash = rt_hash.dup
241
+
242
+ tmp = path.split('/')
243
+ tmp.each do |pair|
244
+ (key, val) = pair.split(';')
245
+ case key
246
+ when 'f'
247
+ @feed = val
248
+ when 'e'
249
+ @env = val
250
+ end
251
+ end
252
+ end
253
+
254
+ # Returns a hash representation of the resource type
255
+ # @return [Hash<String,Object>] hash of the type
256
+ def to_h
257
+ @_hash.dup
258
+ end
259
+ end
260
+
261
+ # A Resource is an instantiation of a {ResourceType}
262
+ class Resource
263
+ # @return [String] Full path of the resource including feed id
264
+ attr_reader :path
265
+ # @return [String] Name of the resource
266
+ attr_reader :name
267
+ # @return [String] Name of the resource
268
+ attr_reader :id
269
+ # @return [String] Name of the feed for this resource
270
+ attr_reader :feed
271
+ # @return [String] Name of the environment for this resource -- currently unused
272
+ attr_reader :env
273
+ # @return [String] Full path of the {ResourceType}
274
+ attr_reader :type_path
275
+ # @return [Hash<String,Object>] Hash with additional, resource specific properties
276
+ attr_reader :properties
277
+
278
+ def initialize(res_hash)
279
+ @id = res_hash['id']
280
+ @path = res_hash['path']
281
+ @properties = res_hash['properties'] || {}
282
+ @type_path = res_hash['type']['path']
283
+ @_hash = res_hash
284
+
285
+ tmp = @path.split('/')
286
+ tmp.each do |pair|
287
+ (key, val) = pair.split(';')
288
+ case key
289
+ when 'f'
290
+ @feed = val
291
+ when 'e'
292
+ @env = val
293
+ when 'n'
294
+ @name = val.nil? ? id : val
295
+ end
296
+ end
297
+ self
298
+ end
299
+
300
+ def to_h
301
+ @_hash.deep_dup
302
+ end
303
+ end
304
+
305
+ # Definition of a Metric inside the inventory.
306
+ class Metric
307
+ # @return [String] Full path of the metric (definition)
308
+ attr_reader :path
309
+ # @return [String] Name of the metric
310
+ attr_reader :name
311
+ attr_reader :id
312
+ attr_reader :feed
313
+ attr_reader :env
314
+ attr_reader :type
315
+ attr_reader :unit
316
+ # @return [Long] collection interval in seconds
317
+ attr_reader :collection_interval
318
+
319
+ def initialize(metric_hash)
320
+ @id = metric_hash['id']
321
+ @path = metric_hash['path']
322
+ @name = metric_hash['name'] || @id
323
+ @_hash = metric_hash.dup
324
+
325
+ tmp = path.split('/')
326
+ tmp.each do |pair|
327
+ (key, val) = pair.split(';')
328
+ case key
329
+ when 'f'
330
+ @feed = val
331
+ when 'e'
332
+ @env = val
333
+ when 'n'
334
+ @name = val.nil? ? id : val
335
+ end
336
+ end
337
+ @type = metric_hash['type']['type']
338
+ @unit = metric_hash['type']['unit']
339
+ @collection_interval = metric_hash['collectionInterval']
340
+ end
341
+
342
+ def to_h
343
+ @_hash.dup
344
+ end
345
+ end
346
+
347
+ # Definition of a Relationship between two entities in Inventory
348
+ class Relationship
349
+ attr_accessor :source_id
350
+ attr_reader :target_id
351
+ attr_reader :properties
352
+ attr_reader :name
353
+ attr_reader :id
354
+
355
+ def initialize(hash = {})
356
+ if hash.empty?
357
+ @properties = {}
358
+ return
359
+ end
360
+
361
+ @source_id = hash['source']
362
+ @target_id = hash['target']
363
+ @properties = hash['properties']
364
+ @name = hash['name']
365
+ @id = hash['id']
366
+ end
367
+
368
+ def to_h
369
+ hash = {}
370
+ hash['source'] = @source_id
371
+ hash['target'] = @target_id
372
+ hash['properties'] = @properties
373
+ hash['name'] = @name
374
+ hash['id'] = @id
375
+ hash
376
+ end
377
+ end
378
+ end
@@ -1,6 +1,7 @@
1
1
  require 'erb'
2
2
 
3
3
  module Hawkular::Metrics
4
+ # Client to access the Hawkular_metrics subsystem
4
5
  class Client
5
6
  # @!visibility private
6
7
  def default_timestamp(array)
@@ -11,6 +12,13 @@ module Hawkular::Metrics
11
12
  array
12
13
  end
13
14
 
15
+ # Return version and status information for the used version of Hawkular-Metrics
16
+ # @return [Hash{String=>String}]
17
+ # ('Implementation-Version', 'Built-From-Git-SHA1', 'Status')
18
+ def fetch_version_and_status
19
+ http_get('/status')
20
+ end
21
+
14
22
  # Push data for multiple metrics of all supported types
15
23
  # @param gauges [Array]
16
24
  # @param counters [Array]
@@ -60,8 +68,9 @@ module Hawkular::Metrics
60
68
  # Query metric definitions by tags
61
69
  # @param tags [Hash]
62
70
  # @return [Array[MetricDefinition]]
63
- def query(tags)
64
- @client.http_get("/metrics/?type=#{@type}&tags=#{tags_param(tags)}").map do |g|
71
+ def query(tags = nil)
72
+ tags_filter = tags.nil? ? '' : "&tags=#{tags_param(tags)}"
73
+ @client.http_get("/metrics/?type=#{@type}#{tags_filter}").map do |g|
65
74
  Hawkular::Metrics::MetricDefinition.new(g)
66
75
  end
67
76
  end
@@ -70,7 +79,8 @@ module Hawkular::Metrics
70
79
  # @param id [String]
71
80
  # @return [MetricDefinition]
72
81
  def get(id)
73
- Hawkular::Metrics::MetricDefinition.new(@client.http_get("/#{@resource}/#{id}"))
82
+ the_id = @client.hawk_escape id
83
+ Hawkular::Metrics::MetricDefinition.new(@client.http_get("/#{@resource}/#{the_id}"))
74
84
  end
75
85
 
76
86
  # update tags for given metric definition
@@ -106,8 +116,8 @@ module Hawkular::Metrics
106
116
  # @param bucketDuration [String] optional interval (default no aggregation)
107
117
  # @return [Array[Hash]] datapoints
108
118
  # @see #push_data #push_data for datapoint detail
109
- def get_data(id, starts: nil, ends: nil, bucketDuration: nil)
110
- params = { start: starts, end: ends, bucketDuration: bucketDuration }
119
+ def get_data(id, starts: nil, ends: nil, bucketDuration: nil, buckets: nil)
120
+ params = { start: starts, end: ends, bucketDuration: bucketDuration, buckets: buckets }
111
121
  resp = @client.http_get("/#{@resource}/#{ERB::Util.url_encode(id)}/data/?" +
112
122
  encode_params(params))
113
123
  resp.is_a?(Array) ? resp : [] # API returns no content (empty Hash) instead of empty array
@@ -159,7 +169,7 @@ module Hawkular::Metrics
159
169
  end
160
170
  end
161
171
 
162
- # Class that interracts with "counter" metric types
172
+ # Class that interacts with "counter" metric types
163
173
  class Counters < Metrics
164
174
  # @param client [Client]
165
175
  def initialize(client)
@@ -170,19 +180,19 @@ module Hawkular::Metrics
170
180
  # @param id [String] metric definition id
171
181
  # @param starts [Integer] optional timestamp (default now - 8h)
172
182
  # @param ends [Integer] optional timestamp (default now)
173
- # @param bucketDuration [String] optional interval (default no
183
+ # @param bucket_duration [String] optional interval (default no
174
184
  # aggregation)
175
185
  # @return [Array[Hash]] rate points
176
- def get_rate(id, starts: nil, ends: nil, bucketDuration: nil)
186
+ def get_rate(id, starts: nil, ends: nil, bucket_duration: nil)
177
187
  path = "/#{@resource}/#{ERB::Util.url_encode(id)}/rate"
178
- params = { start: starts, end: ends, bucketDuration: bucketDuration }
188
+ params = { start: starts, end: ends, bucketDuration: bucket_duration }
179
189
  resp = @client.http_get(path + '?' + encode_params(params))
180
190
  # API returns no content (empty Hash) instead of empty array
181
191
  resp.is_a?(Array) ? resp : []
182
192
  end
183
193
  end
184
194
 
185
- # Class that interracts with "availability" metric types
195
+ # Class that interacts with "availability" metric types
186
196
  class Availability < Metrics
187
197
  # @param client [Client]
188
198
  def initialize(client)