wavefront-cli 8.2.0 → 8.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afeb72ce32ce32e70e1f405234608ce5109d039aa6045b89e73e8351d95e459f
4
- data.tar.gz: 06b2ab6daedba6a696b9c63208bfe9465695f224f6fab58c49c9408051f81e3f
3
+ metadata.gz: 363b1be94331165aacf1538c797d07bdbefda71e801335bb4e35df97cb0bd950
4
+ data.tar.gz: 5563b27f93c679dde5947c220d80c37816ba6faf8844d08111cbf7dcc65a76c1
5
5
  SHA512:
6
- metadata.gz: 75b2159704ea25f5f1dea58b16e9e968b9b3ba17668a6f014a0ff75ce63be91179601a5cc917ab526b281a36d3c4e254ec8dbe0af9ac57f21274a4fbeeb5faab
7
- data.tar.gz: 672954a741cf305255820402b0a62bf9ac8facafb9e5fbf63c633a3355117516253cc50e68247fb019e7b1797f6117062acf32b3e30d012e995a55e37c0bb53f
6
+ metadata.gz: ce61f68ba09a6ba395143fa92abeadcdb0de127f8991fe61b979ae49379d026973c5d47a09d6d4f0b306006a15f95a717cac02160af0b727f2858ba66a9fddae
7
+ data.tar.gz: 111d9d52a0e0c3955164e1872198531b9e2bd61184dc430050029efdf8d19f9cd845885a7f1d5d5685d03dbf7de0845453d95f888e13eb0195b83fd25437116d
data/HISTORY.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 8.5.0 (2021-01-12)
4
+ * Allow attachment of roles and ingestion policies when creating service
5
+ accounts.
6
+ * Improved introspection of service accounts.
7
+ * Refactor `event` command. This improves test coverage, fixes handling
8
+ event names with numeric suffix, and fixes searching.
9
+
10
+ ## 8.4.1 (2021-01-04)
11
+ * Bugfix docopt error on `event` command.
12
+
13
+ ## 8.4.0 (2020-12-16)
14
+ * Add `-f raw` option to dump the raw API response.
15
+ * Bugfix `set` subcommand, which was not reliable on certain object types.
16
+ * Require >=5.4.1 of [the SDK](https://github.com/snltd/wavefront-sdk).
17
+
18
+ ## 8.3.1 (2020-11-17)
19
+ * Catch ctrl-c properly.
20
+
21
+ ## 8.3.0 (2020-10-31)
22
+ * Add `wf proxy shutdown` command.
23
+
3
24
  ## 8.2.0 (2020-10-06)
4
25
  * Display spans in human-readable query output.
5
26
 
@@ -12,7 +33,6 @@
12
33
 
13
34
  ## 8.0.0 (2020-09-20
14
35
  * Drop Ruby 2.4.0 support. (Breaking change.)
15
- >>>>>>> master
16
36
 
17
37
  ## 7.2.0 (2020-08-12)
18
38
  * Add `cloudintegration awsid generate` command.
@@ -147,6 +147,7 @@ module WavefrontCli
147
147
  noop: options[:noop] }
148
148
 
149
149
  ret[:verbose] = options[:noop] ? true : options[:verbose]
150
+ ret[:raw_response] = true if options[:format] == 'raw'
150
151
 
151
152
  ret.merge!(extra_options) if respond_to?(:extra_options)
152
153
  ret
@@ -228,6 +229,8 @@ module WavefrontCli
228
229
 
229
230
  exit if options[:noop]
230
231
 
232
+ ok_exit data if options[:format] == 'raw'
233
+
231
234
  check_response_blocks(data)
232
235
  warning_message(data.status)
233
236
  status_error_handler(data, method)
@@ -10,15 +10,14 @@ class WavefrontCommandEvent < WavefrontCommandBase
10
10
  end
11
11
 
12
12
  def _commands
