wavefront-client 3.5.4 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
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)