wavefront-cli 0.0.2
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 +7 -0
- data/.codeclimate.yml +20 -0
- data/.gitignore +4 -0
- data/.travis.yml +16 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +65 -0
- data/README.md +221 -0
- data/Rakefile +18 -0
- data/bin/wavefront +14 -0
- data/lib/wavefront-cli/alert.rb +60 -0
- data/lib/wavefront-cli/base.rb +320 -0
- data/lib/wavefront-cli/cloudintegration.rb +12 -0
- data/lib/wavefront-cli/commands/alert.rb +38 -0
- data/lib/wavefront-cli/commands/base.rb +105 -0
- data/lib/wavefront-cli/commands/dashboard.rb +29 -0
- data/lib/wavefront-cli/commands/event.rb +44 -0
- data/lib/wavefront-cli/commands/integration.rb +33 -0
- data/lib/wavefront-cli/commands/link.rb +34 -0
- data/lib/wavefront-cli/commands/message.rb +23 -0
- data/lib/wavefront-cli/commands/metric.rb +20 -0
- data/lib/wavefront-cli/commands/proxy.rb +25 -0
- data/lib/wavefront-cli/commands/query.rb +32 -0
- data/lib/wavefront-cli/commands/savedsearch.rb +32 -0
- data/lib/wavefront-cli/commands/source.rb +27 -0
- data/lib/wavefront-cli/commands/user.rb +24 -0
- data/lib/wavefront-cli/commands/webhook.rb +25 -0
- data/lib/wavefront-cli/commands/window.rb +33 -0
- data/lib/wavefront-cli/commands/write.rb +35 -0
- data/lib/wavefront-cli/constants.rb +17 -0
- data/lib/wavefront-cli/controller.rb +134 -0
- data/lib/wavefront-cli/dashboard.rb +27 -0
- data/lib/wavefront-cli/display/alert.rb +44 -0
- data/lib/wavefront-cli/display/base.rb +304 -0
- data/lib/wavefront-cli/display/cloudintegration.rb +18 -0
- data/lib/wavefront-cli/display/dashboard.rb +21 -0
- data/lib/wavefront-cli/display/event.rb +19 -0
- data/lib/wavefront-cli/display/externallink.rb +13 -0
- data/lib/wavefront-cli/display/maintenancewindow.rb +19 -0
- data/lib/wavefront-cli/display/message.rb +8 -0
- data/lib/wavefront-cli/display/metric.rb +22 -0
- data/lib/wavefront-cli/display/proxy.rb +13 -0
- data/lib/wavefront-cli/display/query.rb +69 -0
- data/lib/wavefront-cli/display/savedsearch.rb +17 -0
- data/lib/wavefront-cli/display/source.rb +26 -0
- data/lib/wavefront-cli/display/user.rb +16 -0
- data/lib/wavefront-cli/display/webhook.rb +24 -0
- data/lib/wavefront-cli/display/write.rb +19 -0
- data/lib/wavefront-cli/event.rb +162 -0
- data/lib/wavefront-cli/exception.rb +5 -0
- data/lib/wavefront-cli/externallink.rb +16 -0
- data/lib/wavefront-cli/maintenancewindow.rb +16 -0
- data/lib/wavefront-cli/message.rb +19 -0
- data/lib/wavefront-cli/metric.rb +24 -0
- data/lib/wavefront-cli/opt_handler.rb +62 -0
- data/lib/wavefront-cli/proxy.rb +22 -0
- data/lib/wavefront-cli/query.rb +74 -0
- data/lib/wavefront-cli/savedsearch.rb +24 -0
- data/lib/wavefront-cli/source.rb +20 -0
- data/lib/wavefront-cli/user.rb +25 -0
- data/lib/wavefront-cli/version.rb +1 -0
- data/lib/wavefront-cli/webhook.rb +8 -0
- data/lib/wavefront-cli/write.rb +244 -0
- data/spec/spec_helper.rb +197 -0
- data/spec/wavefront-cli/alert_spec.rb +44 -0
- data/spec/wavefront-cli/base_spec.rb +47 -0
- data/spec/wavefront-cli/cli_help_spec.rb +47 -0
- data/spec/wavefront-cli/cloudintegration_spec.rb +24 -0
- data/spec/wavefront-cli/dashboard_spec.rb +37 -0
- data/spec/wavefront-cli/event_spec.rb +19 -0
- data/spec/wavefront-cli/externallink_spec.rb +18 -0
- data/spec/wavefront-cli/maintanancewindow_spec.rb +19 -0
- data/spec/wavefront-cli/message_spec.rb +28 -0
- data/spec/wavefront-cli/metric_spec.rb +22 -0
- data/spec/wavefront-cli/proxy_spec.rb +26 -0
- data/spec/wavefront-cli/query_spec.rb +63 -0
- data/spec/wavefront-cli/resources/conf.yaml +10 -0
- data/spec/wavefront-cli/savedsearch_spec.rb +18 -0
- data/spec/wavefront-cli/source_spec.rb +18 -0
- data/spec/wavefront-cli/user_spec.rb +31 -0
- data/spec/wavefront-cli/webhook_spec.rb +17 -0
- data/wavefront-cli.gemspec +36 -0
- metadata +279 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cd9a4217e92b817721a7437e19ec3733bd06cd3c
|
4
|
+
data.tar.gz: '019e98583f888391f948e7f82266ff2cdb902a3b'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb04299e0ad36f4f4cc6c587483574859a93794a317e9c54a127b1821894dad3d25a34eade8ad81ce290aedc8b8df24d44b9853d062433d8e3a6c7d1343bb8f4
|
7
|
+
data.tar.gz: 926c982c2fccb55b043c8780662ab37e4f12481c91f24a3fc51d81c8e9a0226a4172522d46bef8db1d18769a7b5fb521c3d1332a22ce0f868a887c87bd5d2386
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
engines:
|
3
|
+
duplication:
|
4
|
+
enabled: true
|
5
|
+
checks:
|
6
|
+
Similar code:
|
7
|
+
enabled: false
|
8
|
+
config:
|
9
|
+
languages:
|
10
|
+
- ruby
|
11
|
+
fixme:
|
12
|
+
enabled: true
|
13
|
+
rubocop:
|
14
|
+
enabled: true
|
15
|
+
ratings:
|
16
|
+
paths:
|
17
|
+
- "**.rb"
|
18
|
+
exclude_paths:
|
19
|
+
- spec/
|
20
|
+
- lib/_wavefront
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
rvm:
|
4
|
+
- 2.2.7
|
5
|
+
- 2.3.4
|
6
|
+
- 2.4.1
|
7
|
+
before_install: gem install bundler --no-rdoc --no-ri
|
8
|
+
deploy:
|
9
|
+
provider: rubygems
|
10
|
+
api_key:
|
11
|
+
secure: dfmL5JwBn+u3cUmyAaDsApDa7ljGajGNz3GDcKd2J8FOt7+a758/lmL8EQ34sDT1ZFotrxn/y1RbgXlaDxAE1XDfrZbjckmx7a6wa2sqR3kBraJ2tx7CiXodbw3Z8XZf9WLb0kYGmlLtI73GNcuunMt/9f1cobqWISRLHw6b7amlO7GW2ZBZgzRS+N8TSS2dicIvKMo5HoMYU+uWLM4zDFBPnGNcMiWxh8ysLzJoKqA9kbBUyCVEZ03MlV7G71ObvWCLasKnZ3W5U+K1NbgU7mgMYfl9KIcA4y9hQ9hUCijk40SmT7ffy3P2gq8zblC/4x5Eefpau9X/bdLwXoRCIzqk05t4f45wstj2auHGK0HJwOYRtx8apdaLSgyJ5lQpGcbCRu40WR9mDkaM8m9n3u2o6GJmftCg3AN1QtsourmQB84x67LEbHzValMaokrbCol4XeWqlC+dCNLPixemQRBvcNfI3V9C6RqVGfjpoGlSTI+RkQqwm01PcxpeqIVfdMd1wnfUuAOywUO6UpvtK9TZaxg0NnVElXpPseQbtzulLwZ7R5Y3A4Ss8Z7w43c1KHxTkg54FWUOp065ItjAc4lmyORXq/2+F7sMvRN6dtCLaXTUlkYuU3cjFLIPlLGFYgqq4T4xQa+e5NEK1XW7nghv+IRfKfyVeZsB0WpY+uc=
|
12
|
+
gem: wavefront-cli
|
13
|
+
on:
|
14
|
+
tags: true
|
15
|
+
repo: snltd/wavefront-cli
|
16
|
+
ruby: 2.3.4
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
wavefront-cli (0.0.2)
|
5
|
+
docopt (= 0.5.0)
|
6
|
+
wavefront-sdk (~> 0.1.5)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.5.1)
|
12
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
13
|
+
ast (2.3.0)
|
14
|
+
crack (0.4.3)
|
15
|
+
safe_yaml (~> 1.0.0)
|
16
|
+
docopt (0.5.0)
|
17
|
+
faraday (0.12.1)
|
18
|
+
multipart-post (>= 1.2, < 3)
|
19
|
+
hashdiff (0.3.2)
|
20
|
+
inifile (3.0.0)
|
21
|
+
map (6.6.0)
|
22
|
+
minitest (5.8.5)
|
23
|
+
multipart-post (2.0.0)
|
24
|
+
parser (2.4.0.0)
|
25
|
+
ast (~> 2.2)
|
26
|
+
powerpack (0.1.1)
|
27
|
+
public_suffix (2.0.5)
|
28
|
+
rainbow (2.2.1)
|
29
|
+
rake (12.0.0)
|
30
|
+
rubocop (0.47.1)
|
31
|
+
parser (>= 2.3.3.1, < 3.0)
|
32
|
+
powerpack (~> 0.1)
|
33
|
+
rainbow (>= 1.99.1, < 3.0)
|
34
|
+
ruby-progressbar (~> 1.7)
|
35
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
36
|
+
ruby-progressbar (1.8.1)
|
37
|
+
safe_yaml (1.0.4)
|
38
|
+
spy (0.4.5)
|
39
|
+
unicode-display_width (1.1.3)
|
40
|
+
wavefront-sdk (0.1.5)
|
41
|
+
addressable (~> 2.4)
|
42
|
+
faraday (>= 0.12.1, < 0.13)
|
43
|
+
inifile (>= 3.0.0)
|
44
|
+
map (~> 6.6.0)
|
45
|
+
webmock (2.3.2)
|
46
|
+
addressable (>= 2.3.6)
|
47
|
+
crack (>= 0.3.2)
|
48
|
+
hashdiff
|
49
|
+
yard (0.9.5)
|
50
|
+
|
51
|
+
PLATFORMS
|
52
|
+
ruby
|
53
|
+
|
54
|
+
DEPENDENCIES
|
55
|
+
bundler (~> 1.3)
|
56
|
+
minitest (~> 5.8, >= 5.8.0)
|
57
|
+
rake (~> 12.0)
|
58
|
+
rubocop (~> 0.47.0)
|
59
|
+
spy (~> 0.4.0)
|
60
|
+
wavefront-cli!
|
61
|
+
webmock (~> 2.3, >= 2.3.2)
|
62
|
+
yard (~> 0.9.5)
|
63
|
+
|
64
|
+
BUNDLED WITH
|
65
|
+
1.14.6
|
data/README.md
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# Wavefront CLI [](https://travis-ci.org/snltd/wavefront-cli) [](https://codeclimate.com/github/snltd/wavefront-cli) [](https://codeclimate.com/github/snltd/wavefront-cli) [](https://snyk.io/test/github/snltd/wavefront-cli)
|
2
|
+
|
3
|
+
|
4
|
+
This package provides a command-line interface to Wavefront's API. Each API path
|
5
|
+
is covered by a different command keyword.
|
6
|
+
|
7
|
+
It is built on [the Wavefront Ruby
|
8
|
+
SDK](https://github.com/snltd/wavefront-sdk) and requires Ruby >= 2.2.
|
9
|
+
|
10
|
+
```
|
11
|
+
$ wavefront --help
|
12
|
+
Wavefront CLI
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
wavefront [options] command [options]
|
16
|
+
wavefront --version
|
17
|
+
wavefront --help
|
18
|
+
|
19
|
+
Commands:
|
20
|
+
alert view and manage alerts
|
21
|
+
integration view and manage cloud integrations
|
22
|
+
dashboard view and manage dashboards
|
23
|
+
event view, manage, open, and close events
|
24
|
+
link view and manage external links
|
25
|
+
message view and mark as read user messages
|
26
|
+
metric view metric details
|
27
|
+
proxy view and manage Wavefront proxies
|
28
|
+
query run timeseries queries
|
29
|
+
savedsearch view and manage saved searches
|
30
|
+
source view and manage source tags and descriptions
|
31
|
+
user view and manage Wavefront users
|
32
|
+
window view and manage maintenance windows
|
33
|
+
webhook view and manage webhooks
|
34
|
+
write send data points to a Wavefront proxy
|
35
|
+
|
36
|
+
Use 'wavefront <command> --help' for further information.
|
37
|
+
```
|
38
|
+
|
39
|
+
## General Rules
|
40
|
+
|
41
|
+
### Credentials and the Config File
|
42
|
+
|
43
|
+
You can pass in your Wavefront API and token with command-line
|
44
|
+
options `-E` and `-t`; with the environment variables
|
45
|
+
`WAVEFRONT_ENDPOINT` and `WAVEFRONT_TOKEN`,
|
46
|
+
or by putting them in a configuration file at `${HOME}/.wavefront`. This is an
|
47
|
+
ini-style file, with a section for each Wavefront account you wish to use. (None
|
48
|
+
of the tokens shown here are real, of course!)
|
49
|
+
|
50
|
+
```
|
51
|
+
[default]
|
52
|
+
token = 106ba476-e3bd-c14c-4a3d-391cd4c11def
|
53
|
+
endpoint = metrics.wavefront.com
|
54
|
+
proxy = wavefront.localnet
|
55
|
+
format = human
|
56
|
+
|
57
|
+
[company]
|
58
|
+
token = 9ac40b15-f47f-a168-a5d3-271ab5bad617
|
59
|
+
endpoint = company.wavefront.com
|
60
|
+
format = yaml
|
61
|
+
```
|
62
|
+
|
63
|
+
You can override the config file location with `-c`, and select a profile with
|
64
|
+
`-P`. If you don't supply `-P`, the `default` profile is used.
|
65
|
+
|
66
|
+
### Listing Things
|
67
|
+
|
68
|
+
Most commands have a `list` subcommand, which will produce brief
|
69
|
+
"one thing per line" output. The unique ID of the "thing" is in the first
|
70
|
+
column.
|
71
|
+
|
72
|
+
```
|
73
|
+
$ wavefront proxy list
|
74
|
+
457d6cf3-5171-45e0-8d31-5c980be889ea test agent
|
75
|
+
917102d1-a10e-997b-ba63-95058f98d4fb Agent on wavefront-2017-03-13-02
|
76
|
+
926dfb4c-23c6-4fb9-8c8d-833625ab8f6f Agent on shark-wavefront
|
77
|
+
```
|
78
|
+
|
79
|
+
You can get more verbose listings with the `-l` flag.
|
80
|
+
|
81
|
+
### Describing Things
|
82
|
+
|
83
|
+
Most commands have a `describe` subcommand which will tell you more about the
|
84
|
+
object.
|
85
|
+
|
86
|
+
```
|
87
|
+
$ wavefront proxy describe 917102d1-a10e-497b-ba63-95058f98d4fb
|
88
|
+
name Agent on wavefront-2017-03-13-02
|
89
|
+
id 917102d1-a10e-497b-ba63-95058f98d4fb
|
90
|
+
version 4.7
|
91
|
+
customerId sysdef
|
92
|
+
inTrash false
|
93
|
+
lastCheckInTime 2017-06-06 14:47:20
|
94
|
+
hostname wavefront-2017-03-13-02
|
95
|
+
timeDrift -751
|
96
|
+
bytesLeftForBuffer 1536094720
|
97
|
+
bytesPerMinuteForBuffer 280109
|
98
|
+
localQueueSize 0
|
99
|
+
sshAgent false
|
100
|
+
ephemeral false
|
101
|
+
deleted false
|
102
|
+
```
|
103
|
+
|
104
|
+
Most timestamps come back from the API as epoch seconds or epoch milliseconds.
|
105
|
+
The CLI, in its human-readable descriptions, will convert those to
|
106
|
+
`YYYY-MM-DD HH:mm:ss` when it `describe`s something.
|
107
|
+
|
108
|
+
### Formats, Importing, and Exporting
|
109
|
+
|
110
|
+
Most commands and sub-commands support the `-f` option. This takes one of
|
111
|
+
`json`, `yaml`, `human` and `raw`, and tells the CLI to present the information
|
112
|
+
it fetches from the Wavefront API in that format. (`raw` is the raw Ruby
|
113
|
+
representation, which, for instance, you could paste into `irb`.)
|
114
|
+
|
115
|
+
Human output can be selective. As well as the time formatting mentioned above,
|
116
|
+
human-readable listings and desctiptions may omit data which is not likely to be
|
117
|
+
useful, or which is extremely hard to present in a readable way.
|
118
|
+
|
119
|
+
If you `describe` an object like a dashboard, user, webhook etc as `json` or
|
120
|
+
`yaml`, and send the output to a file, you can re-import that data. The format of the file to be imported is automatically detected.
|
121
|
+
|
122
|
+
```
|
123
|
+
$ wavefront user list
|
124
|
+
slackboy@gmail.com
|
125
|
+
sysdef.limited@gmail.com
|
126
|
+
$ wavefront user describe -f json sysdef.limited@gmail.com > user.json
|
127
|
+
$ cat user.json
|
128
|
+
{"identifier":"sysdef.limited@gmail.com","customer":"sysdef","groups":["agent_management"]}
|
129
|
+
$ wavefront user delete sysdef.limited@gmail.com
|
130
|
+
Deleted user 'sysdef.limited@gmail.com'.
|
131
|
+
$ wavefront user list
|
132
|
+
slackboy@gmail.com
|
133
|
+
$ wavefront user import user.json
|
134
|
+
Imported user.
|
135
|
+
identifier sysdef.limited@gmail.com
|
136
|
+
customer sysdef
|
137
|
+
groups agent_management
|
138
|
+
$ wavefront user list
|
139
|
+
slackboy@gmail.com
|
140
|
+
sysdef.limited@gmail.com
|
141
|
+
```
|
142
|
+
|
143
|
+
You could, of course, modify certain aspects of the exported data before
|
144
|
+
re-importing.
|
145
|
+
|
146
|
+
### Time Windows
|
147
|
+
|
148
|
+
Commands which operate on a time window, such as `query` or `event`
|
149
|
+
will expect that window to be defined with `-s` and `-e` (or
|
150
|
+
`--start` and `--end`). Times can be in seconds since the epoch, or
|
151
|
+
any format which [Ruby's `strptime`
|
152
|
+
method](https://ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/DateTime.html#method-c-strptime)
|
153
|
+
method can parse unaided. For instance:
|
154
|
+
|
155
|
+
```
|
156
|
+
$ wavefront --start 12:15 --end 12:20 ...
|
157
|
+
```
|
158
|
+
|
159
|
+
will define a window between 12:15 and 12:20pm today. If you ran
|
160
|
+
that in the morning, the time would be invalid, and you would get a
|
161
|
+
400 error from Wavefront, so something of the form
|
162
|
+
`2016-04-17T12:25:00` would remove all ambiguity.
|
163
|
+
|
164
|
+
There is no need to include a timezone in your time: the `wavefront`
|
165
|
+
CLI will automatically use your local timezone when it parses the
|
166
|
+
string.
|
167
|
+
|
168
|
+
The following options are valid in almost all contexts.
|
169
|
+
|
170
|
+
```
|
171
|
+
-c, --config=FILE path to configuration file [default: ~/.wavefront]
|
172
|
+
-P, --profile=NAME profile in configuration file [default: default]
|
173
|
+
-D, --debug enable debug mode
|
174
|
+
-V, --verbose enable verbose mode
|
175
|
+
-h, --help show help for command
|
176
|
+
```
|
177
|
+
|
178
|
+
Debug mode will show you combined options, and debug output from
|
179
|
+
`faraday`. It also shows the full stack trace should a command
|
180
|
+
fail. This output can be very verbose.
|
181
|
+
|
182
|
+
## Writing Points
|
183
|
+
|
184
|
+
Writing a single point is simple:
|
185
|
+
|
186
|
+
```
|
187
|
+
$ wavefront write point cli.example 10
|
188
|
+
```
|
189
|
+
|
190
|
+
and you can add point tags, if you like.
|
191
|
+
|
192
|
+
```
|
193
|
+
$ wavefront write point cli.example 9.4 -E wavefront -T proxy=wavefront \
|
194
|
+
-T from=README
|
195
|
+
```
|
196
|
+
|
197
|
+
or force a timestamp:
|
198
|
+
|
199
|
+
```
|
200
|
+
$ wavefront write point -t 16:53:14 cli.example 8
|
201
|
+
```
|
202
|
+
|
203
|
+
More usefully, you can write from a file. Your file must contain multiple
|
204
|
+
columns: metric name (`m`), metric value (`v`), timestamp(`t`), and point tags
|
205
|
+
(`T`). `v` is mandatory, `m` can be filled in with the `-m` flag, `t` can be
|
206
|
+
filled in with the current timestamp, and `T` is optional, but if used, must be
|
207
|
+
last. You then tell the CLI what order your fields are in.
|
208
|
+
|
209
|
+
```
|
210
|
+
$ cat datafile
|
211
|
+
1496767813 dev.cli.test 12.1
|
212
|
+
1496767813 dev.cli.test 10.0
|
213
|
+
1496767813 dev.cli.test 14.5
|
214
|
+
$ wavefront write file -F tmv datafile
|
215
|
+
```
|
216
|
+
|
217
|
+
If you set the file to `-`, you can read from standard in:
|
218
|
+
|
219
|
+
```
|
220
|
+
$ while true; do echo $RANDOM; sleep 1; done | wavefront write file -m cli.demo -Fv -
|
221
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'yard'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
|
5
|
+
task default: :test
|
6
|
+
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.pattern = 'spec/wavefront-cli/*_spec.rb'
|
9
|
+
t.warning = false
|
10
|
+
end
|
11
|
+
|
12
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
13
|
+
t.options = ['--display-cop-names']
|
14
|
+
end
|
15
|
+
|
16
|
+
YARD::Rake::YardocTask.new do |t|
|
17
|
+
t.files = ['lib/wavefront-cli/*rb']
|
18
|
+
end
|
data/bin/wavefront
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'io/console'
|
5
|
+
require_relative '../lib/wavefront-cli/controller'
|
6
|
+
|
7
|
+
begin
|
8
|
+
TW = IO.console.winsize.last
|
9
|
+
rescue
|
10
|
+
TW = 80
|
11
|
+
end
|
12
|
+
|
13
|
+
CMD = Pathname.new(__FILE__).basename
|
14
|
+
WavefrontCliController.new(ARGV)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontCli
|
4
|
+
#
|
5
|
+
# CLI coverage for the v2 'alert' API.
|
6
|
+
#
|
7
|
+
class Alert < WavefrontCli::Base
|
8
|
+
def do_describe
|
9
|
+
wf.describe(options[:'<id>'], options[:version])
|
10
|
+
end
|
11
|
+
|
12
|
+
def do_snooze
|
13
|
+
wf.snooze(options[:'<id>'], options[:time])
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_unsnooze
|
17
|
+
wf.unsnooze(options[:'<id>'])
|
18
|
+
end
|
19
|
+
|
20
|
+
def do_delete
|
21
|
+
print (if wf.describe(options[:'<id>']).status.code == 200
|
22
|
+
'Soft'
|
23
|
+
else
|
24
|
+
'Permanently'
|
25
|
+
end)
|
26
|
+
|
27
|
+
puts " deleting alert '#{options[:'<id>']}'."
|
28
|
+
wf.delete(options[:'<id>'])
|
29
|
+
end
|
30
|
+
|
31
|
+
def do_summary
|
32
|
+
wf.summary
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_history
|
36
|
+
wf.history(options[:'<id>'], options[:offset], options[:limit])
|
37
|
+
end
|
38
|
+
|
39
|
+
# Take a previously exported alert, and construct a hash which
|
40
|
+
# create() can use to re-create it.
|
41
|
+
#
|
42
|
+
# @param raw [Hash] Ruby hash of imported data
|
43
|
+
#
|
44
|
+
def import_to_create(raw)
|
45
|
+
ret = %w(name condition minutes target severity displayExpression
|
46
|
+
additionalInformation).each_with_object({}) do |k, aggr|
|
47
|
+
aggr[k.to_sym] = raw[k]
|
48
|
+
end
|
49
|
+
|
50
|
+
if raw.key?('resolveAfterMinutes')
|
51
|
+
ret[:resolveMinutes] = raw['resolveAfterMinutes']
|
52
|
+
end
|
53
|
+
|
54
|
+
if raw.key?('customerTagsWithCounts')
|
55
|
+
ret[:sharedTags] = raw['customerTagsWithCounts'].keys
|
56
|
+
end
|
57
|
+
ret
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,320 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
require 'json'
|
4
|
+
require 'wavefront-sdk/validators'
|
5
|
+
# require_relative './constants'
|
6
|
+
require_relative './exception'
|
7
|
+
|
8
|
+
module WavefrontCli
|
9
|
+
#
|
10
|
+
# Parent of all the CLI classes. This class uses metaprogramming
|
11
|
+
# techniques to try to make adding new CLI commands and
|
12
|
+
# sub-commands as simple as possible.
|
13
|
+
#
|
14
|
+
# To define a subcommand 'cmd', you only need add it to the
|
15
|
+
# `docopt` description in the relevant section, and create a
|
16
|
+
# method 'do_cmd'. The WavefrontCli::Base::dispatch() method will
|
17
|
+
# find it, and call it. If your subcommand has multiple words,
|
18
|
+
# like 'delete tag', your do method would be called
|
19
|
+
# `do_delete_tag`. The `do_` methods are able to access the
|
20
|
+
# Wavefront SDK object as `wf`, and all docopt options as
|
21
|
+
# `options`.
|
22
|
+
#
|
23
|
+
class Base
|
24
|
+
attr_accessor :wf, :options, :klass, :klass_word
|
25
|
+
|
26
|
+
include Wavefront::Validators
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
@options = options
|
30
|
+
sdk_class = self.class.name.sub(/Cli/, '')
|
31
|
+
@klass_word = sdk_class.split('::').last.downcase
|
32
|
+
validate_input
|
33
|
+
|
34
|
+
if options.include?(:help) && options[:help]
|
35
|
+
puts options
|
36
|
+
exit 0
|
37
|
+
end
|
38
|
+
|
39
|
+
require File.join('wavefront-sdk', @klass_word)
|
40
|
+
@klass = Object.const_get(sdk_class)
|
41
|
+
|
42
|
+
send(:post_initialize, options) if respond_to?(:post_initialize)
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
@wf = klass.new(mk_creds, mk_opts)
|
47
|
+
dispatch
|
48
|
+
end
|
49
|
+
|
50
|
+
# We normally validate with a predictable method name. Alert IDs are
|
51
|
+
# validated with #wf_alert_id? etc. If you need to change that, override
|
52
|
+
# this method.
|
53
|
+
#
|
54
|
+
def validator_method
|
55
|
+
"wf_#{klass_word}_id?".to_sym
|
56
|
+
end
|
57
|
+
|
58
|
+
def validator_exception
|
59
|
+
Object.const_get(
|
60
|
+
"Wavefront::Exception::Invalid#{klass_word.capitalize}Id"
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_input
|
65
|
+
validate_id if options[:'<id>']
|
66
|
+
validate_tags if options[:'<tag>']
|
67
|
+
send(:extra_validation) if respond_to?(:extra_validation)
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_tags
|
71
|
+
Array(options[:'<tag>']).each do |t|
|
72
|
+
begin
|
73
|
+
send(:wf_tag?, t)
|
74
|
+
rescue Wavefront::Exception::InvalidTag
|
75
|
+
abort "'#{t}' is not a valid tag."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_id
|
81
|
+
send(validator_method, options[:'<id>'])
|
82
|
+
rescue validator_exception
|
83
|
+
abort "'#{options[:'<id>']}' is not a valid #{klass_word} ID."
|
84
|
+
end
|
85
|
+
|
86
|
+
# Make a wavefront-sdk credentials object from standard
|
87
|
+
# options.
|
88
|
+
#
|
89
|
+
# @return [Hash] containing `token` and `endpoint`.
|
90
|
+
#
|
91
|
+
def mk_creds
|
92
|
+
{ token: options[:token], endpoint: options[:endpoint] }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Make a common wavefront-sdk options object from standard CLI
|
96
|
+
# options.
|
97
|
+
#
|
98
|
+
# @return [Hash] containing `debug`, `verbose`, and `noop`.
|
99
|
+
#
|
100
|
+
def mk_opts
|
101
|
+
{ debug: options[:debug], verbose: options[:verbose],
|
102
|
+
noop: options[:noop] }
|
103
|
+
end
|
104
|
+
|
105
|
+
# To allow a user to default to different output formats for
|
106
|
+
# different object, we define a format for each class. For
|
107
|
+
# instance, `alertformat` or `agentformat`. This method returns
|
108
|
+
# such a string appropriate for the inheriting class.
|
109
|
+
#
|
110
|
+
# @return [Symbol] name of the option or config-file key which
|
111
|
+
# sets the default output format for this class
|
112
|
+
#
|
113
|
+
def format_var
|
114
|
+
options[:format].to_sym
|
115
|
+
# (self.class.name.split('::').last.downcase + 'format').to_sym
|
116
|
+
end
|
117
|
+
|
118
|
+
# Works out the user's command by matching any options docopt has
|
119
|
+
# set to 'true' with any 'do_' method in the class. Then calls that
|
120
|
+
# method, and displays whatever it returns.
|
121
|
+
#
|
122
|
+
# @return [nil]
|
123
|
+
# @raise 'unsupported command', if the command does not match a
|
124
|
+
# `do_` method.
|
125
|
+
#
|
126
|
+
def dispatch
|
127
|
+
#
|
128
|
+
# Take a list of do_ methods, remove the 'do_' from their name,
|
129
|
+
# and break them into arrays of '_' separated words.
|
130
|
+
#
|
131
|
+
m_list = methods.select { |m| m.to_s.start_with?('do_') }.map do |m|
|
132
|
+
m.to_s.split('_')[1..-1]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Sort that array of arrays by length, longest first. Then look
|
136
|
+
# through each deconstructed method name and see if the user
|
137
|
+
# supplied an option for each component. Call the first one that
|
138
|
+
# matches. The order will ensure we match "do_delete_tags" before
|
139
|
+
# we match "do_delete".
|
140
|
+
#
|
141
|
+
m_list.sort_by(&:length).reverse.each do |m|
|
142
|
+
if m.reject { |w| options[w.to_sym] }.empty?
|
143
|
+
method = (%w(do) + m).join('_')
|
144
|
+
return display(public_send(method), method)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
if respond_to?(:do_default)
|
149
|
+
return display(public_send(:do_default), :do_default)
|
150
|
+
end
|
151
|
+
|
152
|
+
raise WavefrontCli::Exception::UnhandledCommand
|
153
|
+
end
|
154
|
+
|
155
|
+
# Display a Ruby object as JSON, YAML, or human-readable. We
|
156
|
+
# provide a default method to format human-readable output, but
|
157
|
+
# you can override it by creating your own
|
158
|
+
# `humanize_command_output` method
|
159
|
+
# control how its output is handled by setting the `response`
|
160
|
+
# instance variable.
|
161
|
+
#
|
162
|
+
# @param data [WavefrontResponse] an object returned by a
|
163
|
+
# Wavefront SDK method. This will contain a 'response'
|
164
|
+
# and 'status' structures.
|
165
|
+
# @param method [String] the name of the method which produced
|
166
|
+
# this output. Used to find a suitable humanize method.
|
167
|
+
#
|
168
|
+
def display(data, method)
|
169
|
+
[:status, :response].each do |b|
|
170
|
+
abort "no #{b} block in API response" unless data.respond_to?(b)
|
171
|
+
end
|
172
|
+
|
173
|
+
unless check_status(data.status)
|
174
|
+
handle_error(method, data.status.code) if format_var == :human
|
175
|
+
abort "API #{data.status.code}: #{data.status.message}."
|
176
|
+
end
|
177
|
+
|
178
|
+
resp = if data.response.respond_to?(:items)
|
179
|
+
data.response.items
|
180
|
+
else
|
181
|
+
data.response
|
182
|
+
end
|
183
|
+
|
184
|
+
handle_response(resp, format_var, method)
|
185
|
+
end
|
186
|
+
|
187
|
+
def check_status(status)
|
188
|
+
status.respond_to?(:result) && status.result == 'OK'
|
189
|
+
end
|
190
|
+
|
191
|
+
# This gives us a chance to catch different errors in
|
192
|
+
# WavefrontDisplay classes. If nothing catches, them abort.
|
193
|
+
#
|
194
|
+
def handle_error(method, code)
|
195
|
+
k = load_display_class
|
196
|
+
k.new({}, options).run_error([method, code].join('_'))
|
197
|
+
end
|
198
|
+
|
199
|
+
def handle_response(resp, format, method)
|
200
|
+
case format
|
201
|
+
when :json
|
202
|
+
puts resp.to_json
|
203
|
+
when :yaml # We don't want the YAML keys to be symbols.
|
204
|
+
puts JSON.parse(resp.to_json).to_yaml
|
205
|
+
when :ruby
|
206
|
+
p resp
|
207
|
+
when :human
|
208
|
+
k = load_display_class
|
209
|
+
k.new(resp, options).run(method)
|
210
|
+
else
|
211
|
+
raise "Unknown output format '#{format}'."
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def load_display_class
|
216
|
+
require_relative File.join('display', klass_word)
|
217
|
+
Object.const_get(klass.name.sub('Wavefront', 'WavefrontDisplay'))
|
218
|
+
end
|
219
|
+
|
220
|
+
# There are things we need to have. If we don't have them, stop
|
221
|
+
# the user right now. Also, if we're in debug mode, print out a
|
222
|
+
# hash of options, which can be very useful when doing actual
|
223
|
+
# debugging. Some classes may have to override this method. The
|
224
|
+
# writer, for instance, uses a proxy and has no token.
|
225
|
+
#
|
226
|
+
def validate_opts
|
227
|
+
raise 'Please supply an API token.' unless options[:token]
|
228
|
+
raise 'Please supply an API endpoint.' unless options[:endpoint]
|
229
|
+
end
|
230
|
+
|
231
|
+
# Give it a path to a file (as a string) and it will return the
|
232
|
+
# contents of that file as a Ruby object. Automatically detects
|
233
|
+
# JSON and YAML. Raises an exception if it doesn't look like
|
234
|
+
# either.
|
235
|
+
#
|
236
|
+
# @param path [String] the file to load
|
237
|
+
# @return [Hash] a Ruby object of the loaded file
|
238
|
+
# @raise 'Unsupported file format.' if the filetype is unknown.
|
239
|
+
# @raise pass through any error loading or parsing the file
|
240
|
+
#
|
241
|
+
def load_file(path)
|
242
|
+
file = Pathname.new(path)
|
243
|
+
raise 'Import file does not exist.' unless file.exist?
|
244
|
+
|
245
|
+
if file.extname == '.json'
|
246
|
+
JSON.parse(IO.read(file))
|
247
|
+
elsif file.extname == '.yaml' || file.extname == '.yml'
|
248
|
+
YAML.safe_load(IO.read(file))
|
249
|
+
else
|
250
|
+
raise 'Unsupported file format.'
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Below here are common methods. Most are used by most classes,
|
255
|
+
# but if they don't match a command described in the docopt
|
256
|
+
# text, the dispatcher will never call them. So, there's no
|
257
|
+
# harm inheriting unneeded things. Some classes override them.
|
258
|
+
#
|
259
|
+
def do_list
|
260
|
+
wf.list(options[:offset] || 0, options[:limit] || 100)
|
261
|
+
end
|
262
|
+
|
263
|
+
def do_describe
|
264
|
+
wf.describe(options[:'<id>'])
|
265
|
+
end
|
266
|
+
|
267
|
+
def do_import
|
268
|
+
raw = load_file(options[:'<file>'])
|
269
|
+
|
270
|
+
begin
|
271
|
+
prepped = import_to_create(raw)
|
272
|
+
rescue => e
|
273
|
+
puts e if options[:debug]
|
274
|
+
raise 'could not parse input.'
|
275
|
+
end
|
276
|
+
|
277
|
+
wf.create(prepped)
|
278
|
+
end
|
279
|
+
|
280
|
+
def do_delete
|
281
|
+
wf.delete(options[:'<id>'])
|
282
|
+
end
|
283
|
+
|
284
|
+
def do_undelete
|
285
|
+
wf.undelete(options[:'<id>'])
|
286
|
+
end
|
287
|
+
|
288
|
+
def do_update
|
289
|
+
k, v = options[:'<key=value>'].split('=')
|
290
|
+
wf.update(options[:'<id>'], k => v)
|
291
|
+
end
|
292
|
+
|
293
|
+
def do_tags
|
294
|
+
wf.tags(options[:'<id>'])
|
295
|
+
end
|
296
|
+
|
297
|
+
def do_tag_add
|
298
|
+
wf.tag_add(options[:'<id>'], options[:'<tag>'].first)
|
299
|
+
end
|
300
|
+
|
301
|
+
def do_tag_delete
|
302
|
+
wf.tag_delete(options[:'<id>'], options[:'<tag>'].first)
|
303
|
+
end
|
304
|
+
|
305
|
+
def do_tag_set
|
306
|
+
wf.tag_set(options[:'<id>'], options[:'<tag>'])
|
307
|
+
end
|
308
|
+
|
309
|
+
def do_tag_clear
|
310
|
+
wf.tag_set(options[:'<id>'], [])
|
311
|
+
end
|
312
|
+
|
313
|
+
# Most things will re-import with the POST method if you remove
|
314
|
+
# the ID.
|
315
|
+
#
|
316
|
+
def import_to_create(raw)
|
317
|
+
raw.delete_if { |k, _v| k == 'id' }
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|