wavefront-cli 6.1.0 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +34 -1
  3. data/HISTORY.md +17 -1
  4. data/README.md +2 -3
  5. data/lib/wavefront-cli/account.rb +119 -0
  6. data/lib/wavefront-cli/alert.rb +29 -0
  7. data/lib/wavefront-cli/base.rb +0 -2
  8. data/lib/wavefront-cli/commands/.rubocop.yml +34 -0
  9. data/lib/wavefront-cli/commands/account.rb +61 -0
  10. data/lib/wavefront-cli/commands/alert.rb +1 -0
  11. data/lib/wavefront-cli/commands/base.rb +1 -1
  12. data/lib/wavefront-cli/commands/query.rb +4 -1
  13. data/lib/wavefront-cli/commands/role.rb +44 -0
  14. data/lib/wavefront-cli/commands/spy.rb +0 -5
  15. data/lib/wavefront-cli/commands/usergroup.rb +7 -11
  16. data/lib/wavefront-cli/commands/write.rb +7 -2
  17. data/lib/wavefront-cli/controller.rb +5 -63
  18. data/lib/wavefront-cli/display/account.rb +122 -0
  19. data/lib/wavefront-cli/display/alert.rb +8 -0
  20. data/lib/wavefront-cli/display/base.rb +1 -1
  21. data/lib/wavefront-cli/display/cloudintegration.rb +3 -2
  22. data/lib/wavefront-cli/display/printer/long.rb +2 -1
  23. data/lib/wavefront-cli/display/role.rb +66 -0
  24. data/lib/wavefront-cli/display/settings.rb +1 -0
  25. data/lib/wavefront-cli/display/usergroup.rb +18 -14
  26. data/lib/wavefront-cli/exception_handler.rb +87 -0
  27. data/lib/wavefront-cli/output/hcl/base.rb +1 -1
  28. data/lib/wavefront-cli/query.rb +13 -7
  29. data/lib/wavefront-cli/role.rb +54 -0
  30. data/lib/wavefront-cli/serviceaccount.rb +0 -6
  31. data/lib/wavefront-cli/spy.rb +0 -8
  32. data/lib/wavefront-cli/usergroup.rb +8 -8
  33. data/lib/wavefront-cli/version.rb +1 -1
  34. data/lib/wavefront-cli/write.rb +28 -4
  35. data/spec/.rubocop.yml +34 -0
  36. data/spec/test_mixins/delete.rb +1 -2
  37. data/spec/wavefront-cli/account_spec.rb +303 -0
  38. data/spec/wavefront-cli/alert_spec.rb +28 -0
  39. data/spec/wavefront-cli/commands/write_spec.rb +1 -1
  40. data/spec/wavefront-cli/event_spec.rb +1 -1
  41. data/spec/wavefront-cli/output/csv/query_spec.rb +1 -1
  42. data/spec/wavefront-cli/output/wavefront/query_spec.rb +2 -2
  43. data/spec/wavefront-cli/query_spec.rb +20 -3
  44. data/spec/wavefront-cli/role_spec.rb +187 -0
  45. data/spec/wavefront-cli/serviceaccount_spec.rb +3 -3
  46. data/spec/wavefront-cli/usergroup_spec.rb +48 -43
  47. data/spec/wavefront-cli/write_spec.rb +44 -0
  48. data/wavefront-cli.gemspec +3 -3
  49. metadata +30 -27
  50. data/lib/wavefront-cli/commands/user.rb +0 -54
  51. data/lib/wavefront-cli/display/user.rb +0 -103
  52. data/lib/wavefront-cli/user.rb +0 -92
  53. data/spec/wavefront-cli/resources/responses/user-list.json +0 -1
  54. data/spec/wavefront-cli/user_spec.rb +0 -311
@@ -34,9 +34,4 @@ class WavefrontCommandSpy < WavefrontCommandBase
34
34
  '-T, --tag-key=TAG only show metrics with the given point tag key',
35
35
  '-y, --type=STRING one of METRIC, SPAN, HOST, or STRING']
