wavefront-cli 0.0.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/Gemfile +1 -1
- data/README.md +21 -21
- data/Rakefile +2 -2
- data/bin/{wavefront → wf} +6 -2
- data/lib/wavefront-cli/alert.rb +7 -6
- data/lib/wavefront-cli/base.rb +27 -6
- data/lib/wavefront-cli/commands/alert.rb +2 -1
- data/lib/wavefront-cli/commands/base.rb +54 -29
- data/lib/wavefront-cli/commands/dashboard.rb +1 -0
- data/lib/wavefront-cli/commands/event.rb +7 -3
- data/lib/wavefront-cli/commands/integration.rb +2 -1
- data/lib/wavefront-cli/commands/link.rb +2 -2
- data/lib/wavefront-cli/commands/proxy.rb +2 -1
- data/lib/wavefront-cli/commands/savedsearch.rb +2 -1
- data/lib/wavefront-cli/commands/source.rb +3 -2
- data/lib/wavefront-cli/commands/webhook.rb +2 -1
- data/lib/wavefront-cli/commands/window.rb +2 -1
- data/lib/wavefront-cli/commands/write.rb +10 -6
- data/lib/wavefront-cli/constants.rb +1 -1
- data/lib/wavefront-cli/controller.rb +6 -4
- data/lib/wavefront-cli/dashboard.rb +6 -6
- data/lib/wavefront-cli/display/alert.rb +8 -4
- data/lib/wavefront-cli/display/base.rb +115 -170
- data/lib/wavefront-cli/display/cloudintegration.rb +2 -2
- data/lib/wavefront-cli/display/event.rb +1 -1
- data/lib/wavefront-cli/display/maintenancewindow.rb +1 -1
- data/lib/wavefront-cli/display/metric.rb +6 -7
- data/lib/wavefront-cli/display/printer/base.rb +24 -0
- data/lib/wavefront-cli/display/printer/long.rb +186 -0
- data/lib/wavefront-cli/display/printer/terse.rb +55 -0
- data/lib/wavefront-cli/display/query.rb +1 -2
- data/lib/wavefront-cli/display/savedsearch.rb +1 -1
- data/lib/wavefront-cli/display/source.rb +7 -3
- data/lib/wavefront-cli/display/webhook.rb +3 -4
- data/lib/wavefront-cli/event.rb +62 -23
- data/lib/wavefront-cli/exception.rb +1 -1
- data/lib/wavefront-cli/opt_handler.rb +6 -6
- data/lib/wavefront-cli/query.rb +5 -6
- data/lib/wavefront-cli/source.rb +5 -1
- data/lib/wavefront-cli/string.rb +59 -0
- data/lib/wavefront-cli/version.rb +1 -1
- data/lib/wavefront-cli/write.rb +4 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/wavefront-cli/alert_spec.rb +16 -5
- data/spec/wavefront-cli/base_spec.rb +5 -2
- data/spec/wavefront-cli/cli_help_spec.rb +7 -5
- data/spec/wavefront-cli/cloudintegration_spec.rb +9 -0
- data/spec/wavefront-cli/commands/alert_spec.rb +16 -0
- data/spec/wavefront-cli/commands/base_spec.rb +133 -0
- data/spec/wavefront-cli/commands/dashboard_spec.rb +16 -0
- data/spec/wavefront-cli/commands/event_spec.rb +17 -0
- data/spec/wavefront-cli/commands/integration_spec.rb +21 -0
- data/spec/wavefront-cli/commands/link_spec.rb +21 -0
- data/spec/wavefront-cli/commands/message_spec.rb +16 -0
- data/spec/wavefront-cli/commands/metric_spec.rb +16 -0
- data/spec/wavefront-cli/commands/proxy_spec.rb +16 -0
- data/spec/wavefront-cli/commands/query_spec.rb +16 -0
- data/spec/wavefront-cli/commands/spec_helper.rb +4 -0
- data/spec/wavefront-cli/commands/webhook_spec.rb +16 -0
- data/spec/wavefront-cli/commands/window_spec.rb +21 -0
- data/spec/wavefront-cli/commands/write_spec.rb +17 -0
- data/spec/wavefront-cli/dashboard_spec.rb +14 -4
- data/spec/wavefront-cli/display/base_spec.rb +162 -0
- data/spec/wavefront-cli/display/printer/base_spec.rb +20 -0
- data/spec/wavefront-cli/display/printer/long_spec.rb +137 -0
- data/spec/wavefront-cli/display/printer/terse_spec.rb +46 -0
- data/spec/wavefront-cli/display/spec_helper.rb +5 -0
- data/spec/wavefront-cli/event_spec.rb +9 -0
- data/spec/wavefront-cli/externallink_spec.rb +9 -0
- data/spec/wavefront-cli/maintanancewindow_spec.rb +10 -0
- data/spec/wavefront-cli/proxy_spec.rb +9 -0
- data/spec/wavefront-cli/savedsearch_spec.rb +9 -0
- data/spec/wavefront-cli/source_spec.rb +13 -1
- data/spec/wavefront-cli/string_spec.rb +51 -0
- data/spec/wavefront-cli/user_spec.rb +2 -2
- data/spec/wavefront-cli/webhook_spec.rb +9 -0
- data/wavefront-cli.gemspec +5 -5
- metadata +59 -22
- data/Gemfile.lock +0 -65
@@ -0,0 +1,186 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
require_relative '../../string'
|
3
|
+
|
4
|
+
module WavefrontDisplayPrinter
|
5
|
+
#
|
6
|
+
# Print the long indented descriptions of things
|
7
|
+
#
|
8
|
+
class Long < Base
|
9
|
+
attr_reader :indent, :indent_str, :indent_step, :kw, :hide_blank
|
10
|
+
|
11
|
+
def initialize(data, fields = nil, modified_data = nil)
|
12
|
+
@out = []
|
13
|
+
@indent = 0
|
14
|
+
@indent_step = 2
|
15
|
+
@hide_blank = true
|
16
|
+
_two_columns(modified_data || data, nil, fields)
|
17
|
+
end
|
18
|
+
|
19
|
+
# A recursive function which displays a key-value hash in two
|
20
|
+
# columns. The key column width is automatically calculated.
|
21
|
+
# Multiple-value 'v's are printed one per line. Hashes are nested.
|
22
|
+
#
|
23
|
+
# @param data [Array] and array of objects to display. Each object
|
24
|
+
# should be a hash.
|
25
|
+
# @param indent [Integer] how many characters to indent the current
|
26
|
+
# data.
|
27
|
+
# @kw [Integer] the width of the first (key) column.
|
28
|
+
# @returns [Nil]
|
29
|
+
#
|
30
|
+
def _two_columns(data, kw = nil, fields = nil)
|
31
|
+
[data].flatten.each do |item|
|
32
|
+
preen_fields(item, fields)
|
33
|
+
kw = key_width(item) unless kw
|
34
|
+
@kw = kw unless @kw
|
35
|
+
mk_indent(indent)
|
36
|
+
item.each { |k, v| parse_line(k, v) }
|
37
|
+
add_line(nil) if indent.zero?
|
38
|
+
end
|
39
|
+
|
40
|
+
@indent -= indent_step if indent > 0
|
41
|
+
@kw += 2
|
42
|
+
mk_indent(indent)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Drop any fields not required.
|
46
|
+
#
|
47
|
+
# @param item [Hash, Map] the raw data
|
48
|
+
# @param fields [Array[Symbol]] the fields we wish to keep
|
49
|
+
# @return [Hash, Map]
|
50
|
+
#
|
51
|
+
def preen_fields(item, fields = nil)
|
52
|
+
return item unless fields
|
53
|
+
item.keep_if { |k, _v| fields.include?(k.to_sym) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Remove HTML and stuff
|
57
|
+
#
|
58
|
+
# @param [String] raw value
|
59
|
+
# @return [String] value with all HTML stripped out
|
60
|
+
#
|
61
|
+
def preen_value(value)
|
62
|
+
return value unless value.is_a?(String) && value =~ /<.*>/
|
63
|
+
value.gsub(%r{<\/?[^>]*>}, '').delete("\n")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return true if this line is blank and we don't want to print
|
67
|
+
# blank lines
|
68
|
+
#
|
69
|
+
# @param value [Object] thing to check
|
70
|
+
# @return [Boolean]
|
71
|
+
#
|
72
|
+
def blank?(value)
|
73
|
+
value.respond_to?(:empty?) && value.empty? && hide_blank
|
74
|
+
end
|
75
|
+
|
76
|
+
# Parse a line and add it to the output or pass it on to another
|
77
|
+
# method which knows how to add it to the output.
|
78
|
+
#
|
79
|
+
# @param key [String] a key
|
80
|
+
# @param value [Object] the value: could be anything
|
81
|
+
# @return [Nil]
|
82
|
+
#
|
83
|
+
def parse_line(key, value)
|
84
|
+
return if blank?(value)
|
85
|
+
|
86
|
+
value = preen_value(value)
|
87
|
+
|
88
|
+
if value.is_a?(Hash)
|
89
|
+
add_hash(key, value)
|
90
|
+
elsif value.is_a?(Array)
|
91
|
+
add_array(key, value)
|
92
|
+
else
|
93
|
+
add_line(key, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Add a key-value pair to the output when value is an array. It
|
98
|
+
# will put the key and the first value element on the first
|
99
|
+
# line, with subsequent value elements aligned at the same
|
100
|
+
# offset, but with no key. If any value element is a hash, it is
|
101
|
+
# handled by a separate method. For instance:
|
102
|
+
#
|
103
|
+
# key value1
|
104
|
+
# value2
|
105
|
+
# value3
|
106
|
+
#
|
107
|
+
# @param key [String] the key
|
108
|
+
# @param value_arr [Array] an array of values
|
109
|
+
# @return [Nil]
|
110
|
+
#
|
111
|
+
def add_array(key, value_arr)
|
112
|
+
value_arr.each_with_index do |element, index|
|
113
|
+
if element.is_a?(Hash)
|
114
|
+
add_hash(key, element, value_arr.size, index)
|
115
|
+
else
|
116
|
+
add_line(index.zero? ? key : nil, element)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Add a hash to the output. It will put the key on a line on its
|
122
|
+
# own, followed by other keys indented. All values are aligned
|
123
|
+
# to the same point. If this hash is a member of an array, we
|
124
|
+
# are able to print a horizontal rule at the end of it. We don't
|
125
|
+
# do this if it is the final member of the array.
|
126
|
+
#
|
127
|
+
# For instance:
|
128
|
+
#
|
129
|
+
# key
|
130
|
+
# subkey1 value1
|
131
|
+
# subkey2 value2
|
132
|
+
#
|
133
|
+
# @param key [String] the key
|
134
|
+
# @param value [Hash] hash of values to display
|
135
|
+
# @param size [Integer] the size of the parent array, if there
|
136
|
+
# is one
|
137
|
+
# @param index [Integer] the index of this element in parent
|
138
|
+
# array, if there is one.
|
139
|
+
# @return [Nil]
|
140
|
+
#
|
141
|
+
def add_hash(key, value, arr_size = 0, arr_index = 0)
|
142
|
+
add_line(key) if arr_index.zero?
|
143
|
+
@indent += indent_step
|
144
|
+
@kw -= 2
|
145
|
+
_two_columns([value], kw - indent_step)
|
146
|
+
add_rule(kw) if arr_index + 1 < arr_size
|
147
|
+
end
|
148
|
+
|
149
|
+
# Add a horizontal rule, from the start of the second column to
|
150
|
+
# just shy of the end of the terminal
|
151
|
+
#
|
152
|
+
def add_rule(kw)
|
153
|
+
add_line(nil, '-' * (TW - kw - 4))
|
154
|
+
end
|
155
|
+
|
156
|
+
# Make the string which is prepended to each line. Stepping is
|
157
|
+
# controlled by @indent_step.
|
158
|
+
#
|
159
|
+
# @param indent [Integer] how many characters to indent by.
|
160
|
+
#
|
161
|
+
def mk_indent(indent)
|
162
|
+
@indent_str = ' ' * indent
|
163
|
+
end
|
164
|
+
|
165
|
+
# Print a single line of output, handling the necessary
|
166
|
+
# indentation and tabulation.
|
167
|
+
#
|
168
|
+
# @param key [String] what to print in the first (key) column.
|
169
|
+
# Make this an empty string to print
|
170
|
+
# @param val [String, Numeric] what to print in the second column
|
171
|
+
# @param tw [Integer] terminal width
|
172
|
+
#
|
173
|
+
def mk_line(key, value = '', tw = TW)
|
174
|
+
return indent_str + ' ' * kw + value if !key || key.empty?
|
175
|
+
|
176
|
+
indent_str + format("%-#{kw}s%s", key, value)
|
177
|
+
.fold(tw, kw + indent_str.size, '').rstrip
|
178
|
+
end
|
179
|
+
|
180
|
+
# Add a line, prepped by #mk_line() to the out array.
|
181
|
+
#
|
182
|
+
def add_line(*args)
|
183
|
+
@out.<< mk_line(*args)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplayPrinter
|
4
|
+
|
5
|
+
# Print things which are per-row. The terse listings, primarily
|
6
|
+
#
|
7
|
+
class Terse < Base
|
8
|
+
attr_reader :data, :keys, :fmt_string
|
9
|
+
|
10
|
+
def initialize(data, *keys)
|
11
|
+
# require 'json'
|
12
|
+
# File.open('/tmp/1', 'w') { |f| f.puts data.to_json }
|
13
|
+
@data = data
|
14
|
+
@keys = keys
|
15
|
+
@fmt_string = format_string.rstrip
|
16
|
+
@out = prep_output
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [String] a Ruby format string for each line
|
20
|
+
#
|
21
|
+
def format_string
|
22
|
+
lk = longest_keys
|
23
|
+
keys.each_with_object('') { |k, out| out.<< "%-#{lk[k]}s " }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Find the length of the longest value for each member of @keys,
|
27
|
+
# in @data.
|
28
|
+
#
|
29
|
+
# @return [Hash] with the same keys as :keys and Integer values
|
30
|
+
#
|
31
|
+
def longest_keys
|
32
|
+
keys.each_with_object(Hash[*keys.map { |k| [k, 0] }.flatten]) \
|
33
|
+
do |k, aggr|
|
34
|
+
data.each do |obj|
|
35
|
+
val = obj[k]
|
36
|
+
val = val.join(', ') if val.is_a?(Array)
|
37
|
+
aggr[k] = val.size if val.size > aggr[k]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Print multiple column output. This method does no word
|
43
|
+
# wrapping.
|
44
|
+
#
|
45
|
+
# @param keys [Symbol] the keys you want in the output. They
|
46
|
+
# will be printed in the order given.
|
47
|
+
#
|
48
|
+
def prep_output
|
49
|
+
data.each_with_object([]) do |o, aggr|
|
50
|
+
args = keys.map { |k| o[k].is_a?(Array) ? o[k].join(', ') : o[k] }
|
51
|
+
aggr.<< format(fmt_string, *args).rstrip
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -6,7 +6,6 @@ module WavefrontDisplay
|
|
6
6
|
#
|
7
7
|
class Query < Base
|
8
8
|
def do_default
|
9
|
-
|
10
9
|
ts = if data.key?(:timeseries)
|
11
10
|
data[:timeseries].each do |s|
|
12
11
|
s[:data] = humanize_series(s[:data])
|
@@ -62,7 +61,7 @@ module WavefrontDisplay
|
|
62
61
|
date, time = ht.split
|
63
62
|
ds = date == last_date ? '' : date
|
64
63
|
last_date = date
|
65
|
-
format('
|
64
|
+
format('%-12s %s %s', ds, time, val)
|
66
65
|
end
|
67
66
|
end
|
68
67
|
end
|
@@ -12,13 +12,17 @@ module WavefrontDisplay
|
|
12
12
|
|
13
13
|
def do_list_brief
|
14
14
|
drop_cluster_sources
|
15
|
-
|
15
|
+
multicolumn(:id, :description)
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
def do_search_brief
|
19
|
+
multicolumn(:id)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Filter out the Wavefront cluster sources. Don't sort them, or
|
23
|
+
# using offset and cursor becomes confusing.
|
19
24
|
#
|
20
25
|
def drop_cluster_sources
|
21
|
-
data.sort_by! { |k, _v| k }
|
22
26
|
return if options[:all]
|
23
27
|
data.delete_if { |k| k.id =~ /prod-[\da-f]{2}-/ }
|
24
28
|
end
|
@@ -6,13 +6,12 @@ module WavefrontDisplay
|
|
6
6
|
#
|
7
7
|
class Webhook < Base
|
8
8
|
def do_list
|
9
|
-
long_output([:id, :description, :createdEpochMillis,
|
10
|
-
:updatedEpochMillis, :updaterId, :creatorId
|
11
|
-
:title])
|
9
|
+
long_output([:id, :title, :description, :createdEpochMillis,
|
10
|
+
:updatedEpochMillis, :updaterId, :creatorId])
|
12
11
|
end
|
13
12
|
|
14
13
|
def do_list_brief
|
15
|
-
|
14
|
+
multicolumn(:id, :title)
|
16
15
|
end
|
17
16
|
|
18
17
|
def do_describe
|
data/lib/wavefront-cli/event.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'wavefront-sdk/mixins'
|
3
3
|
require_relative './base'
|
4
|
+
require 'open3'
|
4
5
|
|
5
6
|
EVENT_STATE_DIR = Pathname.new('/var/tmp/wavefront')
|
6
7
|
|
@@ -26,7 +27,7 @@ module WavefrontCli
|
|
26
27
|
options[:start] = Time.now - 600 unless options[:start]
|
27
28
|
options[:end] = Time.now unless options[:end]
|
28
29
|
wf.list(options[:start], options[:end], options[:limit] || 100,
|
29
|
-
options[:
|
30
|
+
options[:cursor] || nil)
|
30
31
|
end
|
31
32
|
|
32
33
|
def do_update
|
@@ -34,32 +35,37 @@ module WavefrontCli
|
|
34
35
|
wf.update(options[:'<id>'], k => v)
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
# You can override the options generated by docopt. This is how
|
39
|
+
# #wrap() works.
|
40
|
+
#
|
41
|
+
def do_create(opts = nil)
|
42
|
+
opts ||= options
|
43
|
+
|
44
|
+
opts[:start] = Time.now unless opts[:start]
|
39
45
|
|
40
|
-
t_start = parse_time(
|
41
|
-
id = [t_start,
|
46
|
+
t_start = parse_time(opts[:start], true)
|
47
|
+
id = [t_start, opts[:'<event>']].join(':')
|
42
48
|
|
43
|
-
body = { name:
|
49
|
+
body = { name: opts[:'<event>'],
|
44
50
|
startTime: t_start,
|
45
51
|
id: id,
|
46
52
|
annotations: {} }
|
47
53
|
|
48
|
-
body[:annotations][:details] =
|
49
|
-
body[:annotations][:severity] =
|
50
|
-
body[:annotations][:type] =
|
51
|
-
body[:hosts] =
|
54
|
+
body[:annotations][:details] = opts[:desc] if opts[:desc]
|
55
|
+
body[:annotations][:severity] = opts[:severity] if opts[:severity]
|
56
|
+
body[:annotations][:type] = opts[:type] if opts[:type]
|
57
|
+
body[:hosts] = opts[:host] if opts[:host]
|
52
58
|
|
53
|
-
if
|
59
|
+
if opts[:instant]
|
54
60
|
body[:endTime] = t_start + 1
|
55
|
-
elsif
|
56
|
-
body[:endTime] = parse_time(
|
61
|
+
elsif opts[:end]
|
62
|
+
body[:endTime] = parse_time(opts[:end], true)
|
57
63
|
end
|
58
64
|
|
59
65
|
resp = wf.create(body)
|
60
66
|
|
61
|
-
unless
|
62
|
-
create_state_file(id,
|
67
|
+
unless opts[:nostate] || opts[:end] || opts[:instant]
|
68
|
+
create_state_file(id, opts[:host])
|
63
69
|
end
|
64
70
|
|
65
71
|
resp
|
@@ -71,19 +77,20 @@ module WavefrontCli
|
|
71
77
|
# name, we'll look for something on the stack. If it does look
|
72
78
|
# like a real event, we'll make and API call straight away.
|
73
79
|
#
|
74
|
-
def do_close
|
80
|
+
def do_close(id = nil)
|
81
|
+
id ||= options[:'<id>']
|
75
82
|
ev_file = nil
|
76
83
|
|
77
|
-
ev = if
|
84
|
+
ev = if !id
|
78
85
|
pop_event
|
79
|
-
elsif
|
80
|
-
ev_file = state_dir +
|
81
|
-
|
86
|
+
elsif id =~ /^\d{13}:.+/
|
87
|
+
ev_file = state_dir + id
|
88
|
+
id
|
82
89
|
else
|
83
|
-
pop_event(
|
90
|
+
pop_event(id)
|
84
91
|
end
|
85
92
|
|
86
|
-
abort "No locally stored event matches '#{
|
93
|
+
abort "No locally stored event matches '#{id}'." unless ev
|
87
94
|
|
88
95
|
res = wf.close(ev)
|
89
96
|
ev_file.unlink if ev_file && ev_file.exist? && res.status.code == 200
|
@@ -106,14 +113,46 @@ module WavefrontCli
|
|
106
113
|
exit
|
107
114
|
end
|
108
115
|
|
116
|
+
def do_wrap
|
117
|
+
create_opts = options
|
118
|
+
create_opts[:desc] ||= create_opts[:command]
|
119
|
+
event_id = do_create(create_opts).response.id
|
120
|
+
exit_code = run_wrapped_cmd(options[:command])
|
121
|
+
do_close(event_id)
|
122
|
+
puts "Command exited #{exit_code}"
|
123
|
+
exit exit_code
|
124
|
+
end
|
125
|
+
|
109
126
|
private
|
110
127
|
|
128
|
+
# Run a command, stream stderr and stdout to the screen (they
|
129
|
+
# get combined -- could be an issue for someone somewhere) and
|
130
|
+
# return the command's exit code
|
131
|
+
#
|
132
|
+
# rubocop:disable Lint/AssignmentInCondition
|
133
|
+
#
|
134
|
+
def run_wrapped_cmd(cmd)
|
135
|
+
puts 'Command output follows, on STDERR:'
|
136
|
+
puts '-' * (TW - 4)
|
137
|
+
ret = nil
|
138
|
+
|
139
|
+
Open3.popen2e(cmd) do |_in, out, thr|
|
140
|
+
while l = out.gets
|
141
|
+
STDERR.puts l
|
142
|
+
end
|
143
|
+
|
144
|
+
ret = thr.value.exitstatus
|
145
|
+
end
|
146
|
+
|
147
|
+
puts '-' * (TW - 4)
|
148
|
+
ret
|
149
|
+
end
|
150
|
+
|
111
151
|
# Write a state file. We put the hosts bound to the event into the
|
112
152
|
# file. These aren't currently used by anything in the CLI, but they
|
113
153
|
# might be useful to someone, somewhere, someday.
|
114
154
|
#
|
115
155
|
def create_state_file(id, hosts = [])
|
116
|
-
puts "statfile fir #{id}"
|
117
156
|
fname = state_dir + id
|
118
157
|
|
119
158
|
begin
|
@@ -37,13 +37,13 @@ module WavefrontCli
|
|
37
37
|
@opts = DEFAULT_OPTS.merge(load_profile).merge(@cli_opts)
|
38
38
|
end
|
39
39
|
|
40
|
+
# Load in configuration options from the (optionally) given
|
41
|
+
# section of an ini-style configuration file. If the file's not
|
42
|
+
# there, we don't consider that an error. Returns a hash of
|
43
|
+
# options which matches what Docopt gives us.
|
44
|
+
#
|
45
|
+
# rubocop:disable Metrics/AbcSize
|
40
46
|
def load_profile
|
41
|
-
#
|
42
|
-
# Load in configuration options from the (optionally) given
|
43
|
-
# section of an ini-style configuration file. If the file's
|
44
|
-
# not there, we don't consider that an error. Returns a hash
|
45
|
-
# of options which matches what Docopt gives us.
|
46
|
-
#
|
47
47
|
unless conf_file.exist?
|
48
48
|
puts "config file '#{conf_file}' not found. Taking options " \
|
49
49
|
'from command-line.'
|
data/lib/wavefront-cli/query.rb
CHANGED
@@ -19,11 +19,11 @@ module WavefrontCli
|
|
19
19
|
sorted: true
|
20
20
|
}
|
21
21
|
|
22
|
-
if options[:start]
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
options[:start] = if options[:start]
|
23
|
+
parse_time(options[:start], true)
|
24
|
+
else
|
25
|
+
(Time.now - 600).to_i
|
26
|
+
end
|
27
27
|
|
28
28
|
if options[:end]
|
29
29
|
options[:end] = parse_time(options[:end], true)
|
@@ -42,7 +42,6 @@ module WavefrontCli
|
|
42
42
|
options[:start], options[:end] || nil, opts)
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
45
|
# Work out a sensible granularity based on the time window
|
47
46
|
#
|
48
47
|
def default_granularity(window)
|
data/lib/wavefront-cli/source.rb
CHANGED
@@ -5,6 +5,10 @@ module WavefrontCli
|
|
5
5
|
# CLI coverage for the v2 'source' API.
|
6
6
|
#
|
7
7
|
class Source < WavefrontCli::Base
|
8
|
+
def do_list
|
9
|
+
wf.list(options[:limit], options[:cursor])
|
10
|
+
end
|
11
|
+
|
8
12
|
def do_clear
|
9
13
|
wf.delete(options[:'<id>'])
|
10
14
|
end
|
@@ -14,7 +18,7 @@ module WavefrontCli
|
|
14
18
|
end
|
15
19
|
|
16
20
|
def do_description_clear
|
17
|
-
wf.update(options[:'<id>'], { description: ''}, false)
|
21
|
+
wf.update(options[:'<id>'], { description: '' }, false)
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Extensions to the String class to help with formatting.
|
2
|
+
#
|
3
|
+
class String
|
4
|
+
# Fold long command lines. We can't break on a space after an
|
5
|
+
# option or it confuses docopt.
|
6
|
+
#
|
7
|
+
# @param tw [Integer] terminal width
|
8
|
+
# @param indent [Integer] size of hanging indent, in chars
|
9
|
+
#
|
10
|
+
def cmd_fold(tw = TW, indent = 10)
|
11
|
+
#gsub(/\s(?=\w+\])/, '^').scan_line(tw - 8).join("\n" + ' ' * indent)
|
12
|
+
gsub(/(-\w) /, "\\1^").scan_line(tw - 12).join("\n" + ' ' * indent)
|
13
|
+
.tr('^', ' ')
|
14
|
+
end
|
15
|
+
|
16
|
+
# Wrapper around #fold()
|
17
|
+
#
|
18
|
+
# @param tw [Integer] width of terminal, in chars
|
19
|
+
# @param indent [Integer] hanging indent of following lines
|
20
|
+
# @return [String] folded and indented string
|
21
|
+
#
|
22
|
+
def opt_fold(tw = TW, indent = 10)
|
23
|
+
fold(tw, indent, ' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fold long lines with a hanging indent. Originally a special case
|
27
|
+
# for option folding, now addded the prefix parameter to make it
|
28
|
+
# more general.
|
29
|
+
#
|
30
|
+
# rubocop:disable Metrics/AbcSize
|
31
|
+
#
|
32
|
+
# @param tw [Integer] terminal width
|
33
|
+
# @param indent [Integer] size of hanging indent, in chars
|
34
|
+
# @param prefix [String] prepended to every line
|
35
|
+
# @return [String] the folded line
|
36
|
+
#
|
37
|
+
def fold(tw = TW, indent = 10, prefix = '')
|
38
|
+
chunks = self.scan_line(tw - 8)
|
39
|
+
|
40
|
+
line_1 = prefix + chunks.shift + "\n"
|
41
|
+
|
42
|
+
return line_1 if chunks.empty?
|
43
|
+
|
44
|
+
rest = chunks.join(' ').scan_line(tw - indent - 5).map do |l|
|
45
|
+
prefix + ' ' * indent + l
|
46
|
+
end
|
47
|
+
|
48
|
+
line_1 + rest.join("\n") + "\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param width [Integer] length of longest string (width of
|
52
|
+
# terminal less some margin)
|
53
|
+
# @return [Array] original string chunked into an array width
|
54
|
+
# elements whose length < width
|
55
|
+
#
|
56
|
+
def scan_line(width)
|
57
|
+
scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/)
|
58
|
+
end
|
59
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
WF_CLI_VERSION = '0.0
|
1
|
+
WF_CLI_VERSION = '1.0.0'.freeze
|
data/lib/wavefront-cli/write.rb
CHANGED
@@ -5,6 +5,7 @@ module WavefrontCli
|
|
5
5
|
#
|
6
6
|
# Send points to a proxy.
|
7
7
|
#
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
8
9
|
class Write < Base
|
9
10
|
attr_reader :fmt
|
10
11
|
include Wavefront::Mixins
|
@@ -13,6 +14,8 @@ module WavefrontCli
|
|
13
14
|
{ proxy: options[:proxy], port: options[:port] || 2878 }
|
14
15
|
end
|
15
16
|
|
17
|
+
# rubocop:disable Metrics/AbcSize
|
18
|
+
# rubocop:disable Metrics/MethodLength
|
16
19
|
def do_point
|
17
20
|
p = { path: options[:'<metric>'],
|
18
21
|
value: options[:'<value>'].to_f,
|
@@ -152,7 +155,7 @@ module WavefrontCli
|
|
152
155
|
# Merge them, making the -T win if there is a collision.
|
153
156
|
#
|
154
157
|
def line_tags(chunks)
|
155
|
-
file_tags =
|
158
|
+
file_tags = fmt.last == 'T' ? extract_tags(chunks) : {}
|
156
159
|
opt_tags = tags_to_hash(options[:tag])
|
157
160
|
file_tags.merge(opt_tags)
|
158
161
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -50,7 +50,7 @@ def cmd_to_call(word, args, call, sdk_class = nil)
|
|
50
50
|
headers = { 'Accept': /.*/,
|
51
51
|
'Accept-Encoding': /.*/,
|
52
52
|
'Authorization': 'Bearer 0123456789-ABCDEF',
|
53
|
-
'User-Agent':
|
53
|
+
'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}"
|
54
54
|
}
|
55
55
|
|
56
56
|
sdk_class ||= Object.const_get("WavefrontCli::#{word.capitalize}")
|
@@ -18,19 +18,30 @@ describe "#{word} command" do
|
|
18
18
|
|
19
19
|
it 'deletes with a check on inTrash' do
|
20
20
|
stub_request(:get,
|
21
|
-
'https://other.wavefront.com/api/v2/alert/1481553823153')
|
22
|
-
|
23
|
-
'Accept-Encoding':
|
21
|
+
'https://other.wavefront.com/api/v2/alert/1481553823153')
|
22
|
+
.with(headers: { 'Accept': '*/*',
|
23
|
+
'Accept-Encoding':
|
24
|
+
'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
24
25
|
'Authorization': 'Bearer 0123456789-ABCDEF',
|
25
|
-
'User-Agent': /wavefront.*/})
|
26
|
-
|
26
|
+
'User-Agent': /wavefront.*/ })
|
27
|
+
.to_return(status: 200, body: '', headers: {})
|
27
28
|
cmd_to_call(word, "delete #{id}",
|
28
29
|
method: :delete, path: "/api/v2/#{word}/#{id}")
|
29
30
|
end
|
31
|
+
|
30
32
|
cmd_to_call(word, "undelete #{id}",
|
31
33
|
method: :post, path: "/api/v2/#{word}/#{id}/undelete")
|
32
34
|
cmd_to_call(word, "snooze #{id}",
|
33
35
|
method: :post, path: "/api/v2/#{word}/#{id}/snooze")
|
36
|
+
cmd_to_call(word, "search id=#{id}",
|
37
|
+
{ method: :post, path: "/api/v2/search/#{word}",
|
38
|
+
body: { limit: 10,
|
39
|
+
offset: 0,
|
40
|
+
query: [{key: 'id',
|
41
|
+
value: id,
|
42
|
+
matchingMethod: 'EXACT'}],
|
43
|
+
sort: {field: 'id', ascending: true}},
|
44
|
+
headers: JSON_POST_HEADERS })
|
34
45
|
cmd_to_call(word, "snooze -T 800 #{id}",
|
35
46
|
method: :post,
|
36
47
|
path: "/api/v2/#{word}/#{id}/snooze?seconds=800")
|