aspera-cli 4.10.0 → 4.11.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 +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)
|