36
36
  end
37
-
38
- def postscript
39
- "\nNOTE: This command uses the unofficial 'spy' API endpoint, which " \
40
- 'is not guaranteed to remain stable.'.cmd_fold(TW, 0)
41
- end
42
37
  end
@@ -24,17 +24,18 @@ class WavefrontCommandUsergroup < WavefrontCommandBase
24
24
  def _commands
25
25
  ["list #{CMN} [-al] [-O fields] [-o offset] [-L limit]",
26
26
  "describe #{CMN} <id>",
27
- "create #{CMN} [-p permission...] <name>",
27
+ "create #{CMN} [-r role_id...] <name>",
28
28
  "delete #{CMN} <id>",
29
29
  "dump #{CMN}",
30
30
  "import #{CMN} [-uU] <file>",
31
31
  "set #{CMN} <key=value> <id>",
32
+ "add to #{CMN} <id> <user>...",
33
+ "remove from #{CMN} <id> <user>...",
32
34
  "users #{CMN} <id>",
35
+ "add role #{CMN} <id> <role>...",
36
+ "remove role #{CMN} <id> <role>...",
37
+ "roles #{CMN} <id>",
33
38
  "permissions #{CMN} <id>",
34
- "add user #{CMN} <id> <user>...",
35
- "remove user #{CMN} <id> <user>...",
36
- "grant #{CMN} <permission> to <id>",
37
- "revoke #{CMN} <permission> from <id>",
38
39
  "search #{CMN} [-al] [-o offset] [-L limit] [-O fields] <condition>..."]
39
40
  end
40
41
 
@@ -47,11 +48,6 @@ class WavefrontCommandUsergroup < WavefrontCommandBase
47
48
  '-O, --fields=F1,F2,... only show given fields',
48
49
  "-u, --update update an existing #{thing}",
49
50
  "-U, --upsert import new or update existing #{thing}",
50
- '-p, --permission=STRING Wavefront permission']
51
- end
52
-
53
- def postscript
54
- "'wf settings list permissions' will give you a list of all " \
55
- 'currently supported permissions.'.fold(TW, 0)
51
+ '-r, --role-id=STRING Wavefront role ID']
56
52
  end
57
53
  end
@@ -18,7 +18,9 @@ class WavefrontCommandWrite < WavefrontCommandBase
18
18
  '<metric> [--] <val>...',
19
19
  'file [-DnViq] [-c file] [-P profile] [-E proxy] [-H host] ' \
20
20
  '[-p port] [-F infileformat] [-m metric] [-T tag...] [-I interval] ' \
21
- '[-u method] [-S socket] <file>']
21
+ '[-u method] [-S socket] <file>',
22
+ 'noise [-DnViq] [-P profile] [-E proxy] [-H host] [-p port] ' \
23
+ '[-T tag...] [-I interval] [-x value] [-X value] <metric>']
22
24
  end
23
25
 
24
26
  def _options
@@ -33,9 +35,12 @@ class WavefrontCommandWrite < WavefrontCommandBase
33
35
  'a file will be assigned. If the file contains a metric name, ' \
34
36
  'the two will be dot-concatenated, with this value first',
35
37
  '-i, --delta increment metric by given value',
36
- "-I, --interval=INTERVAL interval of distribution (default 'm')",
38
+ "-I, --interval=INTERVAL interval of distribution (default 'm'), or " \
39
+ 'time in seconds between noise values (default 1)',
37
40
  '-u, --using=METHOD method by which to send points',
38
41
  '-S, --socket=FILE Unix datagram socket',
42
+ '-x, --min=NUMERIC lower bound of random values (default -10)',
43
+ '-X, --max=NUMERIC upper bound of random values (default 10)',
39
44
  "-q, --quiet don't report the points sent summary " \
40
45
  '(unless there were errors)']
41
46
  end
@@ -17,6 +17,7 @@ require_relative 'version'
17
17
  require_relative 'constants'
18
18
  require_relative 'exception'
19
19
  require_relative 'opt_handler'
