wavefront-cli 8.5.0 → 9.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 +37 -0
- data/.github/workflows/test.yml +23 -0
- data/.rubocop.yml +10 -9
- data/HISTORY.md +15 -0
- data/README.md +4 -2
- data/lib/wavefront-cli/base.rb +2 -2
- data/lib/wavefront-cli/commands/.rubocop.yml +2 -13
- data/lib/wavefront-cli/commands/base.rb +10 -9
- 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 +4 -4
- data/lib/wavefront-cli/constants.rb +2 -1
- data/lib/wavefront-cli/controller.rb +19 -15
- data/lib/wavefront-cli/display/base.rb +3 -2
- data/lib/wavefront-cli/display/metricspolicy.rb +15 -0
- data/lib/wavefront-cli/display/printer/long.rb +11 -13
- 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/event_store.rb +2 -2
- data/lib/wavefront-cli/exception.rb +21 -0
- 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 +3 -4
- data/lib/wavefront-cli/output/csv/query.rb +2 -2
- data/lib/wavefront-cli/output/hcl/dashboard.rb +6 -6
- 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/query.rb +1 -1
- data/lib/wavefront-cli/settings.rb +3 -4
- 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 +14 -18
- data/spec/.rubocop.yml +2 -17
- data/spec/constants.rb +4 -5
- data/spec/support/command_base.rb +12 -0
- data/spec/support/minitest_assertions.rb +15 -11
- 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/commands/base_spec.rb +4 -4
- data/spec/wavefront-cli/commands/config_spec.rb +3 -3
- data/spec/wavefront-cli/config_spec.rb +3 -3
- data/spec/wavefront-cli/controller_spec.rb +4 -0
- data/spec/wavefront-cli/dashboard_spec.rb +1 -1
- data/spec/wavefront-cli/derivedmetric_spec.rb +9 -7
- data/spec/wavefront-cli/display/printer/long_spec.rb +5 -3
- data/spec/wavefront-cli/display/printer/terse_spec.rb +1 -1
- data/spec/wavefront-cli/event_spec.rb +14 -11
- data/spec/wavefront-cli/event_store_spec.rb +16 -12
- 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 +4 -4
- data/spec/wavefront-cli/output/helpers.rb +1 -1
- data/spec/wavefront-cli/proxy_spec.rb +1 -1
- data/spec/wavefront-cli/query_spec.rb +1 -1
- data/spec/wavefront-cli/role_spec.rb +4 -3
- data/spec/wavefront-cli/serviceaccount_spec.rb +7 -7
- data/spec/wavefront-cli/stdlib/string_spec.rb +3 -1
- data/spec/wavefront-cli/usage_spec.rb +1 -1
- data/spec/wavefront-cli/{write_spec.rb → write_class_spec.rb} +1 -14
- data/wavefront-cli.gemspec +13 -12
- metadata +72 -146
- data/.travis.yml +0 -20
- data/spec/spec_helper.rb +0 -113
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
|
@@ -41,7 +41,7 @@ module WavefrontCli
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def event_file(id)
|
44
|
-
|
44
|
+
/^\d{13}:.+/.match?(id) ? dir + id : nil
|
45
45
|
end
|
46
46
|
|
47
47
|
# We can override the temp directory with the WF_EVENT_STATE_DIR env var.
|
@@ -70,7 +70,7 @@ module WavefrontCli
|
|
70
70
|
def event(id)
|
71
71
|
if !id
|
72
72
|
pop_event!
|
73
|
-
elsif
|
73
|
+
elsif /^\d{13}:.+:\d+/.match?(id)
|
74
74
|
id
|
75
75
|
else
|
76
76
|
pop_event!(id)
|
@@ -7,26 +7,47 @@ module WavefrontCli
|
|
7
7
|
#
|
8
8
|
class Exception
|
9
9
|
class CredentialError < RuntimeError; end
|
10
|
+
|
10
11
|
class MandatoryValue < RuntimeError; end
|
12
|
+
|
11
13
|
class ConfigFileNotFound < IOError; end
|
14
|
+
|
12
15
|
class FileNotFound < IOError; end
|
16
|
+
|
13
17
|
class ImpossibleSearch < RuntimeError; end
|
18
|
+
|
14
19
|
class InsufficientData < RuntimeError; end
|
20
|
+
|
15
21
|
class InvalidInput < RuntimeError; end
|
22
|
+
|
16
23
|
class InvalidQuery < RuntimeError; end
|
24
|
+
|
17
25
|
class InvalidValue < RuntimeError; end
|
26
|
+
|
18
27
|
class ProfileExists < RuntimeError; end
|
28
|
+
|
19
29
|
class ProfileNotFound < RuntimeError; end
|
30
|
+
|
20
31
|
class SystemError < RuntimeError; end
|
32
|
+
|
21
33
|
class UnhandledCommand < RuntimeError; end
|
34
|
+
|
22
35
|
class UnparseableInput < RuntimeError; end
|
36
|
+
|
23
37
|
class UnparseableResponse < RuntimeError; end
|
38
|
+
|
24
39
|
class UnparseableSearchPattern < RuntimeError; end
|
40
|
+
|
25
41
|
class UnsupportedFileFormat < RuntimeError; end
|
42
|
+
|
26
43
|
class UnsupportedNoop < RuntimeError; end
|
44
|
+
|
27
45
|
class UnsupportedOperation < RuntimeError; end
|
46
|
+
|
28
47
|
class UnsupportedOutput < RuntimeError; end
|
48
|
+
|
29
49
|
class UserGroupNotFound < RuntimeError; end
|
50
|
+
|
30
51
|
class UserError < RuntimeError; end
|
31
52
|
end
|
32
53
|
end
|
@@ -8,6 +8,7 @@ module WavefrontCli
|
|
8
8
|
# rubocop:disable Metrics/MethodLength
|
9
9
|
# rubocop:disable Metrics/AbcSize
|
10
10
|
# rubocop:disable Metrics/CyclomaticComplexity
|
11
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
11
12
|
def exception_handler(exception)
|
12
13
|
case exception
|
13
14
|
when WavefrontCli::Exception::UnhandledCommand
|
@@ -18,7 +19,8 @@ module WavefrontCli
|
|
18
19
|
abort "\nOperation aborted at user request."
|
19
20
|
when WavefrontCli::Exception::ConfigFileNotFound
|
20
21
|
abort "Configuration file #{exception}' not found."
|
21
|
-
when WavefrontCli::Exception::CredentialError
|
22
|
+
when WavefrontCli::Exception::CredentialError,
|
23
|
+
Wavefront::Exception::CredentialError
|
22
24
|
handle_missing_credentials(exception)
|
23
25
|
when WavefrontCli::Exception::MandatoryValue
|
24
26
|
abort 'A value must be supplied.'
|
@@ -26,6 +28,8 @@ module WavefrontCli
|
|
26
28
|
abort 'Connection timed out.'
|
27
29
|
when Wavefront::Exception::InvalidPermission
|
28
30
|
abort "'#{exception}' is not a valid Wavefront permission."
|
31
|
+
when Wavefront::Exception::InvalidTimestamp
|
32
|
+
abort "'#{exception}' is not a parseable time."
|
29
33
|
when Wavefront::Exception::InvalidUserGroupId
|
30
34
|
abort "'#{exception}' is not a valid user group ID."
|
31
35
|
when Wavefront::Exception::InvalidAccountId
|
@@ -38,6 +42,8 @@ module WavefrontCli
|
|
38
42
|
abort "'#{exception}' is not a valid API token ID."
|
39
43
|
when Wavefront::Exception::InvalidIngestionPolicyId
|
40
44
|
abort "'#{exception}' is not a valid ingestion policy ID."
|
45
|
+
when Wavefront::Exception::InvalidVersion
|
46
|
+
abort "'#{exception}' is not a valid version."
|
41
47
|
when WavefrontCli::Exception::InvalidValue
|
42
48
|
abort "Invalid value for #{exception}."
|
43
49
|
when WavefrontCli::Exception::ProfileExists
|
@@ -80,6 +86,7 @@ module WavefrontCli
|
|
80
86
|
abort
|
81
87
|
end
|
82
88
|
end
|
89
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
83
90
|
# rubocop:enable Metrics/MethodLength
|
84
91
|
# rubocop:enable Metrics/AbcSize
|
85
92
|
# rubocop:enable Metrics/CyclomaticComplexity
|
@@ -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
|
@@ -29,7 +29,7 @@ module WavefrontCli
|
|
29
29
|
|
30
30
|
def initialize(cli_opts = {})
|
31
31
|
cred_opts = setup_cred_opts(cli_opts)
|
32
|
-
cli_opts.
|
32
|
+
cli_opts.compact!
|
33
33
|
@opts = DEFAULT_OPTS.merge(load_profile(cred_opts)).merge(cli_opts)
|
34
34
|
rescue WavefrontCli::Exception::ConfigFileNotFound => e
|
35
35
|
abort "Configuration file '#{e}' not found."
|
@@ -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],
|
@@ -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)
|
@@ -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
|
data/lib/wavefront-cli/query.rb
CHANGED
@@ -7,6 +7,8 @@ module WavefrontCli
|
|
7
7
|
# CLI coverage for the v2 'settings' API.
|
8
8
|
#
|
9
9
|
class Settings < WavefrontCli::Base
|
10
|
+
JOBS = %w[invitePermissions defaultUserGroups].freeze
|
11
|
+
|
10
12
|
def do_list_permissions
|
11
13
|
wf.permissions
|
12
14
|
end
|
@@ -24,10 +26,7 @@ module WavefrontCli
|
|
24
26
|
k, v = o.split('=', 2)
|
25
27
|
next unless v && !v.empty?
|
26
28
|
|
27
|
-
|
28
|
-
v = v.include?(',') ? v.split(',') : [v]
|
29
|
-
end
|
30
|
-
|
29
|
+
v = v.include?(',') ? v.split(',') : [v] if JOBS.include?(k)
|
31
30
|
a[k] = v
|
32
31
|
end
|
33
32
|
|
@@ -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
|
|
@@ -50,7 +50,7 @@ class String
|
|
50
50
|
# undesirable line breaking. This puts it back
|
51
51
|
#
|
52
52
|
def restored
|
53
|
-
tr('^', ' ').chomp
|
53
|
+
tr('^', ' ').chomp
|
54
54
|
end
|
55
55
|
|
56
56
|
# Fold long value lines in two-column output. The returned string
|
@@ -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
@@ -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
|
@@ -375,7 +371,7 @@ module WavefrontCli
|
|
375
371
|
end
|
376
372
|
|
377
373
|
def format_string_is_all_valid_chars?(fmt)
|
378
|
-
return true if
|
374
|
+
return true if /^[dmstTv]+$/.match?(fmt)
|
379
375
|
|
380
376
|
raise(WavefrontCli::Exception::UnparseableInput,
|
381
377
|
'unsupported field in format string')
|
@@ -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/.rubocop.yml
CHANGED
@@ -1,23 +1,8 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
|
2
|
+
inherit_from:
|
3
|
+
- ../.rubocop.yml
|
4
4
|
|
5
5
|
Metrics/MethodLength:
|
6
6
|
Max: 30
|
7
|
-
|
8
7
|
Metrics/AbcSize:
|
9
8
|
Max: 45
|
10
|
-
|
11
|
-
Metrics/ClassLength:
|
12
|
-
Max: 300
|
13
|
-
|
14
|
-
# Is nothing sacred?
|
15
|
-
Layout/LineLength:
|
16
|
-
Max: 80
|
17
|
-
|
18
|
-
Style/IfUnlessModifier:
|
19
|
-
Enabled: false # because it wants to make lines >80 chars
|
20
|
-
Style/StringConcatenation:
|
21
|
-
Enabled: false
|
22
|
-
Style/OptionalBooleanParameter:
|
23
|
-
Enabled: false
|
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
|
15
|
+
RES_DIR = ROOT.join('spec', 'wavefront-cli', 'resources')
|
16
|
+
CF = RES_DIR.join('wavefront.conf')
|
17
17
|
CF_VAL = IniFile.load(CF)
|
18
|
-
JSON_POST_HEADERS = {
|
19
|
-
|
20
|
-
}.freeze
|
18
|
+
JSON_POST_HEADERS = { 'Content-Type': 'application/json',
|
19
|
+
Accept: 'application/json' }.freeze
|
21
20
|
TEE_ZERO = Time.now.freeze
|
@@ -9,11 +9,13 @@ require_relative '../../lib/wavefront-cli/controller'
|
|
9
9
|
# commands.
|
10
10
|
#
|
11
11
|
class EndToEndTest < MiniTest::Test
|
12
|
+
attr_accessor :single_perm
|
12
13
|
attr_reader :wf
|
13
14
|
|
14
15
|
def setup
|
15
16
|
before_setup if respond_to?(:before_setup)
|
16
17
|
@wf = WavefrontCliController
|
18
|
+
@single_perm = false
|
17
19
|
end
|
18
20
|
|
19
21
|
def api_path
|
@@ -79,4 +81,14 @@ class EndToEndTest < MiniTest::Test
|
|
79
81
|
{ status: { result: 'OK', message: '', code: 200 },
|
80
82
|
items: [] }.to_json
|
81
83
|
end
|
84
|
+
|
85
|
+
def blank_envvars
|
86
|
+
%w[WAVEFRONT_ENDPOINT WAVEFRONT_PROXY WAVEFRONT_TOKEN].each do |v|
|
87
|
+
ENV[v] = nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def config?
|
92
|
+
Pathname.new(Dir.home).join('.wavefront').exist?
|
93
|
+
end
|
82
94
|
end
|
@@ -147,10 +147,13 @@ module Minitest
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def assert_cmd_posts(command, api_path, payload = 'null',
|
150
|
-
response =
|
150
|
+
response = nil, extra_headers = {})
|
151
|
+
response ||= dummy_response
|
151
152
|
all_permutations do |p|
|
152
153
|
assert_posts("https://#{p[:endpoint]}#{api_path}",
|
153
|
-
mk_headers(p[:token]
|
154
|
+
mk_headers(p[:token], extra_headers),
|
155
|
+
payload,
|
156
|
+
response) do
|
154
157
|
wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
|
155
158
|
end
|
156
159
|
end
|
@@ -166,7 +169,7 @@ module Minitest
|
|
166
169
|
end
|
167
170
|
|
168
171
|
def assert_cmd_deletes(command, api_path, response = dummy_response)
|
169
|
-
|
172
|
+
all_permutations do |p|
|
170
173
|
assert_deletes("https://#{p[:endpoint]}#{api_path}",
|
171
174
|
mk_headers(p[:token]), response) do
|
172
175
|
wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
|
@@ -188,13 +191,14 @@ module Minitest
|
|
188
191
|
assert_empty(err)
|
189
192
|
end
|
190
193
|
|
191
|
-
# Run tests with all available permutations
|
192
|
-
#
|
193
|
-
#
|
194
|
+
# Run tests with all available permutations, unless the single_perm class
|
195
|
+
# variable is set. This lets us run tests faster by running fewer (but
|
196
|
+
# still a good random selection) and lets us run tests which must only be
|
197
|
+
# run once, like tests which pop stuff off the event stack.
|
194
198
|
#
|
195
199
|
def all_permutations
|
196
200
|
perms = permutations
|
197
|
-
perms =
|
201
|
+
perms = perms.shuffle.take(1) if @single_perm || ENV['FAST_TESTS']
|
198
202
|
|
199
203
|
perms.each do |p|
|
200
204
|
yield(p)
|
@@ -213,11 +217,11 @@ module Minitest
|
|
213
217
|
|
214
218
|
private
|
215
219
|
|
216
|
-
def mk_headers(token = nil)
|
217
|
-
{
|
220
|
+
def mk_headers(token = nil, extra_headers = {})
|
221
|
+
{ Accept: /.*/,
|
218
222
|
'Accept-Encoding': /.*/,
|
219
|
-
|
220
|
-
'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}" }
|
223
|
+
Authorization: "Bearer #{token || '0123456789-ABCDEF'}",
|
224
|
+
'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}" }.merge(extra_headers)
|
221
225
|
end
|
222
226
|
|
223
227
|
# Every command we simulate running is done under the following
|
@@ -14,7 +14,7 @@ class OutputTester
|
|
14
14
|
# @return [Object] canned raw responses used to test outputs
|
15
15
|
#
|
16
16
|
def load_input(file, only_items = true)
|
17
|
-
ret = JSON.parse(
|
17
|
+
ret = JSON.parse(File.read(RES_DIR.join('display', file)),
|
18
18
|
symbolize_names: true)
|
19
19
|
only_items ? ret[:items] : ret
|
20
20
|
end
|
@@ -23,7 +23,7 @@ class OutputTester
|
|
23
23
|
# @return [String]
|
24
24
|
#
|
25
25
|
def load_expected(file)
|
26
|
-
|
26
|
+
File.read(RES_DIR.join('display', file))
|
27
27
|
end
|
28
28
|
|
29
29
|
def in_and_out(input, expected, only_items = true)
|