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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c23ea869e11663cc37756be45e49485350ecc024
4
- data.tar.gz: 1e236ca10f3b38f3c564bd1578dffa86dfe7b707
3
+ metadata.gz: ed7c1be5e375b0389cf9a4849fb45c78641becd0
4
+ data.tar.gz: 03c792250b1ba9ed81c25f9ecda174b983c843e2
5
5
  SHA512:
6
- metadata.gz: a285669dc4d93f4960c5ffddc54b8636a792022c191b571723442acd905300288807342accd267fbaab701461942e070365fd2a4611dae52165a377c52a44e0e
7
- data.tar.gz: ab8cec50610495c531c5e99c987a88df56cc36b71c1b02eb4922b533c347de364343e97faf410e1c56895d3f778e9a8a8e547eae05892f243d979a7418e50b6d
6
+ metadata.gz: b5b8f44790e31b63e0574a4d09b510de537275f121d88e93712e24fc33c1e7543ace9e9539f1beb410ff70f1fce8148edee7b4b7431601d7341407f820d4c05c
7
+ data.tar.gz: b77f46b103e59f10d7568dd1c96de81399192a01fe1fef2038d0f3635fbb8d1a545bcedc785b52bf60cbfea0d29a94eaa2a92f39b7e20f7c6e166057d770bd97
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- # - 1.9.3
5
- # - jruby-19mode
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
data/CHANGES.rdoc CHANGED
@@ -3,6 +3,14 @@
3
3
  This document describes the relevant changes beween releases of the
4
4
  _hawkular-client_ project.
5
5
 
6
+ === V 0.2.0
7
+
8
+ * Add support for Hawkular-Inventory and Hawkular-Alerts
9
+ * Reshuffeling of inner classes
10
+ * The sub-url that is passed to `http_*` methods is escaped via
11
+ `Addressable::URI.escape()`
12
+
13
+
6
14
  === V 0.1.2
7
15
 
8
16
  * Fix exception handling - this was missing `require 'English'`
data/README.rdoc CHANGED
@@ -10,14 +10,21 @@ A Ruby Hawkular Client.
10
10
  * Start a feature/bugfix branch
11
11
  * Commit and push until you are happy with your contribution
12
12
  * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
13
+ * Run your code through RuboCop (which is default when running `rake`) and fix complaints.
14
+ * When you open a pull request, watch out for failures on Travis.
15
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is
16
+ otherwise necessary, that is fine, but please isolate to its own commit so we can cherry-pick around it.
14
17
 
15
18
  == Running the tests
16
19
 