20
+ require_relative 'exception_handler'
20
21
  require_relative 'stdlib/string'
21
22
 
22
23
  CMD_DIR = Pathname.new(__dir__) + 'commands'
@@ -28,6 +29,7 @@ class WavefrontCliController
28
29
  attr_reader :args, :usage, :opts, :cmds, :tw
29
30
 
30
31
  include WavefrontCli::Constants
32
+ include WavefrontCli::ExceptionMixins
31
33
 
32
34
  def initialize(args)
33
35
  @args = args
@@ -107,12 +109,8 @@ class WavefrontCliController
107
109
  #
108
110
  def cli_class(cmd, opts)
109
111
  load_cli_class(cmd, opts)
110
- rescue WavefrontCli::Exception::UnhandledCommand
111
- abort 'Fatal error. Unsupported command. Please open a Github issue.'
112
- rescue WavefrontCli::Exception::InvalidInput => e
113
- abort "Invalid input. #{e.message}"
114
- rescue RuntimeError => e
115
- abort "Unable to run command. #{e.message}."
112
+ rescue StandardError => e
113
+ exception_handler(e)
116
114
  end
117
115
 
118
116
  def load_cli_class(cmd, opts)
@@ -120,68 +118,12 @@ class WavefrontCliController
120
118
  Object.const_get('WavefrontCli').const_get(cmds[cmd].sdk_class).new(opts)
121
119
  end
122
120
 
123
- # rubocop:disable Metrics/MethodLength
124
- # rubocop:disable Metrics/AbcSize
125
121
  def run_command(cli_class_obj)
126
122
  cli_class_obj.validate_opts
127
123
  cli_class_obj.run
128
- rescue Interrupt
129
- abort "\nOperation aborted at user request."
130
- rescue WavefrontCli::Exception::ConfigFileNotFound => e
131
- abort "Configuration file #{e}' not found."
132
- rescue WavefrontCli::Exception::CredentialError => e
133
- handle_missing_credentials(e)
134
- rescue WavefrontCli::Exception::MandatoryValue
135
- abort 'A value must be supplied.'
136
- rescue Wavefront::Exception::NetworkTimeout
137
- abort 'Connection timed out.'
138
- rescue Wavefront::Exception::InvalidPermission => e
139
- abort "'#{e}' is not a valid privilege."
140
- rescue Wavefront::Exception::InvalidUserGroupId => e
141
- abort "'#{e}' is not a valid user group id."
142
- rescue WavefrontCli::Exception::InvalidValue => e
143
- abort "Invalid value for #{e}."
144
- rescue WavefrontCli::Exception::ProfileExists => e
145
- abort "Profile '#{e}' already exists."
146
- rescue WavefrontCli::Exception::ProfileNotFound => e
147
- abort "Profile '#{e}' not found."
148
- rescue WavefrontCli::Exception::FileNotFound
149
- abort 'File not found.'
150
- rescue WavefrontCli::Exception::InsufficientData => e
151
- abort "Insufficient data. #{e.message}"
152
- rescue WavefrontCli::Exception::InvalidQuery => e
153
- abort "Invalid query. API message: '#{e.message}'."
154
- rescue WavefrontCli::Exception::SystemError => e
155
- abort "Host system error. #{e.message}"
156
- rescue WavefrontCli::Exception::UnparseableInput => e
157
- abort "Cannot parse input. #{e.message}"
158
- rescue WavefrontCli::Exception::UnparseableSearchPattern
159
- abort 'Searches require a key, a value, and a match operator.'
160
- rescue WavefrontCli::Exception::UnsupportedFileFormat
161
- abort 'Unsupported file format.'
162
- rescue WavefrontCli::Exception::UnsupportedOperation => e
163
- abort "Unsupported operation.\n#{e.message}"
164
- rescue WavefrontCli::Exception::UnsupportedOutput => e
165
- abort e.message
166
- rescue WavefrontCli::Exception::UnsupportedNoop
167
- abort 'Multiple API call operations cannot be performed as no-ops.'
168
- rescue WavefrontCli::Exception::UserGroupNotFound => e
169
- abort "Cannot find user group '#{e.message}'."
170
- rescue Wavefront::Exception::UnsupportedWriter => e
171
- abort "Unsupported writer '#{e.message}'."
172
- rescue WavefrontCli::Exception::UserError => e
173
- abort "User error: #{e.message}."
174
- rescue WavefrontCli::Exception::ImpossibleSearch
175
- abort 'Search on non-existent key. Please use a top-level field.'
176
- rescue Wavefront::Exception::InvalidSamplingValue
177
- abort 'Sampling rates must be between 0 and 0.05.'
178
124
  rescue StandardError => e
