wavefront-cli 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/snltd/wavefront-cli.svg?branch=master)](https://travis-ci.org/snltd/wavefront-cli) [![Maintainability](https://api.codeclimate.com/v1/badges/9b712047af0b2dafc146/maintainability)](https://codeclimate.com/github/snltd/wavefront-cli/maintainability) [![Gem Version](https://badge.fury.io/rb/wavefront-cli.svg)](https://badge.fury.io/rb/wavefront-cli) ![](http://ruby-gem-downloads-badge.herokuapp.com/wavefront-cli?type=total)
|
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
|