aspera-cli 4.17.0 → 4.18.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -4
  3. data/CHANGELOG.md +23 -0
  4. data/CONTRIBUTING.md +15 -1
  5. data/README.md +620 -378
  6. data/bin/ascli +5 -0
  7. data/bin/asession +2 -2
  8. data/lib/aspera/agent/alpha.rb +6 -4
  9. data/lib/aspera/agent/base.rb +9 -6
  10. data/lib/aspera/agent/connect.rb +4 -4
  11. data/lib/aspera/agent/direct.rb +56 -37
  12. data/lib/aspera/agent/httpgw.rb +23 -324
  13. data/lib/aspera/agent/node.rb +19 -20
  14. data/lib/aspera/agent/trsdk.rb +19 -20
  15. data/lib/aspera/api/aoc.rb +17 -14
  16. data/lib/aspera/api/cos_node.rb +4 -4
  17. data/lib/aspera/api/httpgw.rb +339 -0
  18. data/lib/aspera/api/node.rb +34 -21
  19. data/lib/aspera/ascmd.rb +4 -3
  20. data/lib/aspera/ascp/installation.rb +15 -7
  21. data/lib/aspera/ascp/management.rb +2 -2
  22. data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
  23. data/lib/aspera/cli/extended_value.rb +12 -6
  24. data/lib/aspera/cli/formatter.rb +155 -65
  25. data/lib/aspera/cli/hints.rb +18 -0
  26. data/lib/aspera/cli/main.rb +22 -29
  27. data/lib/aspera/cli/manager.rb +53 -36
  28. data/lib/aspera/cli/plugin.rb +26 -17
  29. data/lib/aspera/cli/plugin_factory.rb +31 -20
  30. data/lib/aspera/cli/plugins/alee.rb +14 -2
  31. data/lib/aspera/cli/plugins/aoc.rb +141 -131
  32. data/lib/aspera/cli/plugins/ats.rb +1 -1
  33. data/lib/aspera/cli/plugins/config.rb +52 -46
  34. data/lib/aspera/cli/plugins/console.rb +8 -5
  35. data/lib/aspera/cli/plugins/faspex.rb +27 -19
  36. data/lib/aspera/cli/plugins/faspex5.rb +222 -149
  37. data/lib/aspera/cli/plugins/faspio.rb +85 -0
  38. data/lib/aspera/cli/plugins/httpgw.rb +55 -0
  39. data/lib/aspera/cli/plugins/node.rb +86 -29
  40. data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
  41. data/lib/aspera/cli/plugins/preview.rb +6 -2
  42. data/lib/aspera/cli/plugins/server.rb +5 -5
  43. data/lib/aspera/cli/plugins/shares.rb +16 -14
  44. data/lib/aspera/cli/sync_actions.rb +6 -6
  45. data/lib/aspera/cli/transfer_agent.rb +5 -4
  46. data/lib/aspera/cli/version.rb +1 -1
  47. data/lib/aspera/environment.rb +7 -6
  48. data/lib/aspera/faspex_gw.rb +5 -4
  49. data/lib/aspera/faspex_postproc.rb +2 -2
  50. data/lib/aspera/log.rb +6 -3
  51. data/lib/aspera/node_simulator.rb +2 -2
  52. data/lib/aspera/oauth/base.rb +31 -19
  53. data/lib/aspera/oauth/factory.rb +12 -13
  54. data/lib/aspera/oauth/generic.rb +1 -0
  55. data/lib/aspera/oauth/jwt.rb +18 -15
  56. data/lib/aspera/oauth/url_json.rb +8 -6
  57. data/lib/aspera/open_application.rb +5 -7
  58. data/lib/aspera/persistency_folder.rb +2 -2
  59. data/lib/aspera/preview/generator.rb +3 -3
  60. data/lib/aspera/preview/options.rb +3 -3
  61. data/lib/aspera/preview/terminal.rb +4 -4
  62. data/lib/aspera/preview/utils.rb +3 -3
  63. data/lib/aspera/proxy_auto_config.rb +5 -1
  64. data/lib/aspera/rest.rb +60 -74
  65. data/lib/aspera/rest_call_error.rb +1 -1
  66. data/lib/aspera/rest_error_analyzer.rb +2 -2
  67. data/lib/aspera/rest_errors_aspera.rb +1 -1
  68. data/lib/aspera/resumer.rb +1 -1
  69. data/lib/aspera/secret_hider.rb +2 -4
  70. data/lib/aspera/ssh.rb +1 -1
  71. data/lib/aspera/transfer/parameters.rb +39 -36
  72. data/lib/aspera/transfer/spec.rb +2 -0
  73. data/lib/aspera/transfer/sync.rb +2 -1
  74. data/lib/aspera/transfer/uri.rb +1 -1
  75. data/lib/aspera/uri_reader.rb +5 -4
  76. data/lib/aspera/web_auth.rb +1 -1
  77. data/lib/aspera/web_server_simple.rb +4 -3
  78. data.tar.gz.sig +0 -0
  79. metadata +5 -3
  80. metadata.gz.sig +0 -0
  81. data/lib/aspera/cli/plugins/bss.rb +0 -71