179
- warn "general error: #{e}"
180
- backtrace_message(e)
181
- abort
125
+ exception_handler(e)
182
126
  end
183
- # rubocop:enable Metrics/MethodLength
184
- # rubocop:enable Metrics/AbcSize
185
127
 
186
128
  def backtrace_message(err)
187
129
  if opts[:debug]
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module WavefrontDisplay
6
+ #
7
+ # Format human-readable output for account management.
8
+ #
9
+ class Account < Base
10
+ def do_list_brief
11
+ filter_user_list
12
+ puts(data.map { |account| account[:identifier] })
13
+ end
14
+
15
+ def do_list
16
+ filter_user_list
17
+ super
18
+ end
19
+
20
+ def do_role_add_to
21
+ puts format("Gave %<quoted_roles>s to '%<id>s'.",
22
+ id: options[:'<id>'],
23
+ quoted_roles: quoted(options[:'<role>']))
24
+ end
25
+
26
+ def do_role_remove_from
27
+ puts format("Removed %<quoted_roles>s from '%<id>s'.",
28
+ id: options[:'<id>'],
29
+ quoted_roles: quoted(options[:'<role>']))
30
+ end
31
+
32
+ def do_roles
33
+ roles = data.fetch(:roles, [])
34
+ puts roles.empty? ? "'#{options[:'<id>']}' has no roles." : roles
35
+ end
36
+
37
+ def do_group_add_to
38
+ puts format("Added '%<id>s' to %<quoted_group>s.",
39
+ id: options[:'<id>'],
40
+ quoted_group: quoted(options[:'<group>']))
41
+ end
42
+
43
+ def do_group_remove_from
44
+ puts format("Removed '%<id>s' from %<quoted_group>s.",
45
+ id: options[:'<id>'],
46
+ quoted_group: quoted(options[:'<group>']))
47
+ end
48
+
49
+ def do_groups
50
+ groups = data.fetch(:userGroups, [])
51
+
52
+ if groups.empty?
53
+ puts "'#{options[:'<id>']}' does not belong to any groups."
54
+ else
55
+ puts groups.sort
56
+ end
57
+ end
58
+
59
+ def do_business_functions
60
+ puts data.sort
61
+ end
62
+
63
+ def do_grant_to
64
+ puts format("Granted '%<permission>s' to %<quoted_accounts>s.",
65
+ permission: options[:'<permission>'],
66
+ quoted_accounts: quoted(options[:'<account>']))
67
+ end
68
+
69
+ def do_revoke_from
70
+ puts format("Revoked '%<permission>s' from %<quoted_accounts>s.",
71
+ permission: options[:'<permission>'],
72
+ quoted_accounts: quoted(options[:'<account>']))
73
+ end
74
+
75
+ def do_permissions
76
+ perms = data.fetch(:groups, [])
77
+
78
+ if perms.empty?
79
+ puts "'#{options[:'<id>']}' does not have any permissions directly " \
80
+ 'attached.'
81
+ else
82
+ puts perms.sort
83
+ end
84
+ end
85
+
86
+ def do_ingestionpolicy_add_to
87
+ puts format("Added '%<policy>s' to '%<id>s'.",
88
+ id: options[:'<id>'],
89
+ policy: options[:'<policy>'])
90
+ end
91
+
92
+ def do_ingestionpolicy_remove_from
93
+ puts format("Removed '%<policy>s' from '%<id>s'.",
94
+ id: options[:'<id>'],
95
+ policy: options[:'<policy>'])
96
+ end
97
+
98
+ def do_ingestionpolicy
99
+ policy = data.fetch(:ingestionPolicyId, [])
100
+
101
+ if policy.empty?
102
+ puts "'#{options[:'<id>']}' has no ingestion policy."
103
+ else
104
+ puts policy
105
+ end
106
+ end
107
+
108
+ def do_invite_user
109
+ puts format("Sent invitation to '%<id>s'.", id: options[:'<id>'])
110
+ end
111
+
112
+ private
113
+
114
+ def filter_user_list
115
+ if options[:user]
116
+ data.delete_if { |a| a[:identifier].start_with?('sa::') }
117
+ elsif options[:service]
118
+ data.delete_if { |a| !a[:identifier].start_with?('sa::') }
119
+ end
120
+ end
121
+ end
122
+ end
@@ -74,5 +74,13 @@ module WavefrontDisplay
74
74
  def do_version
