wavefront-sdk 1.6.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/HISTORY.md +39 -13
  4. data/README.md +75 -28
  5. data/Rakefile +1 -1
  6. data/lib/wavefront-sdk/alert.rb +113 -17
  7. data/lib/wavefront-sdk/cloudintegration.rb +8 -8
  8. data/lib/wavefront-sdk/core/api.rb +99 -0
  9. data/lib/wavefront-sdk/core/api_caller.rb +211 -0
  10. data/lib/wavefront-sdk/{exception.rb → core/exception.rb} +11 -6
  11. data/lib/wavefront-sdk/{logger.rb → core/logger.rb} +2 -3
  12. data/lib/wavefront-sdk/{response.rb → core/response.rb} +69 -52
  13. data/lib/wavefront-sdk/credentials.rb +6 -3
  14. data/lib/wavefront-sdk/dashboard.rb +14 -14
  15. data/lib/wavefront-sdk/{constants.rb → defs/constants.rb} +1 -0
  16. data/lib/wavefront-sdk/defs/version.rb +1 -0
  17. data/lib/wavefront-sdk/derivedmetric.rb +14 -14
  18. data/lib/wavefront-sdk/distribution.rb +75 -0
  19. data/lib/wavefront-sdk/event.rb +13 -13
  20. data/lib/wavefront-sdk/externallink.rb +8 -8
  21. data/lib/wavefront-sdk/integration.rb +9 -9
  22. data/lib/wavefront-sdk/maintenancewindow.rb +54 -8
  23. data/lib/wavefront-sdk/message.rb +4 -4
  24. data/lib/wavefront-sdk/metric.rb +3 -3
  25. data/lib/wavefront-sdk/notificant.rb +9 -9
  26. data/lib/wavefront-sdk/paginator/base.rb +148 -0
  27. data/lib/wavefront-sdk/paginator/delete.rb +11 -0
  28. data/lib/wavefront-sdk/paginator/get.rb +11 -0
  29. data/lib/wavefront-sdk/paginator/post.rb +64 -0
  30. data/lib/wavefront-sdk/paginator/put.rb +11 -0
  31. data/lib/wavefront-sdk/proxy.rb +7 -7
  32. data/lib/wavefront-sdk/query.rb +4 -4
  33. data/lib/wavefront-sdk/report.rb +9 -25
  34. data/lib/wavefront-sdk/savedsearch.rb +8 -8
  35. data/lib/wavefront-sdk/search.rb +16 -13
  36. data/lib/wavefront-sdk/source.rb +14 -14
  37. data/lib/wavefront-sdk/{mixins.rb → support/mixins.rb} +8 -2
  38. data/lib/wavefront-sdk/{parse_time.rb → support/parse_time.rb} +2 -0
  39. data/lib/wavefront-sdk/types/status.rb +52 -0
  40. data/lib/wavefront-sdk/user.rb +8 -8
  41. data/lib/wavefront-sdk/validators.rb +52 -3
  42. data/lib/wavefront-sdk/webhook.rb +8 -8
  43. data/lib/wavefront-sdk/write.rb +153 -52
  44. data/lib/wavefront-sdk/writers/api.rb +38 -0
  45. data/lib/wavefront-sdk/writers/core.rb +146 -0
  46. data/lib/wavefront-sdk/writers/http.rb +42 -0
  47. data/lib/wavefront-sdk/writers/socket.rb +66 -0
  48. data/lib/wavefront-sdk/writers/summary.rb +39 -0
  49. data/lib/wavefront_sdk.rb +9 -0
  50. data/spec/spec_helper.rb +3 -0
  51. data/spec/wavefront-sdk/alert_spec.rb +6 -0
  52. data/spec/wavefront-sdk/{base_spec.rb → core/api_caller_spec.rb} +28 -41
  53. data/spec/wavefront-sdk/core/api_spec.rb +31 -0
  54. data/spec/wavefront-sdk/{logger_spec.rb → core/logger_spec.rb} +3 -3
  55. data/spec/wavefront-sdk/core/response_spec.rb +77 -0
  56. data/spec/wavefront-sdk/credentials_spec.rb +15 -10
  57. data/spec/wavefront-sdk/distribution_spec.rb +78 -0
  58. data/spec/wavefront-sdk/paginator/base_spec.rb +67 -0
  59. data/spec/wavefront-sdk/paginator/post_spec.rb +53 -0
  60. data/spec/wavefront-sdk/report_spec.rb +3 -1
  61. data/spec/wavefront-sdk/search_spec.rb +25 -0
  62. data/spec/wavefront-sdk/stdlib/array_spec.rb +2 -1
  63. data/spec/wavefront-sdk/stdlib/hash_spec.rb +6 -1
  64. data/spec/wavefront-sdk/stdlib/string_spec.rb +2 -0
  65. data/spec/wavefront-sdk/{mixins_spec.rb → support/mixins_spec.rb} +2 -2
  66. data/spec/wavefront-sdk/{parse_time_spec.rb → support/parse_time_spec.rb} +2 -2
  67. data/spec/wavefront-sdk/validators_spec.rb +64 -1
  68. data/spec/wavefront-sdk/write_spec.rb +55 -77
  69. data/spec/wavefront-sdk/writers/api_spec.rb +45 -0
  70. data/spec/wavefront-sdk/writers/core_spec.rb +49 -0
  71. data/spec/wavefront-sdk/writers/http_spec.rb +69 -0
  72. data/spec/wavefront-sdk/writers/socket_spec.rb +104 -0
  73. data/spec/wavefront-sdk/writers/summary_spec.rb +38 -0
  74. data/wavefront-sdk.gemspec +1 -1
  75. metadata +52 -24
  76. data/lib/wavefront-sdk/base.rb +0 -264
  77. data/lib/wavefront-sdk/base_write.rb +0 -185
  78. data/lib/wavefront-sdk/stdlib.rb +0 -5
  79. data/lib/wavefront-sdk/version.rb +0 -1
  80. data/spec/wavefront-sdk/base_write_spec.rb +0 -82
  81. data/spec/wavefront-sdk/response_spec.rb +0 -39