@@ -56,6 +56,9 @@ module Aspera
56
56
  OPTION_SEP_SYMBOL = '_'
57
57
  SOURCE_USER = 'cmdline' # cspell:disable-line
58
58
  TYPE_INTEGER = [Integer].freeze
59
+ OPTION_VALUE_SEPARATOR = '='
60
+ OPTION_PREFIX = '--'
61
+ OPTIONS_STOP = '--'
59
62
 
60
63
  private_constant :FALSE_VALUES, :TRUE_VALUES, :BOOLEAN_VALUES, :OPTION_SEP_LINE, :OPTION_SEP_SYMBOL, :SOURCE_USER, :TYPE_INTEGER
61
64
 
@@ -94,7 +97,7 @@ module Aspera
94
97
  end
95
98
 
96
99
  def option_name_to_line(name)
97
- return "--#{name.to_s.gsub(OPTION_SEP_SYMBOL, OPTION_SEP_LINE)}"
100
+ return "#{OPTION_PREFIX}#{name.to_s.gsub(OPTION_SEP_SYMBOL, OPTION_SEP_LINE)}"
98
101
  end
99
102
 
100
103
  # @param what [Symbol] :option or :argument
@@ -115,22 +118,24 @@ module Aspera
115
118
  attr_writer :fail_on_missing_mandatory
116
119
 
117
120
  def initialize(program_name)
118
- # command line values not starting with '-'
121
+ # command line values *not* starting with '-'
119
122
  @unprocessed_cmd_line_arguments = []
120
123
  # command line values starting with '-'
121
124
  @unprocessed_cmd_line_options = []
122
125
  # a copy of all initial options
123
126
  @initial_cli_options = []
124
- # option description: key = option symbol, value=hash, :read_write, :accessor, :value, :accepted
127
+ # option description: key = option symbol, value=Hash, :read_write, :accessor, :value, :accepted
125
128
  @declared_options = {}
126
129
  # do we ask missing options and arguments to user ?
127
130
  @ask_missing_mandatory = false # STDIN.isatty
128
131
  # ask optional options if not provided and in interactive
129
132
  @ask_missing_optional = false
130
133
  @fail_on_missing_mandatory = true
131
- # those must be set before parse, parse consumes those defined only
132
- @unprocessed_defaults = []
133
- @unprocessed_env = []
134
+ # Array of [key(sym), value]
135
+ # those must be set before parse
136
+ # parse consumes those defined only
137
+ @option_pairs_batch = {}
138
+ @option_pairs_env = {}
134
139
  # NOTE: was initially inherited but it is preferred to have specific methods
135
140
  @parser = OptionParser.new
136
141
  @parser.program_name = program_name
