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
@@ -0,0 +1,56 @@
1
+ require 'json'
2
+ require_relative './exception'
3
+
4
+ module Wavefront
5
+
6
+ # Every API path has its own response class, which allows us to
7
+ # provide a stable interface. If the API changes underneath us,
8
+ # the SDK will break in a predictable way, throwing a
9
+ # Wavefront::Exception::InvalidResponse exception.
10
+ #
11
+ # Most Wavefront::Response classes present the returned data in
12
+ # two parts, each accessible by dot notation.
13
+ # #status is the status object, which normally contains
14
+ # 'result', 'message', and 'code'. It is a struct.
15
+ # #response contains the JSON response body, turned into a Ruby
16
+ # hash.
17
+ #
18
+ class Response
19
+ class Base
20
+ attr_reader :status, :response, :debug
21
+
22
+ # Create and return a Wavefront::Response object
23
+ # @param json [String] a raw response body from the Wavefront API
24
+ # @param status [Integer] HTTP return code from the API
25
+ # @param debug [Boolean] whether or not to print the exception
26
+ # message if one is thrown
27
+ # @raise Wavefront::InvalidResponse if the response cannot be
28
+ # parsed
29
+ # @return a Wavefront::Response object
30
+ #
31
+ def initialize(json, status, debug = false)
32
+ @debug = debug
33
+ populate(JSON.parse(json, symbolize_names: true), status)
34
+ rescue => e
35
+ puts e.message if debug
36
+ raise Wavefront::Exception::InvalidResponse
37
+ end
38
+
39
+ def populate(raw, _status = 200)
40
+ if raw.key?(:status)
41
+ @status = Struct.new(*raw[:status].keys).
42
+ new(*raw[:status].values).freeze
43
+ end
44
+
45
+ if raw.key?(:response)
46
+ if raw[:response].key?(:items)
47
+ @response = Struct.new(*raw[:response].keys).
48
+ new(*raw[:response].values).freeze
49
+ else
50
+ @response = raw[:response]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,88 @@
1
+ require_relative './base'
2
+
3
+ module Wavefront
4
+ #
5
+ # View and manage Cloud Integrations. These are identified by
6
+ # a UUID.
7
+ #
8
+ class SavedSearch < Wavefront::Base
9
+
10
+ # GET /api/v2/savedsearch
11
+ # Get all saved searches for a user.
12
+ #
13
+ # @param offset [Int] saved search at which the list begins
14
+ # @param limit [Int] the number of saved searches 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/savedsearch
22
+ # Create a saved search. Refer to the Swagger API docs for
23
+ # valid keys.
24
+ #
25
+ # @param body [Hash] description of saved search
26
+ # @return [Hash]
27
+ #
28
+ def create(body)
29
+ raise ArgumentError unless body.is_a?(Hash)
30
+ api_post('', body, 'application/json')
31
+ end
32
+
33
+ # DELETE /api/v2/savedsearch/{id}
34
+ # Delete a specific saved search.
35
+ #
36
+ # @param id [String] ID of the saved search
37
+ # @return [Hash]
38
+ #
39
+ def delete(id)
40
+ wf_savedsearch_id?(id)
41
+ api_delete(id)
42
+ end
43
+
44
+ # GET /api/v2/savedsearch/{id}
45
+ # Get a specific saved search.
46
+ #
47
+ # @param id [String] ID of the saved search
48
+ # @return [Hash]
49
+ #
50
+ def describe(id)
51
+ wf_savedsearch_id?(id)
52
+ api_get(id)
53
+ end
54
+
55
+ # PUT /api/v2/savedsearch/{id}
56
+ # Update a specific saved search.
57
+ #
58
+ # @param id [String] ID of the saved search
59
+ # @param body [Hash] description of saved search
60
+ #
61
+ def update(id, body)
62
+ wf_savedsearch_id?(id)
63
+ raise ArgumentError unless body.is_a?(Hash)
64
+ api_put(id, body)
65
+ end
66
+
67
+ # GET /api/v2/savedsearch/type/{entitytype}
68
+ # Get all saved searches for a specific entity type for a user.
69
+ #
70
+ # @param entitytype [String] type of entity to retrieve
71
+ # @param offset [Int] saved search at which the list begins
72
+ # @param limit [Int] the number of saved searches to return
73
+ # @return [Hash]
74
+ #
75
+ def entity(entitytype, offset = 0, limit = 100)
76
+ wf_savedsearch_entity?(entitytype)
77
+ api_get(['type', entitytype].uri_concat, { offset: offset,
78
+ limit: limit })
79
+
80
+ end
81
+ end
82
+
83
+ # A standard response
84
+ #
85
+ class Response
86
+ class SavedSearch < Base; end
87
+ end
88
+ end
@@ -0,0 +1,58 @@
1
+ require_relative './base'
2
+
3
+ module Wavefront
4
+ #
5
+ # Manage and query Wavefront searches. The /search API path has a
6
+ # lot of paths, with a lot of duplication. The current state of
7
+ # this class covers the whole API with two methods, but leaves a
8
+ # lot up to the user. It may grow, with convenience methods.
9
+ #
10
+ class Search < Wavefront::Base
11
+
12
+ # POST /api/v2/search/agent
13
+ # POST /api/v2/search/agent/deleted
14
+ # Run a search query. This single method maps to many API paths.
15
+ #
16
+ # @param entity [String] the type of Wavefront object you wish
17
+ # to search
18
+ # @param body [Hash] the query to use for searching. Refer to
19
+ # the Wavefront Swagger docs for the correct format.
20
+ # @param deleted [Boolean] whether to search deleted (true) or
21
+ # active (false) entities
22
+ #
23
+ def search(entity = nil, body = nil, deleted = false)
24
+ raise ArgumentError unless entity.is_a?(String)
25
+ raise ArgumentError unless body.is_a?(Hash)
26
+ path = ['agent']
27
+ path.<< 'deleted' if deleted
28
+ api_post(path, body, 'application/json')
29
+ end
30
+
31
+ # @param entity [String] the type of Wavefront object you wish
32
+ # to search
33
+ # @param body [Hash] the query to use for searching. Refer to
34
+ # the Wavefront Swagger docs for the correct format.
35
+ # @param deleted [Boolean] whether to search deleted (true) or
36
+ # active (false) entities
37
+ # @param facet [String] the facet on which to search. If this is
38
+ # false, the assumption is that multiple facets will be
39
+ # specified in the body. See the Swagger docs for more
40
+ # information.
41
+ #
42
+ def facet_search(entity = nil, body = nil, deleted = false,
43
+ facet = false)
44
+ raise ArgumentError unless entity.is_a?(String)
45
+ raise ArgumentError unless body.is_a?(Hash)
46
+ path = ['agent']
47
+ path.<< 'deleted' if deleted
48
+ path.<< facet ? facet : 'facets'
49
+ api_post(path, body, 'application/json')
50
+ end
51
+ end
52
+
53
+ # A standard response
54
+ #
55
+ class Response
56
+ class Search < Base; end
57
+ end
58
+ end
@@ -0,0 +1,131 @@
1
+ require_relative './base'
2
+
3
+ module Wavefront
4
+ #
5
+ # View and manage source metadata.
6
+ #
7
+ class Source < Wavefront::Base
8
+
9
+ # GET /api/v2/source
10
+ # Get all sources for a customer
11
+ #
12
+ # @param offset [Int] source at which the list begins
13
+ # @param limit [Int] the number of sources to return
14
+ # @return [Hash]
15
+ #
16
+ def list(offset = 0, limit = 100)
17
+ api_get('', { offset: offset, limit: limit })
18
+ end
19
+
20
+ # POST /api/v2/source
21
+ # Create metadata (description or tags) for a specific source.
22
+ #
23
+ # Refer to the Swagger API docs for valid keys.
24
+ #
25
+ # @param body [Hash] description of source
26
+ # @return [Hash]
27
+ #
28
+ def create(body)
29
+ raise ArgumentError unless body.is_a?(Hash)
30
+ api_post('', body, 'application/json')
31
+ end
32
+
33
+ # DELETE /api/v2/source/{id}
34
+ # Delete metadata (description and tags) for a specific source.
35
+ #
36
+ # @param id [String] ID of the source
37
+ # @return [Hash]
38
+ #
39
+ def delete(id)
40
+ wf_source_id?(id)
41
+ api_delete(id)
42
+ end
43
+
44
+ # GET /api/v2/source/{id}
45
+ # Get a specific source for a customer.
46
+ #
47
+ # @param id [String] ID of the source
48
+ # @return [Hash]
49
+ #
50
+ def describe(id, version = nil)
51
+ wf_source_id?(id)
52
+ wf_version?(version) if version
53
+ fragments = [id]
54
+ fragments += ['history', version] if version
55
+ api_get(fragments.uri_concat)
56
+ end
57
+
58
+ # PUT /api/v2/source/{id}
59
+ # Update metadata (description or tags) for a specific source.
60
+ #
61
+ # Refer to the Swagger API docs for valid keys.
62
+ #
63
+ # @param body [Hash] description of source
64
+ # @return [Hash]
65
+ #
66
+ def update(id, body)
67
+ wf_source_id?(id)
68
+ raise ArgumentError unless body.is_a?(Hash)
69
+ api_put(id, body)
70
+ end
71
+
72
+ # GET /api/v2/source/{id}/tag
73
+ # Get all tags associated with a specific source.
74
+ #
75
+ # @param id [String] ID of the source
76
+ # @returns [Hash] object describing the source with status and
77
+ # response keys
78
+ #
79
+ def tags(id)
80
+ wf_source_id?(id)
81
+ api_get([id, 'tag'].uri_concat)
82
+ end
83
+
84
+ # POST /api/v2/source/{id}/tag
85
+ # Set all tags associated with a specific source.
86
+ #
87
+ # @param id [String] ID of the source
88
+ # @param tags [Array] list of tags to set.
89
+ # @returns [Hash] object describing the source with status and
90
+ # response keys
91
+ #
92
+ def tag_set(id, tags)
93
+ wf_source_id?(id)
94
+ tags = Array(tags)
95
+ tags.each { |t| wf_string?(t) }
96
+ api_post([id, 'tag'].uri_concat, tags.to_json, 'application/json')
97
+ end
98
+
99
+ # DELETE /api/v2/source/{id}/tag/{tagValue}
100
+ # Remove a tag from a specific source.
101
+ #
102
+ # @param id [String] ID of the source
103
+ # @param tag [String] tag to delete
104
+ # @returns [Hash] object with 'status' key and empty 'repsonse'
105
+ #
106
+ def tag_delete(id, tag)
107
+ wf_source_id?(id)
108
+ wf_string?(tag)
109
+ api_delete([id, 'tag', tag].uri_concat)
110
+ end
111
+
112
+ # PUT /api/v2/source/{id}/tag/{tagValue}
113
+ # Add a tag to a specific source
114
+ #
115
+ # @param id [String] ID of the source
116
+ # @param tag [String] tag to set.
117
+ # @returns [Hash] object with 'status' key and empty 'repsonse'
118
+ #
119
+ def tag_add(id, tag)
120
+ wf_source_id?(id)
121
+ wf_string?(tag)
122
+ api_put([id, 'tag', tag].uri_concat)
123
+ end
124
+ end
125
+
126
+ # A standard response
127
+ #
128
+ class Response
129
+ class Source < Base; end
130
+ end
131
+ end
@@ -0,0 +1,108 @@
1
+ require_relative './base'
2
+
3
+ module Wavefront
4
+ #
5
+ # Manage and query Wavefront users
6
+ #
7
+ class User < Wavefront::Base
8
+
9
+ # GET /api/v2/user
10
+ # Get all users.
11
+ #
12
+ def list
13
+ api_get('')
14
+ end
15
+
16
+ # POST /api/v2/user
17
+ # Creates or updates a user
18
+ #
19
+ # @param body [Hash] a hash of parameters describing the user.
20
+ # Please refer to the Wavefront Swagger docs for key:value
21
+ # information
22
+ # @return [Hash]
23
+ #
24
+ def create(body, send_email = false)
25
+ raise ArgumentError unless body.is_a?(Hash)
26
+ api_post("?sendEmail=#{send_email}", body, 'application/json')
27
+ end
28
+
29
+ # DELETE /api/v2/user/{id}
30
+ # Delete a specific user.
31
+ #
32
+ # @param id [String] ID of the user
33
+ # @return [Hash]
34
+ #
35
+ def delete(id)
36
+ wf_user_id?(id)
37
+ api_delete(id)
38
+ end
39
+
40
+ # GET /api/v2/user/{id}
41
+ # Retrieves a user by identifier (email addr).
42
+ #
43
+ # @param id [String] ID of the user
44
+ # @return [Hash]
45
+ #
46
+ def describe(id)
47
+ wf_user_id?(id)
48
+ api_get(id)
49
+ end
50
+
51
+ # PUT /api/v2/user/{id}/grant
52
+ # Grants a specific user permission.
53
+ #
54
+ # @param id [String] ID of the user
55
+ # @param group [String] group to add user to. We do not validate
56
+ # this so that changes to the API do not mandate changes to
57
+ # the SDK. At the time of writing, valid values are browse,
58
+ # agent_management, alerts_management, dashboard_management,
59
+ # embedded_charts, events_management,
60
+ # external_links_management, host_tag_management,
61
+ # metrics_management, user_management,
62
+ # @return [Hash]
63
+ #
64
+ def grant(id, group)
65
+ wf_user_id?(id)
66
+ raise ArgumentError unless group.is_a?(String)
67
+ api_post([id, 'grant'].uri_concat, "group=#{group}",
68
+ 'application/x-www-form-urlencoded')
69
+ end
70
+
71
+ # PUT /api/v2/user/{id}/revoke
72
+ # Revokes a specific user permission.
73
+ #
74
+ # @param id [String] ID of the user
75
+ # @param group [String] group to add user to. We do not validate
76
+ # this so that changes to the API do not mandate changes to
77
+ # the SDK. See #update for valid values.
78
+ # @return [Hash]
79
+ #
80
+ def revoke(id, group)
81
+ wf_user_id?(id)
82
+ raise ArgumentError unless group.is_a?(String)
83
+ api_post([id, 'revoke'].uri_concat, "group=#{group}",
84
+ 'application/x-www-form-urlencoded')
85
+ end
86
+ end
87
+
88
+ class Response
89
+
90
+ # The User response forges status and response methods to look
91
+ # like other classes and create a more consistent interface.
92
+ #
93
+ class User < Base
94
+ def populate(raw, status)
95
+ @response = if raw.is_a?(Array)
96
+ Struct.new(:items).new(raw).freeze
97
+ elsif raw.is_a?(Hash)
98
+ Struct.new(*raw.keys).new(*raw.values).freeze
99
+ end
100
+
101
+ result = status == 200 ? 'OK' : 'ERROR'
102
+
103
+ @status = Struct.new(:result, :message, :code).
104
+ new(result, nil, status)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,395 @@
1
+ require_relative './exception'
2
+
3
+ module Wavefront
4
+ #
5
+ # A module of mixins to validate input. The Wavefront documentation
6
+ # lays down restrictions on types and sizes of various inputs, which
7
+ # we will check on the user's behalf. Most of the information used in
8
+ # this file comes from https://community.wavefront.com/docs/DOC-1031
9
+ # Some comes from the Swagger API documentation, some has come
10
+ # directly from Wavefront engineers.
11
+ #
12
+ module Validators
13
+
14
+ # Ensure the given argument is a valid external link template
15
+ #
16
+ # @return true if it is valid
17
+ # @raise Wavefront::Exception::InvalidTemplate if not
18
+ #
19
+ def wf_link_template?(v)
20
+ if v.is_a?(String) && (v.start_with?('http://') ||
21
+ v.start_with?('https://'))
22
+ return true
23
+ end
24
+
25
+ raise Wavefront::Exception::InvalidLinkTemplate
26
+ end
27
+
28
+ # Ensure the given argument is a valid Wavefront metric name, or
29
+ # path.
30
+ #
31
+ # @param v [String] the metric name to validate
32
+ # @return True if the metric name is valid
33
+ # @raise Wavefront::Exception::InvalidMetricName if metric name
34
+ # is not valid.
35
+ #
36
+ def wf_metric_name?(v)
37
+ if v.is_a?(String) && v.size < 1024 &&
38
+ (v.match(/^[\w\-\.]+$/) || v.match(%r{^\"[\w\-\.\/,]+\"$}))
39
+ return true
40
+ end
41
+
42
+ raise Wavefront::Exception::InvalidMetricName
43
+ end
44
+
45
+ # Ensure the given argument is a valid name, for instance for an
46
+ # event. Names can contain, AFAIK, word characters.
47
+ #
48
+ # @param v [String] the name to validate
49
+ # @return true if the name is valid
50
+ # raise Wavefront::Exception::InvalidName if name is not valid
51
+ #
52
+ def wf_name?(v)
53
+ return true if v.is_a?(String) && v.size < 1024 && v =~ /^\w+$/
54
+ raise Wavefront::Exception::InvalidName
55
+ end
56
+
57
+ # Ensure the given argument is a valid string, for a tag name.
58
+ #
59
+ # @param v [String] the string name to validate
60
+ # @return True if the string is valid
61
+ # @raise Wavefront::Exception::InvalidString if string is not valid.
62
+ #
63
+ def wf_string?(v)
64
+ #
65
+ # Only allows PCRE "word" characters, spaces, full-stops and
66
+ # commas in tags and descriptions. This might be too restrictive,
67
+ # but if it is, this is the only place we need to change it.
68
+ #
69
+ return true if v.is_a?(String) && v.size < 1024 && v =~ /^[\-\w \.,]*$/
70
+
71
+ raise Wavefront::Exception::InvalidString
72
+ end
73
+
74
+ # Ensure the given argument is a valid timestamp
75
+ #
76
+ # @param v [DateTime] the timestamp name to validate
77
+ # @return True if the value is valid
78
+ # @raise Wavefront::Exception::InvalidTimestamp
79
+ #
80
+ def wf_ts?(v)
81
+ return true if v.is_a?(Time) || v.is_a?(Date)
82
+ raise Wavefront::Exception::InvalidTimestamp
83
+ end
84
+
85
+ # Ensure the given argument is a valid millisecond epoch
86
+ # timestamp. We do no checking of the value, because who am I to
87
+ # say that the user doesn't want to send a point relating to 1ms
88
+ # after the epoch, or a thousand years in the future?
89
+ #
90
+ # @param v [Integer] the timestamp name to validate
91
+ # @return True if the value is valid
92
+ # @raise Wavefront::Exception::InvalidTimestamp
93
+ #
94
+ def wf_ms_ts?(v)
95
+ return true if v.is_a?(Numeric)
96
+ raise Wavefront::Exception::InvalidTimestamp
97
+ end
98
+
99
+ # Ensure the given argument is a valid epoch timestamp. Again,
100
+ # no range checking.
101
+ #
102
+ # @param v [String, Integer]
103
+ # @return True if the timestamp is valid
104
+ # @raise Wavefront::Exception::InvalidMaintenanceWindow
105
+ #
106
+ def wf_epoch?(v)
107
+ return true if v.is_a?(Numeric)
108
+ raise Wavefront::Exception::InvalidTimestamp
109
+ end
110
+
111
+ # Ensure one, or an array, of tags are valid. These tags are
112
+ # used as source tags, or tags for maintenance windows etc. They
113
+ # can contain letters, numbers, -, _ and :, and must be less
114
+ # than 256 characters long
115
+ #
116
+ # @param v [String, Array] a tag or list of tags
117
+ # @return True if all tags are valid
118
+ # @raise Wavefront::Exception::InvalidTag
119
+ #
120
+ def wf_tag?(*v)
121
+ Array(*v).each do |t|
122
+ unless t.is_a?(String) && t.size < 255 && t =~ /^[\w:\-\.]+$/
123
+ raise Wavefront::Exception::InvalidTag
124
+ end
125
+ end
126
+
127
+ true
128
+ end
129
+
130
+ # Ensure the given argument is a valid Wavefront value. Can be
131
+ # any form of Numeric, including standard notation.
132
+ #
133
+ # @param v [Numeric] the source name to validate
134
+ # @return True if the value is valid
135
+ # @raise Wavefront::Exception::InvalidValue if the value is not valid
136
+ #
137
+ def wf_value?(v)
138
+ return true if v.is_a?(Numeric)
139
+ raise Wavefront::Exception::InvalidMetricValue
140
+ end
141
+
142
+ # Ensure the given argument is a valid version number
143
+ #
144
+ # @param [Integer] the version number to validate
145
+ # @return True if the version is valid
146
+ # @raise Wavefront::Exception::InvalidVersion if the alert ID is
147
+ # not valid
148
+ #
149
+ def wf_version?(v)
150
+ v = v.to_i if v.is_a?(String) && v =~ /^\d+$/
151
+ return true if v.is_a?(Integer) && v > 0
152
+ raise Wavefront::Exception::InvalidVersion
153
+ end
154
+
155
+ # Ensure a hash of key:value point tags are value. Not to be
156
+ # confused with source tags.
157
+ #
158
+ # @param tags [Hash] a hash of key:value tags
159
+ # @return True if all tags are valid
160
+ # @raise Wavefront::Exception::InvalidTag if any tags in the has
161
+ # do not validate
162
+ #
163
+ def wf_point_tags?(tags)
164
+ raise Wavefront::Exception::InvalidTag unless tags.is_a?(Hash)
165
+
166
+ tags.each do |k, v|
167
+ unless (k.size + v.size < 254) && k.match(/^[\w\-\.:]+$/)
168
+ raise Wavefront::Exception::InvalidTag
169
+ end
170
+ end
171
+ true
172
+ end
173
+
174
+ # Ensure the given argument is a valid Wavefront proxy ID
175
+ #
176
+ # @param v [String] the proxy ID to validate
177
+ # @return True if the proxy ID is valid
178
+ # @raise Wavefront::Exception::InvalidProxyId if the proxy ID
179
+ # is not valid
180
+ #
181
+ def wf_proxy_id?(v)
182
+ if v.is_a?(String) && v.match(
183
+ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
184
+ )
185
+ return true
186
+ end
187
+
188
+ raise Wavefront::Exception::InvalidProxyId
189
+ end
190
+
191
+ # Ensure the given argument is a valid Wavefront alert ID.
192
+ # Alerts are identified by the epoch-nanosecond at which they
193
+ # were created.
194
+ #
195
+ # @param v [String] the alert ID to validate
196
+ # @return True if the alert ID is valid
197
+ # @raise Wavefront::Exception::InvalidAlertId if the alert ID is
198
+ # not valid
199
+ #
200
+ def wf_alert_id?(v)
201
+ v = v.to_s if v.is_a?(Numeric)
202
+ return true if v.is_a?(String) && v.match(/^\d{13}$/)
203
+ raise Wavefront::Exception::InvalidAlertId
204
+ end
205
+
206
+ # Ensure the given argument is a valid Wavefront cloud
207
+ # integration ID
208
+ #
209
+ # @param v [String] the integration name to validate
210
+ # @return True if the integration name is valid
211
+ # @raise Wavefront::Exception::InvalidCloudIntegrationId if the
212
+ # integration ID is not valid
213
+ #
214
+ def wf_cloudintegration_id?(v)
215
+ if v.is_a?(String) && v.match(
216
+ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
217
+ )
218
+ return true
219
+ end
220
+
221
+ raise Wavefront::Exception::InvalidCloudIntegrationId
222
+ end
223
+
224
+ # There doesn't seem to be a public statement on what's allowed
225
+ # in a dashboard name. For now I'm going to assume up to 255 word
226
+ # characters.
227
+ #
228
+ # @param v [String] the dashboard ID to validate
229
+ # @return true if the dashboard ID is valid
230
+ # @raise Wavefront::Exception::InvalidDashboardID if the
231
+ # dashboard ID is not valid
232
+ #
233
+ def wf_dashboard_id?(v)
234
+ return true if v.is_a?(String) && v.size < 256 && v.match(/^[\w\-]+$/)
235
+ raise Wavefront::Exception::InvalidDashboardId
236
+ end
237
+
238
+ # Ensure the given argument is a valid event ID. Event IDs are
239
+ # an epoch-millisecond timestamp followed by a : followed by the
240
+ # name of the event.
241
+ #
242
+ # @param v [String] the event ID to validate
243
+ # @return true if the event ID is valid
244
+ # @raise Wavefront::Exception::InvalidEventID if the
245
+ # event ID is not valid
246
+ #
247
+ def wf_event_id?(v)
248
+ return true if v.is_a?(String) && v =~ /^\d{13}:[\w\- ]+$/
249
+ raise Wavefront::Exception::InvalidEventId
250
+ end
251
+
252
+ # Ensure the given argument is a valid external Link ID
253
+ #
254
+ # @param v [String] the external link ID to validate
255
+ # @return True if the link ID is valid
256
+ # @raise Wavefront::Exception::InvalidExternalLinkId if the
257
+ # link ID is not valid
258
+ #
259
+ def wf_link_id?(v)
260
+ return true if v.is_a?(String) && v =~ /^\w{16}$/
261
+ raise Wavefront::Exception::InvalidExternalLinkId
262
+ end
263
+
264
+ # Ensure the given argument is a valid maintenance window ID.
265
+ # IDs are the millisecond epoch timestamp at which the window
266
+ # was created.
267
+ #
268
+ # @param v [String, Integer]
269
+ # @return True if the ID is valid
270
+ # @raise Wavefront::Exception::InvalidMaintenanceWindowId
271
+ #
272
+ def wf_maintenance_window_id?(v)
273
+ v = v.to_s if v.is_a?(Numeric)
274
+ return true if v.is_a?(String) && v =~ /^\d{13}$/
275
+
276
+ raise Wavefront::Exception::InvalidMaintenanceWindowId
277
+ end
278
+
279
+ # Ensure the given argument is a valid alert severity
280
+ #
281
+ # @param v [String] severity
282
+ # @return true if valid
283
+ # @raise Wavefront::Exceptions::InvalidAlertSeverity if not
284
+ # valid
285
+ #
286
+ def wf_alert_severity?(v)
287
+ return true if %w(INFO SMOKE WARN SEVERE).include?(v)
288
+ raise Wavefront::Exception::InvalidAlertSeverity
289
+ end
290
+
291
+ # Ensure the given argument is a valid message ID
292
+ #
293
+ # @param v [String] severity
294
+ # @return true if valid
295
+ # @raise Wavefront::Exceptions::InvalidMessageId if not
296
+ # valid
297
+ #
298
+ def wf_message_id?(v)
299
+ return true if v.is_a?(String) && v =~ /^\w+$/
300
+ raise Wavefront::Exception::InvalidMessageId
301
+ end
302
+
303
+ # Ensure the given argument is a valid query granularity
304
+ #
305
+ # @param v [String] granularity
306
+ # @return true if valid
307
+ # @raise Wavefront::Exceptions::InvalidGranularity if not
308
+ # valid
309
+ #
310
+ def wf_granularity?(v)
311
+ return true if %w(d h m s).include?(v.to_s)
312
+ raise Wavefront::Exception::InvalidGranularity
313
+ end
314
+
315
+ # Ensure the given argument is a valid saved search ID.
316
+ #
317
+ # @param v [String] saved search ID
318
+ # @return true if valid
319
+ # @raise Wavefront::Exceptions::InvalidSavedSearchId if not valid
320
+ #
321
+ def wf_savedsearch_id?(v)
322
+ return true if v.is_a?(String) && v =~ /^\w{8}$/
323
+ raise Wavefront::Exception::InvalidSavedSearchId
324
+ end
325
+
326
+ # Ensure the given argument is a valid saved search entity type.
327
+ #
328
+ # @param v [String] entity type
329
+ # @return true if valid
330
+ # @raise Wavefront::Exceptions::InvalidSavedSearchEntity if not
331
+ # valid
332
+ #
333
+ def wf_savedsearch_entity?(v)
334
+ return true if %w(DASHBOARD ALERT MAINTENANCE_WINDOW
335
+ NOTIFICANT EVENT SOURCE EXTERNAL_LINK AGENT
336
+ CLOUD_INTEGRATION).include?(v)
337
+ raise Wavefront::Exception::InvalidSavedSearchEntity
338
+ end
339
+
340
+ # Ensure the given argument is a valid Wavefront source name
341
+ #
342
+ # @param v [String] the source name to validate
343
+ # @return True if the source name is valid
344
+ # @raise Wavefront::Exception::InvalidSourceId if the source name
345
+ # is not valid
346
+ #
347
+ def wf_source_id?(v)
348
+ if v.is_a?(String) && v.match(/^[\w\.\-]+$/) && v.size < 1024
349
+ return true
350
+ end
351
+
352
+ raise Wavefront::Exception::InvalidSourceId
353
+ end
354
+
355
+ # Ensure the given argument is a valid user.
356
+ #
357
+ # @param v [String] user identifier
358
+ # @return true if valid
359
+ # @raise Wavefront::Exceptions::InvalidUserId if not valid
360
+ #
361
+ def wf_user_id?(v)
362
+ return true if v.is_a?(String) &&
363
+ v =~ /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
364
+ raise Wavefront::Exception::InvalidUserId
365
+ end
366
+
367
+ # Ensure the given argument is a valid webhook ID.
368
+ #
369
+ # @param v [String] webhook ID
370
+ # @return true if valid
371
+ # @raise Wavefront::Exceptions::InvalidWebhook if not valid
372
+ #
373
+ def wf_webhook_id?(v)
374
+ return true if v.is_a?(String) && v =~ /^[a-zA-Z0-9]{16}$/
375
+ raise Wavefront::Exception::InvalidWebhookId
376
+ end
377
+
378
+ # Validate a point so it conforms to the standard described in
379
+ # https://community.wavefront.com/docs/DOC-1031
380
+ #
381
+ # @param v [Hash] description of point
382
+ # @return true if valie
383
+ # @raise whichever exception is thrown first when validating
384
+ # each component of the point.
385
+ #
386
+ def wf_point?(v)
387
+ wf_metric_name?(v[:path])
388
+ wf_value?(v[:value])
389
+ wf_epoch?(v[:ts]) if v[:ts]
390
+ wf_source_id?(v[:source]) if v[:source]
391
+ wf_point_tags?(v[:tags]) if v[:tags]
392
+ true
393
+ end
394
+ end
395
+ end