aspera-cli 4.17.0 → 4.18.0

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