@@ -138,10 +143,10 @@ module Aspera
138
143
  env_prefix = program_name.upcase + OPTION_SEP_SYMBOL
139
144
  ENV.each do |k, v|
140
145
  if k.start_with?(env_prefix)
141
- @unprocessed_env.push([k[env_prefix.length..-1].downcase.to_sym, v])
146
+ @option_pairs_env[k[env_prefix.length..-1].downcase.to_sym] = v
142
147
  end
143
148
  end
144
- Log.log.debug{"env=#{@unprocessed_env}".red}
149
+ Log.log.debug{"env=#{@option_pairs_env}".red}
145
150
  @unprocessed_cmd_line_options = []
146
151
  @unprocessed_cmd_line_arguments = []
147
152
  end
@@ -156,16 +161,18 @@ module Aspera
156
161
  until argv.empty?
157
162
  value = argv.shift
158
163
  if process_options && value.start_with?('-')
159
- if value.eql?('--')
164
+ Log.log.trace1{"opt: #{value}"}
165
+ if value.eql?(OPTIONS_STOP)
160
166
  process_options = false
161
167
  else
162
168
  @unprocessed_cmd_line_options.push(value)
163
169
  end
164
170
  else
171
+ Log.log.trace1{"arg: #{value}"}
165
172
  @unprocessed_cmd_line_arguments.push(value)
166
173
  end
167
174
  end
168
- @initial_cli_options = @unprocessed_cmd_line_options.dup
175
+ @initial_cli_options = @unprocessed_cmd_line_options.dup.freeze
169
176
  Log.log.debug{"add_cmd_line_options:commands/arguments=#{@unprocessed_cmd_line_arguments},options=#{@unprocessed_cmd_line_options}".red}
170
177
  end
171
178
 
@@ -232,6 +239,7 @@ module Aspera
232
239
  # ask interactively if requested/required
233
240
  # @param mandatory [Boolean] if true, raise error if option not set
234
241
  def get_option(option_symbol, mandatory: false, default: nil)
242
+ Aspera.assert_type(option_symbol, Symbol)
235
243
  attributes = @declared_options[option_symbol]
236
244
  Aspera.assert(attributes){"option not declared: #{option_symbol}"}
237
245
  result = nil
@@ -268,6 +276,7 @@ module Aspera
268
276
 
269
277
  # set an option value by name, either store value or call handler
270
278
  def set_option(option_symbol, value, where='code override')
279
+ Aspera.assert_type(option_symbol, Symbol)
271
280
  raise Cli::BadArgument, "Unknown option: #{option_symbol}" unless @declared_options.key?(option_symbol)
272
281
  attributes = @declared_options[option_symbol]
273
282
  Log.log.warn("#{option_symbol}: Option is deprecated: #{attributes[:deprecation]}") if attributes[:deprecation]
@@ -292,10 +301,11 @@ module Aspera
292
301
  # @param default [Object] default value
293
302
  # @param values [nil, Array, :bool, :date, :none] list of allowed values, :bool for true/false, :date for dates, :none for on/off switch
294
303
  # @param short [String] short option name
295
- # @param coerce [Class] one of the coerce types accepted par option parser
304
+ # @param coerce [Class] one of the coerce types accepted by option parser
296
305
  # @param types [Class, Array] accepted value type(s)
297
306
  # @param block [Proc] block to execute when option is found
298
307
  def declare(option_symbol, description, handler: nil, default: nil, values: nil, short: nil, coerce: nil, types: nil, deprecation: nil, &block)
308
+ Aspera.assert_type(option_symbol, Symbol)
299
309
  Aspera.assert(!@declared_options.key?(option_symbol)){"#{option_symbol} already declared"}
300
310
  Aspera.assert(description[-1] != '.'){"#{option_symbol} ends with dot"}
301
311
  Aspera.assert(description[0] == description[0].upcase){"#{option_symbol} description does not start with capital"}
