wavefront-cli 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +62 -46
- data/lib/wavefront-cli/base.rb +4 -1
- data/lib/wavefront-cli/commands/alert.rb +2 -0
- data/lib/wavefront-cli/commands/query.rb +6 -0
- data/lib/wavefront-cli/controller.rb +2 -0
- data/lib/wavefront-cli/display/printer/sparkline.rb +0 -0
- data/lib/wavefront-cli/exception.rb +1 -0
- data/lib/wavefront-cli/output/base.rb +43 -2
- data/lib/wavefront-cli/output/hcl.rb +1 -10
- data/lib/wavefront-cli/output/json.rb +2 -2
- data/lib/wavefront-cli/output/ruby.rb +5 -1
- data/lib/wavefront-cli/output/wavefront.rb +10 -0
- data/lib/wavefront-cli/output/wavefront/base.rb +14 -0
- data/lib/wavefront-cli/output/wavefront/query.rb +48 -0
- data/lib/wavefront-cli/output/yaml.rb +2 -2
- data/lib/wavefront-cli/version.rb +1 -1
- data/spec/spec_helper.rb +20 -4
- data/spec/wavefront-cli/output/hcl_spec.rb +41 -0
- data/spec/wavefront-cli/output/json_spec.rb +31 -0
- data/spec/wavefront-cli/output/ruby_spec.rb +22 -0
- data/spec/wavefront-cli/output/wavefront/query_spec.rb +66 -0
- data/spec/wavefront-cli/output/wavefront_spec.rb +42 -0
- data/spec/wavefront-cli/output/yaml_spec.rb +27 -0
- data/spec/wavefront-cli/resources/sample_query_response.json +1 -0
- data/spec/wavefront-cli/resources/sample_raw_query_response.json +1 -0
- data/wavefront-cli.gemspec +1 -1
- metadata +25 -7
- data/.rubocop.yml +0 -1147
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 397350925432eb596a2268652590b0690ee115d0f351f4406e807eec465db61c
|
4
|
+
data.tar.gz: e85b47160b148fc9067ea9d14b6265c8fa27004661a65a62dd4bdca67645c4e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f9d17a9f4ceebbadc18e41813b6766b86c07f6a881a1b30814ab747e82782f67ef97d6a5f876d28719c8182b8b6e1ae14b514cfc649efe80f265bdefc623c0f
|
7
|
+
data.tar.gz: 7071d861a7da1bad3322fac62601cc05ed773898b04833384d16178ce67d260861603d36ff669f36dff43d333e9805608d0c6e520513fdf179f9ae074286b93d
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Wavefront CLI
|
2
2
|
[](https://travis-ci.org/snltd/wavefront-cli) [](https://codeclimate.com/github/snltd/wavefront-cli/maintainability) [](https://badge.fury.io/rb/wavefront-cli) 
|
3
3
|
|
4
|
-
This package provides a command-line interface to
|
5
|
-
[Wavefront](https://www.wavefront.com/)'s API.
|
6
|
-
|
4
|
+
This package provides a complete command-line interface to
|
5
|
+
[Wavefront](https://www.wavefront.com/)'s API. It also provides easy
|
6
|
+
ways to write data through a proxy.
|
7
7
|
|
8
8
|
The gem is hosted [on
|
9
9
|
Rubygems](https://rubygems.org/gems/wavefront-cli) and can be
|
@@ -13,12 +13,12 @@ installed with
|
|
13
13
|
$ gem install wavefront-cli
|
14
14
|
```
|
15
15
|
|
16
|
-
It is built on [
|
16
|
+
It is built on [our Wavefront Ruby
|
17
17
|
SDK](https://github.com/snltd/wavefront-sdk) and requires Ruby >=
|
18
18
|
2.2. It has no "native extension" dependencies.
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
For a far more comprehensive overview/tutorial, please read [this
|
21
|
+
article](http://sysdef.xyz/post/2017-07-26-wavefront-cli).
|
22
22
|
|
23
23
|
```
|
24
24
|
$ wf --help
|
@@ -30,21 +30,25 @@ Usage:
|
|
30
30
|
wf --help
|
31
31
|
|
32
32
|
Commands:
|
33
|
-
alert
|
34
|
-
|
35
|
-
dashboard
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
33
|
+
alert view and manage alerts
|
34
|
+
cloudintegration view and manage cloud integrations
|
35
|
+
dashboard view and manage dashboards
|
36
|
+
derivedmetric view and manage derived metrics
|
37
|
+
event open, close, view, and manage events
|
38
|
+
integration view and manage Wavefront integrations
|
39
|
+
link view and manage external links
|
40
|
+
message read and mark user messages
|
41
|
+
metric view metrics
|
42
|
+
notificant view and manage Wavefront notification targets
|
43
|
+
proxy view and manage Wavefront proxies
|
44
|
+
query query the Wavefront API
|
45
|
+
report send data directly to Wavefront
|
46
|
+
savedsearch view and manage saved searches
|
47
|
+
source view and manage source tags and descriptions
|
48
|
+
user view and manage Wavefront users
|
49
|
+
webhook view and manage webhooks
|
50
|
+
window view and manage maintenance windows
|
51
|
+
write send data to a Wavefront proxy
|
48
52
|
|
49
53
|
Use 'wf <command> --help' for further information.
|
50
54
|
```
|
@@ -55,10 +59,10 @@ Use 'wf <command> --help' for further information.
|
|
55
59
|
|
56
60
|
You can pass in your Wavefront API and token with command-line
|
57
61
|
options `-E` and `-t`; with the environment variables
|
58
|
-
`WAVEFRONT_ENDPOINT` and `WAVEFRONT_TOKEN`,
|
59
|
-
|
60
|
-
|
61
|
-
of the tokens shown here are real, of course!)
|
62
|
+
`WAVEFRONT_ENDPOINT` and `WAVEFRONT_TOKEN`, or by putting them in a
|
63
|
+
configuration file at `${HOME}/.wavefront`. This is an ini-style
|
64
|
+
file, with a section for each Wavefront account you wish to use.
|
65
|
+
(None of the tokens shown here are real, of course!)
|
62
66
|
|
63
67
|
```
|
64
68
|
[default]
|
@@ -73,14 +77,15 @@ endpoint = company.wavefront.com
|
|
73
77
|
format = yaml
|
74
78
|
```
|
75
79
|
|
76
|
-
You can override the config file location with `-c`, and select a
|
77
|
-
`-P`. If you don't supply `-P`, the `default` profile
|
80
|
+
You can override the config file location with `-c`, and select a
|
81
|
+
profile with `-P`. If you don't supply `-P`, the `default` profile
|
82
|
+
is used.
|
78
83
|
|
79
84
|
### Listing Things
|
80
85
|
|
81
86
|
Most commands have a `list` subcommand, which will produce brief
|
82
|
-
"one thing per line" output. The unique ID of the "thing" is in the
|
83
|
-
column.
|
87
|
+
"one thing per line" output. The unique ID of the "thing" is in the
|
88
|
+
first column.
|
84
89
|
|
85
90
|
```
|
86
91
|
$ wf proxy list
|
@@ -114,23 +119,30 @@ ephemeral false
|
|
114
119
|
deleted false
|
115
120
|
```
|
116
121
|
|
117
|
-
Most timestamps come back from the API as epoch seconds or epoch
|
118
|
-
The CLI, in its human-readable descriptions, will
|
119
|
-
`YYYY-MM-DD HH:mm:ss` when it `describe`s
|
122
|
+
Most timestamps come back from the API as epoch seconds or epoch
|
123
|
+
milliseconds. The CLI, in its human-readable descriptions, will
|
124
|
+
convert those to `YYYY-MM-DD HH:mm:ss` when it `describe`s
|
125
|
+
something.
|
120
126
|
|
121
127
|
### Formats, Importing, and Exporting
|
122
128
|
|
123
|
-
Most commands and sub-commands support the `-f` option. This takes
|
124
|
-
`json`, `yaml`, `human` and `raw`, and tells the CLI to
|
125
|
-
it fetches from the Wavefront API in that
|
126
|
-
representation, which, for instance,
|
129
|
+
Most commands and sub-commands support the `-f` option. This takes
|
130
|
+
one of `json`, `yaml`, `human` and `raw`, and tells the CLI to
|
131
|
+
present the information it fetches from the Wavefront API in that
|
132
|
+
format. (`raw` is the raw Ruby representation, which, for instance,
|
133
|
+
you could paste into `irb`.) Some object types can be exported in
|
134
|
+
HCL, for easy integration with Space Ape's Wavefront Terraform
|
135
|
+
provider.
|
127
136
|
|
128
|
-
Human output can be selective. As well as the time formatting
|
129
|
-
human-readable listings and desctiptions may omit
|
130
|
-
useful, or which is extremely hard to
|
137
|
+
Human output can be selective. As well as the time formatting
|
138
|
+
mentioned above, human-readable listings and desctiptions may omit
|
139
|
+
data which is not likely to be useful, or which is extremely hard to
|
140
|
+
present in a readable way.
|
131
141
|
|
132
|
-
If you `describe` an object like a dashboard, user, webhook etc as
|
133
|
-
`yaml`, and send the output to a file, you can re-import
|
142
|
+
If you `describe` an object like a dashboard, user, webhook etc as
|
143
|
+
`json` or `yaml`, and send the output to a file, you can re-import
|
144
|
+
that data. The format of the file to be imported is automatically
|
145
|
+
detected.
|
134
146
|
|
135
147
|
```
|
136
148
|
$ wf user list
|
@@ -213,11 +225,12 @@ or force a timestamp:
|
|
213
225
|
$ wf write point -t 16:53:14 cli.example 8
|
214
226
|
```
|
215
227
|
|
216
|
-
More usefully, you can write from a file. Your file must contain
|
217
|
-
columns: metric name (`m`), metric value (`v`),
|
218
|
-
(`T`). `v` is mandatory, `m` can be
|
219
|
-
filled in with the
|
220
|
-
|
228
|
+
More usefully, you can write from a file. Your file must contain
|
229
|
+
multiple columns: metric name (`m`), metric value (`v`),
|
230
|
+
timestamp(`t`), and point tags (`T`). `v` is mandatory, `m` can be
|
231
|
+
filled in with the `-m` flag, `t` can be filled in with the current
|
232
|
+
timestamp, and `T` is optional, but if used, must be last. You then
|
233
|
+
tell the CLI what order your fields are in.
|
221
234
|
|
222
235
|
```
|
223
236
|
$ cat datafile
|
@@ -233,6 +246,9 @@ If you set the file to `-`, you can read from standard in:
|
|
233
246
|
$ while true; do echo $RANDOM; sleep 1; done | wf write file -m cli.demo -Fv -
|
234
247
|
```
|
235
248
|
|
249
|
+
If you wish to write points directly via the API, and you have the
|
250
|
+
"direct ingestion" privilege, just swap `write` for `report`.
|
251
|
+
|
236
252
|
Due to limitations in [docopt](https://github.com/docopt/docopt.rb),
|
237
253
|
writing negative values is a bit of a mess.
|
238
254
|
|
data/lib/wavefront-cli/base.rb
CHANGED
@@ -240,7 +240,10 @@ module WavefrontCli
|
|
240
240
|
format.to_s.capitalize))
|
241
241
|
oclass.new(resp, options).run
|
242
242
|
rescue LoadError
|
243
|
-
raise
|
243
|
+
raise WavefrontCli::Exception::UnsupportedOutput.new(
|
244
|
+
format("The '%s' command does not support '%s' output.",
|
245
|
+
options[:class], format)
|
246
|
+
)
|
244
247
|
end
|
245
248
|
|
246
249
|
def hcl_fields
|
@@ -3,9 +3,11 @@ require_relative 'base'
|
|
3
3
|
# Define the Alert command
|
4
4
|
#
|
5
5
|
class WavefrontCommandAlert < WavefrontCommandBase
|
6
|
+
|
6
7
|
def description
|
7
8
|
'view and manage alerts'
|
8
9
|
end
|
10
|
+
|
9
11
|
def _commands
|
10
12
|
["list #{CMN} [-l] [-f format] [-o offset] [-L limit]",
|
11
13
|
"firing #{CMN} [-o offset] [-L limit]",
|
@@ -34,4 +34,10 @@ class WavefrontCommandQuery < WavefrontCommandBase
|
|
34
34
|
'-k, --nospark do not show sparkline',
|
35
35
|
'-W, --nowarn do not show API warning messages']
|
36
36
|
end
|
37
|
+
|
38
|
+
def postscript
|
39
|
+
'The query command has an additional output format. Using ' \
|
40
|
+
"'-f wavefront' produces output suitable for feeding back into a " \
|
41
|
+
'proxy.'.cmd_fold(TW, 0)
|
42
|
+
end
|
37
43
|
end
|
@@ -92,6 +92,8 @@ class WavefrontCliController
|
|
92
92
|
def run_command(hook)
|
93
93
|
hook.validate_opts
|
94
94
|
hook.run
|
95
|
+
rescue WavefrontCli::Exception::UnsupportedOutput => e
|
96
|
+
abort e.message
|
95
97
|
rescue StandardError => e
|
96
98
|
$stderr.puts "general error: #{e}"
|
97
99
|
$stderr.puts "re-run with '-D' for stack trace." unless opts[:debug]
|
File without changes
|
@@ -1,10 +1,51 @@
|
|
1
1
|
module WavefrontOutput
|
2
|
+
#
|
3
|
+
# WavefrontCli::Base looks for a class WavefrontOutput::Format
|
4
|
+
# where 'Format' is something like 'Json', or 'Yaml'. If it finds
|
5
|
+
# that class it creates a new instance, passing through the
|
6
|
+
# response object (@resp) and options hash (@options), then calls
|
7
|
+
# the #run method.
|
8
|
+
#
|
9
|
+
# All those classes are an extension of this one. Some, like Json
|
10
|
+
# or Yaml, are generic, and dump a straight translation of the
|
11
|
+
# response object. Others, like Hcl or Wavefront, have subclasses
|
12
|
+
# which deal with the output of specific commands.
|
13
|
+
#
|
2
14
|
class Base
|
3
|
-
attr_reader :resp, :options
|
15
|
+
attr_reader :resp, :options, :cmd
|
4
16
|
|
5
|
-
def initialize(resp, options)
|
17
|
+
def initialize(resp = {}, options = {})
|
18
|
+
@cmd = options[:class]
|
6
19
|
@resp = resp
|
7
20
|
@options = options
|
8
21
|
end
|
22
|
+
|
23
|
+
# We used to call #run directly, but now we use this wrapper to
|
24
|
+
# make it easier to test the #_run methods.
|
25
|
+
#
|
26
|
+
def run
|
27
|
+
puts _run
|
28
|
+
end
|
29
|
+
|
30
|
+
def _run
|
31
|
+
command_class.run
|
32
|
+
end
|
33
|
+
|
34
|
+
def my_format
|
35
|
+
self.class.name.split('::').last.downcase
|
36
|
+
end
|
37
|
+
|
38
|
+
def command_class_name
|
39
|
+
format('Wavefront%sOutput::%s', my_format.capitalize, cmd.capitalize)
|
40
|
+
end
|
41
|
+
|
42
|
+
def command_file
|
43
|
+
File.join(my_format, cmd)
|
44
|
+
end
|
45
|
+
|
46
|
+
def command_class
|
47
|
+
require_relative command_file
|
48
|
+
Object.const_get(command_class_name).new(resp, options)
|
49
|
+
end
|
9
50
|
end
|
10
51
|
end
|
@@ -7,14 +7,5 @@ module WavefrontOutput
|
|
7
7
|
# different resource types need various amounts of massaging. Args
|
8
8
|
# are passed through to the child class.
|
9
9
|
#
|
10
|
-
class Hcl < Base
|
11
|
-
def run
|
12
|
-
require_relative File.join('hcl', options[:class])
|
13
|
-
oclass = Object.const_get(format('WavefrontHclOutput::%s',
|
14
|
-
options[:class].to_s.capitalize))
|
15
|
-
oclass.new(resp, options).run
|
16
|
-
rescue LoadError
|
17
|
-
abort "no HCL output for #{options[:class]}."
|
18
|
-
end
|
19
|
-
end
|
10
|
+
class Hcl < Base; end
|
20
11
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'wavefront-sdk/stdlib/hash'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
module WavefrontWavefrontOutput
|
5
|
+
#
|
6
|
+
# Display query results in Wavefront wire format. We have to
|
7
|
+
# handle raw and normal output in different ways.
|
8
|
+
#
|
9
|
+
class Query < Base
|
10
|
+
def _run
|
11
|
+
if options[:raw]
|
12
|
+
raw_output
|
13
|
+
else
|
14
|
+
query_output
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw_output
|
19
|
+
resp.each_with_object('') do |point, a|
|
20
|
+
point[:points].each do |p|
|
21
|
+
a.<< wavefront_format(options[:'<metric>'],
|
22
|
+
p[:value],
|
23
|
+
p[:timestamp],
|
24
|
+
options[:host],
|
25
|
+
point[:tags]) + "\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_output
|
31
|
+
resp[:timeseries].each_with_object('') do |ts, a|
|
32
|
+
ts[:data].each do |point|
|
33
|
+
a.<< wavefront_format(ts[:label],
|
34
|
+
point[1],
|
35
|
+
point[0],
|
36
|
+
ts[:host],
|
37
|
+
ts[:tags]) + "\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def wavefront_format(path, value, ts, source, tags = nil)
|
43
|
+
arr = [path, value, ts, format('source=%s', source)]
|
44
|
+
arr.<< tags.to_wf_tag if tags && !tags.empty?
|
45
|
+
arr.join(' ')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
WF_CLI_VERSION = '2.
|
1
|
+
WF_CLI_VERSION = '2.8.0'.freeze
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,13 @@ require 'minitest/spec'
|
|
7
7
|
require 'pathname'
|
8
8
|
require_relative '../lib/wavefront-cli/controller'
|
9
9
|
|
10
|
+
def all_commands
|
11
|
+
(Pathname.new(__FILE__).dirname.parent + 'lib' + 'wavefront-cli' +
|
12
|
+
'commands').children.each.with_object([]) do |c, a|
|
13
|
+
a.<< c.basename.to_s.chomp('.rb') unless c.basename.to_s == 'base.rb'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
unless defined?(CMD)
|
11
18
|
CMD = 'wavefront'.freeze
|
12
19
|
ENDPOINT = 'metrics.wavefront.com'.freeze
|
@@ -17,10 +24,7 @@ unless defined?(CMD)
|
|
17
24
|
JSON_POST_HEADERS = {
|
18
25
|
'Content-Type': 'application/json', Accept: 'application/json'
|
19
26
|
}.freeze
|
20
|
-
|
21
|
-
CMDS = %w[alert integration dashboard event link message metric
|
22
|
-
proxy query savedsearch source user window webhook write].freeze
|
23
|
-
|
27
|
+
CMDS = all_commands.freeze
|
24
28
|
BAD_TAG = '*BAD_TAG*'.freeze
|
25
29
|
TW = 80
|
26
30
|
end
|
@@ -188,6 +192,18 @@ def tag_tests(cmd, id, bad_id, pth = nil, k = nil)
|
|
188
192
|
invalid_tags(cmd, ["tag add #{id} #{BAD_TAG}", "tag delete #{id} #{BAD_TAG}"])
|
189
193
|
end
|
190
194
|
|
195
|
+
# Load in a canned query response
|
196
|
+
#
|
197
|
+
def load_query_response
|
198
|
+
JSON.parse(IO.read(RES_DIR + 'sample_query_response.json'),
|
199
|
+
symbolize_names: true)
|
200
|
+
end
|
201
|
+
|
202
|
+
def load_raw_query_response
|
203
|
+
JSON.parse(IO.read(RES_DIR + 'sample_raw_query_response.json'),
|
204
|
+
symbolize_names: true)
|
205
|
+
end
|
206
|
+
|
191
207
|
# stdlib extensions
|
192
208
|
#
|
193
209
|
class Hash
|