75
75
  puts data.max
76
76
  end
77
+
78
+ def do_affected_hosts
79
+ if data == [nil]
80
+ puts 'Alert event is not attached to any hosts.'
81
+ else
82
+ long_output
83
+ end
84
+ end
77
85
  end
78
86
  end
@@ -112,7 +112,7 @@ module WavefrontDisplay
112
112
  # long listing objects. Subclasses may define their own.
113
113
  #
114
114
  def priority_keys
115
- %i[id name]
115
+ %i[id name identifier]
116
116
  end
117
117
 
118
118
  def prioritize_keys(data, keys)
@@ -8,11 +8,12 @@ module WavefrontDisplay
8
8
  #
9
9
  class CloudIntegration < Base
10
10
  def do_list_brief
11
- multicolumn(:id, :service)
11
+ multicolumn(:id, :service, :name)
12
12
  end
13
13
 
14
14
  def do_describe
15
- readable_time(:lastReceivedDataPointMs, :lastProcessingTimestamp)
15
+ readable_time(:lastReceivedDataPointMs, :lastProcessingTimestamp,
16
+ :createdEpochMillis, :updatedEpochMillis)
16
17
  drop_fields(:forceSave, :inTrash, :deleted)
17
18
  long_output
18
19
  end
@@ -8,6 +8,7 @@ module WavefrontDisplayPrinter
8
8
  #
9
9
  class Long
10
10
  attr_reader :opts, :list, :kw
11
+
11
12
  #
12
13
  # @param data [Hash] of data to display
13
14
  # @param fields [Array[Symbol]] requred fields
@@ -55,7 +56,7 @@ module WavefrontDisplayPrinter
55
56
  def preened_value(value)
56
57
  return value unless value.is_a?(String) && value =~ /<.*>/
57
58
 
58
- value.gsub(%r{<\/?[^>]*>}, '').delete("\n")
59
+ value.gsub(%r{</?[^>]*>}, '').delete("\n")
59
60
  end
60
61
 