@@ -307,7 +317,7 @@ module Aspera
307
317
  }
308
318
  if !types.nil?
309
319
  types = [types] unless types.is_a?(Array)
310
- Aspera.assert(types.all?(Class)){"types must be Array of Class: #{types}"}
320
+ Aspera.assert(types.all?(Class)){"types must be (Array of) Class: #{types}"}
311
321
  opt[:types] = types
312
322
  description = "#{description} (#{types.map(&:name).join(', ')})"
313
323
  end
@@ -358,7 +368,7 @@ module Aspera
358
368
  end
359
369
  when :none
360
370
  Aspera.assert(!block.nil?){"missing block for #{option_symbol}"}
361
- on_args.push(symbol_to_option(option_symbol, nil))
371
+ on_args.push(symbol_to_option(option_symbol))
362
372
  on_args.push("-#{short}") if short.is_a?(String)
363
373
  @parser.on(*on_args, &block)
364
374
  else Aspera.error_unexpected_value(values)
@@ -368,11 +378,13 @@ module Aspera
368
378
 
369
379
  # Adds each of the keys of specified hash as an option
370
380
  # @param preset_hash [Hash] hash of options to add
371
- def add_option_preset(preset_hash, op: :push)
381
+ def add_option_preset(preset_hash, where, override: true)
372
382
  Aspera.assert_type(preset_hash, Hash)
373
- Log.log.debug{"add_option_preset=#{preset_hash}"}
374
- # incremental override
375
- preset_hash.each{|k, v|@unprocessed_defaults.send(op, [k.to_sym, v])}
383
+ Log.log.debug{"add_option_preset: #{preset_hash}, #{where}, #{override}"}
384
+ preset_hash.each do |k, v|
385
+ option_symbol = k.to_sym
386
+ @option_pairs_batch[option_symbol] = v if override || !@option_pairs_batch.key?(option_symbol)
387
+ end
376
388
  end
377
389
 
378
390
  # check if there were unprocessed values to generate error
@@ -389,20 +401,20 @@ module Aspera
389
401
  end
390
402
 
391
403
  # get all original options on command line used to generate a config in config file
392
- def get_options_table(remove_from_remaining: true)
404
+ def unprocessed_options_with_value
393
405
  result = {}
394
406
  @initial_cli_options.each do |option_value|
395
407
  case option_value
396
- when /^--([^=]+)$/
408
+ when /^#{OPTION_PREFIX}([^=]+)$/o
397
409
  # ignore
398
- when /^--([^=]+)=(.*)$/
410
+ when /^#{OPTION_PREFIX}([^=]+)=(.*)$/o
399
411
  name = Regexp.last_match(1)
400
412
  value = Regexp.last_match(2)
401
413
  name.gsub!(OPTION_SEP_LINE, OPTION_SEP_SYMBOL)
402
414
  value = ExtendedValue.instance.evaluate(value)
403
415
  Log.log.debug{"option #{name}=#{value}"}
404
416
  result[name] = value
405
- @unprocessed_cmd_line_options.delete(option_value) if remove_from_remaining
417
+ @unprocessed_cmd_line_options.delete(option_value)
406
418
  else
407
419
  raise Cli::BadArgument, "wrong option format: #{option_value}"
408
420
  end
@@ -425,8 +437,8 @@ module Aspera
425
437
  def parse_options!
426
438
  Log.log.debug('parse_options!'.red)
427
439
  # first conf file, then env var
428
- apply_options_preset(@unprocessed_defaults, 'file')
429
- apply_options_preset(@unprocessed_env, 'env')
440
+ consume_option_pairs(@option_pairs_batch, 'set')
441
+ consume_option_pairs(@option_pairs_env, 'env')
430
442
  # command line override
431
443
  unknown_options = []
432
444
  begin
@@ -497,9 +509,9 @@ module Aspera
497
509
  private
498
510
 
499
511
  # generate command line option from option symbol
