wavefront-cli 8.5.1 → 10.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/.rubocop.yml +1 -4
- data/Gemfile +10 -0
- data/HISTORY.md +17 -0
- data/README.md +4 -2
- data/lib/wavefront-cli/base.rb +4 -4
- data/lib/wavefront-cli/commands/base.rb +13 -10
- data/lib/wavefront-cli/commands/config.rb +3 -7
- data/lib/wavefront-cli/commands/derivedmetric.rb +1 -1
- data/lib/wavefront-cli/commands/metric.rb +3 -3
- data/lib/wavefront-cli/commands/metricspolicy.rb +33 -0
- data/lib/wavefront-cli/commands/query.rb +5 -5
- data/lib/wavefront-cli/commands/write.rb +12 -12
- data/lib/wavefront-cli/config.rb +31 -35
- data/lib/wavefront-cli/constants.rb +3 -2
- data/lib/wavefront-cli/controller.rb +19 -15
- data/lib/wavefront-cli/display/base.rb +2 -2
- data/lib/wavefront-cli/display/cluster.rb +21 -0
- data/lib/wavefront-cli/display/metricspolicy.rb +15 -0
- data/lib/wavefront-cli/display/printer/long.rb +11 -17
- data/lib/wavefront-cli/display/printer/sparkline.rb +3 -3
- data/lib/wavefront-cli/display/query.rb +1 -1
- data/lib/wavefront-cli/display/write.rb +2 -1
- data/lib/wavefront-cli/event.rb +2 -2
- data/lib/wavefront-cli/exception_handler.rb +8 -1
- data/lib/wavefront-cli/helpers/load_file.rb +2 -2
- data/lib/wavefront-cli/maintenancewindow.rb +1 -1
- data/lib/wavefront-cli/metricspolicy.rb +42 -0
- data/lib/wavefront-cli/opt_handler.rb +2 -3
- data/lib/wavefront-cli/output/csv/query.rb +3 -3
- data/lib/wavefront-cli/output/hcl/base.rb +4 -4
- data/lib/wavefront-cli/output/hcl/dashboard.rb +7 -7
- data/lib/wavefront-cli/output/hcl/stdlib/array.rb +1 -1
- data/lib/wavefront-cli/output/wavefront/query.rb +7 -7
- data/lib/wavefront-cli/stdlib/array.rb +1 -1
- data/lib/wavefront-cli/stdlib/string.rb +5 -5
- data/lib/wavefront-cli/usage.rb +1 -1
- data/lib/wavefront-cli/version.rb +1 -1
- data/lib/wavefront-cli/write.rb +15 -19
- data/spec/constants.rb +5 -6
- data/spec/support/command_base.rb +13 -1
- data/spec/support/minitest_assertions.rb +14 -10
- data/spec/support/output_tester.rb +2 -2
- data/spec/support/supported_commands.rb +3 -1
- data/spec/test_mixins/import.rb +2 -2
- data/spec/test_mixins/search.rb +9 -7
- data/spec/test_mixins/set.rb +1 -1
- data/spec/wavefront-cli/account_spec.rb +6 -4
- data/spec/wavefront-cli/alert_spec.rb +29 -6
- data/spec/wavefront-cli/base_spec.rb +1 -1
- data/spec/wavefront-cli/commands/base_spec.rb +3 -3
- data/spec/wavefront-cli/commands/config_spec.rb +6 -6
- data/spec/wavefront-cli/config_spec.rb +84 -44
- data/spec/wavefront-cli/controller_spec.rb +4 -2
- data/spec/wavefront-cli/dashboard_spec.rb +1 -1
- data/spec/wavefront-cli/derivedmetric_spec.rb +9 -7
- data/spec/wavefront-cli/display/base_spec.rb +1 -1
- data/spec/wavefront-cli/display/printer/long_spec.rb +6 -4
- data/spec/wavefront-cli/display/printer/terse_spec.rb +2 -2
- data/spec/wavefront-cli/event_spec.rb +14 -11
- data/spec/wavefront-cli/event_store_spec.rb +17 -13
- data/spec/wavefront-cli/externallink_spec.rb +5 -3
- data/spec/wavefront-cli/maintenancewindow_spec.rb +25 -19
- data/spec/wavefront-cli/message_spec.rb +3 -3
- data/spec/wavefront-cli/metricspolicy_spec.rb +30 -0
- data/spec/wavefront-cli/opt_handler_spec.rb +2 -2
- data/spec/wavefront-cli/output/csv/query_spec.rb +1 -1
- data/spec/wavefront-cli/output/csv_spec.rb +1 -1
- data/spec/wavefront-cli/output/hcl_spec.rb +1 -1
- data/spec/wavefront-cli/output/helpers.rb +1 -1
- data/spec/wavefront-cli/output/json_spec.rb +1 -1
- data/spec/wavefront-cli/output/ruby_spec.rb +1 -1
- data/spec/wavefront-cli/output/wavefront/query_spec.rb +1 -1
- data/spec/wavefront-cli/output/wavefront_spec.rb +1 -1
- data/spec/wavefront-cli/output/yaml_spec.rb +1 -1
- data/spec/wavefront-cli/proxy_spec.rb +1 -1
- data/spec/wavefront-cli/query_spec.rb +2 -2
- data/spec/wavefront-cli/role_spec.rb +4 -3
- data/spec/wavefront-cli/serviceaccount_spec.rb +7 -5
- data/spec/wavefront-cli/stdlib/array_spec.rb +1 -1
- data/spec/wavefront-cli/stdlib/string_spec.rb +4 -2
- data/spec/wavefront-cli/usage_spec.rb +2 -2
- data/spec/wavefront-cli/{write_spec.rb → write_class_spec.rb} +2 -15
- data/wavefront-cli.gemspec +4 -16
- metadata +17 -259
- data/spec/spec_helper.rb +0 -113
@@ -45,8 +45,8 @@ module WavefrontDisplay
|
|
45
45
|
run_list
|
46
46
|
elsif method == 'do_search'
|
47
47
|
run_search
|
48
|
-
elsif respond_to?("#{method}_brief") && !options[:long]
|
49
|
-
send("#{method}_brief")
|
48
|
+
elsif respond_to?(:"#{method}_brief") && !options[:long]
|
49
|
+
send(:"#{method}_brief")
|
50
50
|
elsif respond_to?(method)
|
51
51
|
send(method)
|
52
52
|
else
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module WavefrontDisplay
|
6
|
+
#
|
7
|
+
# Format human-readable output for config commands.
|
8
|
+
#
|
9
|
+
class Cluster < Base
|
10
|
+
def do_location
|
11
|
+
puts data
|
12
|
+
end
|
13
|
+
alias do_profiles do_location
|
14
|
+
alias do_show do_location
|
15
|
+
alias do_envvars do_location
|
16
|
+
|
17
|
+
def do_about
|
18
|
+
long_output
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module WavefrontDisplay
|
6
|
+
#
|
7
|
+
# Format human-readable output of the metrics policy.
|
8
|
+
#
|
9
|
+
class MetricsPolicy < Base
|
10
|
+
def do_history
|
11
|
+
readable_time_arr(:updateTime)
|
12
|
+
long_output
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -77,17 +77,15 @@ module WavefrontDisplayPrinter
|
|
77
77
|
#
|
78
78
|
# Make an array of hashes: { key, value, depth }
|
79
79
|
#
|
80
|
-
# rubocop:disable Style/CaseLikeIf
|
81
80
|
def make_list(data, aggr = [], depth = 0, last_key = nil)
|
82
81
|
if data.is_a?(Hash)
|
83
82
|
append_hash(data, aggr, depth)
|
84
83
|
elsif data.is_a?(Array)
|
85
84
|
append_array(data, aggr, depth, last_key)
|
86
85
|
else
|
87
|
-
aggr
|
86
|
+
aggr << ['', preened_value(data), depth]
|
88
87
|
end
|
89
88
|
end
|
90
|
-
# rubocop:enable Style/CaseLikeIf
|
91
89
|
|
92
90
|
def smart_value(val)
|
93
91
|
val.to_s.empty? && opts[:none] ? '<none>' : preened_value(val)
|
@@ -99,16 +97,14 @@ module WavefrontDisplayPrinter
|
|
99
97
|
# @return [Integer]
|
100
98
|
#
|
101
99
|
def longest_key_col(data)
|
102
|
-
data.map { |d| d[0].size + opts[:padding] + opts[:indent] * d[2] }.max
|
100
|
+
data.map { |d| d[0].size + opts[:padding] + (opts[:indent] * d[2]) }.max
|
103
101
|
end
|
104
102
|
|
105
103
|
# Turn the list made by #make_list into user output
|
106
104
|
# @return [String]
|
107
105
|
#
|
108
106
|
def to_s
|
109
|
-
list.map
|
110
|
-
stringify_line(item)
|
111
|
-
end.join("\n")
|
107
|
+
list.map { |item| stringify_line(item) }.join("\n")
|
112
108
|
end
|
113
109
|
|
114
110
|
# @param item [Array] of the form [key, value, indent_level]
|
@@ -154,7 +150,6 @@ module WavefrontDisplayPrinter
|
|
154
150
|
# @param depth [Integer]
|
155
151
|
# @return [Array[Array]]
|
156
152
|
#
|
157
|
-
# rubocop:disable Style/CaseLikeIf
|
158
153
|
def append_hash(data, aggr, depth)
|
159
154
|
data.each_pair do |k, v|
|
160
155
|
if v.is_a?(Hash)
|
@@ -162,13 +157,12 @@ module WavefrontDisplayPrinter
|
|
162
157
|
elsif v.is_a?(Array)
|
163
158
|
aggr = append_array_values(k, v, aggr, depth)
|
164
159
|
else
|
165
|
-
aggr
|
160
|
+
aggr << [k, smart_value(v), depth]
|
166
161
|
end
|
167
162
|
end
|
168
163
|
|
169
164
|
aggr
|
170
165
|
end
|
171
|
-
# rubocop:enable Style/CaseLikeIf
|
172
166
|
|
173
167
|
# Part of the #make_list recursion. Deals with arrays.
|
174
168
|
#
|
@@ -183,7 +177,7 @@ module WavefrontDisplayPrinter
|
|
183
177
|
|
184
178
|
if opts[:separator] && element.is_a?(Hash) && i < data.size &&
|
185
179
|
depth < opts[:sep_depth]
|
186
|
-
aggr
|
180
|
+
aggr << ['', :separator, depth]
|
187
181
|
end
|
188
182
|
end
|
189
183
|
|
@@ -202,9 +196,9 @@ module WavefrontDisplayPrinter
|
|
202
196
|
#
|
203
197
|
def append_hash_values(key, values, aggr, depth)
|
204
198
|
if values.empty? && opts[:none]
|
205
|
-
aggr
|
199
|
+
aggr << [key, '<none>', depth]
|
206
200
|
else
|
207
|
-
aggr
|
201
|
+
aggr << [key, nil, depth]
|
208
202
|
make_list(values, aggr, depth + 1)
|
209
203
|
end
|
210
204
|
end
|
@@ -218,13 +212,13 @@ module WavefrontDisplayPrinter
|
|
218
212
|
#
|
219
213
|
def append_array_values(key, values, aggr, depth)
|
220
214
|
if values.empty? && opts[:none]
|
221
|
-
aggr
|
222
|
-
elsif values.all?
|
215
|
+
aggr << [key, '<none>', depth]
|
216
|
+
elsif values.all?(String)
|
223
217
|
values.sort!
|
224
|
-
aggr
|
218
|
+
aggr << [key, preened_value(values.shift), depth]
|
225
219
|
make_list(values, aggr, depth, key)
|
226
220
|
else
|
227
|
-
aggr
|
221
|
+
aggr << [key, nil, depth]
|
228
222
|
make_list(values, aggr, depth + 1, key)
|
229
223
|
end
|
230
224
|
end
|
@@ -16,7 +16,7 @@ class WavefrontSparkline
|
|
16
16
|
attr_reader :sparkline
|
17
17
|
|
18
18
|
def initialize(series)
|
19
|
-
@sparkline =
|
19
|
+
@sparkline = ">#{generate_sparkline(series)}<"
|
20
20
|
end
|
21
21
|
|
22
22
|
# @return [String] the block corresponding to the given value in
|
@@ -38,8 +38,8 @@ class WavefrontSparkline
|
|
38
38
|
def make_fit(vals)
|
39
39
|
return vals if vals.size < SPARK_WIDTH
|
40
40
|
|
41
|
-
vals
|
42
|
-
ret = vals.each_slice(2).with_object([]) { |s, a| a
|
41
|
+
vals << vals.last if vals.size.odd?
|
42
|
+
ret = vals.each_slice(2).with_object([]) { |s, a| a << (s.sum / 2) }
|
43
43
|
make_fit(ret)
|
44
44
|
end
|
45
45
|
|
data/lib/wavefront-cli/event.rb
CHANGED
@@ -38,7 +38,7 @@ module WavefrontCli
|
|
38
38
|
def do_show
|
39
39
|
events = state.list
|
40
40
|
|
41
|
-
if events.
|
41
|
+
if events.empty?
|
42
42
|
puts 'No open events.'
|
43
43
|
else
|
44
44
|
events.sort.reverse_each { |e| puts e.basename }
|
@@ -94,7 +94,7 @@ module WavefrontCli
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def window_start
|
97
|
-
parse_time((options[:start] || Time.now - 600), true)
|
97
|
+
parse_time((options[:start] || (Time.now - 600)), true)
|
98
98
|
end
|
99
99
|
|
100
100
|
def window_end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'faraday'
|
4
|
+
|
3
5
|
module WavefrontCli
|
4
6
|
#
|
5
7
|
# Handle fatal errors.
|
@@ -19,7 +21,8 @@ module WavefrontCli
|
|
19
21
|
abort "\nOperation aborted at user request."
|
20
22
|
when WavefrontCli::Exception::ConfigFileNotFound
|
21
23
|
abort "Configuration file #{exception}' not found."
|
22
|
-
when WavefrontCli::Exception::CredentialError
|
24
|
+
when WavefrontCli::Exception::CredentialError,
|
25
|
+
Wavefront::Exception::CredentialError
|
23
26
|
handle_missing_credentials(exception)
|
24
27
|
when WavefrontCli::Exception::MandatoryValue
|
25
28
|
abort 'A value must be supplied.'
|
@@ -41,6 +44,8 @@ module WavefrontCli
|
|
41
44
|
abort "'#{exception}' is not a valid API token ID."
|
42
45
|
when Wavefront::Exception::InvalidIngestionPolicyId
|
43
46
|
abort "'#{exception}' is not a valid ingestion policy ID."
|
47
|
+
when Wavefront::Exception::InvalidVersion
|
48
|
+
abort "'#{exception}' is not a valid version."
|
44
49
|
when WavefrontCli::Exception::InvalidValue
|
45
50
|
abort "Invalid value for #{exception}."
|
46
51
|
when WavefrontCli::Exception::ProfileExists
|
@@ -77,6 +82,8 @@ module WavefrontCli
|
|
77
82
|
abort 'Search on non-existent key. Please use a top-level field.'
|
78
83
|
when Wavefront::Exception::InvalidSamplingValue
|
79
84
|
abort 'Sampling rates must be between 0 and 0.05.'
|
85
|
+
when Faraday::ConnectionFailed
|
86
|
+
abort 'Error connecting to remote host.'
|
80
87
|
else
|
81
88
|
warn "general error: #{exception}"
|
82
89
|
backtrace_message(exception)
|
@@ -40,11 +40,11 @@ module WavefrontCli
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def load_json(file)
|
43
|
-
read_json(
|
43
|
+
read_json(File.read(file))
|
44
44
|
end
|
45
45
|
|
46
46
|
def load_yaml(file)
|
47
|
-
read_yaml(
|
47
|
+
read_yaml(File.read(file))
|
48
48
|
end
|
49
49
|
|
50
50
|
# Read STDIN and return a Ruby object, assuming that STDIN is
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'wavefront-sdk/support/mixins'
|
4
|
+
require_relative 'base'
|
5
|
+
require_relative 'helpers/load_file'
|
6
|
+
|
7
|
+
module WavefrontCli
|
8
|
+
#
|
9
|
+
# CLI coverage for the metricspolicy part of the v2 'usage' API.
|
10
|
+
#
|
11
|
+
class MetricsPolicy < WavefrontCli::Base
|
12
|
+
def do_describe
|
13
|
+
wf.describe(options[:version])
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_history
|
17
|
+
wf.history(options[:offset] || 0, options[:limit] || 100)
|
18
|
+
end
|
19
|
+
|
20
|
+
def do_revert
|
21
|
+
wf.revert(options[:'<version>'])
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_update
|
25
|
+
raw = WavefrontCli::Helper::LoadFile.new(options[:'<file>']).load
|
26
|
+
rules = process_update(raw)
|
27
|
+
wf.update(policyRules: rules)
|
28
|
+
end
|
29
|
+
|
30
|
+
# It looks like the API expects arrays of ID strings for accounts, groups,
|
31
|
+
# and roles, but when you export one, those fields are objects with name
|
32
|
+
# and ID.
|
33
|
+
#
|
34
|
+
def process_update(raw)
|
35
|
+
raw[:policyRules].tap do |rule|
|
36
|
+
rule[:accounts] = rule[:accounts].map { |r| r[:id] }
|
37
|
+
rule[:userGroups] = rule[:userGroups].map { |r| r[:id] }
|
38
|
+
rule[:roles] = rule[:roles].map { |r| r[:id] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -43,11 +43,10 @@ module WavefrontCli
|
|
43
43
|
# constructor.
|
44
44
|
# @param cli_opts [Hash] options from docopt, which may include
|
45
45
|
# the location of the config file and the stanza within it
|
46
|
-
# @return [Hash] keys are none, one, or both of :file and
|
47
|
-
# :profile
|
46
|
+
# @return [Hash] keys are none, one, or both of :file and :profile
|
48
47
|
#
|
49
48
|
def setup_cred_opts(cli_opts)
|
50
|
-
cred_opts = { raise_on_no_profile: true }
|
49
|
+
cred_opts = cli_opts[:config] ? { raise_on_no_profile: true } : {}
|
51
50
|
|
52
51
|
if cli_opts[:config]
|
53
52
|
cred_opts[:file] = Pathname.new(cli_opts[:config])
|
@@ -32,7 +32,7 @@ module WavefrontCsvOutput
|
|
32
32
|
def raw_output
|
33
33
|
resp.each_with_object([]) do |point, a|
|
34
34
|
point[:points].each do |p|
|
35
|
-
a
|
35
|
+
a << csv_format(options[:'<metric>'],
|
36
36
|
p[:value],
|
37
37
|
p[:timestamp],
|
38
38
|
options[:host],
|
@@ -48,7 +48,7 @@ module WavefrontCsvOutput
|
|
48
48
|
|
49
49
|
resp[:timeseries].each_with_object([]) do |ts, a|
|
50
50
|
ts[:data].each do |point|
|
51
|
-
a
|
51
|
+
a << csv_format(ts[:label],
|
52
52
|
point[1],
|
53
53
|
point[0],
|
54
54
|
ts[:host],
|
@@ -92,7 +92,7 @@ module WavefrontCsvOutput
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def quote_value(value)
|
95
|
-
format('"%<value>s"', value: value.to_s.gsub(
|
95
|
+
format('"%<value>s"', value: value.to_s.gsub('"', '\"'))
|
96
96
|
end
|
97
97
|
|
98
98
|
# Turn a string of output options into an easy-to-query array
|
@@ -61,9 +61,9 @@ module WavefrontHclOutput
|
|
61
61
|
# @return [String]
|
62
62
|
#
|
63
63
|
def handler(key, val)
|
64
|
-
key_handler = "khandle_#{key}"
|
65
|
-
value_handler = "vhandle_#{key}"
|
66
|
-
quote_handler = "qhandle_#{key}"
|
64
|
+
key_handler = :"khandle_#{key}"
|
65
|
+
value_handler = :"vhandle_#{key}"
|
66
|
+
quote_handler = :"qhandle_#{key}"
|
67
67
|
key = send(key_handler) if respond_to?(key_handler)
|
68
68
|
val = send(value_handler, val) if respond_to?(value_handler)
|
69
69
|
|
@@ -92,7 +92,7 @@ module WavefrontHclOutput
|
|
92
92
|
def quote_value(val)
|
93
93
|
case val.class.to_s.to_sym
|
94
94
|
when :String
|
95
|
-
format('"%<value>s"', value: val.gsub(
|
95
|
+
format('"%<value>s"', value: val.gsub('"', '\"'))
|
96
96
|
else
|
97
97
|
val
|
98
98
|
end
|
@@ -32,19 +32,19 @@ module WavefrontHclOutput
|
|
32
32
|
# @return [String] HCL list of vals
|
33
33
|
#
|
34
34
|
def listmaker(vals, method)
|
35
|
-
vals.each_with_object([]) { |v, a| a
|
35
|
+
vals.each_with_object([]) { |v, a| a << send(method, v) }.to_hcl_list
|
36
36
|
end
|
37
37
|
|
38
38
|
def vhandle_sections(vals)
|
39
39
|
vals.each_with_object([]) do |section, a|
|
40
|
-
a
|
40
|
+
a << ("name = \"#{section[:name]}\"\n row = " +
|
41
41
|
handle_rows(section[:rows])).braced(4)
|
42
42
|
end.to_hcl_list
|
43
43
|
end
|
44
44
|
|
45
45
|
def handle_rows(rows)
|
46
46
|
rows.each_with_object([]) do |row, a|
|
47
|
-
a
|
47
|
+
a << "chart = #{handle_charts(row[:charts])}".braced(8)
|
48
48
|
end.to_hcl_list
|
49
49
|
end
|
50
50
|
|
@@ -58,10 +58,10 @@ module WavefrontHclOutput
|
|
58
58
|
lines = chart.each_with_object([]) do |(k, v), a|
|
59
59
|
next unless fields.include?(k)
|
60
60
|
|
61
|
-
a
|
61
|
+
a << format('%<key>s = %<value>s', key: k, value: quote_value(v))
|
62
62
|
end
|
63
63
|
|
64
|
-
lines
|
64
|
+
lines << "source = #{handle_sources(chart[:sources])}"
|
65
65
|
lines.to_hcl_obj(10)
|
66
66
|
end
|
67
67
|
|
@@ -75,7 +75,7 @@ module WavefrontHclOutput
|
|
75
75
|
|
76
76
|
k = 'queryBuilderEnabled' if k == 'querybuilderEnabled'
|
77
77
|
|
78
|
-
a
|
78
|
+
a << format('%<key>s = %<value>s',
|
79
79
|
key: k.to_snake,
|
80
80
|
value: quote_value(v))
|
81
81
|
end.to_hcl_obj(14)
|
@@ -91,7 +91,7 @@ module WavefrontHclOutput
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def quote_value(val)
|
94
|
-
val.gsub!(
|
94
|
+
val.gsub!('$', '$$') if val.is_a?(String)
|
95
95
|
super
|
96
96
|
end
|
97
97
|
end
|
@@ -20,11 +20,11 @@ module WavefrontWavefrontOutput
|
|
20
20
|
def raw_output
|
21
21
|
resp.each_with_object('') do |point, a|
|
22
22
|
point[:points].each do |p|
|
23
|
-
a
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
a << "#{wavefront_format(options[:'<metric>'],
|
24
|
+
p[:value],
|
25
|
+
p[:timestamp],
|
26
|
+
options[:host],
|
27
|
+
point[:tags])}\n"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -34,7 +34,7 @@ module WavefrontWavefrontOutput
|
|
34
34
|
|
35
35
|
resp[:timeseries].each_with_object([]) do |ts, a|
|
36
36
|
ts[:data].each do |point|
|
37
|
-
a
|
37
|
+
a << wavefront_format(ts[:label],
|
38
38
|
point[1],
|
39
39
|
point[0],
|
40
40
|
ts[:host],
|
@@ -46,7 +46,7 @@ module WavefrontWavefrontOutput
|
|
46
46
|
def wavefront_format(path, value, timestamp, source, tags = nil)
|
47
47
|
arr = [path, value, timestamp, format('source=%<source>s',
|
48
48
|
source: source)]
|
49
|
-
arr
|
49
|
+
arr << tags.to_wf_tag if tags && !tags.empty?
|
50
50
|
arr.join(' ')
|
51
51
|
end
|
52
52
|
end
|
@@ -10,7 +10,7 @@ class String
|
|
10
10
|
# @param indent [Integer] size of hanging indent, in chars
|
11
11
|
#
|
12
12
|
def cmd_fold(twidth = TW, indent = 10)
|
13
|
-
gsub(/(-\w) /, '\\1^').scan_line(twidth - 12).join("\n
|
13
|
+
gsub(/(-\w) /, '\\1^').scan_line(twidth - 12).join("\n#{' ' * indent}")
|
14
14
|
.restored
|
15
15
|
end
|
16
16
|
|
@@ -35,7 +35,7 @@ class String
|
|
35
35
|
# @return [String] the folded line
|
36
36
|
#
|
37
37
|
def fold(twidth = TW, indent = 10, prefix = '')
|
38
|
-
chunks = gsub(
|
38
|
+
chunks = gsub('default: ', 'default:^').scan_line(twidth - 8)
|
39
39
|
first_line = format("%<padding>s%<text>s\n",
|
40
40
|
padding: prefix,
|
41
41
|
text: chunks.shift)
|
@@ -58,7 +58,7 @@ class String
|
|
58
58
|
#
|
59
59
|
def value_fold(indent = 0, twidth = TW)
|
60
60
|
max_line_length = twidth - indent - 4
|
61
|
-
scan_line(max_line_length).join("\n
|
61
|
+
scan_line(max_line_length).join("\n#{' ' * indent}")
|
62
62
|
end
|
63
63
|
|
64
64
|
# @param width [Integer] length of longest string (width of
|
@@ -94,7 +94,7 @@ class String
|
|
94
94
|
#
|
95
95
|
def to_snake
|
96
96
|
gsub(/(.)([A-Z])/) do
|
97
|
-
Regexp.last_match[1]
|
97
|
+
"#{Regexp.last_match[1]}_#{Regexp.last_match[2].downcase}"
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -102,7 +102,7 @@ class String
|
|
102
102
|
|
103
103
|
def indent_folded_lines(chunks, twidth, indent, prefix)
|
104
104
|
chunks.join(' ').scan_line(twidth - indent - 5).map do |line|
|
105
|
-
prefix
|
105
|
+
"#{prefix}#{' ' * indent}#{line}"
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
data/lib/wavefront-cli/usage.rb
CHANGED
data/lib/wavefront-cli/write.rb
CHANGED
@@ -11,7 +11,7 @@ module WavefrontCli
|
|
11
11
|
attr_reader :fmt
|
12
12
|
|
13
13
|
include Wavefront::Mixins
|
14
|
-
SPLIT_PATTERN = /\s(?=(?:[^"]|"[^"]*")*$)
|
14
|
+
SPLIT_PATTERN = /\s(?=(?:[^"]|"[^"]*")*$)/
|
15
15
|
|
16
16
|
# rubocop:disable Metrics/AbcSize
|
17
17
|
def do_point(value = options[:'<value>'])
|
@@ -74,8 +74,8 @@ module WavefrontCli
|
|
74
74
|
end
|
75
75
|
# rubocop:enable Metrics/AbcSize
|
76
76
|
|
77
|
-
# Turn our user's representation of a distribution into one
|
78
|
-
#
|
77
|
+
# Turn our user's representation of a distribution into one which suits
|
78
|
+
# Wavefront. The SDK can do this for us.
|
79
79
|
#
|
80
80
|
def mk_dist
|
81
81
|
xpanded = expand_dist(options[:'<val>'])
|
@@ -83,7 +83,11 @@ module WavefrontCli
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def extra_options
|
86
|
-
|
86
|
+
if options[:using]
|
87
|
+
{ writer: options[:using] }
|
88
|
+
else
|
89
|
+
{ writer: :http }
|
90
|
+
end
|
87
91
|
end
|
88
92
|
|
89
93
|
# I chose to prioritise UI consistency over internal elegance
|
@@ -108,6 +112,7 @@ module WavefrontCli
|
|
108
112
|
port: options[:port] || default_port,
|
109
113
|
socket: options[:socket],
|
110
114
|
endpoint: options[:endpoint],
|
115
|
+
agent: "wavefront-cli-#{WF_CLI_VERSION}",
|
111
116
|
token: options[:token] }
|
112
117
|
end
|
113
118
|
|
@@ -115,18 +120,9 @@ module WavefrontCli
|
|
115
120
|
distribution? ? 40_000 : 2878
|
116
121
|
end
|
117
122
|
|
123
|
+
# The SDK writer plugins validate the credentials they need
|
118
124
|
def validate_opts
|
119
125
|
validate_opts_file if options[:file]
|
120
|
-
|
121
|
-
if options[:using] == 'unix'
|
122
|
-
return true if options[:socket]
|
123
|
-
|
124
|
-
raise(WavefrontCli::Exception::CredentialError, 'No socket path.')
|
125
|
-
end
|
126
|
-
|
127
|
-
return true if options[:proxy]
|
128
|
-
|
129
|
-
raise(WavefrontCli::Exception::CredentialError, 'No proxy address.')
|
130
126
|
end
|
131
127
|
|
132
128
|
def validate_opts_file
|
@@ -167,7 +163,7 @@ module WavefrontCli
|
|
167
163
|
#
|
168
164
|
def process_input_file(data)
|
169
165
|
data.each_with_object([]) do |l, a|
|
170
|
-
a
|
166
|
+
a << process_line(l)
|
171
167
|
rescue WavefrontCli::Exception::UnparseableInput => e
|
172
168
|
puts "Bad input. #{e.message}."
|
173
169
|
next
|
@@ -239,7 +235,7 @@ module WavefrontCli
|
|
239
235
|
#
|
240
236
|
def extract_ts(chunks)
|
241
237
|
ts = chunks[fmt.index('t')]
|
242
|
-
|
238
|
+
parse_time(ts) if valid_timestamp?(ts)
|
243
239
|
rescue TypeError
|
244
240
|
Time.now.utc.to_i
|
245
241
|
end
|
@@ -426,17 +422,17 @@ module WavefrontCli
|
|
426
422
|
#
|
427
423
|
def valid_timestamp?(timestamp)
|
428
424
|
(timestamp.is_a?(Integer) ||
|
429
|
-
timestamp.is_a?(String) && timestamp.match(/^\d+$/)) &&
|
425
|
+
(timestamp.is_a?(String) && timestamp.match(/^\d+$/))) &&
|
430
426
|
timestamp.to_i > 946_684_800 &&
|
431
427
|
timestamp.to_i < (Time.now.to_i + 31_557_600)
|
432
428
|
end
|
433
429
|
|
434
430
|
def setup_fmt(fmt)
|
435
|
-
@fmt = fmt.
|
431
|
+
@fmt = fmt.chars
|
436
432
|
end
|
437
433
|
|
438
434
|
def load_data(file)
|
439
|
-
|
435
|
+
File.read(file)
|
440
436
|
rescue StandardError
|
441
437
|
raise WavefrontCli::Exception::FileNotFound
|
442
438
|
end
|
data/spec/constants.rb
CHANGED
@@ -12,10 +12,9 @@ TW = 80
|
|
12
12
|
|
13
13
|
ENDPOINT = 'metrics.wavefront.com'
|
14
14
|
TOKEN = '0123456789-ABCDEF'
|
15
|
-
RES_DIR = ROOT
|
16
|
-
CF = RES_DIR
|
17
|
-
CF_VAL =
|
18
|
-
JSON_POST_HEADERS = {
|
19
|
-
|
20
|
-
}.freeze
|
15
|
+
RES_DIR = ROOT.join('spec', 'wavefront-cli', 'resources')
|
16
|
+
CF = RES_DIR.join('wavefront.conf')
|
17
|
+
CF_VAL = IniFile.load(CF)
|
18
|
+
JSON_POST_HEADERS = { 'Content-Type': 'application/json',
|
19
|
+
Accept: 'application/json' }.freeze
|
21
20
|
TEE_ZERO = Time.now.freeze
|