13
- ["list #{CMN} [-l] [-O fields] [-s start] [-e end] " \
14
- '[-L limit] [-o cursor]',
13
+ ["list #{CMN} [-l] [-O fields] [-s start] [-e end] [-L limit] [-o cursor]",
15
14
  "describe #{CMN} <id>",
16
- "create #{CMN} [-d description] [-s time] [-i | -e time] " \
15
+ "create #{CMN} [-d description] [-s start] [-i | -e end] " \
17
16
  '[-S severity] [-T type] [-H host...] [-g tag...] [-N] <event>',
18
17
  "close #{CMN} [<id>]",
19
18
  "delete #{CMN} <id>",
20
19
  "set #{CMN} <key=value> <id>",
21
- "search #{CMN} [-o offset] [-L limit] [-l] [-O fields] <condition>...",
20
+ "search #{CMN} [-al] [-o cursor] [-L limit] [-O fields] <condition>...",
22
21
  "wrap #{CMN} [-C command] [-d description] [-S severity] [-T type] " \
23
22
  '[-H host...] [-g tag...] <event>',
24
23
  tag_commands,
@@ -28,11 +27,14 @@ class WavefrontCommandEvent < WavefrontCommandBase
28
27
  def _options
29
28
  [common_options,
30
29
  "-l, --long list #{things} in detail",
30
+ "-a, --all list all #{things}",
31
31
  "-o, --cursor=EVENT start listing from given #{thing}",
32
32
  '-O, --fields=F1,F2,... only show given fields',
33
33
  "-L, --limit=COUNT number of #{things} to list",
34
- "-s, --start=TIME time at which #{thing} begins",
35
- "-e, --end=TIME time at which #{thing} ends",
34
+ "-s, --start=TIME start of listed #{things} or time at which " \
35
+ "#{thing} begins",
36
+ "-e, --end=TIME end of listed #{things} or time at which " \
37
+ "#{thing} ends",
36
38
  "-S, --severity=SEVERITY severity of #{thing}",
37
39
  "-i, --instant create an instantaneous #{thing}",
38
40
  "-T, --type=TYPE type of #{thing}",
@@ -16,6 +16,7 @@ class WavefrontCommandProxy < WavefrontCommandBase
16
16
  "undelete #{CMN} <id>",
17
17
  "rename #{CMN} <id> <name>",
18
18
  "search #{CMN} [-al] [-o offset] [-L limit] [-O fields] <condition>...",
19
+ "shutdown #{CMN} <id>",
19
20
  "versions #{CMN}"]
20
21
  end
21
22
 
@@ -20,14 +20,15 @@ class WavefrontCommandServiceaccount < WavefrontCommandBase
20
20
  def _commands
21
21
  ["list #{CMN} [-l] [-O fields]",
22
22
  "describe #{CMN} <id>",
23
- "create #{CMN} [-I] [-d description] [-p permission...] [-g group...] " \
24
- '[-k usertoken...] <id>',
23
+ "create #{CMN} [-I] [-d description] [-p policy] [-r role...] " \
24
+ '[-g group...] [-k usertoken...] <id>',
25
25
  "activate #{CMN} <id>",
26
26
  "delete #{CMN} <account>...",
27
27
  "deactivate #{CMN} <id>",
28
28
  "dump #{CMN}",
29
29
  "groups #{CMN} <id>",
30
- "permissions #{CMN} <id>",
30
+ "roles #{CMN} <id>",
31
+ "ingestionpolicy #{CMN} <id>",
31
32
  "join #{CMN} <id> <group>...",
32
33
  "leave #{CMN} <id> <group>...",
33
34
  "grant #{CMN} <permission> to <id>",
@@ -52,7 +53,8 @@ class WavefrontCommandServiceaccount < WavefrontCommandBase
52
53
  "-U, --upsert import new or update existing #{thing}",
53
54
  "-I, --inactive create an inactive #{thing}",
54
55
  "-d, --desc=STRING description of #{thing}",
55
- "-p, --permission=STRING give #{thing} this permission",
56
+ "-r, --role=STRING give #{thing} this role",
57
+ "-p, --policy=STRING give #{thing} this ingestion policy",
56
58
  "-g, --group=STRING add #{thing} to this user group",
57
59
  '-N, --name=STRING name of token',
58
60
  '-k, --usertoken=STRING API token']
@@ -39,6 +39,15 @@ class WavefrontCliController
39
39
  @opts = parse_opts(opts)
40
40
  cli_class_obj = cli_class(cmd, @opts)
41
41
  run_command(cli_class_obj)
42
+ rescue Interrupt
43
+ handle_interrupt!
44
+ end
45
+
46
+ def handle_interrupt!
47
+ raise if opts[:debug]
48
+
49
+ puts "\nCancelled at user's request."
50
+ exit 0
42
51
  end
43
52
 
44
53
  # What you see when you do 'wf --help'
@@ -26,6 +26,10 @@ module WavefrontDisplay
26
26
  multicolumn(:id, :version, :name)
27
27
  end
28
28
 
29
+ def do_shutdown
30
+ puts "Requested shutdown of proxy '#{options[:'<id>']}'."
31
+ end
32
+
29
33
  private
30
34
 
31
35
  def filter_inactive_proxies!
@@ -35,14 +35,22 @@ module WavefrontDisplay
35
35
  end
36
36
  end
37
37
 
38
+ def do_roles
39
+ if data[:roles].empty?
40
+ puts 'Account does not have any roles attached.'
41
+ else
42
+ data[:roles].each { |r| puts format('%<id>s (%<name>s)', r) }
43
+ end
44
+ end
45
+
38
46
  alias do_join do_groups
39
47
  alias do_leave do_groups
40
48
 
41
- def do_permissions
42
- if data[:groups].empty?
43
- puts 'Account does not have any Wavefront permissions.'
49
+ def do_ingestionpolicy
50
+ if data[:ingestionPolicy].empty?
51
+ puts 'Account does not have an ingestion policy attached.'
44
52
  else
45
- puts data[:groups]
53
+ puts format('%<id>s (%<name>s)', data[:ingestionPolicy])
46
54
  end
47
55
  end
48
56
 
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
- require 'open3'
5
3
  require 'wavefront-sdk/support/mixins'
6
4
  require_relative 'base'
5
+ require_relative 'event_store'
7
6
  require_relative 'command_mixins/tag'
8
7
 
9
8
  module WavefrontCli
@@ -11,14 +10,13 @@ module WavefrontCli
11
10
  # CLI coverage for the v2 'event' API.
12
11
  #
13
12
  class Event < Base
14
- attr_reader :state_dir
13
+ attr_reader :state
15
14
 
16
15
  include Wavefront::Mixins
17
16
  include WavefrontCli::Mixin::Tag
18
17
 
19
- def post_initialize(_options)
20
- @state_dir = event_state_dir + (Etc.getlogin || 'notty')
21
- create_dir(state_dir)
18
+ def post_initialize(options)
19
+ @state = WavefrontCli::EventStore.new(options)
22
20
  end
23
21
 
24
22
  def do_list
@@ -31,38 +29,14 @@ module WavefrontCli
31
29
  t_start = parse_time(opts[:start], true)
32
30
  body = create_body(opts, t_start)
33
31
  resp = wf.create(body)
34
- create_state_file(resp.response[:id]) if state_file_needed?(opts)
35
- resp
36
- end
37
-
38
- def state_file_needed?(opts)
39
- !(opts[:nostate] || opts[:end] || opts[:instant])
40
- end
41
-
42
- # The user doesn't have to give us an event ID. If no event
43
- # name is given, we'll pop the last event off the stack. If an
44
- # event name is given and it doesn't look like a full WF event
45
- # name, we'll look for something on the stack. If it does look
46
- # like a real event, we'll make an API call straight away.
47
- #
48
- def do_close(id = nil)
49
- id ||= options[:'<id>']
50
- ev = local_event(id)
51
- ev_file = event_file(id)
52
-
53
- abort "No locally stored event matches '#{id}'." unless ev
54
-
55
- res = wf.close(ev)
56
- ev_file.unlink if ev_file&.exist? && res.status.code == 200
57
- res
58
- end
32
+ return if opts[:noop]
59
33
 
60
- def event_file(id)
61
- id =~ /^\d{13}:.+/ ? state_dir + id : nil
34
+ state.create!(resp.response[:id])
35
+ resp
62
36
  end
63
37
 
64
38
  def do_show
65
- events = local_event_list
39
+ events = state.list
66
40
 
67
41
  if events.size.zero?
68
42
  puts 'No open events.'
@@ -77,21 +51,54 @@ module WavefrontCli
77
51
  create_opts = options
78
52
  create_opts[:desc] ||= create_opts[:command]
79
53
  event_id = do_create(create_opts).response.id
80
- exit_code = run_wrapped_cmd(options[:command])
54
+ exit_code = state.run_wrapped_cmd(options[:command])
81
55
  do_close(event_id)
82
56
  puts "Command exited #{exit_code}."
83
57
  exit exit_code
84
58
  end
85
59
 
86
- # We can override the temp directory with the WF_EVENT_STATE_DIR. This is
87
- # primarily for testing.
60
+ # The user doesn't have to give us an event ID. If no event name is given,
61
+ # we'll pop the last event off the stack. If an event name is given and it
62
+ # doesn't look like a full WF event name, we'll look for something on the
63
+ # stack. If it does look like a real event, we'll make an API call
64
+ # straight away.
88
65
  #
89
- def event_state_dir
90
- if ENV['WF_EVENT_STATE_DIR']
91
- Pathname.new(ENV['WF_EVENT_STATE_DIR'])
92
- else
93
- EVENT_STATE_DIR
94
- end
66
+ def do_close(id = nil)
67
+ id ||= options[:'<id>']
68
+ ev = state.event(id)
69
+ ev_file = state.event_file(id)
70
+
71
+ abort "No locally stored event matches '#{id}'." unless ev
72
+
73
+ res = wf.close(ev)
74
+ ev_file.unlink if ev_file&.exist? && res.status.code == 200
75
+ res
76
+ end
77
+
78
+ # We have to override the normal validation methods because an event can
79
+ # be referred to by only a part of its name. This happens when the user
80
+ # refers to events on the local stack.
81
+ #
82
+ def validate_input
83
+ validate_id if options[:'<id>'] && !options[:close]
84
+ validate_tags if options[:'<tag>']
85
+ validate_tags(:evtag) if options[:evtag]
86
+ send(:extra_validation) if respond_to?(:extra_validation)
87
+ end
88
+
89
+ def list_args
90
+ [window_start,
91
+ window_end,
92
+ options[:limit] || 100,
93
+ options[:cursor] || nil]
94
+ end
95
+
96
+ def window_start
97
+ parse_time((options[:start] || Time.now - 600), true)
98
+ end
99
+
100
+ def window_end
101
+ parse_time((options[:end] || Time.now), true)
95
102
  end
96
103
 
97
104
  # return [Hash] body for #create() method
@@ -122,128 +129,5 @@ module WavefrontCli
122
129
  r[:type] = opts[:type] if opts[:type]
123
130
  end
124
131
  end
125
-
126
- # @return a local event from the stack directory
127
- #
128
- def local_event(id)
129
- if !id
130
- pop_event
131
- elsif id =~ /^\d{13}:.+/
132
- id
133
- else
134
- pop_event(id)
135
- end
136
- end
137
-
138
- def local_event_list
139
- events = state_dir.children
140
- abort 'No locally recorded events.' if events.empty?
141
-
142
- events
143
- rescue Errno::ENOENT
144
- raise(WavefrontCli::Exception::SystemError,
145
- 'There is no event state directory on this host.')
146
- end
147
-
148
- # Run a command, stream stderr and stdout to the screen (they
149
- # get combined -- could be an issue for someone somewhere) and
150
- # return the command's exit code
151
- #
152
- def run_wrapped_cmd(cmd)
153
- separator = '-' * (TW - 4)
154
-
155
- puts "Command output follows, on STDERR:\n#{separator}"
156
- ret = nil
157
-
158
- Open3.popen2e(cmd) do |_in, out, thr|
159
- # rubocop:disable Lint/AssignmentInCondition
160
- while l = out.gets do warn l end
161
- # rubocop:enable Lint/AssignmentInCondition
162
- ret = thr.value.exitstatus
163
- end
164
-
165
- puts separator
166
- ret
167
- end
168
-
169
- # Write a state file. We put the hosts bound to the event into the
170
- # file. These aren't currently used by anything in the CLI, but they
171
- # might be useful to someone, somewhere, someday.
172
- #
173
- def create_state_file(id)
174
- fname = state_dir + id
175
- File.open(fname, 'w') { |fh| fh.puts(event_file_data) }
176
- puts "Event state recorded at #{fname}."
177
- rescue StandardError
178
- puts 'NOTICE: event was created but state file was not.'
179
- end
180
-
181
- # Record event data in the state file. We don't currently use it, but it
182
- # might be useful to someone someday.
183
- #
184
- # @return [String]
185
- #
186
- def event_file_data
187
- { hosts: options[:host],
188
- description: options[:desc],
189
- severity: options[:severity],
190
- tags: options[:evtag] }.to_json
191
- end
192
-
193
- def create_dir(state_dir)
194
- FileUtils.mkdir_p(state_dir)
195
- raise unless state_dir.exist? && state_dir.directory? &&
196
- state_dir.writable?
197
- rescue StandardError
198
- raise(WavefrontCli::Exception::SystemError,
199
- "Cannot create writable system directory at '#{state_dir}'.")
200
- end
201
-
202
- def validate_input
203
- validate_id if options[:'<id>'] && !options[:close]
204
- validate_tags if options[:'<tag>']
205
- validate_tags(:evtag) if options[:evtag]
206
- send(:extra_validation) if respond_to?(:extra_validation)
207
- end
208
-
209
- # Get the last event this script created. If you supply a name, you
210
- # get the last event with that name. If not, you get the last event.
211
- # Chances are you'll only ever have one in-play at once.
212
- #
213
- # @param name [String] name of event
214
- # @eturn an array of [timestamp, event_name]
215
- #
216
- def pop_event(name = nil)
217
- return false unless state_dir.exist?
218
-
219
- list = local_events_with_name(name)
220
- return false if list.empty?
221
-
222
- ev_file = list.max
223
- File.unlink(ev_file)
224
- ev_file.basename.to_s
225
- end
226
-
227
- def local_events_with_name(name = nil)
228
- list = local_event_list
229
- return list unless name
230
-
231
- list.select { |f| f.basename.to_s.split(':').last == name }
232
- end
233
-
234
- def list_args
235
- [window_start,
236
- window_end,
237
- options[:limit] || 100,
238
- options[:cursor] || nil]
239
- end
240
-
241
- def window_start
242
- parse_time((options[:start] || Time.now - 600), true)
243
- end
244
-
245
- def window_end
246
- parse_time((options[:end] || Time.now), true)
247
- end
248
132
  end
249
133
  end