@@ -1,10 +1,10 @@
1
- require_relative 'base'
1
+ require_relative 'core/api'
2
2
 
3
3
  module Wavefront
4
4
  #
5
5
  # Manage and query Wavefront integrations.
6
6
  #
7
- class Integration < Base
7
+ class Integration < CoreApi
8
8
  # GET /api/v2/integration
9
9
  # Gets a flat list of all Wavefront integrations available,
10
10
  # along with their status
@@ -13,7 +13,7 @@ module Wavefront
13
13
  # @param limit [Int] the number of proxies to return
14
14
  #
15
15
  def list(offset = 0, limit = 100)
16
- api_get('', offset: offset, limit: limit)
16
+ api.get('', offset: offset, limit: limit)
17
17
  end
18
18
 
19
19
  # GET /api/v2/integration/id
@@ -25,7 +25,7 @@ module Wavefront
25
25
  #
26
26
  def describe(id)
27
27
  wf_integration_id?(id)
28
- api_get(id)
28
+ api.get(id)
29
29
  end
30
30
 
31
31
  # POST /api/v2/integration/id/install
@@ -36,7 +36,7 @@ module Wavefront
36
36
  #
37
37
  def install(id)
38
38
  wf_integration_id?(id)
39
- api_post([id, 'install'].uri_concat, nil)
39
+ api.post([id, 'install'].uri_concat, nil)
40
40
  end
41
41
 
42
42
  # POST /api/v2/integration/id/uninstall
@@ -47,7 +47,7 @@ module Wavefront
47
47
  #
48
48
  def uninstall(id)
49
49
  wf_integration_id?(id)
