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.
- 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
|