wavefront-sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +20 -0
  3. data/.gitignore +4 -0
  4. data/.rubocop.yml +1157 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +58 -0
  8. data/LICENSE.txt +27 -0
  9. data/README.md +103 -0
  10. data/Rakefile +18 -0
  11. data/lib/wavefront-sdk/alert.rb +195 -0
  12. data/lib/wavefront-sdk/base.rb +251 -0
  13. data/lib/wavefront-sdk/cloudintegration.rb +88 -0
  14. data/lib/wavefront-sdk/credentials.rb +79 -0
  15. data/lib/wavefront-sdk/dashboard.rb +157 -0
  16. data/lib/wavefront-sdk/event.rb +173 -0
  17. data/lib/wavefront-sdk/exception.rb +39 -0
  18. data/lib/wavefront-sdk/externallink.rb +77 -0
  19. data/lib/wavefront-sdk/maintenancewindow.rb +75 -0
  20. data/lib/wavefront-sdk/message.rb +36 -0
  21. data/lib/wavefront-sdk/metric.rb +52 -0
  22. data/lib/wavefront-sdk/mixins.rb +60 -0
  23. data/lib/wavefront-sdk/proxy.rb +95 -0
  24. data/lib/wavefront-sdk/query.rb +96 -0
  25. data/lib/wavefront-sdk/response.rb +56 -0
  26. data/lib/wavefront-sdk/savedsearch.rb +88 -0
  27. data/lib/wavefront-sdk/search.rb +58 -0
  28. data/lib/wavefront-sdk/source.rb +131 -0
  29. data/lib/wavefront-sdk/user.rb +108 -0
  30. data/lib/wavefront-sdk/validators.rb +395 -0
  31. data/lib/wavefront-sdk/version.rb +1 -0
  32. data/lib/wavefront-sdk/webhook.rb +73 -0
  33. data/lib/wavefront-sdk/write.rb +225 -0
  34. data/pkg/wavefront-client-3.5.0.gem +0 -0
  35. data/spec/.rubocop.yml +14 -0
  36. data/spec/spec_helper.rb +157 -0
  37. data/spec/wavefront-sdk/alert_spec.rb +83 -0
  38. data/spec/wavefront-sdk/base_spec.rb +88 -0
  39. data/spec/wavefront-sdk/cloudintegration_spec.rb +54 -0
  40. data/spec/wavefront-sdk/credentials_spec.rb +55 -0
  41. data/spec/wavefront-sdk/dashboard_spec.rb +74 -0
  42. data/spec/wavefront-sdk/event_spec.rb +83 -0
  43. data/spec/wavefront-sdk/externallink_spec.rb +65 -0
  44. data/spec/wavefront-sdk/maintenancewindow_spec.rb +48 -0
  45. data/spec/wavefront-sdk/message_spec.rb +19 -0
  46. data/spec/wavefront-sdk/metric_spec.rb +21 -0
  47. data/spec/wavefront-sdk/mixins_spec.rb +27 -0
  48. data/spec/wavefront-sdk/proxy_spec.rb +41 -0
  49. data/spec/wavefront-sdk/query_spec.rb +51 -0
  50. data/spec/wavefront-sdk/resources/test.conf +10 -0
  51. data/spec/wavefront-sdk/response_spec.rb +47 -0
  52. data/spec/wavefront-sdk/savedsearch_spec.rb +54 -0
  53. data/spec/wavefront-sdk/search_spec.rb +47 -0
  54. data/spec/wavefront-sdk/source_spec.rb +48 -0
  55. data/spec/wavefront-sdk/user_spec.rb +56 -0
  56. data/spec/wavefront-sdk/validators_spec.rb +238 -0
  57. data/spec/wavefront-sdk/webhook_spec.rb +50 -0
  58. data/spec/wavefront-sdk/write_spec.rb +167 -0
  59. data/wavefront-sdk.gemspec +34 -0
  60. metadata +269 -0
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.2.7
5
+ - 2.3.4
6
+ - 2.4.1
7
+ before_install: gem install bundler --no-rdoc --no-ri
8
+ deploy:
9
+ provider: rubygems
10
+ api_key:
11
+ secure: dfmL5JwBn+u3cUmyAaDsApDa7ljGajGNz3GDcKd2J8FOt7+a758/lmL8EQ34sDT1ZFotrxn/y1RbgXlaDxAE1XDfrZbjckmx7a6wa2sqR3kBraJ2tx7CiXodbw3Z8XZf9WLb0kYGmlLtI73GNcuunMt/9f1cobqWISRLHw6b7amlO7GW2ZBZgzRS+N8TSS2dicIvKMo5HoMYU+uWLM4zDFBPnGNcMiWxh8ysLzJoKqA9kbBUyCVEZ03MlV7G71ObvWCLasKnZ3W5U+K1NbgU7mgMYfl9KIcA4y9hQ9hUCijk40SmT7ffy3P2gq8zblC/4x5Eefpau9X/bdLwXoRCIzqk05t4f45wstj2auHGK0HJwOYRtx8apdaLSgyJ5lQpGcbCRu40WR9mDkaM8m9n3u2o6GJmftCg3AN1QtsourmQB84x67LEbHzValMaokrbCol4XeWqlC+dCNLPixemQRBvcNfI3V9C6RqVGfjpoGlSTI+RkQqwm01PcxpeqIVfdMd1wnfUuAOywUO6UpvtK9TZaxg0NnVElXpPseQbtzulLwZ7R5Y3A4Ss8Z7w43c1KHxTkg54FWUOp065ItjAc4lmyORXq/2+F7sMvRN6dtCLaXTUlkYuU3cjFLIPlLGFYgqq4T4xQa+e5NEK1XW7nghv+IRfKfyVeZsB0WpY+uc=
12
+ gem: wavefront-sdk
13
+ on:
14
+ tags: true
15
+ repo: snltd/wavefront-sdk
16
+ ruby: 2.3.4
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wavefront-sdk (0.0.1)
5
+ faraday (>= 0.12.1, < 0.13)
6
+ inifile (>= 3.0.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.5.1)
12
+ public_suffix (~> 2.0, >= 2.0.2)
13
+ ast (2.3.0)
14
+ crack (0.4.3)
15
+ safe_yaml (~> 1.0.0)
16
+ faraday (0.12.1)
17
+ multipart-post (>= 1.2, < 3)
18
+ hashdiff (0.3.2)
19
+ inifile (3.0.0)
20
+ minitest (5.8.5)
21
+ multipart-post (2.0.0)
22
+ parser (2.4.0.0)
23
+ ast (~> 2.2)
24
+ powerpack (0.1.1)
25
+ public_suffix (2.0.5)
26
+ rainbow (2.2.1)
27
+ rake (12.0.0)
28
+ rubocop (0.47.1)
29
+ parser (>= 2.3.3.1, < 3.0)
30
+ powerpack (~> 0.1)
31
+ rainbow (>= 1.99.1, < 3.0)
32
+ ruby-progressbar (~> 1.7)
33
+ unicode-display_width (~> 1.0, >= 1.0.1)
34
+ ruby-progressbar (1.8.1)
35
+ safe_yaml (1.0.4)
36
+ spy (0.4.5)
37
+ unicode-display_width (1.1.3)
38
+ webmock (2.3.2)
39
+ addressable (>= 2.3.6)
40
+ crack (>= 0.3.2)
41
+ hashdiff
42
+ yard (0.9.5)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ bundler (~> 1.3)
49
+ minitest (~> 5.8, >= 5.8.0)
50
+ rake (~> 12.0)
51
+ rubocop (~> 0.47.0)
52
+ spy (~> 0.4.0)
53
+ wavefront-sdk!
54
+ webmock (~> 2.3, >= 2.3.2)
55
+ yard (~> 0.9.5)
56
+
57
+ BUNDLED WITH
58
+ 1.14.6
data/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2017, Sysdef Ltd
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in
13
+ the documentation and/or other materials provided with the
14
+ distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20
+ COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # wavefront-sdk [![Build Status](https://travis-ci.org/snltd/wavefront-sdk.svg?branch=master)](https://travis-ci.org/snltd/wavefront-sdk) [![Code Climate](https://codeclimate.com/github/snltd/wavefront-sdk/badges/gpa.svg)](https://codeclimate.com/github/snltd/wavefront-sdk) [![Issue Count](https://codeclimate.com/github/snltd/wavefront-sdk/badges/issue_count.svg)](https://codeclimate.com/github/snltd/wavefront-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/snltd/wavefront-sdk/badge.svg)](https://snyk.io/test/github/snltd/wavefront-sdk)
2
+
3
+ This is a Ruby SDK for v2 of
4
+ [Wavefront](https://www.wavefront.com/)'s public API. It supports Ruby >= 2.2.
5
+
6
+ Note that it currently has major version number `0`. This means *it
7
+ is not finished*. Until version `1` comes out, I reserve the right
8
+ to change, break, and befoul the code and the gem.
9
+
10
+ ## Installation
11
+
12
+ ```
13
+ $ gem install wavefront-sdk
14
+ ```
15
+
16
+ or to build locally,
17
+
18
+ ```
19
+ $ gem build wavefront-sdk.gemspec
20
+ ```
21
+
22
+ ## Examples
23
+
24
+ First, let's list the IDs of the users in our account. The `list()` method
25
+ will return a `Wavefront::Response::User` object with a list of items. Most
26
+ response classes behave this way.
27
+
28
+ ```ruby
29
+ # Define our API endpoint. (This is not a valid token!)
30
+
31
+ CREDS = { endpoint: 'metrics.wavefront.com',
32
+ token: 'c7a1ff30-0dd8-fa60-e14d-f58f91bafc0e' }
33
+
34
+ require 'wavefront-sdk/user'
35
+
36
+ # You can pass in a Ruby logger object, and tell the SDK to be
37
+ # verbose.
38
+
39
+ require 'logger'
40
+ log = Logger.new(STDOUT)
41
+
42
+ wf = Wavefront::User.new(CREDS, verbose: true, logger: log)
43
+
44
+ wf.list.response.items.each { |user| puts user[:identifier] }
45
+
46
+ # And delete the user 'lolex@oldplace.com'
47
+
48
+ wf.delete('lolex@oldplace.com')
49
+ ```
50
+
51
+ Retrieve a timeseries over the last 10 minutes, with one minute bucket
52
+ granularity. We will describe the time as a Ruby object, but could also use
53
+ an epoch timestamp.
54
+
55
+
56
+ ```ruby
57
+ require 'wavefront-sdk/query'
58
+
59
+ Wavefront::Query.new(CREDS).query(
60
+ 'ts("prod.www.host.tenant.physicalmem.usage")',
61
+ :m,
62
+ (Time.now - 600)
63
+ )
64
+ ```
65
+
66
+ We can write points too, assuming we have a proxy. You can't write points
67
+ directly via the API. Unlike all other classes, this one requires the proxy
68
+ address and port as its credential hash.
69
+
70
+ ```ruby
71
+ require 'wavefront-sdk/write'
72
+
73
+ W_CREDS = { proxy: 'wavefront.localnet', port: 2878 }
74
+
75
+ wf = Wavefront::Write.new(W_CREDS, debug: true)
76
+
77
+ task = wf.write( [{ path: 'dev.test.sdk', value: 10 }])
78
+
79
+ p task.response
80
+ #<struct sent=1, rejected=0, unsent=0>
81
+ puts task.status.result
82
+ #OK
83
+ ```
84
+
85
+ The SDK also provides a helper class for extracting credentials from a
86
+ configuration file. If you don't supply a file, defaults will be
87
+ used.
88
+
89
+ ```ruby
90
+ require 'wavefront-sdk/credentials'
91
+
92
+ c = Wavefront::Credentials.new
93
+
94
+ # Now use that to list the proxies in our account
95
+
96
+ require 'wavefront-sdk/proxy'
97
+
98
+ p Wavefront::Proxy.new(c.creds).list
99
+
100
+ # It works for proxies too:
101
+
102
+ wf = Wavefront::Write.new(c.proxy)
103
+ ```
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'yard'
2
+ require 'rake/testtask'
3
+ require 'rubocop/rake_task'
4
+
5
+ task default: :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = 'spec/wavefront-sdk/*_spec.rb'
9
+ t.warning = false
10
+ end
11
+
12
+ RuboCop::RakeTask.new(:rubocop) do |t|
13
+ t.options = ['--display-cop-names']
14
+ end
15
+
16
+ YARD::Rake::YardocTask.new do |t|
17
+ t.files = ['lib/wavefront-sdk/*rb']
18
+ end
@@ -0,0 +1,195 @@
1
+ require_relative './base'
2
+
3
+ module Wavefront
4
+ #
5
+ # View and manage alerts. Alerts are identified by their millisecond
6
+ # epoch timestamp. Returns a Wavefront::Response::Alert object.
7
+ #
8
+ class Alert < Wavefront::Base
9
+
10
+ # GET /api/v2/alert
11
+ # Get all alerts for a customer
12
+ #
13
+ # @param offset [Int] alert at which the list begins
14
+ # @param limit [Int] the number of alerts to return
15
+ # @return [Hash]
16
+ #
17
+ def list(offset = 0, limit = 100)
18
+ api_get('', { offset: offset, limit: limit })
19
+ end
20
+
21
+ # POST /api/v2/alert
22
+ # Create a specific alert. We used to validate input here, but
23
+ # this couples the SDK too tightly to the API. Now it's just a
24
+ # generic POST of a hash.
25
+ #
26
+ # @param body [Hash] description of alert
27
+ # @return [Hash]
28
+ #
29
+ def create(body)
30
+ raise ArgumentError unless body.is_a?(Hash)
31
+ api_post('', body, 'application/json')
32
+ end
33
+
34
+ # DELETE /api/v2/alert/{id}
35
+ # Delete a specific alert.
36
+ #
37
+ # Deleting an active alert moves it to 'trash', from where it can
38
+ # be restored with an #undelete operation. Deleting an alert in
39
+ # 'trash' removes it for ever.
40
+ #
41
+ # @param id [String] ID of the alert
42
+ # @return [Hash]
43
+ #
44
+ def delete(id)
45
+ wf_alert_id?(id)
46
+ api_delete(id)
47
+ end
48
+
49
+ # GET /api/v2/alert/{id}
50
+ # GET /api/v2/alert/{id}/history/{version}
51
+ # Get a specific alert / Get a specific historical version of a
52
+ # specific alert.
53
+ #
54
+ # @param id [String] ID of the alert
55
+ # @param version [Integer] version of alert
56
+ # @return [Hash]
57
+ #
58
+ def describe(id, version = nil)
59
+ wf_alert_id?(id)
60
+ wf_version?(version) if version
61
+ fragments = [id]
62
+ fragments += ['history', version] if version
63
+ api_get(fragments.uri_concat)
64
+ end
65
+
66
+ # PUT /api/v2/alert/{id}
67
+ # Update a specific alert.
68
+ #
69
+ # @param id [String] a Wavefront alert ID
70
+ # @param body [Hash] description of event. See body_desc()
71
+ # @return [Hash]
72
+ #
73
+ def update(id, body)
74
+ wf_alert_id?(id)
75
+ raise ArgumentError unless body.is_a?(Hash)
76
+ api_put(id, body, 'application/json')
77
+ end
78
+
79
+ # GET /api/v2/alert/{id}/history
80
+ # Get the version history of a specific alert.
81
+ #
82
+ # @param id [String] ID of the alert
83
+ # @return [Hash]
84
+ #
85
+ def history(id)
86
+ wf_alert_id?(id)
87
+ api_get([id, 'history'].uri_concat)
88
+ end
89
+
90
+ # POST /api/v2/alert/{id}/snooze
91
+ # Snooze a specific alert for some number of seconds.
92
+ #
93
+ # @param id [String] ID of the alert
94
+ # @param time [Integer] how many seconds to snooze for. Nil is indefinite
95
+ # @returns [Hash] object describing the alert with status and
96
+ # response keys
97
+ #
98
+ def snooze(id, seconds = nil)
99
+ wf_alert_id?(id)
100
+ qs = seconds ? "?seconds=#{seconds}" : ''
101
+ api_post([id, "snooze#{qs}"].uri_concat, nil)
102
+ end
103
+
104
+ # GET /api/v2/alert/{id}/tag
105
+ # Get all tags associated with a specific alert.
106
+ #
107
+ # @param id [String] ID of the alert
108
+ # @returns [Hash] object describing the alert with status and
109
+ # response keys
110
+ #
111
+ def tags(id)
112
+ wf_alert_id?(id)
113
+ api_get([id, 'tag'].uri_concat)
114
+ end
115
+
116
+ # POST /api/v2/alert/{id}/tag
117
+ # Set all tags associated with a specific alert.
118
+ #
119
+ # @param id [String] ID of the alert
120
+ # @param tags [Array] list of tags to set.
121
+ # @returns [Hash] object describing the alert with status and
122
+ # response keys
123
+ #
124
+ def tag_set(id, tags)
125
+ wf_alert_id?(id)
126
+ tags = Array(tags)
127
+ tags.each { |t| wf_string?(t) }
128
+ api_post([id, 'tag'].uri_concat, tags.to_json, 'application/json')
129
+ end
130
+
131
+ # DELETE /api/v2/alert/{id}/tag/{tagValue}
132
+ # Remove a tag from a specific alert.
133
+ #
134
+ # @param id [String] ID of the alert
135
+ # @param tag [String] tag to delete
136
+ # @returns [Hash] object with 'status' key and empty 'repsonse'
137
+ #
138
+ def tag_delete(id, tag)
139
+ wf_alert_id?(id)
140
+ wf_string?(tag)
141
+ api_delete([id, 'tag', tag].uri_concat)
142
+ end
143
+
144
+ # PUT /api/v2/alert/{id}/tag/{tagValue}
145
+ # Add a tag to a specific alert.
146
+ #
147
+ # @param id [String] ID of the alert
148
+ # @param tag [String] tag to set.
149
+ # @returns [Hash] object with 'status' key and empty 'repsonse'
150
+ #
151
+ def tag_add(id, tag)
152
+ wf_alert_id?(id)
153
+ wf_string?(tag)
154
+ api_put([id, 'tag', tag].uri_concat)
155
+ end
156
+
157
+ # POST /api/v2/alert/{id}/undelete
158
+ # Undelete a specific alert.
159
+ #
160
+ # @param id [String] ID of the alert
161
+ # @return [Hash]
162
+ #
163
+ def undelete(id)
164
+ wf_alert_id?(id)
165
+ api_post([id, 'undelete'].uri_concat)
166
+ end
167
+
168
+ # POST /api/v2/alert/{id}/unsnooze
169
+ # Unsnooze a specific alert.
170
+ #
171
+ # @param id [String] ID of the alert
172
+ # @returns [Hash] object describing the alert with status and
173
+ # response keys
174
+ #
175
+ def unsnooze(id)
176
+ wf_alert_id?(id)
177
+ api_post([id, 'unsnooze'].uri_concat)
178
+ end
179
+
180
+ # GET /api/v2/alert/summary
181
+ # Count alerts of various statuses for a customer
182
+ #
183
+ # @return [Hash]
184
+ #
185
+ def summary
186
+ api_get('summary')
187
+ end
188
+ end
189
+
190
+ # A standard response
191
+ #
192
+ class Response
193
+ class Alert < Base; end
194
+ end
195
+ end
@@ -0,0 +1,251 @@
1
+ require 'json'
2
+ require 'time'
3
+ require 'faraday'
4
+ require 'pp'
5
+ require 'ostruct'
6
+ require_relative './exception'
7
+ require_relative './mixins'
8
+ require_relative './response'
9
+ require_relative './validators'
10
+ require_relative './version'
11
+
12
+ module Wavefront
13
+ #
14
+ # Abstract class from which all API classes inherit. When you make
15
+ # any call to the Wavefront API from this SDK, you are returned an
16
+ # OpenStruct object.
17
+ #
18
+ # @returns a Wavefront::Class::Response object where Class matches
19
+ # the inheriting class name.
20
+ #
21
+ class Base
22
+ include Wavefront::Validators
23
+ include Wavefront::Mixins
24
+ attr_reader :opts, :debug, :noop, :verbose, :net, :api_base, :conn,
25
+ :update_keys, :logger
26
+
27
+ # Create a new API object. This will always be called from a
28
+ # class which inherits this one. If the inheriting class defines
29
+ # #post_initialize, that method will be called afterwards, with
30
+ # the same arguments.
31
+ #
32
+ # @param creds [Hash] must contain the keys `endpoint` (the
33
+ # Wavefront API server) and `token`, the user token with which
34
+ # you wish to access the endpoint. Can optionally contain
35
+ # `agent`, which will become the `user-agent` string sent with
36
+ # all requests.
37
+ # @param opts [Hash] options governing class behaviour. Expected
38
+ # keys are `debug`, `noop` and `verbose`, all boolean; and
39
+ # `logger`, which must be a standard Ruby logger object. You
40
+ # can also pass :response_only. If this is true, you will only
41
+ # be returned a hash of the 'response' object returned by
42
+ # Wavefront.
43
+ # @return [Nil]
44
+ #
45
+ def initialize(creds = {}, opts = {})
46
+ @opts = opts
47
+ @debug = opts[:debug] || false
48
+ @noop = opts[:noop] || false
49
+ @verbose = opts[:verbose] || false
50
+ @logger = opts[:logger] || nil
51
+ setup_endpoint(creds)
52
+
53
+ post_initialize(creds, opts) if respond_to?(:post_initialize)
54
+ end
55
+
56
+ # Convert an epoch timestamp into epoch milliseconds. If the
57
+ # timestamp looks like it's already epoch milliseconds, return
58
+ # it as-is.
59
+ #
60
+ # @param t [Integer] epoch timestamp
61
+ # @return [Ingeter] epoch millisecond timestamp
62
+ #
63
+ def time_to_ms(t)
64
+ return false unless t.is_a?(Integer)
65
+ return t if t.to_s.size == 13
66
+ (t.to_f * 1000).round
67
+ end
68
+
69
+ # Derive the first part of the API path from the class name. You
70
+ # can override this in your class if you wish
71
+ #
72
+ # @return [String] portion of API URI
73
+ #
74
+ def api_base
75
+ self.class.name.split('::').last.downcase
76
+ end
77
+
78
+ # Create a Faraday connection object. The server comes from the
79
+ # endpoint passed to the initializer in the 'creds' hash; the
80
+ # root of the URI is dynamically derived by the #setup_endpoint
81
+ # method.
82
+ #
83
+ # @param headers [Hash] additional headers
84
+ # @return [URI::HTTPS]
85
+ #
86
+ def mk_conn(path, headers = {})
87
+ Faraday.new(
88
+ url: "https://#{net[:endpoint]}" +
89
+ [net[:api_base], path].uri_concat,
90
+ headers: net[:headers].merge(headers)
91
+ )
92
+ end
93
+
94
+ # Make a GET call to the Wavefront API and return the result as
95
+ # a Ruby hash. Can optionally perform a verbose noop, if the
96
+ # #noop class variable is set. If #verbose is set, then prints
97
+ # the information used to build the URI.
98
+ #
99
+ # @param path [String] path to be appended to the
100
+ # #net[:api_base] path.
101
+ # @param qs [String] optional query string
102
+ # @return [Hash] API response
103
+ #
104
+ def api_get(path, query = {})
105
+ make_call(mk_conn(path), :get, nil, query)
106
+ end
107
+
108
+ # Make a POST call to the Wavefront API and return the result as
109
+ # a Ruby hash. Can optionally perform a verbose noop, if the
110
+ # #noop class variable is set. If #verbose is set, then prints
111
+ # the information used to build the URI.
112
+ #
113
+ # @param path [String] path to be appended to the
114
+ # #net[:api_base] path.
115
+ # @param body [String] optional body text to post
116
+ # @param ctype [String] the content type to use when posting
117
+ # @return [Hash] API response
118
+ #
119
+ def api_post(path, body = nil, ctype = 'text/plain')
120
+ body = body.to_json unless body.is_a?(String)
121
+ make_call(mk_conn(path, { 'Content-Type': ctype,
122
+ 'Accept': 'application/json'}),
123
+ :post, nil, body)
124
+ end
125
+
126
+ # Make a PUT call to the Wavefront API and return the result as
127
+ # a Ruby hash. Can optionally perform a verbose noop, if the
128
+ # #noop class variable is set. If #verbose is set, then prints
129
+ # the information used to build the URI.
130
+ #
131
+ # @param path [String] path to be appended to the
132
+ # #net[:api_base] path.
133
+ # @param body [String] optional body text to post
134
+ # @param ctype [String] the content type to use when putting
135
+ # @return [Hash] API response
136
+ #
137
+ def api_put(path, body = nil, ctype = 'application/json')
138
+ make_call(mk_conn(path, { 'Content-Type': ctype,
139
+ 'Accept': 'application/json' }),
140
+ :put, nil, body.to_json)
141
+ end
142
+
143
+ # Make a DELETE call to the Wavefront API and return the result
144
+ # as a Ruby hash. Can optionally perform a verbose noop, if the
145
+ # #noop class variable is set. If #verbose is set, then prints
146
+ # the information used to build the URI.
147
+ #
148
+ # @param path [String] path to be appended to the
149
+ # #net[:api_base] path.
150
+ # @return [Hash] API response
151
+ #
152
+ def api_delete(path)
153
+ make_call(mk_conn(path), :delete)
154
+ end
155
+
156
+ # doing a PUT to update an object requires only a certain subset of
157
+ # the keys returned by #describe().
158
+ #
159
+ # @param body [Hash] a hash of the existing object merged with the
160
+ # hash describing the user's change(s).
161
+ # @param keys [Array, String] the keys(s) the user wishes to update
162
+ # @return [Hash] a hash containing only the keys which need to be
163
+ # sent to the API. Keys will be symbolized.
164
+ #
165
+ def hash_for_update(old, new)
166
+ raise ArgumentError unless old.is_a?(Hash) && new.is_a?(Hash)
167
+
168
+ Hash[old.merge(new).map { |k, v| [k.to_sym, v] }].select do |k, _v|
169
+ update_keys.include?(k)
170
+ end
171
+ end
172
+
173
+ # Send a message to a Ruby logger object if the user supplied
174
+ # one, or print to standard out if not.
175
+ #
176
+ # @param msg [String] the string to print
177
+ # @param level [Symbol] the level of the message.
178
+ # :verbose messages equate to a standard INFO log level and
179
+ # :debug to DEBUG.
180
+ #
181
+ def log(msg, level = nil)
182
+
183
+ if logger
184
+ logger.send(level || :info, msg)
185
+ else
186
+ # print it unless it's a debug and we're not in debug
187
+ #
188
+ return if level == :debug && ! opts[:debug]
189
+ return if level == :info && ! opts[:verbose]
190
+
191
+ puts msg
192
+ end
193
+ end
194
+
195
+ def respond(resp)
196
+ response_class.send(:new, resp.body, resp.status || {})
197
+ end
198
+
199
+ private
200
+
201
+ # Try to describe the actual HTTP calls we make. There's a bit
202
+ # of clumsy guesswork here
203
+ #
204
+ def verbosity(conn, method, *args)
205
+ log "uri: #{method.upcase} #{conn.url_prefix}"
206
+
207
+ if args.last && ! args.last.empty?
208
+ puts log method == :get ? "params: #{args.last}" :
209
+ "body: #{args.last}"
210
+ end
211
+ end
212
+
213
+ # Make the API call, or not, if noop is set.
214
+ #
215
+ def make_call(conn, method, *args)
216
+ verbosity(conn, method, *args) if noop || verbose
217
+ return if noop
218
+
219
+ resp = conn.public_send(method, *args)
220
+
221
+ if debug
222
+ require 'pp'
223
+ pp resp
224
+ end
225
+
226
+ respond(resp)
227
+ end
228
+
229
+ def response_class
230
+ Object.const_get(
231
+ "Wavefront::Response::#{self.class.name.split('::').last}")
232
+ end
233
+
234
+ def setup_endpoint(creds)
235
+ %w(endpoint token).each do |k|
236
+ raise "creds must contain #{k}" unless creds.key?(k.to_sym)
237
+ end
238
+
239
+ unless creds.key?(:agent) && creds[:agent]
240
+ creds[:agent] = "wavefront-sdk #{WF_SDK_VERSION}"
241
+ end
242
+
243
+ @net = {
244
+ headers: { 'Authorization': "Bearer #{creds[:token]}",
245
+ 'user-agent': creds[:agent] },
246
+ endpoint: creds[:endpoint],
247
+ api_base: ['', 'api', 'v2', api_base].uri_concat
248
+ }
249
+ end
250
+ end
251
+ end