wavefront-cli 8.2.0 → 8.5.0

Sign up to get free protection for your applications and to get access to all the features.
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