wavefront-sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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