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
data/bin/ascli CHANGED
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ old_verbose = $VERBOSE
5
+ $VERBOSE = nil
6
+ # internal representation of strings (ruby) is UTF-8
4
7
  Encoding.default_internal = Encoding::UTF_8
8
+ # external representation of strings (terminal, files)
5
9
  Encoding.default_external = Encoding::UTF_8
10
+ $VERBOSE = old_verbose
6
11
 
7
12
  begin
8
13
  gem_lib_folder = File.join(File.dirname(File.dirname(File.realpath(__FILE__))), 'lib')
data/bin/asession CHANGED
@@ -41,7 +41,7 @@ def assert_usage(assertion, error_message)
41
41
  $stderr.puts('EXAMPLES')
42
42
  $stderr.puts(%Q( asession @json:'{"#{PARAM_SPEC}":{#{SAMPLE_DEMO},#{SAMPLE_DEMO2},"paths":[{"source":"/aspera-test-dir-tiny/200KB.1"}]}}'))
43
43
  $stderr.puts(%Q( echo '{"#{PARAM_SPEC}":{"remote_host":...}}'|asession @json:@stdin))
44
- Process.exit(1)
44
+ Process.exit(0)
45
45
  end
46
46
  Aspera::Ascp::Installation.instance.sdk_folder = File.join(Dir.home, '.aspera', 'sdk')
47
47
 
@@ -78,7 +78,7 @@ session_spec['agent']['management_cb'] = ->(event) do
78
78
  puts JSON.generate(Aspera::Ascp::Management.enhanced_event_format(event))
79
79
  end
80
80
  # get local agent (ascp), disable ascp output on stdout to not mix with JSON events
81
- client = Aspera::Agent::Direct.new(session_spec['agent'])
81
+ client = Aspera::Agent::Direct.new(**session_spec['agent'].symbolize_keys)
82
82
  # start transfer (asynchronous)
83
83
  job_id = client.start_transfer(session_spec[PARAM_SPEC])
84
84
  # async commands
@@ -9,6 +9,7 @@ require 'securerandom'
9
9
 
10
10
  module Aspera
11
11
  module Agent
12
+ # Aspera Desktop Alpha Client
12
13
  class Alpha < Base
13
14
  # try twice the main init url in sequence
14
15
  START_URIS = ['aspera://', 'aspera://', 'aspera://']
@@ -17,9 +18,10 @@ module Aspera
17
18
  APP_IDENTIFIER = 'com.ibm.software.aspera.desktop'
18
19
  APP_NAME = 'Aspera Desktop Alpha Client'
19
20
  private_constant :START_URIS, :SLEEP_SEC_BETWEEN_RETRY
20
- def initialize(options)
21
+ def initialize(**base_options)
21
22
  @application_id = SecureRandom.uuid
22
- super(options)
23
+ @xfer_id = nil
24
+ super(**base_options)
23
25
  raise 'Using client requires a graphical environment' if !OpenApplication.default_gui_mode.eql?(:graphical)
24
26
  method_index = 0
25
27
  begin
@@ -111,7 +113,7 @@ module Aspera
111
113
  return [e]
112
114
  end
113
115
  return [:success]
114
- end # wait
115
- end # AgentAlpha
116
+ end
117
+ end
116
118
  end
117
119
  end
@@ -8,8 +8,14 @@ module Aspera
8
8
  class Base
9
9
  RUBY_EXT = '.rb'
10
10
  class << self
11
+ def factory_create(agent, options)
12
+ # Aspera.assert_values(agent, agent_list)
13
+ require "aspera/agent/#{agent}"
14
+ Aspera::Agent.const_get(agent.to_s.capitalize).new(**options)
15
+ end
16
+
11
17
  # compute options from user provided and default options
12
- def options(default:, options:)
18
+ def to_move_options(default:, options:)
13
19
  result = options.symbolize_keys
14
20
  available = default.map{|k, v|"#{k}(#{v})"}.join(', ')
15
21
  result.each_key do |k|
@@ -43,14 +49,11 @@ module Aspera
43
49
 
44
50
  private
45
51
 
46
- def initialize(options)
52
+ def initialize(progress: nil)
47
53
  # method `shutdown` is optional
48
54
  Aspera.assert(respond_to?(:start_transfer))
49
55
  Aspera.assert(respond_to?(:wait_for_transfers_completion))
50
- Aspera.assert_type(options, Hash){'transfer agent options'}
51
- Log.log.debug{Log.dump(:agent_options, options)}
52
- @progress = options[:progress]
53
- options.delete(:progress)
56
+ @progress = progress
54
57
  end
55
58
 
56
59
  def notify_progress(**parameters)
@@ -13,8 +13,8 @@ module Aspera
13
13
  # delay between each try to start connect
14
14
  SLEEP_SEC_BETWEEN_RETRY = 5
15
15
  private_constant :CONNECT_START_URIS, :SLEEP_SEC_BETWEEN_RETRY
16
- def initialize(options)
17
- super(options)
16
+ def initialize(**base_options)
17
+ super(**base_options)
18
18
  @connect_settings = {
19
19
  'app_id' => SecureRandom.uuid
20
20
  }
