wavefront-sdk 3.7.1 → 5.2.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +43 -2
- data/.travis.yml +0 -1
- data/HISTORY.md +33 -0
- data/README.md +4 -3
- data/lib/wavefront-sdk/account.rb +104 -3
- data/lib/wavefront-sdk/api_mixins/user.rb +10 -0
- data/lib/wavefront-sdk/cloudintegration.rb +27 -0
- data/lib/wavefront-sdk/core/api_caller.rb +50 -7
- data/lib/wavefront-sdk/core/exception.rb +6 -0
- data/lib/wavefront-sdk/credentials.rb +28 -9
- data/lib/wavefront-sdk/defs/version.rb +1 -3
- data/lib/wavefront-sdk/paginator/base.rb +21 -15
- data/lib/wavefront-sdk/query.rb +0 -1
- data/lib/wavefront-sdk/role.rb +128 -0
- data/lib/wavefront-sdk/spy.rb +126 -0
- data/lib/wavefront-sdk/stdlib/array.rb +1 -1
- data/lib/wavefront-sdk/stdlib/time.rb +13 -0
- data/lib/wavefront-sdk/unstable/README.md +4 -0
- data/lib/wavefront-sdk/unstable/chart.rb +90 -0
- data/lib/wavefront-sdk/unstable/unstable.rb +9 -0
- data/lib/wavefront-sdk/user.rb +31 -0
- data/lib/wavefront-sdk/usergroup.rb +17 -16
- data/lib/wavefront-sdk/validators.rb +52 -7
- data/lib/wavefront-sdk/write.rb +9 -9
- data/spec/.rubocop.yml +41 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/minitest_assertions.rb +4 -4
- data/spec/wavefront-sdk/account_spec.rb +107 -1
- data/spec/wavefront-sdk/cloudintegration_spec.rb +38 -0
- data/spec/wavefront-sdk/core/api_caller_spec.rb +43 -0
- data/spec/wavefront-sdk/credentials_spec.rb +3 -4
- data/spec/wavefront-sdk/metric_helper_spec.rb +1 -1
- data/spec/wavefront-sdk/role_spec.rb +96 -0
- data/spec/wavefront-sdk/spy_spec.rb +113 -0
- data/spec/wavefront-sdk/unstable/chart_spec.rb +39 -0
- data/spec/wavefront-sdk/user_spec.rb +8 -0
- data/spec/wavefront-sdk/usergroup_spec.rb +21 -11
- data/spec/wavefront-sdk/validators_spec.rb +31 -0
- data/wavefront-sdk.gemspec +8 -8
- metadata +32 -21
@@ -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
|
-
#
|
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
|
-
#
|
13
|
-
#
|
14
|
-
#
|
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
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
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,
|
data/lib/wavefront-sdk/query.rb
CHANGED
@@ -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
|
@@ -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,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
|