wavefront-client 3.5.4 → 3.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5c289e188276ac63035e6acd3ea84ab59721e63b
4
- data.tar.gz: eb9d96bae403aa21ed775bf37bb5ad85d8c078c3
3
+ metadata.gz: 27196556716ec832044c8587e6d395caddc4c39f
4
+ data.tar.gz: b8acc4e5aa6ce54130fd6abc143d3f2f8fffe44b
5
5
  SHA512:
6
- metadata.gz: 18b87b4ff437336b124a353fb982bdea69c0a34ed32314a0fad69db6f636cb33c0b529cad6dffa95137ef18a952b1ad0d1066959e01fa25e652bceb04e78b5e8
7
- data.tar.gz: c926ec0a4245bba66b92f64daa28cbb300c8abad127d3a2f302b6c05b14e234e0109b6986678bb220c6651886125a716e96a154e75ac5c7ee81fc9a25d0564e1
6
+ metadata.gz: 656b1215fe52afbdcfeb62212e458f900807edf84621e2968c50f44ff23b60b1f2424d2a32753d3f19e14de3894c0f8d479dd6320d55e3fa3307c7117ee5936d
7
+ data.tar.gz: c8c9741dfc418ba90aab20f6b4b3d898e978dd98677baae33ec506b42c0c377ce77dc0a31291210b99e556c071af542a19e42dcd3702e84206ecd8099188b251
data/README-cli.md CHANGED
@@ -102,23 +102,37 @@ $ ./wavefront ts -f human -m --start=18:00 --end=20:00 'events()'
102
102
  Output is different for event queries. The columns are: start time -> end
103
103
  time, (duration), severity, event type, [source(s)], details.
104
104
 
105
- ## `alerts` Mode: Retrieving Alert Data
105
+ ## `alerts` Mode: Retrieving and Importing Alert Data
106
106
 
107
- The `alerts` command lets you view alerts. It does not currently
108
- allow creation and removal of alerts. Alert data can be presented in
109
- a number of formats, but defaults to a human-readable form. If you
110
- wish to parse the output, please use the `ruby` or `json`
111
- formatters.
107
+ The `alerts` command lets you view, export, and import alerts. It
108
+ does not currently modification removal, or reacting to alerts, as
109
+ these actions are not supported by the v1 API.
110
+
111
+ Alerts can be presented in a number of formats, but defaults to a
112
+ human-readable form. If you wish to parse the output, please use the
113
+ `ruby`, `yaml` or `json` formatters.
112
114
 
113
115
  ```
114
116
  Usage:
115
- wavefront alerts [-D] [-c file] [-P profile] [-E endpoint] [-t token] [-V]
117
+ wavefront alerts [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
116
118
  [-f format] [-p tag] [ -s tag] <state>
119
+ wavefront alerts export [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
120
+ [-f format] <timestamp>
121
+ wavefront alerts import [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
122
+ <file>
123
+
124
+ Global options:
125
+ -c, --config=FILE path to configuration file [/home/rob/.wavefront]
126
+ -P, --profile=NAME profile in configuration file [default]
127
+ -D, --debug enable debug mode
128
+ -n, --noop don't perform API calls
129
+ -V, --verbose be verbose
130
+ -h, --help show this message
117
131
 
118
132
  Options:
119
133
  -E, --endpoint=URI cluster endpoint [metrics.wavefront.com]
120
134
  -t, --token=TOKEN Wavefront authentication token
121
- -f, --alertformat=STRING output format (ruby, json, human)
135
+ -f, --alertformat=STRING output format (ruby, json, human, yaml)
122
136
  []
123
137
  -p, --private=TAG retrieve only alerts with named private tags,
124
138
  comma delimited.
@@ -126,6 +140,17 @@ Options:
126
140
  comma delimited.
127
141
  ```
128
142
 
143
+ When exporting an alert, you must refer to it my its millisecond
144
+ timestamp. This value is in the `created` field when you view an
145
+ alert as `json` or `YAML`, and it is shown in brackets on the
146
+ `created` line if you use `human` output.
147
+
148
+ Due to v1 API limitations, not all an alert's properties will
149
+ survive the import/export process.
150
+
151
+ Imports can only be alerted from a file. Importing from stdin is
152
+ currently unsupported.
153
+
129
154
  ### Examples
130
155
 
131
156
  List all alerts in human-readable format. Alerts are separated by a
@@ -157,10 +182,23 @@ severity WARN
157
182
  Show alerts currently firing, in JSON format:
158
183
 