500
- def symbol_to_option(symbol, opt_val)
501
- result = '--' + symbol.to_s.gsub(OPTION_SEP_SYMBOL, OPTION_SEP_LINE)
502
- result = result + '=' + opt_val unless opt_val.nil?
512
+ def symbol_to_option(symbol, opt_val = nil)
513
+ result = [OPTION_PREFIX, symbol.to_s.gsub(OPTION_SEP_SYMBOL, OPTION_SEP_LINE)].join
514
+ result = [result, OPTION_VALUE_SEPARATOR, opt_val].join unless opt_val.nil?
503
515
  return result
504
516
  end
505
517
 
@@ -507,23 +519,28 @@ module Aspera
507
519
  $stdout.isatty ? value.to_s.red.bold : "[#{value}]"
508
520
  end
509
521
 
510
- def apply_options_preset(preset, where)
511
- unprocessed = []
512
- preset.each do |pair|
513
- k, v = *pair
522
+ # try to evaluate options set ib batch
523
+ # @param unprocessed_options [Array] list of options to apply (key_sym,value)
524
+ # @param where [String] where the options come from
525
+ def consume_option_pairs(unprocessed_options, where)
526
+ Log.log.debug{"consume_option_pairs: #{where}"}
527
+ options_to_set = {}
528
+ unprocessed_options.each do |k, v|
514
529
  if @declared_options.key?(k)
515
530
  # constrained parameters as string are revert to symbol
516
531
  if @declared_options[k].key?(:values) && v.is_a?(String)
517
- v = self.class.get_from_list(v, k.to_s + " in #{where}", @declared_options[k][:values])
532
+ v = self.class.get_from_list(v, "#{k} in #{where}", @declared_options[k][:values])
518
533
  end
519
- set_option(k, v, where)
534
+ options_to_set[k] = v
520
535
  else
521
- unprocessed.push(pair)
536
+ Log.log.debug{"unprocessed: #{k}: #{v}"}
522
537
  end
523
538
  end
524
- # keep only unprocessed values for next parse
525
- preset.clear
526
- preset.push(*unprocessed)
539
+ options_to_set.each do |k, v|
540
+ set_option(k, v, where)
541
+ # keep only unprocessed values for next parse
542
+ unprocessed_options.delete(k)
543
+ end
527
544
  end
528
545
  end
529
546
  end
@@ -19,6 +19,7 @@ module Aspera
19
19
  MAX_PAGES = 'pmax'
20
20
  # special identifier format: look for this name to find where supported
21
21
  REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)$/.freeze
22
+ # instance variables, also constructor parameters
22
23
  INIT_PARAMS = %i[options transfer config formatter persistency only_manual].freeze
23
24
 
24
25
  class << self
@@ -62,15 +63,16 @@ module Aspera
62
63
  # @param description [String] description of the identifier
63
64
  # @param as_option [Symbol] option name to use if identifier is an option
64
65
  # @param block [Proc] block to search for identifier based on attribute value
65
- # @return [String] identifier
66
+ # @return [String, Array] identifier or list of ids
66
67
  def instance_identifier(description: 'identifier', as_option: nil, &block)
67
68
  if as_option.nil?
69
+ # use of option `id` is deprecated
68
70
  res_id = options.get_option(:id)
69
71
  res_id = options.get_next_argument(description) if res_id.nil?
70
72
  else
71
73
  res_id = options.get_option(as_option)
72
74
  end
73
- # cab be an Array
75
+ # can be an Array
74
76
  if res_id.is_a?(String) && (m = res_id.match(REGEX_LOOKUP_ID_BY_FIELD))
75
77
  if block
76
78
  res_id = yield(m[1], ExtendedValue.instance.evaluate(m[2]))
@@ -108,7 +110,9 @@ module Aspera
108
110
  # execute custom code
109
111
  res = yield(param)
110
112
  # if block returns a hash, let's use this (create)