@@ -122,7 +122,7 @@ module Aspera
122
122
  return [e]
123
123
  end
124
124
  return [:success]
125
- end # wait
126
- end # AgentConnect
125
+ end
126
+ end
127
127
  end
128
128
  end
@@ -18,23 +18,10 @@ module Aspera
18
18
  module Agent
19
19
  # executes a local "ascp", connects mgt port, equivalent of "Fasp Manager"
20
20
  class Direct < Base
21
- # options for initialize (same as values in option transfer_info)
22
- DEFAULT_OPTIONS = {
23
- wss: true, # true: if both SSH and wss in ts: prefer wss
24
- ascp_args: [],
25
- spawn_timeout_sec: 2,
26
- spawn_delay_sec: 2, # optional delay to start between sessions
27
- multi_incr_udp: true,
28
- trusted_certs: [], # list of files with trusted certificates (stores)
29
- resume: {},
30
- quiet: true, # by default no native ascp progress bar
31
- check_ignore_cb: nil, # callback with host,port
32
- management_cb: nil # callback for management events
33
- }.freeze
34
21
  LISTEN_LOCAL_ADDRESS = '127.0.0.1'
35
22
  ANY_AVAILABLE_PORT = 0 # 0 means any available port
36
23
  # spellchecker: enable
37
- private_constant :DEFAULT_OPTIONS, :LISTEN_LOCAL_ADDRESS, :ANY_AVAILABLE_PORT
24
+ private_constant :LISTEN_LOCAL_ADDRESS, :ANY_AVAILABLE_PORT
38
25
 
39
26
  # method of Base
40
27
  # start ascp transfer(s) (non blocking), single or multi-session
@@ -71,7 +58,7 @@ module Aspera
71
58
  elsif multi_session_info[:count].eql?(0)
72
59
  Log.log.debug('multi_session count is zero: no multi session')
73
60
  multi_session_info = nil
74
- elsif @options[:multi_incr_udp] # multi_session_info[:count] > 0
61
+ elsif @multi_incr_udp # multi_session_info[:count] > 0
75
62
  # if option not true: keep default udp port for all sessions
76
63
  multi_session_info[:udp_base] = transfer_spec.key?('fasp_port') ? transfer_spec['fasp_port'] : Transfer::Spec::UDP_PORT
77
64
  # delete from original transfer spec, as we will increment values
@@ -90,19 +77,19 @@ module Aspera
90
77
  io: nil, # management port server socket
91
78
  token_regenerator: token_regenerator, # regenerate bearer token with oauth
92
79
  # env vars and args to ascp (from transfer spec)
93
- env_args: Transfer::Parameters.new(transfer_spec, @options).ascp_args
80
+ env_args: Transfer::Parameters.new(transfer_spec, **@tr_opts).ascp_args
94
81
  }
95
82
 
96
83
  if multi_session_info.nil?
97
84
  Log.log.debug('Starting single session thread')
98
85
  # single session for transfer : simple
99
- session[:thread] = Thread.new(session) {|s|transfer_thread_entry(s)}
86
+ session[:thread] = Thread.new(session) {|session_info|transfer_thread_entry(session_info)}
100
87
  @sessions.push(session)
101
88
  else
102
89
  Log.log.debug('Starting multi session threads')
103
90
  1.upto(multi_session_info[:count]) do |i|
104
91
  # do not delay the first session
105
- sleep(@options[:spawn_delay_sec]) unless i.eql?(1)
92
+ sleep(@spawn_delay_sec) unless i.eql?(1)
106
93
  # do deep copy (each thread has its own copy because it is modified here below and in thread)
107
94
  this_session = session.clone
108
95
  this_session[:ts] = this_session[:ts].clone
@@ -111,14 +98,14 @@ module Aspera
111
98
  # set multi session part
112
99
  this_session[:env_args][:args].unshift("-C#{i}:#{multi_session_info[:count]}")
113
100
  # option: increment (default as per ascp manual) or not (cluster on other side ?)
114
- this_session[:env_args][:args].unshift('-O', (multi_session_info[:udp_base] + i - 1).to_s) if @options[:multi_incr_udp]
101
+ this_session[:env_args][:args].unshift('-O', (multi_session_info[:udp_base] + i - 1).to_s) if @multi_incr_udp
115
102
  # finally start the thread
116
- this_session[:thread] = Thread.new(this_session) {|s|transfer_thread_entry(s)}
103
+ this_session[:thread] = Thread.new(this_session) {|session_info|transfer_thread_entry(session_info)}
117
104
  @sessions.push(this_session)
118
105
  end
119
106
  end
120
107
  return session[:job_id]
121
- end # start_transfer
108
+ end
122
109
 
123
110
  # wait for completion of all jobs started
124
111
  # @return list of :success or error message
@@ -219,8 +206,8 @@ module Aspera
219
206
  notify_progress(session_id: nil, type: :pre_start, info: 'waiting for ascp')
220
207
  mgt_server_socket.listen(1)
221
208
  # TODO: timeout does not work when Process.spawn is used... until process exits, then it works