159
184
  ```
160
- $ wavefront alerts -P sysdef --format ruby active
185
+ $ wavefront alerts -P sysdef --format json active
161
186
  "[{\"customerTagsWithCounts\":{},\"userTagsWithCounts\":{},\"created\":1459508340708,\"name\":\"Point Rate\",\"conditionQBEnabled\":false,\"displayExpressionQBEnabled\":false,\"condition\":\"sum(deriv(ts(~collector.points.valid))) > 50000\",\"displayExpression\":\"sum(deriv(ts(~collector.points.valid)))\",\"minutes\":5,\"target\":\"alerts@company.com,\",\"event\":{\"name\":\"Point Rate\",\"startTime\":1467049323203,\"annotations\":{\"severity\":\"severe\",\"type\":\"alert\",\"created\":\"1459508340708\",\"target\":\"alerts@company.com,\"},\"hosts\":[\"\"],\"table\":\"sysdef\"},\"failingHostLabelPairs\":[{\"label\":\"\",\"observed\":5,\"firing\":5}],\"updated\":1467049317802,\"severity\":\"SEVERE\",\"additionalInformation\":\"We have exceeded our agreed point rate.\",\"activeMaintenanceWindows\":[],\"inMaintenanceHostLabelPairs\":[],\"prefiringHostLabelPairs\":[],\"alertStates\":[\"ACTIVE\"],\"inTrash\":false,\"numMetricsUsed\":1,\"numHostsUsed\":1}]"
162
187
  ```
163
188
 
189
+ Export an alert from your default account, in JSON format:
190
+
191
+ ```
192
+ $ wavefront alerts export -f json 1488995981076 >my_alert.json
193
+ ```
194
+
195
+ and re-import it:
196
+
197
+ ```
198
+ $ wavefront alerts import my_alert.json
199
+ Alert imported.
200
+ ```
201
+
164
202
  ## `event` Mode: Opening and Closing Events
165
203
 
166
204
  The `event` command is used to open and close Wavefront events.
@@ -473,6 +511,121 @@ physical 10
473
511
  zone 363
