aspera-cli 4.10.0 → 4.11.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 +0 -0
- data/BUGS.md +20 -0
- data/CHANGELOG.md +509 -0
- data/CONTRIBUTING.md +118 -0
- data/README.md +621 -378
- data/bin/ascli +4 -4
- data/bin/asession +11 -11
- data/docs/test_env.conf +28 -19
- data/examples/aoc.rb +4 -4
- data/examples/dascli +11 -9
- data/examples/faspex4.rb +8 -8
- data/examples/node.rb +11 -11
- data/examples/server.rb +9 -9
- data/lib/aspera/aoc.rb +273 -266
- data/lib/aspera/ascmd.rb +56 -54
- data/lib/aspera/ats_api.rb +4 -4
- data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
- data/lib/aspera/cli/extended_value.rb +5 -5
- data/lib/aspera/cli/formater.rb +64 -64
- data/lib/aspera/cli/listener/line_dump.rb +1 -1
- data/lib/aspera/cli/listener/logger.rb +1 -1
- data/lib/aspera/cli/listener/progress.rb +5 -6
- data/lib/aspera/cli/listener/progress_multi.rb +14 -19
- data/lib/aspera/cli/main.rb +66 -67
- data/lib/aspera/cli/manager.rb +110 -110
- data/lib/aspera/cli/plugin.rb +54 -37
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +308 -669
- data/lib/aspera/cli/plugins/ats.rb +44 -46
- data/lib/aspera/cli/plugins/bss.rb +10 -10
- data/lib/aspera/cli/plugins/config.rb +447 -344
- data/lib/aspera/cli/plugins/console.rb +12 -12
- data/lib/aspera/cli/plugins/cos.rb +18 -20
- data/lib/aspera/cli/plugins/faspex.rb +110 -112
- data/lib/aspera/cli/plugins/faspex5.rb +67 -46
- data/lib/aspera/cli/plugins/node.rb +364 -288
- data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
- data/lib/aspera/cli/plugins/preview.rb +122 -114
- data/lib/aspera/cli/plugins/server.rb +137 -83
- data/lib/aspera/cli/plugins/shares.rb +30 -29
- data/lib/aspera/cli/plugins/sync.rb +13 -33
- data/lib/aspera/cli/transfer_agent.rb +57 -57
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +27 -27
- data/lib/aspera/cos_node.rb +22 -20
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +30 -28
- data/lib/aspera/fasp/agent_base.rb +15 -15
- data/lib/aspera/fasp/agent_connect.rb +23 -21
- data/lib/aspera/fasp/agent_direct.rb +65 -67
- data/lib/aspera/fasp/agent_httpgw.rb +72 -68
- data/lib/aspera/fasp/agent_node.rb +23 -21
- data/lib/aspera/fasp/agent_trsdk.rb +20 -20
- data/lib/aspera/fasp/error.rb +3 -2
- data/lib/aspera/fasp/error_info.rb +11 -8
- data/lib/aspera/fasp/installation.rb +78 -78
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +75 -72
- data/lib/aspera/fasp/parameters.yaml +2 -2
- data/lib/aspera/fasp/resume_policy.rb +8 -8
- data/lib/aspera/fasp/transfer_spec.rb +35 -2
- data/lib/aspera/fasp/uri.rb +7 -7
- data/lib/aspera/faspex_gw.rb +7 -5
- data/lib/aspera/hash_ext.rb +3 -3
- data/lib/aspera/id_generator.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +23 -28
- data/lib/aspera/keychain/macos_security.rb +21 -20
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +19 -18
- data/lib/aspera/node.rb +209 -35
- data/lib/aspera/oauth.rb +37 -36
- data/lib/aspera/open_application.rb +19 -11
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +13 -13
- data/lib/aspera/preview/file_types.rb +8 -8
- data/lib/aspera/preview/generator.rb +67 -67
- data/lib/aspera/preview/utils.rb +27 -27
- data/lib/aspera/proxy_auto_config.js +41 -41
- data/lib/aspera/proxy_auto_config.rb +16 -16
- data/lib/aspera/rest.rb +56 -60
- data/lib/aspera/rest_call_error.rb +2 -1
- data/lib/aspera/rest_error_analyzer.rb +18 -17
- data/lib/aspera/rest_errors_aspera.rb +16 -16
- data/lib/aspera/secret_hider.rb +15 -13
- data/lib/aspera/ssh.rb +11 -10
- data/lib/aspera/sync.rb +158 -44
- data/lib/aspera/temp_file_manager.rb +2 -2
- data/lib/aspera/uri_reader.rb +4 -4
- data/lib/aspera/web_auth.rb +14 -13
- data.tar.gz.sig +0 -0
- metadata +8 -5
- metadata.gz.sig +0 -0
@@ -42,9 +42,9 @@ module Aspera
|
|
42
42
|
</default>
|
43
43
|
</CONF>
|
44
44
|
END_OF_CONFIG_FILE
|
45
|
-
DUMMY_CERT_INFO='/C=US/ST=California/L=Emeryville/O=Aspera Inc./OU=Corporate/CN=Aspera Inc./emailAddress=info@asperasoft.com'
|
46
|
-
private_constant :PRODUCT_CONNECT
|
47
|
-
:ONE_YEAR_SECONDS
|
45
|
+
DUMMY_CERT_INFO = '/C=US/ST=California/L=Emeryville/O=Aspera Inc./OU=Corporate/CN=Aspera Inc./emailAddress=info@asperasoft.com'
|
46
|
+
private_constant :PRODUCT_CONNECT, :PRODUCT_CLI_V1, :PRODUCT_DRIVE, :PRODUCT_ENTSRV, :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER,
|
47
|
+
:ONE_YEAR_SECONDS, :DEFAULT_ASPERA_CONF, :DUMMY_CERT_INFO
|
48
48
|
# set ascp executable path
|
49
49
|
def ascp_path=(v)
|
50
50
|
@path_to_ascp = v
|
@@ -55,7 +55,7 @@ module Aspera
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def sdk_ruby_folder
|
58
|
-
ruby_pb_folder = File.join(sdk_folder,RB_SDK_FOLDER)
|
58
|
+
ruby_pb_folder = File.join(sdk_folder, RB_SDK_FOLDER)
|
59
59
|
FileUtils.mkdir_p(ruby_pb_folder) unless Dir.exist?(ruby_pb_folder)
|
60
60
|
return ruby_pb_folder
|
61
61
|
end
|
@@ -87,7 +87,7 @@ module Aspera
|
|
87
87
|
raise "no such product installed: #{product_name}" if pl.nil?
|
88
88
|
end
|
89
89
|
self.ascp_path = pl[:ascp_path]
|
90
|
-
Log.log.debug
|
90
|
+
Log.log.debug{"ascp_path=#{@path_to_ascp}"}
|
91
91
|
end
|
92
92
|
|
93
93
|
# @return the list of installed products in format of product_locations
|
@@ -104,15 +104,15 @@ module Aspera
|
|
104
104
|
@found_products = scan_locations.select! do |item|
|
105
105
|
# skip if not main folder
|
106
106
|
next false unless Dir.exist?(item[:app_root])
|
107
|
-
Log.log.debug
|
107
|
+
Log.log.debug{"Found #{item[:app_root]}"}
|
108
108
|
sub_bin = item[:sub_bin] || BIN_SUBFOLDER
|
109
|
-
item[:ascp_path] = File.join(item[:app_root],sub_bin,ascp_filename)
|
109
|
+
item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
|
110
110
|
# skip if no ascp
|
111
111
|
next false unless File.exist?(item[:ascp_path])
|
112
112
|
# read info from product info file if present
|
113
113
|
product_info_file = "#{item[:app_root]}/#{PRODUCT_INFO}"
|
114
114
|
if File.exist?(product_info_file)
|
115
|
-
res_s = XmlSimple.xml_in(File.read(product_info_file),{'ForceArray' => false})
|
115
|
+
res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
|
116
116
|
item[:name] = res_s['name']
|
117
117
|
item[:version] = res_s['version']
|
118
118
|
else
|
@@ -131,20 +131,20 @@ module Aspera
|
|
131
131
|
# keys and certs are generated locally... (they are well known values, arch. independant)
|
132
132
|
def path(k)
|
133
133
|
case k
|
134
|
-
when :ascp
|
134
|
+
when :ascp, :ascp4
|
135
135
|
use_ascp_from_product(FIRST_FOUND) if @path_to_ascp.nil?
|
136
136
|
file = @path_to_ascp
|
137
|
-
#
|
138
|
-
file = file.gsub('ascp','ascp4') if k.eql?(:ascp4)
|
137
|
+
# NOTE: that there might be a .exe at the end
|
138
|
+
file = file.gsub('ascp', 'ascp4') if k.eql?(:ascp4)
|
139
139
|
when :transferd
|
140
140
|
file = transferd_filepath
|
141
141
|
when :ssh_bypass_key_dsa
|
142
|
-
file=Environment.write_file_restricted(File.join(sdk_folder,'aspera_bypass_dsa.pem')) {get_key('dsa',1)}
|
142
|
+
file = Environment.write_file_restricted(File.join(sdk_folder, 'aspera_bypass_dsa.pem')) {get_key('dsa', 1)}
|
143
143
|
when :ssh_bypass_key_rsa
|
144
|
-
file=Environment.write_file_restricted(File.join(sdk_folder,'aspera_bypass_rsa.pem')) {get_key('rsa',2)}
|
144
|
+
file = Environment.write_file_restricted(File.join(sdk_folder, 'aspera_bypass_rsa.pem')) {get_key('rsa', 2)}
|
145
145
|
when :aspera_license
|
146
|
-
file=Environment.write_file_restricted(File.join(sdk_folder,'aspera-license')) do
|
147
|
-
clear=[
|
146
|
+
file = Environment.write_file_restricted(File.join(sdk_folder, 'aspera-license')) do
|
147
|
+
clear = [
|
148
148
|
Zlib::Inflate.inflate(DataRepository.instance.data(6)),
|
149
149
|
"==SIGNATURE==\n",
|
150
150
|
Base64.strict_encode64(DataRepository.instance.data(7))
|
@@ -152,10 +152,10 @@ module Aspera
|
|
152
152
|
Base64.strict_encode64(clear.join)
|
153
153
|
end
|
154
154
|
when :aspera_conf
|
155
|
-
file=Environment.write_file_restricted(File.join(sdk_folder,'aspera.conf')) {DEFAULT_ASPERA_CONF}
|
156
|
-
when :fallback_cert
|
157
|
-
file_key = File.join(sdk_folder,'aspera_fallback_key.pem')
|
158
|
-
file_cert = File.join(sdk_folder,'aspera_fallback_cert.pem')
|
155
|
+
file = Environment.write_file_restricted(File.join(sdk_folder, 'aspera.conf')) {DEFAULT_ASPERA_CONF}
|
156
|
+
when :fallback_cert, :fallback_key
|
157
|
+
file_key = File.join(sdk_folder, 'aspera_fallback_key.pem')
|
158
|
+
file_cert = File.join(sdk_folder, 'aspera_fallback_cert.pem')
|
159
159
|
if !File.exist?(file_key) || !File.exist?(file_cert)
|
160
160
|
require 'openssl'
|
161
161
|
# create new self signed certificate for http fallback
|
@@ -182,10 +182,10 @@ module Aspera
|
|
182
182
|
# @return the file path of local connect where API's URI can be read
|
183
183
|
def connect_uri
|
184
184
|
connect = get_product_folders(PRODUCT_CONNECT)
|
185
|
-
folder = File.join(connect[:run_root],VARRUN_SUBFOLDER)
|
186
|
-
['','s'].each do |ext|
|
187
|
-
uri_file = File.join(folder,"http#{ext}.uri")
|
188
|
-
Log.log.debug
|
185
|
+
folder = File.join(connect[:run_root], VARRUN_SUBFOLDER)
|
186
|
+
['', 's'].each do |ext|
|
187
|
+
uri_file = File.join(folder, "http#{ext}.uri")
|
188
|
+
Log.log.debug{"checking connect port file: #{uri_file}"}
|
189
189
|
if File.exist?(uri_file)
|
190
190
|
return File.open(uri_file, &:gets).strip
|
191
191
|
end
|
@@ -196,12 +196,12 @@ module Aspera
|
|
196
196
|
# @ return path to configuration file of aspera CLI
|
197
197
|
def cli_conf_file
|
198
198
|
connect = get_product_folders(PRODUCT_CLI_V1)
|
199
|
-
return File.join(connect[:app_root],BIN_SUBFOLDER,'.aspera_cli_conf')
|
199
|
+
return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
|
200
200
|
end
|
201
201
|
|
202
202
|
# default bypass key phrase
|
203
203
|
def bypass_pass
|
204
|
-
return format('%08x-%04x-%04x-%04x-%04x%08x'
|
204
|
+
return format('%08x-%04x-%04x-%04x-%04x%08x', *DataRepository.instance.data(3).unpack('NnnnnN'))
|
205
205
|
end
|
206
206
|
|
207
207
|
def bypass_keys
|
@@ -210,11 +210,11 @@ module Aspera
|
|
210
210
|
|
211
211
|
# use in plugin `config`
|
212
212
|
def get_ascp_version(exe_path)
|
213
|
-
return get_exe_version(exe_path,'-A')
|
213
|
+
return get_exe_version(exe_path, '-A')
|
214
214
|
end
|
215
215
|
|
216
216
|
# Check that specified path is ascp and get version
|
217
|
-
def get_exe_version(exe_path,vers_arg)
|
217
|
+
def get_exe_version(exe_path, vers_arg)
|
218
218
|
raise 'ERROR: nil arg' if exe_path.nil?
|
219
219
|
return nil unless File.exist?(exe_path)
|
220
220
|
exe_version = nil
|
@@ -233,18 +233,18 @@ module Aspera
|
|
233
233
|
# SDK is organized by architecture, check this first, in case architecture is not supported
|
234
234
|
arch_filter = "#{Environment.architecture}/"
|
235
235
|
require 'zip'
|
236
|
-
sdk_zip_path = File.join(Dir.tmpdir,'sdk.zip')
|
236
|
+
sdk_zip_path = File.join(Dir.tmpdir, 'sdk.zip')
|
237
237
|
if sdk_url.start_with?('file:')
|
238
238
|
# require specific file scheme: the path part is "relative", or absolute if there are 4 slash
|
239
239
|
raise 'use format: file:///<path>' unless sdk_url.start_with?('file:///')
|
240
|
-
sdk_zip_path = sdk_url.gsub(%r{^file:///},'')
|
240
|
+
sdk_zip_path = sdk_url.gsub(%r{^file:///}, '')
|
241
241
|
else
|
242
|
-
Aspera::Rest.new(base_url: sdk_url, redirect_max: 3).call(operation: 'GET',save_to_file: sdk_zip_path)
|
242
|
+
Aspera::Rest.new(base_url: sdk_url, redirect_max: 3).call(operation: 'GET', save_to_file: sdk_zip_path)
|
243
243
|
end
|
244
244
|
# rename old install
|
245
245
|
if !Dir.empty?(sdk_folder)
|
246
246
|
Log.log.warn('Previous install exists, renaming folder.')
|
247
|
-
File.rename(sdk_folder,"#{sdk_folder}.#{Time.now.strftime('%Y%m%d%H%M%S')}")
|
247
|
+
File.rename(sdk_folder, "#{sdk_folder}.#{Time.now.strftime('%Y%m%d%H%M%S')}")
|
248
248
|
# TODO: delete old archives ?
|
249
249
|
end
|
250
250
|
# extract files from archive
|
@@ -258,7 +258,7 @@ module Aspera
|
|
258
258
|
# ruby adapters
|
259
259
|
dest_folder = sdk_ruby_folder if entry.name.end_with?(EXT_RUBY_PROTOBUF)
|
260
260
|
next if dest_folder.nil?
|
261
|
-
File.open(File.join(dest_folder,File.basename(entry.name)), 'wb') do |output_stream|
|
261
|
+
File.open(File.join(dest_folder, File.basename(entry.name)), 'wb') do |output_stream|
|
262
262
|
IO.copy_stream(entry.get_input_stream, output_stream)
|
263
263
|
end
|
264
264
|
end
|
@@ -267,17 +267,17 @@ module Aspera
|
|
267
267
|
# ensure license file are generated so that ascp invokation for version works
|
268
268
|
path(:aspera_license)
|
269
269
|
path(:aspera_conf)
|
270
|
-
ascp_path = File.join(sdk_folder,ascp_filename)
|
270
|
+
ascp_path = File.join(sdk_folder, ascp_filename)
|
271
271
|
raise "No #{ascp_filename} found in SDK archive" unless File.exist?(ascp_path)
|
272
|
-
Environment.restrict_file_access(ascp_path, mode:
|
273
|
-
Environment.restrict_file_access(ascp_path.gsub('ascp','ascp4'), mode:
|
274
|
-
ascp_version = get_ascp_version(File.join(sdk_folder,ascp_filename))
|
272
|
+
Environment.restrict_file_access(ascp_path, mode: 0o755)
|
273
|
+
Environment.restrict_file_access(ascp_path.gsub('ascp', 'ascp4'), mode: 0o755)
|
274
|
+
ascp_version = get_ascp_version(File.join(sdk_folder, ascp_filename))
|
275
275
|
trd_path = transferd_filepath
|
276
|
-
Log.log.warn
|
277
|
-
Environment.restrict_file_access(trd_path, mode:
|
278
|
-
transferd_version = get_exe_version(trd_path,'version')
|
276
|
+
Log.log.warn{"No #{trd_path} in SDK archive"} unless File.exist?(trd_path)
|
277
|
+
Environment.restrict_file_access(trd_path, mode: 0o755) if File.exist?(trd_path)
|
278
|
+
transferd_version = get_exe_version(trd_path, 'version')
|
279
279
|
sdk_version = transferd_version || ascp_version
|
280
|
-
File.write(File.join(sdk_folder,PRODUCT_INFO),"<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
|
280
|
+
File.write(File.join(sdk_folder, PRODUCT_INFO), "<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
|
281
281
|
return sdk_version
|
282
282
|
end
|
283
283
|
|
@@ -285,13 +285,13 @@ module Aspera
|
|
285
285
|
|
286
286
|
BIN_SUBFOLDER = 'bin'
|
287
287
|
ETC_SUBFOLDER = 'etc'
|
288
|
-
VARRUN_SUBFOLDER = File.join('var','run')
|
288
|
+
VARRUN_SUBFOLDER = File.join('var', 'run')
|
289
289
|
# product information manifest: XML (part of aspera product)
|
290
290
|
PRODUCT_INFO = 'product-info.mf'
|
291
291
|
# policy for product selection
|
292
292
|
FIRST_FOUND = 'FIRST'
|
293
293
|
|
294
|
-
private_constant :BIN_SUBFOLDER
|
294
|
+
private_constant :BIN_SUBFOLDER, :ETC_SUBFOLDER, :VARRUN_SUBFOLDER, :PRODUCT_INFO
|
295
295
|
|
296
296
|
def initialize
|
297
297
|
@path_to_ascp = nil
|
@@ -313,7 +313,7 @@ module Aspera
|
|
313
313
|
end
|
314
314
|
|
315
315
|
def transferd_filepath
|
316
|
-
return File.join(sdk_folder,'asperatransferd' + Environment.exe_extension)
|
316
|
+
return File.join(sdk_folder, 'asperatransferd' + Environment.exe_extension)
|
317
317
|
end
|
318
318
|
|
319
319
|
# @return product folders depending on OS fields
|
@@ -326,54 +326,54 @@ module Aspera
|
|
326
326
|
case Aspera::Environment.os
|
327
327
|
when Aspera::Environment::OS_WINDOWS; return [{
|
328
328
|
expected: PRODUCT_CONNECT,
|
329
|
-
app_root: File.join(ENV['LOCALAPPDATA'],'Programs','Aspera','Aspera Connect'),
|
330
|
-
log_root: File.join(ENV['LOCALAPPDATA'],'Aspera','Aspera Connect','var','log'),
|
331
|
-
run_root: File.join(ENV['LOCALAPPDATA'],'Aspera','Aspera Connect')
|
332
|
-
},{
|
329
|
+
app_root: File.join(ENV['LOCALAPPDATA'], 'Programs', 'Aspera', 'Aspera Connect'),
|
330
|
+
log_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect', 'var', 'log'),
|
331
|
+
run_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect')
|
332
|
+
}, {
|
333
333
|
expected: PRODUCT_CLI_V1,
|
334
|
-
app_root: File.join('C:','Program Files','Aspera','cli'),
|
335
|
-
log_root: File.join('C:','Program Files','Aspera','cli','var','log')
|
336
|
-
},{
|
334
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
|
335
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
|
336
|
+
}, {
|
337
337
|
expected: PRODUCT_ENTSRV,
|
338
|
-
app_root: File.join('C:','Program Files','Aspera','Enterprise Server'),
|
339
|
-
log_root: File.join('C:','Program Files','Aspera','Enterprise Server','var','log')
|
338
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
|
339
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
|
340
340
|
}]
|
341
341
|
when Aspera::Environment::OS_X; return [{
|
342
342
|
expected: PRODUCT_CONNECT,
|
343
|
-
app_root: File.join(Dir.home,'Applications','Aspera Connect.app'),
|
344
|
-
log_root: File.join(Dir.home,'Library','Logs','Aspera_Connect'),
|
345
|
-
run_root: File.join(Dir.home,'Library','Application Support','Aspera','Aspera Connect'),
|
346
|
-
sub_bin: File.join('Contents','Resources')
|
347
|
-
},{
|
343
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
|
344
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
345
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
346
|
+
sub_bin: File.join('Contents', 'Resources')
|
347
|
+
}, {
|
348
348
|
expected: PRODUCT_CONNECT,
|
349
|
-
app_root: File.join('','Applications','Aspera Connect.app'),
|
350
|
-
log_root: File.join(Dir.home,'Library','Logs','Aspera_Connect'),
|
351
|
-
run_root: File.join(Dir.home,'Library','Application Support','Aspera','Aspera Connect'),
|
352
|
-
sub_bin: File.join('Contents','Resources')
|
353
|
-
},{
|
349
|
+
app_root: File.join('', 'Applications', 'Aspera Connect.app'),
|
350
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
351
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
352
|
+
sub_bin: File.join('Contents', 'Resources')
|
353
|
+
}, {
|
354
354
|
expected: PRODUCT_CLI_V1,
|
355
|
-
app_root: File.join(Dir.home,'Applications','Aspera CLI'),
|
356
|
-
log_root: File.join(Dir.home,'Library','Logs','Aspera')
|
357
|
-
},{
|
355
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
|
356
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
357
|
+
}, {
|
358
358
|
expected: PRODUCT_ENTSRV,
|
359
|
-
app_root: File.join('','Library','Aspera'),
|
360
|
-
log_root: File.join(Dir.home,'Library','Logs','Aspera')
|
361
|
-
},{
|
359
|
+
app_root: File.join('', 'Library', 'Aspera'),
|
360
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
361
|
+
}, {
|
362
362
|
expected: PRODUCT_DRIVE,
|
363
|
-
app_root: File.join('','Applications','Aspera Drive.app'),
|
364
|
-
log_root: File.join(Dir.home,'Library','Logs','Aspera_Drive'),
|
365
|
-
sub_bin: File.join('Contents','Resources')
|
363
|
+
app_root: File.join('', 'Applications', 'Aspera Drive.app'),
|
364
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
|
365
|
+
sub_bin: File.join('Contents', 'Resources')
|
366
366
|
}]
|
367
367
|
else; return [{ # other: Linux and Unix family
|
368
368
|
expected: PRODUCT_CONNECT,
|
369
|
-
app_root: File.join(Dir.home,'.aspera','connect'),
|
370
|
-
run_root: File.join(Dir.home,'.aspera','connect')
|
371
|
-
},{
|
369
|
+
app_root: File.join(Dir.home, '.aspera', 'connect'),
|
370
|
+
run_root: File.join(Dir.home, '.aspera', 'connect')
|
371
|
+
}, {
|
372
372
|
expected: PRODUCT_CLI_V1,
|
373
|
-
app_root: File.join(Dir.home,'.aspera','cli')
|
374
|
-
},{
|
373
|
+
app_root: File.join(Dir.home, '.aspera', 'cli')
|
374
|
+
}, {
|
375
375
|
expected: PRODUCT_ENTSRV,
|
376
|
-
app_root: File.join('','opt','aspera')
|
376
|
+
app_root: File.join('', 'opt', 'aspera')
|
377
377
|
}]
|
378
378
|
end
|
379
379
|
end
|
@@ -381,7 +381,7 @@ module Aspera
|
|
381
381
|
# @return a standard bypass key
|
382
382
|
# @param type rsa or dsa
|
383
383
|
# @param id in repository 1 for dsa, 2 for rsa
|
384
|
-
def get_key(type,id)
|
384
|
+
def get_key(type, id)
|
385
385
|
# generate PEM from DER
|
386
386
|
OpenSSL::PKey.const_get(type.upcase).new(DataRepository.instance.data(id)).to_pem
|
387
387
|
end
|
data/lib/aspera/fasp/listener.rb
CHANGED
@@ -31,29 +31,29 @@ module Aspera
|
|
31
31
|
def description
|
32
32
|
if @param_description_cache.nil?
|
33
33
|
# config file in same folder with same name as this source
|
34
|
-
description_from_yaml=YAML.load_file("#{__FILE__[0..-3]}yaml")
|
34
|
+
description_from_yaml = YAML.load_file("#{__FILE__[0..-3]}yaml")
|
35
35
|
@param_description_cache = Aspera::CommandLineBuilder.normalize_description(description_from_yaml)
|
36
36
|
end
|
37
37
|
return @param_description_cache
|
38
38
|
end
|
39
39
|
|
40
40
|
# @return a table suitable to display in manual
|
41
|
-
def man_table
|
41
|
+
def man_table(to_text: true)
|
42
42
|
result = []
|
43
|
-
description.each do |k,i|
|
44
|
-
param = {name: k, type: [i[:accepted_types]].flatten.join(','),description: i[:desc]}
|
43
|
+
description.each do |k, i|
|
44
|
+
param = {name: k, type: [i[:accepted_types]].flatten.join(','), description: i[:desc]}
|
45
45
|
# add flags for supported agents in doc
|
46
46
|
SUPPORTED_AGENTS.each do |a|
|
47
47
|
param[a.to_s[0].to_sym] = i[:tragents].nil? || i[:tragents].include?(a) ? 'Y' : ''
|
48
48
|
end
|
49
49
|
# only keep lines that are usable in supported agents
|
50
|
-
next if SUPPORTED_AGENTS_SHORT.inject(true){|m,j|m && param[j].empty?}
|
50
|
+
next if SUPPORTED_AGENTS_SHORT.inject(true){|m, j|m && param[j].empty?}
|
51
51
|
param[:cli] =
|
52
52
|
case i[:cltype]
|
53
53
|
when :envvar then 'env:' + i[:clvarname]
|
54
54
|
when :opt_without_arg then i[:clswitch]
|
55
55
|
when :opt_with_arg
|
56
|
-
values=if i.
|
56
|
+
values = if i.key?(:enum)
|
57
57
|
['enum']
|
58
58
|
elsif i[:accepted_types].is_a?(Array)
|
59
59
|
i[:accepted_types]
|
@@ -62,20 +62,21 @@ module Aspera
|
|
62
62
|
else
|
63
63
|
raise "error: #{param}"
|
64
64
|
end.map{|n|"{#{n}}"}.join('|')
|
65
|
-
conv=i.
|
65
|
+
conv = i.key?(:clconvert) ? '(conversion)' : ''
|
66
66
|
"#{i[:clswitch]} #{conv}#{values}"
|
67
67
|
else ''
|
68
68
|
end
|
69
|
-
if i.
|
69
|
+
if i.key?(:enum)
|
70
70
|
param[:description] += "\nAllowed values: #{i[:enum].join(', ')}"
|
71
71
|
end
|
72
|
+
param[:description] = param[:description].gsub('/', '/') if to_text
|
72
73
|
result.push(param)
|
73
74
|
end
|
74
75
|
return result
|
75
76
|
end
|
76
77
|
|
77
78
|
# special encoding methods used in YAML (key: :clconvert)
|
78
|
-
def clconv_remove_hyphen(v); v.tr('-',''); end
|
79
|
+
def clconv_remove_hyphen(v); v.tr('-', ''); end
|
79
80
|
|
80
81
|
# special encoding methods used in YAML (key: :clconvert)
|
81
82
|
def clconv_json64(v); Base64.strict_encode64(JSON.generate(v)); end
|
@@ -85,13 +86,13 @@ module Aspera
|
|
85
86
|
|
86
87
|
# file list is provided directly with ascp arguments
|
87
88
|
def ts_has_ascp_file_list(ts)
|
88
|
-
(ts['EX_ascp_args'].is_a?(Array) && ['--file-list','--file-pair-list'].any?{|i|ts['EX_ascp_args'].include?(i)}) ||
|
89
|
-
|
90
|
-
|
89
|
+
(ts['EX_ascp_args'].is_a?(Array) && ['--file-list', '--file-pair-list'].any?{|i|ts['EX_ascp_args'].include?(i)}) ||
|
90
|
+
ts.key?('EX_file_list') ||
|
91
|
+
ts.key?('EX_file_pair_list')
|
91
92
|
end
|
92
93
|
|
93
|
-
def ts_to_env_args(transfer_spec,options)
|
94
|
-
return Parameters.new(transfer_spec,options).ascp_args
|
94
|
+
def ts_to_env_args(transfer_spec, options)
|
95
|
+
return Parameters.new(transfer_spec, options).ascp_args
|
95
96
|
end
|
96
97
|
|
97
98
|
# temp file list files are created here
|
@@ -107,11 +108,56 @@ module Aspera
|
|
107
108
|
end # self
|
108
109
|
|
109
110
|
# @param options [Hash] key: :wss: bool
|
110
|
-
def initialize(job_spec,options)
|
111
|
+
def initialize(job_spec, options)
|
111
112
|
@job_spec = job_spec
|
112
113
|
@options = options
|
113
|
-
@builder = Aspera::CommandLineBuilder.new(@job_spec,self.class.description)
|
114
|
-
Log.log.debug
|
114
|
+
@builder = Aspera::CommandLineBuilder.new(@job_spec, self.class.description)
|
115
|
+
Log.log.debug{"agent options: #{@options}"}
|
116
|
+
end
|
117
|
+
|
118
|
+
def process_file_list
|
119
|
+
# is the file list provided through EX_ parameters?
|
120
|
+
ascp_file_list_provided = self.class.ts_has_ascp_file_list(@job_spec)
|
121
|
+
# set if paths is mandatory in ts
|
122
|
+
@builder.params_definition['paths'][:mandatory] = !@job_spec.key?('keepalive') && !ascp_file_list_provided
|
123
|
+
# get paths in transfer spec (after setting if it is mandatory)
|
124
|
+
ts_paths_array = @builder.process_param('paths', :get_value)
|
125
|
+
if ascp_file_list_provided && !ts_paths_array.nil?
|
126
|
+
raise 'file list provided both in transfer spec and ascp file list. Remove one of them.'
|
127
|
+
end
|
128
|
+
# option 1: EX_file_list
|
129
|
+
file_list_file = @builder.process_param('EX_file_list', :get_value)
|
130
|
+
if file_list_file.nil?
|
131
|
+
# option 2: EX_file_pair_list
|
132
|
+
file_list_file = @builder.process_param('EX_file_pair_list', :get_value)
|
133
|
+
if !file_list_file.nil?
|
134
|
+
option = '--file-pair-list'
|
135
|
+
elsif !ts_paths_array.nil?
|
136
|
+
# option 3: in TS, it is an array
|
137
|
+
if self.class.file_list_folder.nil?
|
138
|
+
# not safe for special characters ? (maybe not, depends on OS)
|
139
|
+
Log.log.debug('placing source file list on command line (no file list file)')
|
140
|
+
@builder.add_command_line_options(ts_paths_array.map{|i|i['source']})
|
141
|
+
else
|
142
|
+
# safer option: generate a file list file if there is storage defined for it
|
143
|
+
# if there is destination in paths, then use filepairlist
|
144
|
+
# TODO: well, we test only the first one, but anyway it shall be consistent
|
145
|
+
if ts_paths_array.first.key?('destination')
|
146
|
+
option = '--file-pair-list'
|
147
|
+
lines = ts_paths_array.each_with_object([]){|e, m|m.push(e['source'], e['destination']); }
|
148
|
+
else
|
149
|
+
option = '--file-list'
|
150
|
+
lines = ts_paths_array.map{|i|i['source']}
|
151
|
+
end
|
152
|
+
file_list_file = Aspera::TempFileManager.instance.new_file_path_in_folder(self.class.file_list_folder)
|
153
|
+
File.write(file_list_file, lines.join("\n"))
|
154
|
+
Log.log.debug{"#{option}=\n#{File.read(file_list_file)}".red}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
else
|
158
|
+
option = '--file-list'
|
159
|
+
end
|
160
|
+
@builder.add_command_line_options(["#{option}=#{file_list_file}"]) unless option.nil?
|
115
161
|
end
|
116
162
|
|
117
163
|
# translate transfer spec to env vars and command line arguments for ascp
|
@@ -123,22 +169,22 @@ module Aspera
|
|
123
169
|
ascp_version: :ascp
|
124
170
|
}
|
125
171
|
# some ssh credentials are required to avoid interactive password input
|
126
|
-
if !@job_spec.
|
127
|
-
|
128
|
-
|
172
|
+
if !@job_spec.key?('remote_password') &&
|
173
|
+
!@job_spec.key?('ssh_private_key') &&
|
174
|
+
!@job_spec.key?('EX_ssh_key_paths')
|
129
175
|
raise Fasp::Error, 'required: password or ssh key (value or path)'
|
130
176
|
end
|
131
177
|
|
132
178
|
# special cases
|
133
|
-
@job_spec.delete('source_root') if @job_spec.
|
179
|
+
@job_spec.delete('source_root') if @job_spec.key?('source_root') && @job_spec['source_root'].empty?
|
134
180
|
|
135
181
|
# use web socket session initiation ?
|
136
|
-
if @builder.process_param('wss_enabled'
|
182
|
+
if @builder.process_param('wss_enabled', :get_value) && (@options[:wss] || !@job_spec.key?('fasp_port'))
|
137
183
|
# by default use web socket session if available, unless removed by user
|
138
184
|
@builder.add_command_line_options(['--ws-connect'])
|
139
185
|
# TODO: option to give order ssh,ws (legacy http is implied bu ssh)
|
140
186
|
# quel bordel:
|
141
|
-
@job_spec['ssh_port'] = @builder.process_param('wss_port'
|
187
|
+
@job_spec['ssh_port'] = @builder.process_param('wss_port', :get_value)
|
142
188
|
@job_spec.delete('fasp_port')
|
143
189
|
@job_spec.delete('EX_ssh_key_paths')
|
144
190
|
@job_spec.delete('sshfp')
|
@@ -154,68 +200,25 @@ module Aspera
|
|
154
200
|
@builder.process_params
|
155
201
|
|
156
202
|
# symbol must be index of Installation.paths
|
157
|
-
if @builder.process_param('use_ascp4'
|
203
|
+
if @builder.process_param('use_ascp4', :get_value)
|
158
204
|
env_args[:ascp_version] = :ascp4
|
159
205
|
else
|
160
206
|
env_args[:ascp_version] = :ascp
|
161
207
|
# destination will be base64 encoded, put before path arguments
|
162
208
|
@builder.add_command_line_options(['--dest64'])
|
163
209
|
end
|
164
|
-
#
|
165
|
-
|
166
|
-
# is the file list provided through EX_ parameters?
|
167
|
-
ascp_file_list_provided = self.class.ts_has_ascp_file_list(@job_spec)
|
168
|
-
# set if paths is mandatory in ts
|
169
|
-
@builder.params_definition['paths'][:mandatory] = !@job_spec.has_key?('keepalive') && !ascp_file_list_provided
|
170
|
-
# get paths in transfer spec (after setting if it is mandatory)
|
171
|
-
ts_paths_array = @builder.process_param('paths',:get_value)
|
172
|
-
if ascp_file_list_provided && !ts_paths_array.nil?
|
173
|
-
raise 'file list provided both in transfer spec and ascp file list. Remove one of them.'
|
174
|
-
end
|
175
|
-
# option 1: EX_file_list
|
176
|
-
file_list_file = @builder.process_param('EX_file_list',:get_value)
|
177
|
-
if !file_list_file.nil?
|
178
|
-
option = '--file-list'
|
179
|
-
else
|
180
|
-
# option 2: EX_file_pair_list
|
181
|
-
file_list_file = @builder.process_param('EX_file_pair_list',:get_value)
|
182
|
-
if !file_list_file.nil?
|
183
|
-
option = '--file-pair-list'
|
184
|
-
elsif !ts_paths_array.nil?
|
185
|
-
# option 3: in TS, it is an array
|
186
|
-
if !self.class.file_list_folder.nil?
|
187
|
-
# safer option: generate a file list file if there is storage defined for it
|
188
|
-
# if there is destination in paths, then use filepairlist
|
189
|
-
# TODO: well, we test only the first one, but anyway it shall be consistent
|
190
|
-
if ts_paths_array.first.has_key?('destination')
|
191
|
-
option = '--file-pair-list'
|
192
|
-
lines = ts_paths_array.each_with_object([]){|e,m|m.push(e['source'],e['destination']);}
|
193
|
-
else
|
194
|
-
option = '--file-list'
|
195
|
-
lines = ts_paths_array.map{|i|i['source']}
|
196
|
-
end
|
197
|
-
file_list_file = Aspera::TempFileManager.instance.new_file_path_in_folder(self.class.file_list_folder)
|
198
|
-
File.write(file_list_file, lines.join("\n"))
|
199
|
-
Log.log.debug{"#{option}=\n#{File.read(file_list_file)}".red}
|
200
|
-
else
|
201
|
-
# not safe for special characters ? (maybe not, depends on OS)
|
202
|
-
Log.log.debug('placing source file list on command line (no file list file)')
|
203
|
-
@builder.add_command_line_options(ts_paths_array.map{|i|i['source']})
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
@builder.add_command_line_options(["#{option}=#{file_list_file}"]) unless option.nil?
|
208
|
-
end
|
210
|
+
# get list of files to transfer and build arg for ascp
|
211
|
+
process_file_list
|
209
212
|
# optional args, at the end to override previous ones (to allow override)
|
210
|
-
@builder.add_command_line_options(@builder.process_param('EX_ascp_args'
|
213
|
+
@builder.add_command_line_options(@builder.process_param('EX_ascp_args', :get_value))
|
211
214
|
# process destination folder
|
212
|
-
destination_folder = @builder.process_param('destination_root'
|
215
|
+
destination_folder = @builder.process_param('destination_root', :get_value) || '/'
|
213
216
|
# ascp4 does not support base64 encoding of destination
|
214
217
|
destination_folder = Base64.strict_encode64(destination_folder) unless env_args[:ascp_version].eql?(:ascp4)
|
215
218
|
# destination MUST be last command line argument to ascp
|
216
219
|
@builder.add_command_line_options([destination_folder])
|
217
220
|
|
218
|
-
@builder.add_env_args(env_args[:env],env_args[:args])
|
221
|
+
@builder.add_env_args(env_args[:env], env_args[:args])
|
219
222
|
|
220
223
|
return env_args
|
221
224
|
end
|
@@ -313,8 +313,8 @@ ssh_port:
|
|
313
313
|
ssh_private_key:
|
314
314
|
:desc: |-
|
315
315
|
Private key used for SSH authentication.
|
316
|
-
Shall look like: -----BEGIN RSA PRIV4TE KEY
|
317
|
-
Note the JSON encoding:
|
316
|
+
Shall look like: -----BEGIN RSA PRIV4TE KEY-----/nMII...
|
317
|
+
Note the JSON encoding: /n for newlines.
|
318
318
|
|
319
319
|
|
320
320
|
:tragents:
|
@@ -20,13 +20,13 @@ module Aspera
|
|
20
20
|
@parameters = DEFAULTS.dup
|
21
21
|
if !params.nil?
|
22
22
|
raise "expecting Hash (or nil), but have #{params.class}" unless params.is_a?(Hash)
|
23
|
-
params.each do |k,v|
|
24
|
-
raise "unknown resume parameter: #{k}, expect one of #{DEFAULTS.keys.map(&:to_s).join(',')}" unless DEFAULTS.
|
23
|
+
params.each do |k, v|
|
24
|
+
raise "unknown resume parameter: #{k}, expect one of #{DEFAULTS.keys.map(&:to_s).join(',')}" unless DEFAULTS.key?(k)
|
25
25
|
raise "#{k} must be Integer" unless v.is_a?(Integer)
|
26
26
|
@parameters[k] = v
|
27
27
|
end
|
28
28
|
end
|
29
|
-
Log.log.debug
|
29
|
+
Log.log.debug{"resume params=#{@parameters}"}
|
30
30
|
end
|
31
31
|
|
32
32
|
# calls block a number of times (resumes) until success or limit reached
|
@@ -36,20 +36,20 @@ module Aspera
|
|
36
36
|
# maximum of retry
|
37
37
|
remaining_resumes = @parameters[:iter_max]
|
38
38
|
sleep_seconds = @parameters[:sleep_initial]
|
39
|
-
Log.log.debug
|
39
|
+
Log.log.debug{"retries=#{remaining_resumes}"}
|
40
40
|
# try to send the file until ascp is succesful
|
41
41
|
loop do
|
42
|
-
Log.log.debug('transfer starting')
|
42
|
+
Log.log.debug('transfer starting')
|
43
43
|
begin
|
44
44
|
# call provided block
|
45
45
|
yield
|
46
46
|
break
|
47
47
|
rescue Fasp::Error => e
|
48
|
-
Log.log.warn
|
48
|
+
Log.log.warn{"An error occurred: #{e.message}"}
|
49
49
|
# failure in ascp
|
50
50
|
if e.retryable?
|
51
51
|
# exit if we exceed the max number of retry
|
52
|
-
raise Fasp::Error,'Maximum number of retry reached' if remaining_resumes <= 0
|
52
|
+
raise Fasp::Error, 'Maximum number of retry reached' if remaining_resumes <= 0
|
53
53
|
else
|
54
54
|
# give one chance only to non retryable errors
|
55
55
|
unless remaining_resumes.eql?(@parameters[:iter_max])
|
@@ -61,7 +61,7 @@ module Aspera
|
|
61
61
|
|
62
62
|
# take this retry in account
|
63
63
|
remaining_resumes -= 1
|
64
|
-
Log.log.warn
|
64
|
+
Log.log.warn{"resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
|
65
65
|
|
66
66
|
# wait a bit before retrying, maybe network condition will be better
|
67
67
|
sleep(sleep_seconds)
|