17
- * Copy the file spec/endpoint.yml.example to spec/endpoint.yml
18
- * Edit the endpoint properties in the file `spec/endpoint.yml`(user, password and host
19
- name)
20
- * From command line run => rake spec
20
+ Integration tests are recorded and played against cassettes recorded with VCR
21
+ (http://www.relishapp.com/vcr/vcr/docs)
22
+
23
+ * Edit the endpoint properties in the file `spec/endpoint.yml`(user, password and host name) if needed
24
+ * From command line run
25
+ rake spec
26
+ * To run the tests against a live server, set VCR_OFF to 1 as in
27
+ VCR_OFF=1 rake spec
21
28
 
22
29
  == Logging
23
30
 
@@ -1,11 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'metrics/version'
4
+ require 'version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = 'hawkular-client'
8
- gem.version = Hawkular::Metrics::VERSION
8
+ gem.version = Hawkular::VERSION
9
9
  gem.authors = ['Libor Zoubek', 'Heiko W. Rupp', 'Federico Simoncelli']
10
10
  gem.email = %w(lzoubek@redhat.com hrupp@redhat.com)
11
11
  gem.homepage = 'https://github.com/hawkular/hawkular-client-ruby'
@@ -0,0 +1,193 @@
1
+ require 'hawkular'
2
+ require 'ostruct'
3
+
4
+ # Alerts module provides access to Hawkular-Alerts.
5
+ # There are two main parts here: Triggers, that define alertable conditions
6
+ # and Alerts that represent a fired trigger.
7
+ # @see http://www.hawkular.org/docs/rest/rest-alerts.html
8
+ module Hawkular::Alerts
9
+ # Interface to use to talk to the Hawkular-Alerts component.
10
+ # @param entrypoint [String] base url of Hawkular-Alerts - e.g
11
+ # http://localhost:8080/hawkular/alerts
12
+ # @param credentials [Hash{String=>String}] Hash of username, password, token(optional)
13
+ class AlertsClient < Hawkular::BaseClient
14
+ def initialize(entrypoint = nil, credentials = {})
15
+ @entrypoint = entrypoint
16
+
17
+ super(entrypoint, credentials)
18
+ end
19
+
20
+ # Lists defined triggers in the system
21
+ # @param [Array] ids List of trigger ids. If provided, limits to the given triggers
22
+ # @param [Array] tags List of tags. If provided, limits to the given tags. Individual
23
+ # tags are of the format # key|value. Tags are OR'd together. If a tag-key shows up
24
+ # more than once, only the last one is accepted
25
+ # @return [Array<Trigger>] Triggers found
26
+ def list_triggers(ids = [], tags = [])
27
+ query = generate_query_params 'triggerIds' => ids, 'tags' => tags
28
+ sub_url = '/triggers' + query
29
+
30
+ ret = http_get(sub_url)
31
+
32
+ val = []
33
+ ret.each { |t| val.push(Trigger.new(t)) }
34
+ val
35
+ end
36
+
37
+ # Obtains one Trigger definition from the server.
38
+ # @param [String] trigger_id Id of the trigger to fetch
39
+ # @param full If true then conditions and dampenings for the trigger are also fetched
40
+ # @return [Trigger] the selected trigger
41
+ def get_single_trigger(trigger_id, full = false)
42
+ the_trigger = '/triggers/' + trigger_id
43
+ ret = http_get(the_trigger)
44
+ trigger = Trigger.new(ret)
45
+
46
+ if full
47
+ ret = http_get(the_trigger + '/conditions')
48
+ ret.each { |c| trigger.conditions.push(Trigger::Condition.new(c)) }
49
+ ret = http_get(the_trigger + '/dampenings')
50
+ ret.each { |c| trigger.dampenings.push(Trigger::Dampening.new(c)) }
51
+ end
52
+
53
+ trigger
54
+ end
55
+
56
+ # Obtain the alerts for the Trigger with the passed id
57
+ # @param [String] trigger_id Id of the trigger that has fired the alerts
58
+ # @return [Array<Alert>] List of alerts for the trigger. Can be empty
59
+ def get_alerts_for_trigger(trigger_id) # TODO: add additional filters
60
+ return [] unless trigger_id
61
+
62
+ url = '/?triggerIds=' + trigger_id
63
+ ret = http_get(url)
64
+ val = []
65
+ ret.each { |a| val.push(Alert.new(a)) }
66
+ val
67
+ end
68
+
69
+ # List fired alerts
70
+ # @return [Array<Alert>] List of alerts in the system. Can be empty
71
+ def list_alerts
72
+ ret = http_get('/')
73
+ val = []
74
+ ret.each { |a| val.push(Alert.new(a)) }
75
+ val
76
+ end
77
+
78
+ # Retrieve a single Alert by its id
79
+ # @param [String] alert_id id of the alert to fetch
80
+ # @return [Alert] Alert object retrieved
81
+ def get_single_alert(alert_id)
82
+ ret = http_get('/alert/' + alert_id)
83
+ val = Alert.new(ret)
84
+ val
85
+ end
86
+
87
+ # Mark one alert as resolved
88
+ # @param [String] alert_id Id of the alert to resolve
89
+ # @param [String] by name of the user resolving the alert
90
+ # @param [String] comment A comment on the resolution
91
+ def resolve_alert(alert_id, by = nil, comment = nil)
92
+ sub_url = "/resolve/#{alert_id}"
93
+ query = generate_query_params 'resolvedBy' => by, 'resolvedNotes' => comment
94
+ sub_url += query
95
+ http_put(sub_url, {})
96
+
97
+ true
98
+ end
99
+
100
+ # Mark one alert as acknowledged
101
+ # @param [String] alert_id Id of the alert to ack
102
+ # @param [String] by name of the user acknowledging the alert
103
+ # @param [String] comment A comment on the acknowledge
104
+ def acknowledge_alert(alert_id, by = nil, comment = nil)
105
+ sub_url = "/ack/#{alert_id}"
106
+ query = generate_query_params 'ackBy' => by, 'ackNotes' => comment
107
+ sub_url += query
108
+ http_put(sub_url, {})
109
+
110
+ true
111
+ end
112
+ end
113
+
114
+ # Representation of one Trigger
115
+ class Trigger
116
+ attr_reader :id, :name, :context, :actions, :auto_disable, :auto_enable
117
+ attr_reader :auto_resolve, :auto_resolve_alerts
118
+ attr_reader :tenant, :description, :group, :severity
119
+ attr_reader :conditions, :dampenings, :event_type
120
+ attr_accessor :enabled
121
+
122
+ def initialize(trigger_hash)
123
+ @_hash = trigger_hash
124
+ @conditions = []
125
+ @dampenings = []
126
+ @id = trigger_hash['id']
127
+ @name = trigger_hash['name']
128
+ @enabled = trigger_hash['enabled']
129
+ @severity = trigger_hash['severity']
130
+ @auto_resolve = trigger_hash['autoResolve']
131
+ @auto_resolve_alerts = trigger_hash['autoResolveAlerts']
132
+ @event_type = trigger_hash['eventType']
133
+ @tenant = trigger_hash['tenantId']
134
+ @description = trigger_hash['description']
135
+ @auto_enable = trigger_hash['autoEnable']
136
+ @auto_disable = trigger_hash['autoDisable']
137
+ end
138
+
139
+ # def enable
140
+ # @enabled = true
141
+ # @_hash['enabled'] = true
142
+ # url = '/triggers/' + @id
143
+ # Hawkular::BaseClient.http_put(url, @_hash)
144
+ # end
145
+ #
146
+ # def disable
147
+ # @enabled = false
148
+ # url = '/triggers/' + @id
149
+ # AlertsClient.http_put(url, self)
150
+ # end
151
+
152
+ # Representing of one Condition
153
+ class Condition
154
+ attr_reader :condition_id, :type, :operator_low, :operator_high, :threshold_low
155
+ attr_reader :in_range, :threshold_high
156
+
157
+ def initialize(cond_hash)
158
+ @condition_id = cond_hash['conditionId']
159
+ @type = cond_hash['type']
160
+ @operator_low = cond_hash['operatorLow']
161
+ @operator_high = cond_hash['operatorHigh']
162
+ @threshold_low = cond_hash['thresholdLow']
163
+ @threshold_high = cond_hash['thresholdHigh']
164
+ @in_range = cond_hash['inRange']
165
+ end
166
+ end
167
+
168
+ # Representation of one Dampening setting
169
+ class Dampening
170
+ attr_reader :dampening_id, :type, :eval_true_setting, :eval_total_setting, :eval_time_setting
171
+ attr_reader :current_evals
172
+
173
+ def initialize(damp_hash)
174
+ @current_evals = {}
175
+ @dampening_id = damp_hash['dampeningId']
176
+ @type = damp_hash['type']
177
+ @eval_true_setting = damp_hash['evalTrueSetting']
178
+ @eval_total_setting = damp_hash['evalTotalSetting']
179
+ @eval_time_setting = damp_hash['evalTimeSetting']
180
+ end
181
+ end
182
+ end
183
+
184
+ # Representation of one alert.
185
+ # The name of the members are literally what they are in the JSON sent from the
186
+ # server and not 'rubyfied'. So 'alertId' and not 'alert_ic'
187
+ # Check http://www.hawkular.org/docs/rest/rest-alerts.html#Alert for details
188
+ class Alert < OpenStruct
189
+ def initialize(alert_hash)
190
+ super(alert_hash)
191
+ end
192
+ end
193
+ end
@@ -1,60 +1,20 @@
1
-
2
-
3
- require 'json'
4
- require 'rest-client'
5
- require 'English'
1
+ require 'base64'
2
+ require 'addressable/uri'
6
3
 
7
4
  module Hawkular
8
- # Metrics module provides access to Hawkular Metrics REST API
9
- # @see http://www.hawkular.org/docs/rest/rest-metrics.html Hawkular Metrics REST API Documentation
10
- # @example Create Hawkular-Metrics client and start pushing some metric data
11
- # # create client instance
12
- # client = Hawkular::Metrics::Client::new("http://server","username",
13
- # "password",{"tenant" => "your tenant ID"})
14
- # # push gauge metric data for metric called "myGauge" (no need to create metric definition
15
- # # unless you wish to specify data retention)
16
- # client.gauges.push_data("myGauge", {:value => 3.1415925})
17
5
  module Metrics
18
6
  end
19
- end
20
-
21
- require 'metrics/types'
22
- require 'metrics/tenant_api'
23
- require 'metrics/metric_api'
24
-
25
- module Hawkular::Metrics
26
- class HawkularException < StandardError
27
- def initialize(message)
28
- @message = message
29
- super
30
- end
31
-
32
- attr_reader :message
33
- end
34
7
 
35
- class Client
8
+ # This is the base functionality for all the clients,
9
+ # that inherit from it. You should not directly use it,
10
+ # but through the more specialized clients.
11
+ class BaseClient
36
12
  # @!visibility private
37
13
  attr_reader :credentials, :entrypoint, :options
38
14
  # @return [Tenants] access tenants API
39
15
  attr_reader :tenants
40
- # @return [Counters] access counters API
41
- attr_reader :counters
42
- # @return [Gauges] access gauges API
43
- attr_reader :gauges
44
- # @return [Availability] access counters API
45
- attr_reader :avail
46
-
47
- # Construct a new Hawkular Metrics client class.
48
- # optional parameters
49
- # @param entrypoint [String] Base url of the Hawkular (metrics) server
50
- # @param credentials Hash of username, password, token(optional)
51
- # @param options [Hash{String=>String}] client options
52
- # @example initialize with Hawkular-tenant option
53
- # Hawkular::Metrics::Client::new("http://server",
54
- # {username:"username",password:"password"},
55
- # {"tenant" => "your tenant ID"})
56
- #
57
- def initialize(entrypoint = 'http://localhost:8080/hawkular/metrics',
16
+
17
+ def initialize(entrypoint = nil,
58
18
  credentials = {},
59
19
  options = {})
60
20
  @entrypoint = entrypoint
@@ -72,10 +32,7 @@ module Hawkular::Metrics
72
32
  headers: {}
73
33
  }.merge(options)
74
34
 
75
- @tenants = Client::Tenants.new self
76
- @counters = Client::Counters.new self
77
- @gauges = Client::Gauges.new self
78
- @avail = Client::Availability.new self
35
+ fail 'You need to provide an entrypoint' if entrypoint.nil?
79
36
  end
80
37
 
81
38
  def http_get(suburl, headers = {})
@@ -86,6 +43,25 @@ module Hawkular::Metrics
86
43
  handle_fault $ERROR_INFO
87
44
  end
88
45
 
46
+ # Escapes the passed url part. This is necessary,
47
+ # as many ids inside Hawkular can contain characters
48
+ # that are invalid for an url/uri.
49
+ # The passed value is duplicated
50
+ # @param [String] url_part Part of an url to be escaped
51
+ # @return [String] escaped url_part as new string
52
+ def hawk_escape(url_part)
53
+ sub_url = url_part.dup
54
+ sub_url.gsub!('%', '%25')
55
+ sub_url.gsub!(' ', '%20')
56
+ sub_url.gsub!('[', '%5b')
57
+ sub_url.gsub!(']', '%5d')
58
+ sub_url.gsub!('|', '%7c')
59
+ sub_url.gsub!('(', '%28')
60
+ sub_url.gsub!(')', '%29')
61
+ sub_url.gsub!('/', '%2f')
62
+ sub_url
63
+ end
64
+
89
65
  def http_post(suburl, hash, headers = {})
90
66
  body = JSON.generate(hash)
91
67
  res = rest_client(suburl).post(body, http_headers(headers))
@@ -153,8 +129,62 @@ module Hawkular::Metrics
153
129
  Integer(Time.now.to_f * 1000)
154
130
  end
155
131
 
132
+ # Encode the passed credentials (username/password) into a base64
133
+ # representation that can be used to generate a Http-Authentication header
134
+ # @param credentials [Hash{:username,:password}]
135
+ # @return [String] Base64 encoded result
136
+ def base_64_credentials(credentials = {})
137
+ creds = credentials.empty? ? @credentials : credentials
138
+
139
+ encoded = Base64.encode64(creds[:username] + ':' + creds[:password])
140
+ encoded.rstrip!
141
+ end
142
+
143
+ # Generate a query string from the passed hash.
144
+ # This string starts with a `?` if the hash is
145
+ # not empty.
146
+ # Values may be an array, in which case the array values are joined together by `,`.
147
+ # @param param_hash [Hash] key-values pairs
148
+ # @return [String] complete query string to append to a base url
149
+ def generate_query_params(param_hash = {})
150
+ return '' if param_hash.size == 0
151
+
152
+ num = count_non_nil_values(param_hash)
153
+
154
+ i = 0
155
+ ret = ''
156
+ ret = '?' if num > 0
157
+ param_hash.each do |k, v|
158
+ next if not_suitable?(v)
159
+
160
+ if v.instance_of? Array
161
+ part = "#{k}=#{v.join(',')}"
162
+ else
163
+ part = "#{k}=#{v}"
164
+ end
165
+
166
+ ret += hawk_escape part
167
+
168
+ i += 1
169
+ ret += '&' if i < num
170
+ end
171
+ ret
172
+ end
173
+
156
174
  private
157
175
 
176
+ def not_suitable?(v)
177
+ v.nil? || (v.instance_of? Array) && v.size == 0
178
+ end
179
+
180
+ def count_non_nil_values(param_hash)
181
+ num = 0
182
+ param_hash.each do |_k, v|
183
+ num += 1 unless not_suitable?(v)
184
+ end
185
+ num
186
+ end
187
+
158
188
  def token_header
159
189
  @credentials[:token].nil? ? {} : { 'Authorization' => "Bearer #{@credentials[:token]}" }
160
190
  end
@@ -178,4 +208,15 @@ module Hawkular::Metrics
178
208
  end
179
209
  end
180
210
  end
211
+
212
+ # Specialized exception to be thrown
213
+ # when the interction with Hawkular fails
214
+ class HawkularException < StandardError
215
+ def initialize(message)
216
+ @message = message
217
+ super
218
+ end
219
+
220
+ attr_reader :message
221
+ end
181
222
  end