wavefront-sdk 3.7.1 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +43 -2
  3. data/.travis.yml +0 -1
  4. data/HISTORY.md +33 -0
  5. data/README.md +4 -3
  6. data/lib/wavefront-sdk/account.rb +104 -3
  7. data/lib/wavefront-sdk/api_mixins/user.rb +10 -0
  8. data/lib/wavefront-sdk/cloudintegration.rb +27 -0
  9. data/lib/wavefront-sdk/core/api_caller.rb +50 -7
  10. data/lib/wavefront-sdk/core/exception.rb +6 -0
  11. data/lib/wavefront-sdk/credentials.rb +28 -9
  12. data/lib/wavefront-sdk/defs/version.rb +1 -3
  13. data/lib/wavefront-sdk/paginator/base.rb +21 -15
  14. data/lib/wavefront-sdk/query.rb +0 -1
  15. data/lib/wavefront-sdk/role.rb +128 -0
  16. data/lib/wavefront-sdk/spy.rb +126 -0
  17. data/lib/wavefront-sdk/stdlib/array.rb +1 -1
  18. data/lib/wavefront-sdk/stdlib/time.rb +13 -0
  19. data/lib/wavefront-sdk/unstable/README.md +4 -0
  20. data/lib/wavefront-sdk/unstable/chart.rb +90 -0
  21. data/lib/wavefront-sdk/unstable/unstable.rb +9 -0
  22. data/lib/wavefront-sdk/user.rb +31 -0
  23. data/lib/wavefront-sdk/usergroup.rb +17 -16
  24. data/lib/wavefront-sdk/validators.rb +52 -7
  25. data/lib/wavefront-sdk/write.rb +9 -9
  26. data/spec/.rubocop.yml +41 -0
  27. data/spec/spec_helper.rb +4 -0
  28. data/spec/support/minitest_assertions.rb +4 -4
  29. data/spec/wavefront-sdk/account_spec.rb +107 -1
  30. data/spec/wavefront-sdk/cloudintegration_spec.rb +38 -0
  31. data/spec/wavefront-sdk/core/api_caller_spec.rb +43 -0
  32. data/spec/wavefront-sdk/credentials_spec.rb +3 -4
  33. data/spec/wavefront-sdk/metric_helper_spec.rb +1 -1
  34. data/spec/wavefront-sdk/role_spec.rb +96 -0
  35. data/spec/wavefront-sdk/spy_spec.rb +113 -0
  36. data/spec/wavefront-sdk/unstable/chart_spec.rb +39 -0
  37. data/spec/wavefront-sdk/user_spec.rb +8 -0
  38. data/spec/wavefront-sdk/usergroup_spec.rb +21 -11
  39. data/spec/wavefront-sdk/validators_spec.rb +31 -0
  40. data/wavefront-sdk.gemspec +8 -8
  41. metadata +32 -21
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
- WF_SDK_VERSION = '3.7.1'
3
+ WF_SDK_VERSION = '5.2.0'
6
4
  WF_SDK_LOCATION = Pathname.new(__dir__).parent.parent.parent
@@ -5,23 +5,29 @@ require_relative '../defs/constants'
5
5
  module Wavefront
6
6
  module Paginator
7
7
  #
8
- # Automatically handle pagination. This is an abstract class
9
- # made concrete by an extension for each HTTP request type.
8
+ # Automatically handle pagination. This is an abstract class made concrete
9
+ # by an extension for each HTTP request type.
10
10
  #
11
- # This class and its children do slightly unpleasant things with
12
- # the HTTP request passed to us by the user, extracting and
13
- # changing values in the URI, query string, or POST/PUT body.
14
- # The POST class is particularly onerous.
11
+ # This class and its children do slightly unpleasant things with the HTTP
12
+ # request passed to us by the user, extracting and changing values in the
13
+ # URI, query string, or POST/PUT body. The POST class is particularly
14
+ # onerous.
15
15
  #
16
- # Automatic pagination works by letting the user override the
17
- # limit and offset values in API calls. Setting the limit to
18
- # :all iteratively calls the Wavefront API, returning all
19
- # requested objects an a standard Wavefront::Response wrapper;
20
- # setting limit to :lazy returns a lazy Enumerable. The number
21
- # of objects fetched in each API call, whether eager or lazy
22
- # defaults to PAGE_SIZE, but the user can override that value by
23
- # using the offset argument in conjunction with limit = :lazy |
24
- # :all.
16
+ # Automatic pagination works by letting the user override the limit and
17
+ # offset values in API calls.
18
+ #
19
+ # * Calling with limit = :all iteratively calls the Wavefront API,
20
+ # returning all requested objects in a standard Wavefront::Response
21
+ # wrapper.
22
+ #
23
+ # * Calling with limit = :lazy returns a lazy Enumerable.
24
+ #
25
+ # The number of objects fetched in each API call, eager or lazy, defaults
26
+ # to PAGE_SIZE, but the user can override that value by using the offset
27
+ # argument in conjunction with limit = :lazy | :all.
28
+ #
29
+ # So, for example, to fetch all objects in blocks of ten (which could
30
+ # require a lot of API calls) you would use { limit: :all, offset: 10 }
25
31
  #