474
512
  ```
475
513
 
514
+ ## `dashboard` Mode:
515
+
516
+ The `dashboard` command implements all of the v1 API's `dashboard`
517
+ paths.
518
+
519
+ ```
520
+ Usage:
521
+ wavefront dashboard list [-DnV] [-c file] [-P profile] [-E endpoint]
522
+ [-f format] [-t token] [-T tag...] [-p tag...] [-a]
523
+ wavefront dashboard import [-DnV] [-c file] [-P profile] [-E endpoint]
524
+ [-f format] [-F] <file>
525
+ wavefront dashboard export [-DnV] [-c file] [-P profile] [-E endpoint]
526
+ [-f format] [-v version] <dashboard_id>
527
+ wavefront dashboard create [-DnV] [-c file] [-P profile] [-E endpoint]
528
+ <dashboard_id> <name>
529
+ wavefront dashboard clone [-DnV] [-c file] [-P profile] [-E endpoint]
530
+ [-v version] -s source_id <new_id> <new_name>
531
+ wavefront dashboard delete [-DnV] [-c file] [-P profile] [-E endpoint]
532
+ <dashboard_id>
533
+ wavefront dashboard undelete [-DnV] [-c file] [-P profile] [-E endpoint]
534
+ <dashboard_id>
535
+ wavefront dashboard history [-DnV] [-c file] [-P profile] [-E endpoint]
536
+ [-f format] [-S version] [-L limit] <dashboard_id>
537
+ ```
538
+
539
+ Dashboard IDs are the same as their `url` fields when listed or exported.
540
+
541
+ Deleting a dashboard once will move it to "trash". Deleting a second
542
+ time removes it for ever. Dashboards can be recovered from the trash
543
+ with the `undelete` command.
544
+
545
+ Listing dashboards with `-f human` will not ordinarily display
546
+ dashboards in the trash. Supplying the `-a` option will list all
547
+ dashboards, and trashed ones will have `(in trash)` appended to
548
+ their name field. Listing dashboards in a machine-parseable format
549
+ does not do this filtering.
550
+
551
+ When cloning a dashboard you may use the `-v` flag to clone from a
552
+ specific version. Without `-v` the current dashboard is cloned.
553
+
554
+ If your dashboard output format, defined either by the `-f` flag or
555
+ the `dashformat` config-file setting is `human`, and you use
556
+ `dashboard export`, the output format will silently switch to JSON
557
+ for that one command.
558
+
559
+ Importing a dashboard will fail if a dashboard with the same url
560
+ already exists. If you supply the `-F` flag, the existing dashboard
561
+ will be overwritten.
562
+
563
+ Dashboards can be imported from YAML or JSON files, but not
564
+ currently from standard in. The file format is automatically
565
+ detected.
566
+
567
+ ### Examples
568
+
569
+ List active dashboards in a human-readable form:
570
+
571
+ ```
572
+ $ wavefront dashboard list -f human
573
+ ID NAME
574
+ S3 S3
575
+ box how busy is box?
576
+ discogs discogs data
577
+ internal_metrics Internal Metrics
578
+ intro-anomaly-detection-series-1 Intro: Use Case: Anomaly Detection
579
+ Series - Part 1
580
+ intro-code-push-example Intro: Use Case: Code Push Event
581
+ ...
582
+ ```
583
+
584
+ Show the modification history of a dashboard, in human-readable
585
+ form:
586
+
587
+ ```
588
+ $ wavefront dashboard history shark-overview
589
+ 25 2016-10-01 16:08:29 +0100 (slackboy@gmail.com)
590
+ Dashboard Section: Incoming Chart added
591
+ Chart: swapping events in Section: Memory updated
592
+ 24 2016-10-01 16:06:25 +0100 (slackboy@gmail.com)
593
+ Chart: swapping events in Section: Memory updated
594
+ 23 2016-10-01 15:35:39 +0100 (slackboy@gmail.com)
595
+ Chart: SMF services added to Section: System Health
596
+ Chart: ZFS ARC in Section: ZFS updated
597
+ 22 2016-10-01 15:31:18 +0100 (slackboy@gmail.com)
598
+ Chart: ZFS ARC in Section: ZFS updated
599
+ 21 2016-10-01 15:30:57 +0100 (slackboy@gmail.com)
600
+ Dashboard Section: Incoming Chart removed
601
+ Dashboard Section: Memory added
602
+ Dashboard Section: Memory added
603
+ 20 2016-10-01 15:30:07 +0100 (slackboy@gmail.com)
604
+ Chart: swapping events added to Section: Incoming Chart
605
+ 19 2016-10-01 15:25:40 +0100 (slackboy@gmail.com)
606
+ Dashboard Section: Incoming Chart added
607
+ Chart: ZFS ARC in Section: ZFS updated
608
+ ...
609
+ ```
610
+
611
+ The first column is the version of the dashboard.
612
+
613
+ Export a dashboard to a JSON file
614
+
615
+ ```
616
+ $ wavefront dashboard export -f json shark-overview >shark_overview.json
617
+ ```
618
+
619
+ And import it back in
620
+ ```
621
+ $ wavefront dashboard import shark_overview.json
622
+ ```
623
+
624
+ ### Caveats
625
+
626
+ It is not currently possible to delete the example dashboards
627
+ supplied by Wavefront. This is not the fault of the CLI or SDK.
628
+
476
629
  ## Notes on Options
477
630
 
478
631
  ### Times
data/bin/wavefront CHANGED
@@ -17,7 +17,7 @@
17
17
  require 'pathname'
18
18
 
19
19
  # uncomment for development
20
- $LOAD_PATH.<< Pathname.new(__FILE__).dirname.realpath.parent + 'lib'
20
+ # $LOAD_PATH.<< Pathname.new(__FILE__).dirname.realpath.parent + 'lib'
21
21
 
22
22
  require 'wavefront/client'
23
23
  require 'wavefront/client/version'
@@ -87,6 +87,10 @@ alerts: %(
87
87
  Usage:
88
88
  #{ME} alerts [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
89
89
  [-f format] [-p tag] [ -s tag] <state>
90
+ #{ME} alerts export [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
91
+ [-f format] <timestamp>
92
+ #{ME} alerts import [-DnV] [-c file] [-P profile] [-E endpoint] [-t token]
93
+ <file>
90
94
  #{global_opts}
91
95
  Options:
92
96
  -E, --endpoint=URI cluster endpoint [#{DEFAULT_OPTS[:endpoint]}]
@@ -180,6 +184,38 @@ Options:
180
184
  -H, --host=STRING source to manipulate
181
185
  -f, --sourceformat=STRING output format (#{SOURCE_FORMATS.join(', ')}) [#{DEFAULT_OPTS[:sourceformat]}]
182
186
  ),
187
+ dashboard: %(
188
+ Usage:
189
+ #{ME} dashboard list [-DnV] [-c file] [-P profile] [-E endpoint]
190
+ [-t token] [-f format] [-a] [-T tag...] [-p tag...]
191
+ #{ME} dashboard import [-DnV] [-c file] [-P profile] [-E endpoint]
192
+ [-t token] [-f format] [-F] <file>
193
+ #{ME} dashboard export [-DnV] [-c file] [-P profile] [-E endpoint]
194
+ [-t token] [-f format] [-v version] <dashboard_id>
195
+ #{ME} dashboard create [-DnV] [-c file] [-P profile] [-E endpoint]
196
+ [-t token] <dashboard_id> <name>
197
+ #{ME} dashboard clone [-DnV] [-c file] [-P profile] [-E endpoint]
198
+ [-t token] [-v version] <source_id> <new_id> <new_name>
199
+ #{ME} dashboard delete [-DnV] [-c file] [-P profile] [-E endpoint]
200
+ [-t token] <dashboard_id>
201
+ #{ME} dashboard undelete [-DnV] [-c file] [-P profile] [-E endpoint]
202
+ [-t token] <dashboard_id>
203
+ #{ME} dashboard history [-DnV] [-c file] [-P profile] [-E endpoint]
204
+ [-t token] [-f format] [-S version] [-L limit] <dashboard_id>
205
+ #{ME} dashboard --help
206
+ #{global_opts}
207
+ Options:
208
+ -E, --endpoint=URI cluster endpoint [#{DEFAULT_OPTS[:endpoint]}]
209
+ -t, --token=TOKEN Wavefront authentication token
210
+ -a, --all in human output mode, list all dashboards
211
+ -T, --sharedtag=TAG only select dashboards with this shared tag
212
+ -p, --privatetag=TAG only select dashboards with this private tag
213
+ -S, --start=VERSION highest version number from which to descend
214
+ -L, --limit=COUNT number of versions to report
215
+ -v, --version=INTEGER version of dashboard to clone
216
+ -F, --force import dashboard even if it already exists
217
+ -f, --dashformat=STRING output format (#{DASH_FORMATS.join(', ')}) [#{DEFAULT_OPTS[:dashformat]}]
218
+ ),
183
219
  default: %(
184
220
  Wavefront CLI
185
221
 
@@ -191,6 +227,7 @@ Usage:
191
227
  Commands:
192
228
  ts view timeseries data
193
229
  alerts view alerts
230
+ dashboard view and manage dashboards
194
231
  event open and close events
195
232
  source view and manage source tags and descriptions
196
233
  write send data points to a Wavefront proxy
@@ -247,6 +284,9 @@ when :write
247
284
  require 'wavefront/cli/write'
248
285
  cli = Wavefront::Cli::Write.new(opts, [opts[:'<state>']])
249
286
  end
287
+ when :dashboard
288
+ require 'wavefront/cli/dashboards'
289
+ cli = Wavefront::Cli::Dashboards.new(opts, [opts[:'<state>']])
250
290
  end
251
291
 
252
292
  begin
@@ -29,7 +29,7 @@ module Wavefront
29
29
  include Wavefront::Mixins
30
30
  DEFAULT_PATH = '/api/alert/'
31
31
 
32
- attr_reader :token, :noop, :verbose, :endpoint
32
+ attr_reader :token, :noop, :verbose, :endpoint, :headers, :options
33
33
 
34
34
  def initialize(token, host = DEFAULT_HOST, debug=false, options = {})
35
35
  #
@@ -41,26 +41,108 @@ module Wavefront
41
41
  debug(debug)
42
42
  @noop = options[:noop]
43
43
  @verbose = options[:verbose]
44
+ @options = options
45
+ end
46
+
47
+ def import_to_create(raw)
48
+ #
49
+ # Take a previously exported alert, and construct a hash which
50
+ # create_alert() can use to re-create it.
51
+ #
52
+ ret = {
53
+ name: raw['name'],
54
+ condition: raw['condition'],
55
+ minutes: raw['minutes'],
56
+ notifications: raw['target'].split(','),
57
+ severity: raw['severity'],
58
+ }
59
+
60
+ if raw.key?('displayExpression')
61
+ ret[:displayExpression] = raw['displayExpression']
62
+ end
63
+
64
+ if raw.key?('resolveAfterMinutes')
65
+ ret[:resolveMinutes] = raw['resolveAfterMinutes']
66
+ end
67
+
68
+ if raw.key?('customerTagsWithCounts')
69
+ ret[:sharedTags] = raw['customerTagsWithCounts'].keys
70
+ end
71
+
72
+ if raw.key?('additionalInformation')
73
+ ret[:additionalInformation] = raw['additionalInformation']
74
+ end
75
+
76
+ ret
77
+ end
78
+
79
+ def create_alert(alert={})
80
+ #
81
+ # Create an alert. Expects you to provide it with a hash of
82
+ # the form:
83
+ #
84
+ # {
85
+ # name: string
86
+ # condition: string
87
+ # displayExpression: string (optional)
88
+ # minutes: int
89
+ # resolveMinutes: int (optional)
90
+ # notifications: array
91
+ # severity: INFO | SMOKE | WARN | SEVERE
92
+ # privateTags: array (optional)
93
+ # sharedTags: array (optional)
94
+ # additionalInformation string (optional)
95
+ # }
96
+ #
97
+ %w(name condition minutes notifications severity).each do |f|
98
+ raise "missing field: #{f}" unless alert.key?(f.to_sym)
99
+ end
100
+
101
+ unless %w(INFO SMOKE WARN SEVERE).include?(alert[:severity])
102
+ raise 'invalid severity'
103
+ end
104
+
105
+ %w(notifications privateTags sharedTags).each do |f|
106
+ f = f.to_sym
107
+ alert[f] = alert[f].join(',') if alert[f] && alert[f].is_a?(Array)
108
+ end
109
+
110
+ call_post(create_uri(path: 'create'),
111
+ hash_to_qs(alert), 'application/x-www-form-urlencoded')
112
+ end
113
+
114
+ def get_alert(id, options = {})
115
+ #
116
+ # Alerts are identified by the timestamp at which they were
117
+ # created. Returns a hash. Exceptions are just passed on
118
+ # through. You get a 500 if the alert doesn't exist.
119
+ #
120
+ resp = call_get(create_uri(path: id)) || '{}'
121
+ return JSON.parse(resp)
44
122
  end
45
123
 
46
124
  def active(options={})
47
- get_alerts('active', options)
125
+ call_get(create_uri(options.merge(path: 'active',
126
+ qs: mk_qs(options))))
48
127
  end
49
128
 
50
129
  def all(options={})
51
- get_alerts('all', options)
130
+ call_get(create_uri(options.merge(path: 'all', qs: mk_qs(options))))
52
131
  end
53
132
 
54
133
  def invalid(options={})
55
- get_alerts('invalid', options)
134
+ call_get(create_uri(options.merge(path: 'invalid',
135
+ qs: mk_qs(options))))
56
136
  end
57
137
 
58
138
  def snoozed(options={})
59
- get_alerts('snoozed', options)
139
+ call_get(create_uri(options.merge(path: 'snoozed',
140
+ qs: mk_qs(options))))
60
141
  end
61
142
 
62
143
  def affected_by_maintenance(options={})
63
- get_alerts('affected_by_maintenance', options)
144
+ call_get(create_uri(options.merge(path: 'affected_by_maintenance',
145
+ qs: mk_qs(options))))
64
146
  end
65
147
 
66
148
  private
@@ -70,33 +152,38 @@ module Wavefront
70
152
  end
71
153
 
72
154
  def mk_qs(options)
73
- query = "t=#{token}"
155
+ query = []
74
156
 
75
- query += '&' + list_of_tags(options[:shared_tags]).map do |t|
76
- "customerTag=#{t}"
77
- end.join('&') if options[:shared_tags]
157
+ if options[:shared_tags]
158
+ query.push(list_of_tags(options[:shared_tags]).map do |t|
159
+ "customerTag=#{t}"
160
+ end.join('&'))
161
+ end
78
162
 
79
- query += '&' + list_of_tags(options[:private_tags]).map do |t|
80
- "userTag=#{t}"
81
- end.join('&') if options[:private_tags]
163
+ if options[:private_tags]
164
+ query.push(list_of_tags(options[:private_tags]).map do |t|
165
+ "userTag=#{t}"
166
+ end.join('&'))
167
+ end
82
168
 
83
- query
169
+ query.join('&')
84
170
  end
85
171
 
86
- def get_alerts(path, options={})
172
+ def create_uri(options = {})
173
+ #
174
+ # Build the URI we use to send a 'create' request.
175
+ #
87
176
  options[:host] ||= endpoint
88
- options[:path] ||= DEFAULT_PATH
177
+ options[:path] ||= ''
178
+ options[:qs] ||= nil
179
+
180
+ options[:qs] = nil if options[:qs] && options[:qs].empty?
89
181
 
90
- uri = URI::HTTPS.build(
182
+ URI::HTTPS.build(
91
183
  host: options[:host],
92
- path: uri_concat(options[:path], path),
93
- query: mk_qs(options),
184
+ path: uri_concat(DEFAULT_PATH, options[:path]),
185
+ query: options[:qs],
94
186
  )
95
-
96
- puts "GET #{uri.to_s}" if (verbose || noop)
97
- return if noop
98
-
99
- RestClient.get(uri.to_s)
100
187
  end
101
188
 
102
189
  def debug(enabled)