61
62
  # A recursive function which takes a structure, most likely a
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module WavefrontDisplay
6
+ #
7
+ # Format human-readable output for role command
8
+ #
9
+ class Role < Base
10
+ def do_list_brief
11
+ data.map! do |d|
12
+ d.merge(acct_count: "#{d[:linkedAccountsCount]} accounts",
13
+ group_count: "#{d[:linkedGroupsCount]} groups")
14
+ end
15
+ multicolumn(:id, :name, :acct_count, :group_count)
16
+ end
17
+
18
+ def do_accounts
19
+ if data.empty?
20
+ puts "No accounts have role '#{options[:'<id>']}'."
21
+ else
22
+ multicolumn(:identifier)
23
+ end
24
+ end
25
+
26
+ def do_groups
27
+ if data.empty?
28
+ puts "No groups have role '#{options[:'<id>']}'."
29
+ else
30
+ multicolumn(:id, :name)
31
+ end
32
+ end
33
+
34
+ def do_permissions
35
+ if data[:permissions].empty?
36
+ puts "Role '#{options[:'<id>']}' has no permissions."
37
+ else
38
+ puts data[:permissions]
39
+ end
40
+ end
41
+
42
+ def do_grant
43
+ puts format("Granted '%<perm>s' permission to '%<id>s'.",
44
+ perm: options[:'<permission>'],
45
+ id: options[:'<id>'])
46
+ end
47
+
48
+ def do_revoke
49
+ puts format("Revoked '%<perm>s' permission from '%<id>s'.",
50
+ perm: options[:'<permission>'],
51
+ id: options[:'<id>'])
52
+ end
53
+
54
+ def do_give_to
55
+ puts format("Gave '%<role>s' to %<members>s.",
56
+ members: quoted(options[:'<member>']),
57
+ role: options[:'<id>']).fold(TW, 0)
58
+ end
59
+
60
+ def do_take_from
61
+ puts format("Took '%<role>s' from %<members>s.",
62
+ members: quoted(options[:'<member>']),
63
+ role: options[:'<id>']).fold(TW, 0)
64
+ end
65
+ end
66
+ end
@@ -8,6 +8,7 @@ module WavefrontDisplay
8
8
  #
9
9
  class Settings < Base
10
10
  def do_list_permissions
11
+ data.sort_by! { |p| p[:groupName] }
11
12
  options[:long] ? long_output : multicolumn(:groupName)
12
13
  end
13
14
 
@@ -15,28 +15,28 @@ module WavefrontDisplay
15
15
  puts "Deleted user group '#{options[:'<id>']}'."
16
16
  end
17
17
 
18
- def do_add_user
18
+ def do_add_to
19
19
  puts format("Added %<quoted_user>s to '%<group_id>s'.",
20
20
  quoted_user: quoted(options[:'<user>']),
21
21
  group_id: options[:'<id>']).fold(TW, 0)
22
22
  end
23
23
 
24
- def do_remove_user
24
+ def do_remove_from
25
25
  puts format("Removed %<quoted_user>s from '%<group_id>s'.",
26
26
  quoted_user: quoted(options[:'<user>']),
27
27
  group_id: options[:'<id>']).fold(TW, 0)
28
28
  end
29
29
 
30
- def do_grant
31
- puts format("Granted '%<perm>s' permission to '%<group_id>s'.",
32
- perm: options[:'<permission>'],
33
- group_id: options[:'<id>'])
30
+ def do_add_role
31
+ puts format("Added %<quoted_role>s to '%<group_id>s'.",
32
+ quoted_role: quoted(options[:'<role>']),
33
+ group_id: options[:'<id>']).fold(TW, 0)
34
34
  end
35
35
 
36
- def do_revoke
37
- puts format("Revoked '%<perm>s' permission from '%<group_id>s'.",
38
- perm: options[:'<permission>'],
39
- group_id: options[:'<id>'])
36
+ def do_remove_role
37
+ puts format("Removed %<quoted_role>s from '%<group_id>s'.",
38
+ quoted_role: quoted(options[:'<role>']),
39
+ group_id: options[:'<id>']).fold(TW, 0)
40
40
  end
41
41
 
42
42
  def do_users
@@ -47,12 +47,16 @@ module WavefrontDisplay
47
47
  end)
48
48
  end
49
49
 
50
- def do_permissions
51
- puts(if !data.include?(:permissions) || data[:permissions].empty?
52
- "Group '#{options[:'<id>']}' has no permissions."
50
+ def do_roles
51
+ puts(if !data.include?(:roles) || data[:roles].empty?
52
+ "Group '#{options[:'<id>']}' has no roles attached."
53
53
  else
54
- data[:permissions]
54
+ data[:roles].map { |r| r[:id] }
55
55
  end)
56
56
  end
57
+
58
+ def do_permissions
59
+ puts data[:roles].map { |r| r[:permissions] }.flatten.sort.uniq
60
+ end
57
61
  end
58
62
  end