50
- api_post([id, 'uninstall'].uri_concat, nil)
50
+ api.post([id, 'uninstall'].uri_concat, nil)
51
51
  end
52
52
 
53
53
  # GET /api/v2/integration/id/status
@@ -58,7 +58,7 @@ module Wavefront
58
58
  #
59
59
  def status(id)
60
60
  wf_integration_id?(id)
61
- api_get([id, 'status'].uri_concat)
61
+ api.get([id, 'status'].uri_concat)
62
62
  end
63
63
 
64
64
  # GET /api/v2/integration/status
@@ -67,7 +67,7 @@ module Wavefront
67
67
  # @return [Wavefront::Response]
68
68
  #
69
69
  def statuses
70
- api_get('status')
70
+ api.get('status')
71
71
  end
72
72
 
73
73
  # GET /api/v2/integration/manifests
@@ -75,7 +75,7 @@ module Wavefront
75
75
  # integration manifests, along with their status
76
76
  #
77
77
  def manifests
78
- api_get('manifests')
78
+ api.get('manifests')
79
79
  end
80
80
  end
81
81
  end
@@ -1,10 +1,10 @@
1
- require_relative 'base'
1
+ require_relative 'core/api'
2
2
 
3
3
  module Wavefront
4
4
  #
5
5
  # Manage and query Wavefront maintenance windows
6
6
  #
7
- class MaintenanceWindow < Base
7
+ class MaintenanceWindow < CoreApi
8
8
  def update_keys
9
9
  %i[reason title startTimeInSeconds endTimeInSeconds
10
10
  relevantCustomerTags relevantHostTags relevantHostNames]
@@ -17,7 +17,7 @@ module Wavefront
17
17
  # @param limit [Integer] the number of window to return
18
18
  #
19
19
  def list(offset = 0, limit = 100)
20
- api_get('', offset: offset, limit: limit)
20
+ api.get('', offset: offset, limit: limit)
21
21
  end
22
22
 
23
23
  # POST /api/v2/maintenancewindow
@@ -32,7 +32,7 @@ module Wavefront
32
32
  #
33
33
  def create(body)
34
34
  raise ArgumentError unless body.is_a?(Hash)
35
- api_post('', body, 'application/json')
35
+ api.post('', body, 'application/json')
36
36
  end
37
37
 
38
38
  # DELETE /api/v2/maintenancewindow/id
@@ -43,7 +43,7 @@ module Wavefront
43
43
  #
44
44
  def delete(id)
45
45
  wf_maintenance_window_id?(id)
46
- api_delete(id)
46
+ api.delete(id)
47
47
  end
48
48
 
49
49
  # GET /api/v2/maintenancewindow/id
@@ -54,7 +54,7 @@ module Wavefront
54
54
  #
55
55
  def describe(id)
56
56
  wf_maintenance_window_id?(id)
57
- api_get(id)
57
+ api.get(id)
58
58
  end
59
59
 
60
60
  # PUT /api/v2/maintenancewindow/id
@@ -72,10 +72,56 @@ module Wavefront
72
72
  wf_maintenance_window_id?(id)
73
73
  raise ArgumentError unless body.is_a?(Hash)
74
74
 
75
- return api_put(id, body, 'application/json') unless modify
75
+ return api.put(id, body, 'application/json') unless modify
76
76
 