111
- result = res if param.is_a?(Hash)
113
+ result = res if res.is_a?(Hash)
114
+ # TODO: remove when faspio gw api fixes this
115
+ result = res.first if res.is_a?(Array) && res.first.is_a?(Hash)
112
116
  # create -> created
113
117
  result['status'] = "#{command}#{'e' unless command.to_s.end_with?('e')}d".gsub(/yed$/, 'ied')
114
118
  rescue StandardError => e
@@ -133,9 +137,16 @@ module Aspera
133
137
  # @param item_list_key [String] result is in a sub key of the json
134
138
  # @param id_as_arg [String] if set, the id is provided as url argument ?<id_as_arg>=<id>
135
139
  # @param is_singleton [Boolean] if true, res_class_path is the full path to the resource
140
+ # @param delete_style [String] if set, the delete operation by array in payload
136
141
  # @param block [Proc] block to search for identifier based on attribute value
137
142
  # @return result suitable for CLI result
138
- def entity_command(command, rest_api, res_class_path, display_fields: nil, item_list_key: false, id_as_arg: false, is_singleton: false, &block)
143
+ def entity_command(command, rest_api, res_class_path,
144
+ display_fields: nil,
145
+ item_list_key: false,
146
+ id_as_arg: false,
147
+ is_singleton: false,
148
+ delete_style: nil,
149
+ &block)
139
150
  if is_singleton
140
151
  one_res_path = res_class_path
141
152
  elsif INSTANCE_OPS.include?(command)
@@ -152,14 +163,20 @@ module Aspera
152
163
  end
153
164
  when :delete
154
165
  raise 'cannot delete singleton' if is_singleton
166
+ if !delete_style.nil?
167
+ one_res_id = [one_res_id] unless one_res_id.is_a?(Array)
168
+ Aspera.assert_type(one_res_id, Array, exception_class: Cli::BadArgument)
169
+ rest_api.call(operation: 'DELETE', subpath: res_class_path, headers: {'Accept' => 'application/json'}, body: {delete_style => one_res_id}, body_type: :json)
170
+ return Main.result_status('deleted')
171
+ end
155
172
  return do_bulk_operation(command: command, descr: 'identifier', values: one_res_id) do |one_id|
156
- rest_api.delete("#{res_class_path}/#{one_id}", old_query_read_delete)
173
+ rest_api.delete("#{res_class_path}/#{one_id}", query_read_delete)
157
174
  {'id' => one_id}
158
175
  end
159
176
  when :show
160
177
  return {type: :single_object, data: rest_api.read(one_res_path)[:data], fields: display_fields}
161
178
  when :list
162
- resp = rest_api.read(res_class_path, old_query_read_delete)
179
+ resp = rest_api.read(res_class_path, query_read_delete)
163
180
  return Main.result_empty if resp[:http].code == '204'
164
181
  data = resp[:data]
165
182
  # TODO: not generic : which application is this for ?
@@ -215,14 +232,6 @@ module Aspera
215
232
  return query
216
233
  end
217
234
 
218
- # TODO: when deprecation of `value` is completed: remove this method, replace with query_read_delete
219
- # deprecation: 4.14
220
- def old_query_read_delete
221
- query = options.get_option(:value) # legacy, deprecated, remove, one day...
222
- query = query_read_delete if query.nil?
223
- return query
224
- end
225
-
226
235
  # TODO: when deprecation of `value` is completed: remove this method, replace with options.get_option(:query)
227
236
  # deprecation: 4.14
228
237
  def query_option(mandatory: false, default: nil)
@@ -262,6 +271,6 @@ module Aspera
262
271
  end
263
272
  return value
264
273
  end
265
- end # Plugin
266
- end # Cli
267
- end # Aspera
274
+ end
275
+ end
276
+ end
@@ -6,34 +6,25 @@ module Aspera
6
6
  # option is retrieved from another object using accessor
7
7
  class PluginFactory
8
8
  include Singleton