26
32
  class Base
27
33
  attr_reader :api_caller, :conn, :method, :args, :page_size,
@@ -43,7 +43,6 @@ module Wavefront
43
43
  options[:s] = parse_time(t_start, true)
44
44
  options[:e] = parse_time(t_end, true) if t_end
45
45
 
46
- options.delete_if { |k, v| v == false && k != :i }
47
46
  api.get('api', options)
48
47
  end
49
48
 
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'core/api'
4
+ require_relative 'api_mixins/user'
5
+
6
+ module Wavefront
7
+ #
8
+ # Manage and query Wavefront roles
9
+ #
10
+ class Role < CoreApi
11
+ include Wavefront::Mixin::User
12
+
13
+ def update_keys
14
+ %i[id name description]
15
+ end
16
+
17
+ # GET /api/v2/role
18
+ # Get all roles for a customer
19
+ # @param offset [Int] alert at which the list begins
20
+ # @param limit [Int] the number of alerts to return
21
+ # @return [Wavefront::Response]
22
+ #
23
+ def list(offset = 0, limit = 100)
24
+ api.get('', offset: offset, limit: limit)
25
+ end
26
+
27
+ # POST /api/v2/role
28
+ # Create a specific role
29
+ # @param body [Hash] a hash of parameters describing the role. Please
30
+ # refer to the Wavefront Swagger docs for key:value information
31
+ # @return [Wavefront::Response]
32
+ #
33
+ def create(body)
34
+ raise ArgumentError unless body.is_a?(Hash)
35
+
36
+ api.post('', body, 'application/json')
37
+ end
38
+
39
+ # DELETE /api/v2/role/{id}
40
+ # Delete a specific role
41
+ # @param id [String] ID of the role
42
+ # @return [Wavefront::Response]
43
+ #
44
+ def delete(id)
45
+ wf_role_id?(id)
46
+ api.delete(id)
47
+ end
48
+
49
+ # GET /api/v2/role/{id}
50
+ # Get a specific role
51
+ # @param id [String] ID of the role
52
+ # @return [Wavefront::Response]
53
+ #
54
+ def describe(id)
55
+ wf_role_id?(id)
56
+ api.get(id)
57
+ end
58
+
59
+ # PUT /api/v2/role/{id}
60
+ # Update a specific role
61
+ # @param id [String] role ID
62
+ # @param body [Hash] key-value hash of the parameters you wish to change
63
+ # @param modify [true, false] if true, use {#describe()} to get a hash
64
+ # describing the existing object, and modify that with the new body. If
65
+ # false, pass the new body straight through.
66
+ # @return [Wavefront::Response]
67
+ #
68
+ def update(id, body, modify = true)
69
+ wf_role_id?(id)
70
+ raise ArgumentError unless body.is_a?(Hash)
71
+
72
+ return api.put(id, body, 'application/json') unless modify
73
+
74
+ api.put(id, hash_for_update(describe(id).response, body),
75
+ 'application/json')
76
+ end
77
+
78
+ # POST /api/v2/role/{id}/addAssignees
79
+ # Add multiple users and user groups to a specific role
80
+ # @param id [String] role ID
81
+ # @param assignees [Array[String]] list of roles or accounts to be added
82
+ # @return [Wavefront::Response]
83
+ #
84
+ def add_assignees(id, assignees)
85
+ wf_role_id?(id)
86
+ validate_user_list(assignees)
87
+ api.post([id, 'addAssignees'].uri_concat, assignees, 'application/json')
88
+ end
89
+
90
+ # POST /api/v2/role/{id}/removeAssignees
91
+ # Remove multiple users and user groups from a specific role
92
+ # @param id [String] role ID
93
+ # @param assignees [Array[String]] list of roles or accounts to be removed
94
+ # @return [Wavefront::Response]
95
+ #
96
+ def remove_assignees(id, assignees)
97
+ wf_role_id?(id)
98
+ validate_user_list(assignees)
99
+ api.post([id, 'removeAssignees'].uri_concat,
100
+ assignees,
101
+ 'application/json')
102
+ end
103
+
104
+ # POST /api/v2/role/grant/{permission}
105
+ # Grants a single permission to role(s)
106
+ # @param permission [String] permission to grant
107
+ # @param roles [Array[String]] list of roles to receive permission
108
+ # @return [Wavefront::Response]
109
+ #
110
+ def grant(permission, roles)
111
+ wf_permission?(permission)
112
+ validate_role_list(roles)
113
+ api.post(['grant', permission].uri_concat, roles, 'application/json')
114
+ end
115
+
116
+ # POST /api/v2/role/revoke/{permission}
117
+ # Revokes a single permission from role(s)
118
+ # @param permission [String] permission to revoke
119
+ # @param roles [Array[String]] list of roles to lose permission
120
+ # @return [Wavefront::Response]
121
+ #
122
+ def revoke(permission, roles)
123
+ wf_permission?(permission)
124
+ validate_role_list(roles)
125
+ api.post(['revoke', permission].uri_concat, roles, 'application/json')
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'defs/constants'
4
+ require_relative 'core/api'
5
+
6
+ module Wavefront
7
+ #
8
+ # Spy on data going into Wavefront
9
+ #
10
+ class Spy < CoreApi
11
+ # GET /api/spy/points
12
+ # Gets new metric data points that are added to existing time series.
13
+ # @param sampling [Float] the amount of points to sample, from 0
14
+ # (none) to 1 (all)
15
+ # @param filter [Hash] with the following keys:
16
+ # :prefix [String] only list points whose metric name begins with this
17
+ # case-sensitive string
18
+ # :host [Array] only list points if source name begins with this
19
+ # case-sensitive string
20
+ # :tag_key [String,Array[String]] only list points with one or more of
21
+ # the given points tags
22
+ # @param options [Hash] with the following keys
23
+ # :timestamp [Boolean] prefix each block of streamed data with a
24
+ # timestamp
25
+ # :timeout [Integer] how many seconds to run the spy. After this time
26
+ # the method returns
27
+ # @raise Wavefront::Exception::InvalidSamplingValue
28
+ # @return [Nil]
29
+ #
30
+ def points(sampling = 0.01, filters = {}, options = {})
31
+ wf_sampling_value?(sampling)
32
+ api.get_stream('points', points_filter(sampling, filters), options)
33
+ end
34
+
35
+ # GET /api/spy/histograms
36
+ # Gets new histograms that are added to existing time series.
37
+ # @param sampling [Float] see #points
38
+ # @param filter [Hash] see #points
39
+ # @param options [Hash] see #points
40
+ # @raise Wavefront::Exception::InvalidSamplingValue
41
+ # @return [Nil]
42
+ #
43
+ def histograms(sampling = 0.01, filters = {}, options = {})
44
+ wf_sampling_value?(sampling)
45
+ api.get_stream('histograms',
46
+ histograms_filter(sampling, filters),
47
+ options)
48
+ end
49
+
50
+ # GET /api/spy/spans
51
+ # Gets new spans with existing source names and span tags.
52
+ # @param sampling [Float] see #points
53
+ # @param filter [Hash] see #points
54
+ # @param options [Hash] see #points
55
+ # @raise Wavefront::Exception::InvalidSamplingValue
56
+ # @return [Nil]
57
+ #
58
+ def spans(sampling = 0.01, filters = {}, options = {})
59
+ wf_sampling_value?(sampling)
60
+ api.get_stream('spans', spans_filter(sampling, filters), options)
61
+ end
62
+
63
+ # GET /api/spy/ids
64
+ # Gets newly allocated IDs that correspond to new metric names, source
65
+ # names, point tags, or span tags. A new ID generally indicates that a
66
+ # new time series has been introduced.
67
+ # @param sampling [Float] see #points
68
+ # @param filter [Hash] with keys:
69
+ # :prefix [String] only list assignments whose metric name begins with
70
+ # this case-sensitive string
71
+ # :type [String] one of METRIC, SPAN, HOST or STRING
72
+ # @param options [Hash] see #points
73
+ #
74
+ def ids(sampling = 0.01, filters = {}, options = {})
75
+ wf_sampling_value?(sampling)
76
+ api.get_stream('ids', ids_filter(sampling, filters), options)
77
+ end
78
+
79
+ def api_path
80
+ '/api/spy'
81
+ end
82
+
83
+ # We have to try to make the response we get from the API look
84
+ # like the one we get from the public API. To begin with, it's
85
+ # nothing like it.
86
+ #
87
+ # This method must be public because a #respond_to? looks for
88
+ # it.
89
+ #
90
+ def _response_shim(resp, status)
91
+ { response: parse_response(resp),
92
+ status: { result: status == 200 ? 'OK' : 'ERROR',
93
+ message: extract_api_message(status, resp),
94
+ code: status } }.to_json
95
+ end
96
+
97
+ private
98
+
99
+ def points_filter(sampling, filters)
100
+ { metric: filters.fetch(:prefix, nil),
101
+ host: filters.fetch(:host, nil),
102
+ sampling: sampling,
103
+ pointTagKey: filters.fetch(:tag_key, nil) }.compact
104
+ end
105
+
106
+ def histograms_filter(sampling, filters)
107
+ { histogram: filters.fetch(:prefix, nil),
108
+ host: filters.fetch(:host, nil),
109
+ sampling: sampling,
110
+ histogramTagKey: filters.fetch(:tag_key, nil) }.compact
111
+ end
112
+
113
+ def spans_filter(sampling, filters)
114
+ { name: filters.fetch(:prefix, nil),
115
+ host: filters.fetch(:host, nil),
116
+ sampling: sampling,
117
+ spanTagKey: filters.fetch(:tag_key, nil) }.compact
118
+ end
119
+
120
+ def ids_filter(sampling, filters)
121
+ { name: filters.fetch(:prefix, nil),
122
+ type: filters.fetch(:type, nil),
123
+ sampling: sampling }.compact
124
+ end
125
+ end
126
+ end
@@ -11,6 +11,6 @@ class Array
11
11
  # @return [String] a URI path