77
- api_put(id, hash_for_update(describe(id).response, body),
77
+ api.put(id, hash_for_update(describe(id).response, body),
78
78
  'application/json')
79
79
  end
80
+
81
+ # Windows currently open.
82
+ # @return [Wavefront::Response]
83
+ #
84
+ def ongoing
85
+ windows_in_state(:ongoing)
86
+ end
87
+
88
+ # Get the windows which will be open in the next so-many hours
89
+ # @param hours [Numeric] how many hours to look ahead
90
+ # @return [Wavefront::Response]
91
+ #
92
+ def pending(hours = 24)
93
+ cutoff = Time.now.to_i + hours * 3600
94
+
95
+ windows_in_state(:pending).tap do |r|
96
+ r.response.items.delete_if { |w| w.startTimeInSeconds > cutoff }
97
+ end
98
+ end
99
+
100
+ # This method mimics the similarly named method from the v1 SDK,
101
+ # which called the 'GET /api/alert/maintenancewindow/summary'
102
+ # path.
103
+ # @return [Wavefront::Response]
104
+ #
105
+ def summary
106
+ ret = pending
107
+
108
+ items = { UPCOMING: ret.response.items,
109
+ CURRENT: ongoing.response.items }
110
+
111
+ ret.response.items = items
112
+ ret
113
+ end
114
+
115
+ # Return all maintenance windows in the given state. At the time
116
+ # of writing valid states are ONGOING, PENDING, and ENDED.
117
+ # @param state [Symbol]
118
+ # @return [Wavefront::Response]
119
+ #
120
+ def windows_in_state(state)
121
+ require_relative 'search'
122
+ wfs = Wavefront::Search.new(creds, opts)
123
+ query = { key: 'runningState', value: state, matchingMethod: 'EXACT' }
124
+ wfs.search(:maintenancewindow, query, limit: :all, offset: PAGE_SIZE)
125
+ end
80
126
  end
81
127
  end
@@ -1,10 +1,10 @@
1
- require_relative 'base'
1
+ require_relative 'core/api'
2
2
 
3
3
  module Wavefront
4
4
  #
5
5
  # Manage and query Wavefront messages.
6
6
  #
7
- class Message < Base
7
+ class Message < CoreApi
8
8
  # GET /api/v2/message
9
9
  # Gets messages applicable to the current user, i.e. within time
10
10
  # range and distribution scope
@@ -13,7 +13,7 @@ module Wavefront
13
13
  # @param limit [Int] the number of agents to return
14
14
  #
15
15
  def list(offset = 0, limit = 100, unread_only = true)
16
- api_get('', offset: offset, limit: limit, unreadOnly: unread_only)
16
+ api.get('', offset: offset, limit: limit, unreadOnly: unread_only)
17
17
  end
18
18
 
19
19
  # POST /api/v2/message/id/read
@@ -23,7 +23,7 @@ module Wavefront
23
23
  #
24
24
  def read(id)
25
25
  wf_message_id?(id)
26
- api_post([id, 'read'].uri_concat)
26
+ api.post([id, 'read'].uri_concat)
27
27
  end
28
28
  end
29
29
  end
@@ -1,10 +1,10 @@
1
- require_relative 'base'
1
+ require_relative 'core/api'
2
2
 
3
3
  module Wavefront
4
4
  #
5
5
  # Query Wavefront metrics.
6
6
  #
7
- class Metric < Base
7
+ class Metric < CoreApi
8
8
  def api_base
9
9
  'chart/metric'
10
10
  end
@@ -29,7 +29,7 @@ module Wavefront
29
29
 
30
30
  sources.each { |source| query.<< [:h, source] }
31
31
 
32
- api_get('detail', query)
32
+ api.get('detail', query)
33
33
  end
34
34
  end
35
35
  end
@@ -1,10 +1,10 @@
1
- require_relative 'base'
1
+ require_relative 'core/api'
2
2
 
3
3
  module Wavefront
4
4
  #
5
5
  # Manage and query Wavefront notification targets.
6
6
  #
7
- class Notificant < Base
7
+ class Notificant < CoreApi
8
8
  # GET /api/v2/notificant
9
9
  # Get all notification targets for a customer
10
10
  #
@@ -12,7 +12,7 @@ module Wavefront
12
12
  # @param limit [Int] the number of notification targets to return
13
13
  #
14
14
  def list(offset = 0, limit = 100)
15
- api_get('', offset: offset, limit: limit)
15
+ api.get('', offset: offset, limit: limit)
16
16
  end
17
17
 
18
18
  # POST /api/v2/notificant
@@ -23,7 +23,7 @@ module Wavefront
23
23
  #
24
24
  def create(body)
25
25
  raise ArgumentError unless body.is_a?(Hash)
26
- api_post('', body, 'application/json')
26
+ api.post('', body, 'application/json')
27
27
  end
28
28
 
29
29
  # DELETE /api/v2/notificant/id
@@ -34,7 +34,7 @@ module Wavefront
34
34
  #
35
35
  def delete(id)
36
36
  wf_notificant_id?(id)
37
- api_delete(id)
37
+ api.delete(id)
38
38
  end
39
39
 
40
40
  # GET /api/v2/notificant/id
@@ -45,7 +45,7 @@ module Wavefront
45
45
  #
46
46
  def describe(id)
47
47
  wf_notificant_id?(id)
48
- api_get(id)
48
+ api.get(id)
49
49
  end
50
50
 
51
51
  # PUT /api/v2/notificant/id
@@ -63,9 +63,9 @@ module Wavefront
63
63
  wf_notificant_id?(id)
64
64
  raise ArgumentError unless body.is_a?(Hash)
65
65
 
66
- return api_put(id, body, 'application/json') unless modify
66
+ return api.put(id, body, 'application/json') unless modify
67
67
 
68
- api_put(id, hash_for_update(describe(id).response, body),
68
+ api.put(id, hash_for_update(describe(id).response, body),
69
69
  'application/json')
70
70
  end
71
71
 
@@ -77,7 +77,7 @@ module Wavefront
77
77
  #
78
78
  def test(id)
79
79
  wf_notificant_id?(id)
80
- api_post(['test', id].uri_concat, nil)
80
+ api.post(['test', id].uri_concat, nil)
81
81
  end
82
82
  end
83
83
  end
@@ -0,0 +1,148 @@
1
+ require_relative '../defs/constants'
2
+
3
+ module Wavefront
4
+ module Paginator
5
+ #
6
+ # Automatically handle pagination. This is an abstract class
7
+ # made concrete by an extension for each HTTP request type.
8
+ #
9
+ # This class and its children do slightly unpleasant things with
10
+ # the HTTP request passed to us by the user, extracting and
11
+ # changing values in the URI, query string, or POST/PUT body.
12
+ # The POST class is particularly onerous.
13
+ #
14
+ # Automatic pagination works by letting the user override the
15
+ # limit and offset values in API calls. Setting the limit to
16
+ # :all iteratively calls the Wavefront API, returning all
17
+ # requested objects an a standard Wavefront::Response wrapper;
18
+ # setting limit to :lazy returns a lazy Enumerable. The number
19
+ # of objects fetched in each API call, whether eager or lazy
20
+ # defaults to PAGE_SIZE, but the user can override that value by
21
+ # using the offset argument in conjunction with limit = :lazy |
22
+ # :all.
23
+ #
24
+ class Base
25
+ attr_reader :api_caller, :conn, :method, :args, :page_size,
26
+ :initial_limit
27
+
28
+ # @param api_caller [Wavefront::ApiCaller] the class which
29
+ # creates an instance of this one. We need to access its
30
+ # #response method.
31
+ # @param conn [Faraday::Connection]
32
+ # @param method [Symbol] HTTP request method
33
+ # @param *args arguments to pass to Faraday's #get method
34
+ #
35
+ def initialize(api_caller, conn, method, *args)
36
+ @api_caller = api_caller
37
+ @conn = conn
38
+ @method = method
39
+ @args = args
40
+ setup_vars
41
+ end
42
+
43
+ def setup_vars
44
+ @initial_limit = limit_and_offset(args)[:limit]
45
+ @page_size = user_page_size(args) unless initial_limit.is_a?(Integer)
46
+ end
47
+
48
+ # An API call may or may not have a limit and/or offset value.
49
+ # They could (I think) be anywhere. Safely find and return
50
+ # them. If multiple elements of @args have :limit or :offset
51
+ # keys, the last value wins.
52
+ #
53
+ # @param args [Array] arguments to be passed to a Faraday
54
+ # connection object
55
+ # @return [Hash] with keys :offset and :limit. Either's value
56
+ # can be nil
57
+ #
58
+ def limit_and_offset(args)
59
+ ret = { offset: nil, limit: nil }
60
+
61
+ args.select { |a| a.is_a?(Hash) }.each_with_object(ret) do |arg|
62
+ ret[:limit] = arg[:limit] if arg.key?(:limit)
63
+ ret[:offset] = arg[:offset] if arg.key?(:offset)
64
+ end
65
+ end
66
+
67
+ # How many objects to get on each iteration? The user can pass
68
+ # it in as an alternative to the offset argument, If it's not a
69
+ # positive integer, default to 999
70
+ #
71
+ def user_page_size(args)
72
+ arg_val = limit_and_offset(args)[:offset].to_i
73
+ return arg_val if arg_val && arg_val > 0
74
+ PAGE_SIZE
75
+ end
76
+
77
+ # @param offset [Integer] where to start fetching from
78
+ # @param page_size [Integer] how many objects to fetch
79
+ # @param args [Array] arguments to pass to Faraday.get
80
+ #
81
+ def set_pagination(offset, page_size, args)
82
+ args.map do |arg|
83
+ if arg.is_a?(Hash)
84
+ arg.tap do |a|
85
+ a[:limit] = page_size if a.key?(:limit)
86
+ a[:offset] = offset if a.key?(:offset)
87
+ end
88
+ end
89
+ arg
90
+ end
91
+ end
92
+
93
+ # 'get' eagerly. Re-run the get operation, merging together
94
+ # returned items until we have them all.
95
+ # @return [Wavefront::Response]
96
+ #
97
+ # rubocop:disable Metrics/MethodLength
98
+ # rubocop:disable Metrics/AbcSize
99
+ def make_recursive_call
100
+ offset = 0
101
+ p_args = set_pagination(offset, page_size, args)
102
+ ret = api_caller.respond(conn.public_send(method, *p_args))
103
+
104
+ return ret unless ret.more_items?
105
+
106
+ loop do
107
+ offset += page_size
108
+ p_args = set_pagination(offset, page_size, p_args)
109
+ api_caller.verbosity(conn, method, *p_args)
110
+ resp = api_caller.respond(conn.public_send(method, *p_args))
111
+ raise StopIteration unless resp.ok?
112
+ ret.response.items += resp.response.items
113
+ raise StopIteration unless resp.more_items?
114
+ end
115
+
116
+ ret
117
+ end
118
+
119
+ # Return all objects using a lazy enumerator.
120
+ # @return [Enumerable] with each item being
121
+ # @raise [Wavefront::Exception::EnumerableError] if an API error
122
+ # is encountered at any point. The exception message is a
123
+ # Wavefront::Type::Status object, which will include the HTTP
124
+ # status code and any error string passed back by the API.
125
+ #
126
+ def make_lazy_call
127
+ offset = 0
128
+ p_args = set_pagination(offset, page_size, args)
129
+
130
+ Enumerator.new do |y|
131
+ loop do
132
+ offset += page_size
133
+ api_caller.verbosity(conn, method, *p_args)
134
+ resp = api_caller.respond(conn.public_send(method, *p_args))
135
+ unless resp.ok?
136
+ raise(Wavefront::Exception::EnumerableError, resp.status)
137
+ end
138
+ p_args = set_pagination(offset, page_size, p_args)
139
+ resp.response.items.map { |i| y.<< i }
140
+ raise StopIteration unless resp.more_items?
141
+ end
142
+ end.lazy
143
+ end
144
+ # rubocop:enable Metrics/AbcSize
145
+ # rubocop:enable Metrics/MethodLength
146
+ end
147
+ end
148
+ end