9
- attr_reader :lookup_folders, :plugins
10
9
 
11
10
  RUBY_FILE_EXT = '.rb'
12
11
  PLUGINS_MODULE = 'Plugins'
13
- private_constant :RUBY_FILE_EXT
14
- class << self
15
- # instantiate a plugin
16
- # plugins must be Capitalized
17
- def plugin_class(plugin_name_sym)
18
- # Module.nesting[2] is Cli::Plugins
19
- return Object.const_get("#{Module.nesting[2]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
20
- end
21
- end
12
+ private_constant :RUBY_FILE_EXT, :PLUGINS_MODULE
13
+
14
+ attr_reader :lookup_folders
22
15
 
23
16
  def initialize
24
17
  @lookup_folders = []
18
+ # information on plugins
25
19
  @plugins = {}
26
20
  end
27
21
 
28
- def add_plugin_info(path)
29
- raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
30
- plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
31
- req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
32
- if @plugins.key?(plugin_symbol)
33
- Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
34
- return
35
- end
36
- @plugins[plugin_symbol] = {source: path, require_stanza: req}
22
+ def plugin_list
23
+ @plugins.keys
24
+ end
25
+
26
+ def plugin_source(plugin_name_sym)
27
+ @plugins[plugin_name_sym][:source]
37
28
  end
38
29
 
39
30
  def add_lookup_folder(folder)
@@ -52,9 +43,29 @@ module Aspera
52
43
  end
53
44
  end
54
45
 
46
+ def plugin_class(plugin_name_sym)
47
+ raise "ERROR: plugin not found: #{plugin_name_sym}" unless @plugins.key?(plugin_name_sym)
48
+ require @plugins[plugin_name_sym][:require_stanza]
49
+ # Module.nesting[1] is Aspera::Cli
50
+ return Object.const_get("#{Module.nesting[1]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
51
+ end
52
+
55
53
  def create(plugin_name_sym, **args)
56
54
  # TODO: check that ancestor is Plugin?
57
- self.class.plugin_class(plugin_name_sym).new(**args)
55
+ plugin_class(plugin_name_sym).new(**args)
56
+ end
57
+
58
+ private
59
+
60
+ def add_plugin_info(path)
61
+ raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
62
+ plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
63
+ req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
64
+ if @plugins.key?(plugin_symbol)
65
+ Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
66
+ return
67
+ end
68
+ @plugins[plugin_symbol] = {source: path, require_stanza: req}
58
69
  end
59
70
  end
60
71
  end
@@ -1,20 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'aspera/api/aoc'
4
+ require 'aspera/nagios'
4
5
 
5
6
  module Aspera
6
7
  module Cli
7
8
  module Plugins
8
9
  class Alee < Cli::BasicAuthPlugin
9
- ACTIONS = %i[entitlement].freeze
10
+ ACTIONS = %i[health entitlement].freeze
10
11
 
11
12
  def execute_action
12
13
  command = options.get_next_command(ACTIONS)
13
14
  case command
15
+ when :health
16
+ nagios = Nagios.new
17
+ begin
18
+ api = Api::Alee.new(nil, nil, version: 'ping')
19
+ result = api.call(operation: 'GET', subpath: '')
20
+ raise "unexpected response: #{result[:http].body}" unless result[:http].body.eql?('pong')
21
+ nagios.add_ok('api', 'answered ok')
22
+ rescue StandardError => e
23
+ nagios.add_critical('api', e.to_s)
24
+ end
25
+ return nagios.result
14
26
  when :entitlement
15
27
  entitlement_id = options.get_option(:username, mandatory: true)
16
28
  customer_id = options.get_option(:password, mandatory: true)
17
- api_metering = Api::AoC.metering_api(entitlement_id, customer_id)
29
+ api_metering = Api::Alee.new(entitlement_id, customer_id)
18
30
  return {type: :single_object, data: api_metering.read('entitlement')[:data]}
19
31
  end
20
32
  end