12
12
  #
13
13
  def uri_concat
14
- join('/').squeeze('/').sub(%r{\/$}, '').sub(%r{\/\?}, '?')
14
+ join('/').squeeze('/').sub(%r{/$}, '').sub(%r{/\?}, '?')
15
15
  end
16
16
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extensions to the stdlib Time class
4
+ #
5
+ class Time
6
+ #
7
+ # The real hi-res time. See
8
+ # https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/
9
+ #
10
+ def self.right_now
11
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ The classes in here use undocumented APIs. They are thus subject to
2
+ change or revocation at any time.
3
+
4
+ Use them at your own risk.
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../defs/constants'
4
+ require_relative '../core/api'
5
+
6
+ module Wavefront
7
+ module Unstable
8
+ #
9
+ # This is an unstable class. Please refer to README.md.
10
+ #
11
+ class Chart < CoreApi
12
+ def all_metrics
13
+ metrics_under('')
14
+ end
15
+
16
+ # Gets a list of metrics under the given path. This must be done via
17
+ # recursive calls to the API, so calls can take a while. If you ask for
18
+ # all your metrics, expect to be waiting some time.
19
+ #
20
+ # @return [Wavefront::Response]
21
+ #
22
+ # rubocop:disable Metrics/MethodLength
23
+ # rubocop:disable Metrics/AbcSize
24
+ def metrics_under(path, cursor = nil, limit = 100)
25
+ resp = api.get('metrics/all',
26
+ { trie: true, q: path, p: cursor, l: limit }.compact)
27
+
28
+ return resp unless resp.ok?
29
+
30
+ metrics = resp.response.items
31
+
32
+ metrics.each do |m|
33
+ if m.end_with?('.')
34
+ metrics += metrics_under(m).response.items
35
+ metrics.delete(m)
36
+ end
37
+ end
38
+
39
+ # resp.more_items? doesn't work: we don't get that from this API
40
+
41
+ if metrics.size == limit
42
+ metrics += metrics_under(path, metrics.last, limit).response.items
43
+ end
44
+
45
+ resp.response.items = metrics.sort
46
+ resp
47
+ end
48
+ # rubocop:enable Metrics/MethodLength
49
+ # rubocop:enable Metrics/AbcSize
50
+
51
+ def api_path
52
+ '/chart'
53
+ end
54
+
55
+ # We have to try to make the response we get from the API look
56
+ # like the one we get from the public API. To begin with, it's
57
+ # nothing like it.
58
+ #
59
+ # This method must be public because a #respond_to? looks for
60
+ # it.
61
+ #
62
+ def response_shim(resp, status)
63
+ { response: parse_response(resp),
64
+ status: { result: status == 200 ? 'OK' : 'ERROR',
65
+ message: extract_api_message(status, resp),
66
+ code: status } }.to_json
67
+ end
68
+
69
+ private
70
+
71
+ def parse_response(resp)
72
+ metrics = JSON.parse(resp, symbolize_names: true)[:metrics]
73
+
74
+ { items: metrics,
75
+ offset: 0,
76
+ limit: metrics.size,
77
+ totalItems: metrics.size,
78
+ moreItems: false }
79
+ rescue JSON::ParserError
80
+ nil
81
+ end
82
+
83
+ def extract_api_message(_status, resp)
84
+ resp.match(/^message='(.*)'/)[1]
85
+ rescue NoMethodError
86
+ ''
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wavefront
4
+ #
5
+ # Placeholder for unstable API classes
6
+ #
7
+ module Unstable
8
+ end
9
+ end