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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -4
- data/CHANGELOG.md +23 -0
- data/CONTRIBUTING.md +15 -1
- data/README.md +620 -378
- data/bin/ascli +5 -0
- data/bin/asession +2 -2
- data/lib/aspera/agent/alpha.rb +6 -4
- data/lib/aspera/agent/base.rb +9 -6
- data/lib/aspera/agent/connect.rb +4 -4
- data/lib/aspera/agent/direct.rb +56 -37
- data/lib/aspera/agent/httpgw.rb +23 -324
- data/lib/aspera/agent/node.rb +19 -20
- data/lib/aspera/agent/trsdk.rb +19 -20
- data/lib/aspera/api/aoc.rb +17 -14
- data/lib/aspera/api/cos_node.rb +4 -4
- data/lib/aspera/api/httpgw.rb +339 -0
- data/lib/aspera/api/node.rb +34 -21
- data/lib/aspera/ascmd.rb +4 -3
- data/lib/aspera/ascp/installation.rb +15 -7
- data/lib/aspera/ascp/management.rb +2 -2
- data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
- data/lib/aspera/cli/extended_value.rb +12 -6
- data/lib/aspera/cli/formatter.rb +155 -65
- data/lib/aspera/cli/hints.rb +18 -0
- data/lib/aspera/cli/main.rb +22 -29
- data/lib/aspera/cli/manager.rb +53 -36
- data/lib/aspera/cli/plugin.rb +26 -17
- data/lib/aspera/cli/plugin_factory.rb +31 -20
- data/lib/aspera/cli/plugins/alee.rb +14 -2
- data/lib/aspera/cli/plugins/aoc.rb +141 -131
- data/lib/aspera/cli/plugins/ats.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +52 -46
- data/lib/aspera/cli/plugins/console.rb +8 -5
- data/lib/aspera/cli/plugins/faspex.rb +27 -19
- data/lib/aspera/cli/plugins/faspex5.rb +222 -149
- data/lib/aspera/cli/plugins/faspio.rb +85 -0
- data/lib/aspera/cli/plugins/httpgw.rb +55 -0
- data/lib/aspera/cli/plugins/node.rb +86 -29
- data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
- data/lib/aspera/cli/plugins/preview.rb +6 -2
- data/lib/aspera/cli/plugins/server.rb +5 -5
- data/lib/aspera/cli/plugins/shares.rb +16 -14
- data/lib/aspera/cli/sync_actions.rb +6 -6
- data/lib/aspera/cli/transfer_agent.rb +5 -4
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +7 -6
- data/lib/aspera/faspex_gw.rb +5 -4
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/log.rb +6 -3
- data/lib/aspera/node_simulator.rb +2 -2
- data/lib/aspera/oauth/base.rb +31 -19
- data/lib/aspera/oauth/factory.rb +12 -13
- data/lib/aspera/oauth/generic.rb +1 -0
- data/lib/aspera/oauth/jwt.rb +18 -15
- data/lib/aspera/oauth/url_json.rb +8 -6
- data/lib/aspera/open_application.rb +5 -7
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/preview/options.rb +3 -3
- data/lib/aspera/preview/terminal.rb +4 -4
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +5 -1
- data/lib/aspera/rest.rb +60 -74
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +2 -2
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +2 -4
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/parameters.rb +39 -36
- data/lib/aspera/transfer/spec.rb +2 -0
- data/lib/aspera/transfer/sync.rb +2 -1
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +5 -4
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +4 -3
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
- 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(
|
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
|
data/lib/aspera/agent/alpha.rb
CHANGED
@@ -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(
|
21
|
+
def initialize(**base_options)
|
21
22
|
@application_id = SecureRandom.uuid
|
22
|
-
|
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
|
115
|
-
end
|
116
|
+
end
|
117
|
+
end
|
116
118
|
end
|
117
119
|
end
|
data/lib/aspera/agent/base.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
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)
|
data/lib/aspera/agent/connect.rb
CHANGED
@@ -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(
|
17
|
-
super(
|
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
|
126
|
-
end
|
125
|
+
end
|
126
|
+
end
|
127
127
|
end
|
128
128
|
end
|
data/lib/aspera/agent/direct.rb
CHANGED
@@ -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 :
|
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 @
|
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,
|
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) {|
|
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(@
|
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 @
|
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) {|
|
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
|
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: #{@
|
223
|
-
readable, _, _ = IO.select([mgt_server_socket], nil, nil, @
|
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
|
-
@
|
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
|
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
|
290
|
-
end
|
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{|
|
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{|
|
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
|
-
#
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
377
|
+
end
|
359
378
|
end
|
360
379
|
end
|