222
- Log.log.debug{"before select, timeout: #{@options[:spawn_timeout_sec]}"}
223
- readable, _, _ = IO.select([mgt_server_socket], nil, nil, @options[:spawn_timeout_sec])
209
+ Log.log.debug{"before select, timeout: #{@spawn_timeout_sec}"}
210
+ readable, _, _ = IO.select([mgt_server_socket], nil, nil, @spawn_timeout_sec)
224
211
  Log.log.debug('after select, before accept')
225
212
  Aspera.assert(readable, exception_class: Transfer::Error){'timeout waiting mgt port connect (select not readable)'}
226
213
  # There is a connection to accept
@@ -239,7 +226,7 @@ module Aspera
239
226
  next unless event
240
227
  # event is ready
241
228
  Log.log.trace1{Log.dump(:management_port, event)}
242
- @options[:management_cb]&.call(event)
229
+ @management_cb&.call(event)
243
230
  process_progress(event)
244
231
  Log.log.error((event['Description']).to_s) if event['Type'].eql?('FILEERROR') # cspell:disable-line
245
232
  end
@@ -261,7 +248,7 @@ module Aspera
261
248
  nil
262
249
  else
263
250
  raise "unexpected last event type: #{last_event['Type']}"
264
- end # case
251
+ end
265
252
  end
266
253
  rescue SystemCallError => e
267
254
  # Process.spawn failed, or socket error
@@ -286,17 +273,17 @@ module Aspera
286
273
  Log.log.error(message)
287
274
  end
288
275
  end
289
- end # begin-ensure
290
- end # start_transfer_with_args_env
276
+ end
277
+ end
291
278
 
292
279
  # @return [Array] list of sessions for a job
293
280
  def sessions_by_job(job_id)
294
- @sessions.select{|s| s[:job_id].eql?(job_id)}
281
+ @sessions.select{|session_info| session_info[:job_id].eql?(job_id)}
295
282
  end
296
283
 
297
284
  # @return [Hash] session information
298
285
  def session_by_id(id)
299
- matches = @sessions.select{|s| s[:id].eql?(id)}
286
+ matches = @sessions.select{|session_info| session_info[:id].eql?(id)}
300
287
  raise 'no such session' if matches.empty?
301
288
  raise 'more than one session' if matches.length > 1
302
289
  return matches.first
@@ -324,13 +311,45 @@ module Aspera
324
311
 
325
312
  private
326
313
 
327
- # @param options : keys(symbol): see DEFAULT_OPTIONS
328
- def initialize(options={})
329
- super(options)
330
- # set default options and override if specified
331
- @options = Base.options(default: DEFAULT_OPTIONS, options: options)
332
- Log.log.debug{Log.dump(:agent_options, @options)}
333
- @resume_policy = Resumer.new(@options[:resume].symbolize_keys)
314
+ # options for initialize (same as values in option transfer_info)
315
+ # @param wss [Boolean] true: if both SSH and wss in ts: prefer wss
316
+ # @param ascp_args [Array] additional arguments to ascp
317
+ # @param spawn_timeout_sec [Integer] timeout for ascp spawn
318
+ # @param spawn_delay_sec [Integer] optional delay to start between sessions
319
+ # @param multi_incr_udp [Boolean] true: increment udp port for each session
320
+ # @param trusted_certs [Array] list of files with trusted certificates (stores)
321
+ # @param resume [Hash] resume policy
322
+ # @param quiet [Boolean] by default no native ascp progress bar
323
+ # @param check_ignore_cb [Proc] callback with host,port
324
+ # @param management_cb [Proc] callback for management events
325
+ # @param base_options [Hash] other options for base class
326
+ def initialize(
327
+ wss: true,
328
+ ascp_args: [],
329
+ spawn_timeout_sec: 2,
330
+ spawn_delay_sec: 2,
331
+ multi_incr_udp: true,
332
+ trusted_certs: [],
333
+ resume: {},
334
+ quiet: true,
335
+ check_ignore_cb: nil,
336
+ management_cb: nil,
337
+ **base_options
338
+ )
339
+ super(**base_options)
340
+ @tr_opts = {
341
+ ascp_args: ascp_args,
342
+ wss: wss,
343
+ quiet: quiet,
344
+ trusted_certs: trusted_certs,
345
+ check_ignore_cb: check_ignore_cb
346
+ }
347
+ @spawn_timeout_sec = spawn_timeout_sec
348
+ @spawn_delay_sec = spawn_delay_sec
349
+ @multi_incr_udp = multi_incr_udp
350
+ @resume = resume
351
+ @management_cb = management_cb
352
+ @resume_policy = Resumer.new(@resume.symbolize_keys)
334
353
  # all transfer jobs, key = SecureRandom.uuid, protected by mutex, cond var on change
335
354
  @sessions = []
336
355
  # mutex protects global data accessed by threads
@@ -355,6 +374,6 @@ module Aspera
355
374
  end
356
375
  Log.log.debug{"EXIT (#{Thread.current[:name]})"}
357
376
  end
358
- end # AgentDirect
377
+ end
359
378
  end
360
379
  end