aspera-cli 4.7.0 → 4.9.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/README.md +1267 -999
- data/bin/ascli +20 -1
- data/bin/asession +37 -34
- data/docs/test_env.conf +7 -3
- data/examples/aoc.rb +13 -12
- data/examples/dascli +23 -0
- data/examples/faspex4.rb +34 -29
- data/examples/{transfer.rb → node.rb} +31 -59
- data/examples/server.rb +93 -0
- data/lib/aspera/aoc.rb +153 -143
- data/lib/aspera/ascmd.rb +56 -45
- data/lib/aspera/ats_api.rb +9 -6
- data/lib/aspera/cli/basic_auth_plugin.rb +18 -16
- data/lib/aspera/cli/extended_value.rb +33 -30
- data/lib/aspera/cli/formater.rb +105 -111
- data/lib/aspera/cli/info.rb +3 -2
- data/lib/aspera/cli/listener/line_dump.rb +1 -0
- data/lib/aspera/cli/listener/logger.rb +1 -0
- data/lib/aspera/cli/listener/progress.rb +13 -12
- data/lib/aspera/cli/listener/progress_multi.rb +21 -20
- data/lib/aspera/cli/main.rb +110 -90
- data/lib/aspera/cli/manager.rb +99 -88
- data/lib/aspera/cli/plugin.rb +98 -39
- data/lib/aspera/cli/plugins/alee.rb +6 -5
- data/lib/aspera/cli/plugins/aoc.rb +581 -450
- data/lib/aspera/cli/plugins/ats.rb +84 -83
- data/lib/aspera/cli/plugins/bss.rb +30 -27
- data/lib/aspera/cli/plugins/config.rb +488 -397
- data/lib/aspera/cli/plugins/console.rb +17 -15
- data/lib/aspera/cli/plugins/cos.rb +26 -35
- data/lib/aspera/cli/plugins/faspex.rb +206 -172
- data/lib/aspera/cli/plugins/faspex5.rb +109 -74
- data/lib/aspera/cli/plugins/node.rb +379 -189
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -65
- data/lib/aspera/cli/plugins/preview.rb +131 -122
- data/lib/aspera/cli/plugins/server.rb +50 -150
- data/lib/aspera/cli/plugins/shares.rb +61 -27
- data/lib/aspera/cli/plugins/sync.rb +15 -14
- data/lib/aspera/cli/transfer_agent.rb +75 -64
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +29 -28
- data/lib/aspera/command_line_builder.rb +50 -43
- data/lib/aspera/cos_node.rb +64 -38
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +33 -10
- data/lib/aspera/fasp/agent_base.rb +35 -30
- data/lib/aspera/fasp/agent_connect.rb +35 -30
- data/lib/aspera/fasp/agent_direct.rb +68 -60
- data/lib/aspera/fasp/agent_httpgw.rb +71 -64
- data/lib/aspera/fasp/agent_node.rb +24 -23
- data/lib/aspera/fasp/agent_trsdk.rb +19 -20
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +79 -68
- data/lib/aspera/fasp/installation.rb +130 -126
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +71 -60
- data/lib/aspera/fasp/parameters.yaml +69 -17
- data/lib/aspera/fasp/resume_policy.rb +14 -11
- data/lib/aspera/fasp/transfer_spec.rb +6 -5
- data/lib/aspera/fasp/uri.rb +25 -24
- data/lib/aspera/faspex_gw.rb +83 -72
- data/lib/aspera/hash_ext.rb +23 -13
- data/lib/aspera/id_generator.rb +16 -13
- data/lib/aspera/keychain/encrypted_hash.rb +61 -46
- data/lib/aspera/keychain/macos_security.rb +26 -24
- data/lib/aspera/log.rb +35 -39
- data/lib/aspera/nagios.rb +36 -28
- data/lib/aspera/node.rb +19 -19
- data/lib/aspera/oauth.rb +120 -100
- data/lib/aspera/open_application.rb +25 -22
- data/lib/aspera/persistency_action_once.rb +9 -8
- data/lib/aspera/persistency_folder.rb +13 -9
- data/lib/aspera/preview/file_types.rb +261 -266
- data/lib/aspera/preview/generator.rb +74 -73
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +7 -6
- data/lib/aspera/preview/utils.rb +30 -33
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.rb +27 -23
- data/lib/aspera/rest.rb +73 -74
- data/lib/aspera/rest_call_error.rb +1 -0
- data/lib/aspera/rest_error_analyzer.rb +23 -19
- data/lib/aspera/rest_errors_aspera.rb +43 -40
- data/lib/aspera/secret_hider.rb +74 -0
- data/lib/aspera/ssh.rb +13 -10
- data/lib/aspera/sync.rb +49 -47
- data/lib/aspera/temp_file_manager.rb +7 -5
- data/lib/aspera/timer_limiter.rb +9 -8
- data/lib/aspera/uri_reader.rb +17 -18
- data/lib/aspera/web_auth.rb +17 -15
- data.tar.gz.sig +5 -0
- metadata +119 -35
- metadata.gz.sig +0 -0
- data/bin/dascli +0 -13
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'aspera/log'
|
3
4
|
require 'aspera/command_line_builder'
|
4
5
|
require 'aspera/temp_file_manager'
|
@@ -14,40 +15,45 @@ module Aspera
|
|
14
15
|
# translate transfer specification to ascp parameter list
|
15
16
|
class Parameters
|
16
17
|
# Agents shown in manual for parameters (sub list)
|
17
|
-
SUPPORTED_AGENTS=[
|
18
|
+
SUPPORTED_AGENTS = %i[direct node connect].freeze
|
18
19
|
# Short names of columns in manual
|
19
|
-
SUPPORTED_AGENTS_SHORT=SUPPORTED_AGENTS.map{|a|a.to_s[0].to_sym}
|
20
|
+
SUPPORTED_AGENTS_SHORT = SUPPORTED_AGENTS.map{|a|a.to_s[0].to_sym}
|
21
|
+
|
22
|
+
private_constant :SUPPORTED_AGENTS
|
20
23
|
|
21
24
|
class << self
|
22
25
|
# Temp folder for file lists, must contain only file lists
|
23
26
|
# because of garbage collection takes any file there
|
24
27
|
# this could be refined, as , for instance, on macos, temp folder is already user specific
|
25
|
-
@file_list_folder=TempFileManager.instance.new_file_path_global('asession_filelists')
|
26
|
-
@param_description_cache=nil
|
28
|
+
@file_list_folder = TempFileManager.instance.new_file_path_global('asession_filelists')
|
29
|
+
@param_description_cache = nil
|
27
30
|
# @return normalized description of transfer spec parameters, direct from yaml
|
28
31
|
def description
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
if @param_description_cache.nil?
|
33
|
+
# config file in same folder with same name as this source
|
34
|
+
description_from_yaml=YAML.load_file("#{__FILE__[0..-3]}yaml")
|
35
|
+
@param_description_cache = Aspera::CommandLineBuilder.normalize_description(description_from_yaml)
|
36
|
+
end
|
37
|
+
return @param_description_cache
|
33
38
|
end
|
34
39
|
|
35
40
|
# @return a table suitable to display in manual
|
36
41
|
def man_table
|
37
|
-
result=[]
|
42
|
+
result = []
|
38
43
|
description.each do |k,i|
|
39
|
-
param={name: k, type: [i[:accepted_types]].flatten.join(','),description: i[:desc]}
|
44
|
+
param = {name: k, type: [i[:accepted_types]].flatten.join(','),description: i[:desc]}
|
45
|
+
# add flags for supported agents in doc
|
40
46
|
SUPPORTED_AGENTS.each do |a|
|
41
|
-
param[a.to_s[0].to_sym]=i[:tragents].nil? || i[:tragents].include?(a) ? 'Y' : ''
|
47
|
+
param[a.to_s[0].to_sym] = i[:tragents].nil? || i[:tragents].include?(a) ? 'Y' : ''
|
42
48
|
end
|
43
49
|
# only keep lines that are usable in supported agents
|
44
50
|
next if SUPPORTED_AGENTS_SHORT.inject(true){|m,j|m && param[j].empty?}
|
45
|
-
param[:cli]=
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
+
param[:cli] =
|
52
|
+
case i[:cltype]
|
53
|
+
when :envvar then 'env:' + i[:clvarname]
|
54
|
+
when :opt_without_arg,:opt_with_arg then i[:clswitch]
|
55
|
+
else ''
|
56
|
+
end
|
51
57
|
if i.has_key?(:enum)
|
52
58
|
param[:description] += "\nAllowed values: #{i[:enum].join(', ')}"
|
53
59
|
end
|
@@ -65,17 +71,20 @@ module Aspera
|
|
65
71
|
# special encoding methods used in YAML (key: :clconvert)
|
66
72
|
def clconv_base64(v); Base64.strict_encode64(v); end
|
67
73
|
|
68
|
-
|
69
|
-
|
74
|
+
# file list is provided directly with ascp arguments
|
75
|
+
def ts_has_ascp_file_list(ts)
|
76
|
+
(ts['EX_ascp_args'].is_a?(Array) && ['--file-list','--file-pair-list'].any?{|i|ts['EX_ascp_args'].include?(i)}) ||
|
77
|
+
ts.has_key?('EX_file_list') ||
|
78
|
+
ts.has_key?('EX_file_pair_list')
|
70
79
|
end
|
71
80
|
|
72
81
|
def ts_to_env_args(transfer_spec,options)
|
73
|
-
return Parameters.new(transfer_spec,options).ascp_args
|
82
|
+
return Parameters.new(transfer_spec,options).ascp_args
|
74
83
|
end
|
75
84
|
|
76
85
|
# temp file list files are created here
|
77
86
|
def file_list_folder=(v)
|
78
|
-
@file_list_folder=v
|
87
|
+
@file_list_folder = v
|
79
88
|
return if @file_list_folder.nil?
|
80
89
|
FileUtils.mkdir_p(@file_list_folder)
|
81
90
|
TempFileManager.instance.cleanup_expired(@file_list_folder)
|
@@ -87,18 +96,18 @@ module Aspera
|
|
87
96
|
|
88
97
|
# @param options [Hash] key: :wss: bool
|
89
98
|
def initialize(job_spec,options)
|
90
|
-
@job_spec=job_spec
|
91
|
-
@options=options
|
92
|
-
@builder=Aspera::CommandLineBuilder.new(@job_spec,self.class.description)
|
99
|
+
@job_spec = job_spec
|
100
|
+
@options = options
|
101
|
+
@builder = Aspera::CommandLineBuilder.new(@job_spec,self.class.description)
|
93
102
|
Log.log.debug("agent options: #{@options}")
|
94
103
|
end
|
95
104
|
|
96
105
|
# translate transfer spec to env vars and command line arguments for ascp
|
97
106
|
# NOTE: parameters starting with "EX_" (extended) are not standard
|
98
107
|
def ascp_args
|
99
|
-
env_args={
|
100
|
-
args:
|
101
|
-
env:
|
108
|
+
env_args = {
|
109
|
+
args: [],
|
110
|
+
env: {},
|
102
111
|
ascp_version: :ascp
|
103
112
|
}
|
104
113
|
# some ssh credentials are required to avoid interactive password input
|
@@ -117,12 +126,12 @@ module Aspera
|
|
117
126
|
@builder.add_command_line_options(['--ws-connect'])
|
118
127
|
# TODO: option to give order ssh,ws (legacy http is implied bu ssh)
|
119
128
|
# quel bordel:
|
120
|
-
@job_spec['ssh_port']
|
129
|
+
@job_spec['ssh_port'] = @builder.process_param('wss_port',:get_value)
|
121
130
|
@job_spec.delete('fasp_port')
|
122
131
|
@job_spec.delete('EX_ssh_key_paths')
|
123
132
|
@job_spec.delete('sshfp')
|
124
133
|
# set location for CA bundle to be the one of Ruby, see env var SSL_CERT_FILE / SSL_CERT_DIR
|
125
|
-
@job_spec['EX_ssh_key_paths']=[OpenSSL::X509::DEFAULT_CERT_FILE]
|
134
|
+
@job_spec['EX_ssh_key_paths'] = [OpenSSL::X509::DEFAULT_CERT_FILE]
|
126
135
|
Log.log.debug('CA certs: EX_ssh_key_paths <- DEFAULT_CERT_FILE from openssl')
|
127
136
|
else
|
128
137
|
# remove unused parameter (avoid warning)
|
@@ -140,48 +149,50 @@ module Aspera
|
|
140
149
|
# destination will be base64 encoded, put before path arguments
|
141
150
|
@builder.add_command_line_options(['--dest64'])
|
142
151
|
end
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
#
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
@builder.add_command_line_options(paths_array.map{|i|i['source']})
|
152
|
+
# process file lists
|
153
|
+
begin
|
154
|
+
# is the file list provided through EX_ parameters?
|
155
|
+
ascp_file_list_provided = self.class.ts_has_ascp_file_list(@job_spec)
|
156
|
+
# set if paths is mandatory in ts
|
157
|
+
@builder.params_definition['paths'][:mandatory] = !@job_spec.has_key?('keepalive') && !ascp_file_list_provided
|
158
|
+
# get paths in transfer spec (after setting if it is mandatory)
|
159
|
+
ts_paths_array = @builder.process_param('paths',:get_value)
|
160
|
+
if ascp_file_list_provided && !ts_paths_array.nil?
|
161
|
+
raise 'file list provided both in transfer spec and ascp file list. Remove one of them.'
|
162
|
+
end
|
163
|
+
# option 1: EX_file_list
|
164
|
+
file_list_file = @builder.process_param('EX_file_list',:get_value)
|
165
|
+
if !file_list_file.nil?
|
166
|
+
option = '--file-list'
|
159
167
|
else
|
160
|
-
|
168
|
+
# option 2: EX_file_pair_list
|
169
|
+
file_list_file = @builder.process_param('EX_file_pair_list',:get_value)
|
161
170
|
if !file_list_file.nil?
|
162
|
-
option='--file-list'
|
163
|
-
|
164
|
-
|
165
|
-
if !
|
166
|
-
option
|
167
|
-
else
|
168
|
-
# safer option: file list
|
171
|
+
option = '--file-pair-list'
|
172
|
+
elsif !ts_paths_array.nil?
|
173
|
+
# option 3: in TS, it is an array
|
174
|
+
if !self.class.file_list_folder.nil?
|
175
|
+
# safer option: generate a file list file if there is storage defined for it
|
169
176
|
# if there is destination in paths, then use filepairlist
|
170
177
|
# TODO: well, we test only the first one, but anyway it shall be consistent
|
171
|
-
if
|
172
|
-
option='--file-pair-list'
|
173
|
-
lines=
|
178
|
+
if ts_paths_array.first.has_key?('destination')
|
179
|
+
option = '--file-pair-list'
|
180
|
+
lines = ts_paths_array.each_with_object([]){|e,m|m.push(e['source'],e['destination']);}
|
174
181
|
else
|
175
|
-
option='--file-list'
|
176
|
-
lines=
|
182
|
+
option = '--file-list'
|
183
|
+
lines = ts_paths_array.map{|i|i['source']}
|
177
184
|
end
|
178
|
-
file_list_file=Aspera::TempFileManager.instance.new_file_path_in_folder(self.class.file_list_folder)
|
185
|
+
file_list_file = Aspera::TempFileManager.instance.new_file_path_in_folder(self.class.file_list_folder)
|
179
186
|
File.write(file_list_file, lines.join("\n"))
|
180
187
|
Log.log.debug{"#{option}=\n#{File.read(file_list_file)}".red}
|
188
|
+
else
|
189
|
+
# not safe for special characters ? (maybe not, depends on OS)
|
190
|
+
Log.log.debug('placing source file list on command line (no file list file)')
|
191
|
+
@builder.add_command_line_options(ts_paths_array.map{|i|i['source']})
|
181
192
|
end
|
182
193
|
end
|
183
|
-
@builder.add_command_line_options(["#{option}=#{file_list_file}"])
|
184
194
|
end
|
195
|
+
@builder.add_command_line_options(["#{option}=#{file_list_file}"]) unless option.nil?
|
185
196
|
end
|
186
197
|
# optional args, at the end to override previous ones (to allow override)
|
187
198
|
@builder.add_command_line_options(@builder.process_param('EX_ascp_args',:get_value))
|
@@ -49,7 +49,13 @@ create_dir:
|
|
49
49
|
:cltype: :opt_without_arg
|
50
50
|
:clswitch: "-d"
|
51
51
|
delete_before_transfer:
|
52
|
-
:desc:
|
52
|
+
:desc: |-
|
53
|
+
Before transfer, delete files that exist at the destination but not at the source.
|
54
|
+
The source and destination arguments must be directories that have matching names.
|
55
|
+
Objects on the destination that have the same name but different type or size as objects
|
56
|
+
on the source are not deleted.
|
57
|
+
|
58
|
+
|
53
59
|
:cltype: :opt_without_arg
|
54
60
|
delete_source: # duplicate of remove_after_transfer ?
|
55
61
|
:desc: Remove SRC files after transfer success
|
@@ -138,16 +144,24 @@ https_fallback_port:
|
|
138
144
|
:cltype: :opt_with_arg
|
139
145
|
:clswitch: "-t"
|
140
146
|
move_after_transfer:
|
147
|
+
:desc: The relative path to which the files will be moved after the transfer at the source side.
|
141
148
|
:cltype: :opt_with_arg
|
142
149
|
multi_session:
|
143
|
-
:desc:
|
144
|
-
|
145
|
-
|
150
|
+
:desc: |
|
151
|
+
Use multi-session transfer. max 128.
|
152
|
+
Each participant on one host needs an independent UDP (-O) port.
|
153
|
+
Large files are split between sessions only when transferring with resume_policy=none.
|
154
|
+
|
155
|
+
|
146
156
|
:accepted_types: :int
|
147
157
|
:cltype: :ignore
|
148
158
|
:clswitch: "-C"
|
149
159
|
multi_session_threshold:
|
150
|
-
:desc:
|
160
|
+
:desc: |-
|
161
|
+
Split files across multiple ascp sessions if their size in bytes is greater than or equal to the specified value.
|
162
|
+
(0=no file is split)
|
163
|
+
|
164
|
+
|
151
165
|
:accepted_types: :int
|
152
166
|
:tragents:
|
153
167
|
- :direct
|
@@ -163,6 +177,18 @@ overwrite:
|
|
163
177
|
- older
|
164
178
|
- diff+older
|
165
179
|
:cltype: :opt_with_arg
|
180
|
+
password:
|
181
|
+
:desc: |-
|
182
|
+
Password for local Windows user when transfer user associated with node api user is not the same as the one running asperanoded.
|
183
|
+
Allows impersonating the transfer user and have access to resources (e.g. network shares).
|
184
|
+
Windows only, node api only.
|
185
|
+
|
186
|
+
|
187
|
+
:required: false
|
188
|
+
:accepted_types: :string
|
189
|
+
:cltype: :ignore
|
190
|
+
:tragents:
|
191
|
+
- :node
|
166
192
|
paths:
|
167
193
|
:desc: Array of path to the source (required) and a path to the destination (optional).
|
168
194
|
:required: true
|
@@ -233,10 +259,13 @@ remove_skipped:
|
|
233
259
|
- :node
|
234
260
|
:cltype: :opt_without_arg
|
235
261
|
proxy:
|
236
|
-
:desc:
|
237
|
-
|
238
|
-
|
239
|
-
|
262
|
+
:desc: |-
|
263
|
+
Specify the address of the Aspera high-speed proxy server.
|
264
|
+
dnat(s)://[user[:password]@]server:port
|
265
|
+
Default ports for DNAT and DNATS protocols are 9091 and 9092.
|
266
|
+
Password, if specified here, overrides the value of environment variable ASPERA_PROXY_PASS.
|
267
|
+
|
268
|
+
|
240
269
|
:tragents:
|
241
270
|
- :direct
|
242
271
|
- :sdk
|
@@ -279,9 +308,12 @@ ssh_port:
|
|
279
308
|
:cltype: :opt_with_arg
|
280
309
|
:clswitch: "-P"
|
281
310
|
ssh_private_key:
|
282
|
-
:desc:
|
283
|
-
|
284
|
-
|
311
|
+
:desc: |-
|
312
|
+
Private key used for SSH authentication.
|
313
|
+
Shall look like: -----BEGIN RSA PRIV4TE KEY-----\nMII...
|
314
|
+
Note the JSON encoding: \n for newlines.
|
315
|
+
|
316
|
+
|
285
317
|
:tragents:
|
286
318
|
- :direct
|
287
319
|
- :sdk
|
@@ -355,8 +387,11 @@ use_system_ssh:
|
|
355
387
|
:cltype: :ignore
|
356
388
|
:clswitch: "-SSH"
|
357
389
|
source_root:
|
358
|
-
:desc:
|
359
|
-
|
390
|
+
:desc: |-
|
391
|
+
Path to be prepended to each source path.
|
392
|
+
This is either a conventional path or it can be a URI but only if there is no root defined.
|
393
|
+
|
394
|
+
|
360
395
|
:cltype: :opt_with_arg
|
361
396
|
:clswitch: "--source-prefix64"
|
362
397
|
:clconvert: Aspera::Fasp::Parameters.clconv_base64
|
@@ -377,6 +412,20 @@ apply_local_docroot:
|
|
377
412
|
- :direct
|
378
413
|
- :sdk
|
379
414
|
:cltype: :opt_without_arg
|
415
|
+
src_base:
|
416
|
+
:desc: |-
|
417
|
+
Specify the prefix to be stripped off from each source object.
|
418
|
+
The remaining portion of the source path is kept intact at the destination.
|
419
|
+
Special care must be taken when used with cloud storage.
|
420
|
+
|
421
|
+
|
422
|
+
:tragents:
|
423
|
+
- :direct
|
424
|
+
- :node
|
425
|
+
- :sdk
|
426
|
+
:cltype: :opt_with_arg
|
427
|
+
:clswitch: "--src-base64"
|
428
|
+
:clconvert: Aspera::Fasp::Parameters.clconv_base64
|
380
429
|
preserve_acls:
|
381
430
|
:desc: "Preserve access control lists."
|
382
431
|
:enum:
|
@@ -440,14 +489,17 @@ remove_empty_source_directory:
|
|
440
489
|
- :sdk
|
441
490
|
:cltype: :opt_without_arg
|
442
491
|
EX_at_rest_password:
|
443
|
-
:desc: "
|
492
|
+
:desc: "DEPRECATED: Prefer to use standard parameter: content_protection_password"
|
444
493
|
:tragents:
|
445
494
|
- :direct
|
446
495
|
:cltype: :envvar
|
447
496
|
:clvarname: ASPERA_SCP_FILEPASS
|
448
497
|
EX_proxy_password:
|
449
|
-
:desc:
|
450
|
-
|
498
|
+
:desc: |-
|
499
|
+
Password used for Aspera proxy server authentication.
|
500
|
+
May be overridden by password in URL EX_fasp_proxy_url.
|
501
|
+
|
502
|
+
|
451
503
|
:tragents:
|
452
504
|
- :direct
|
453
505
|
:cltype: :envvar
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'singleton'
|
3
4
|
require 'aspera/log'
|
4
5
|
|
@@ -7,22 +8,22 @@ module Aspera
|
|
7
8
|
# implements a simple resume policy
|
8
9
|
class ResumePolicy
|
9
10
|
# list of supported parameters and default values
|
10
|
-
DEFAULTS={
|
11
|
-
iter_max:
|
12
|
-
sleep_initial:
|
13
|
-
sleep_factor:
|
14
|
-
sleep_max:
|
15
|
-
}
|
11
|
+
DEFAULTS = {
|
12
|
+
iter_max: 7,
|
13
|
+
sleep_initial: 2,
|
14
|
+
sleep_factor: 2,
|
15
|
+
sleep_max: 60
|
16
|
+
}.freeze
|
16
17
|
|
17
18
|
# @param params see DEFAULTS
|
18
19
|
def initialize(params=nil)
|
19
|
-
@parameters=DEFAULTS.
|
20
|
+
@parameters = DEFAULTS.dup
|
20
21
|
if !params.nil?
|
21
22
|
raise "expecting Hash (or nil), but have #{params.class}" unless params.is_a?(Hash)
|
22
23
|
params.each do |k,v|
|
23
24
|
raise "unknown resume parameter: #{k}, expect one of #{DEFAULTS.keys.map(&:to_s).join(',')}" unless DEFAULTS.has_key?(k)
|
24
25
|
raise "#{k} must be Integer" unless v.is_a?(Integer)
|
25
|
-
@parameters[k]=v
|
26
|
+
@parameters[k] = v
|
26
27
|
end
|
27
28
|
end
|
28
29
|
Log.log.debug("resume params=#{@parameters}")
|
@@ -30,7 +31,8 @@ module Aspera
|
|
30
31
|
|
31
32
|
# calls block a number of times (resumes) until success or limit reached
|
32
33
|
# this is re-entrant, one resumer can handle multiple transfers in //
|
33
|
-
def
|
34
|
+
def execute_with_resume
|
35
|
+
raise 'block manndatory' unless block_given?
|
34
36
|
# maximum of retry
|
35
37
|
remaining_resumes = @parameters[:iter_max]
|
36
38
|
sleep_seconds = @parameters[:sleep_initial]
|
@@ -39,7 +41,8 @@ module Aspera
|
|
39
41
|
loop do
|
40
42
|
Log.log.debug('transfer starting');
|
41
43
|
begin
|
42
|
-
block
|
44
|
+
# call provided block
|
45
|
+
yield
|
43
46
|
break
|
44
47
|
rescue Fasp::Error => e
|
45
48
|
Log.log.warn("An error occured: #{e.message}");
|
@@ -57,7 +60,7 @@ module Aspera
|
|
57
60
|
end
|
58
61
|
|
59
62
|
# take this retry in account
|
60
|
-
remaining_resumes-=1
|
63
|
+
remaining_resumes -= 1
|
61
64
|
Log.log.warn("resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})");
|
62
65
|
|
63
66
|
# wait a bit before retrying, maybe network condition will be better
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'aspera/fasp/parameters'
|
3
4
|
|
4
5
|
module Aspera
|
@@ -6,14 +7,14 @@ module Aspera
|
|
6
7
|
# parameters for Transfer Spec
|
7
8
|
class TransferSpec
|
8
9
|
# default transfer username for access key based transfers
|
9
|
-
ACCESS_KEY_TRANSFER_USER='xfer'
|
10
|
-
SSH_PORT=33_001
|
11
|
-
UDP_PORT=33_001
|
12
|
-
AK_TSPEC_BASE={
|
10
|
+
ACCESS_KEY_TRANSFER_USER = 'xfer'
|
11
|
+
SSH_PORT = 33_001
|
12
|
+
UDP_PORT = 33_001
|
13
|
+
AK_TSPEC_BASE = {
|
13
14
|
'remote_user' => ACCESS_KEY_TRANSFER_USER,
|
14
15
|
'ssh_port' => SSH_PORT,
|
15
16
|
'fasp_port' => UDP_PORT
|
16
|
-
}
|
17
|
+
}.freeze
|
17
18
|
# define constants for enums of parameters: <paramater>_<enum>, e.g. CIPHER_AES_128
|
18
19
|
Aspera::Fasp::Parameters.description.each do |k,v|
|
19
20
|
next unless v[:enum].is_a?(Array)
|
data/lib/aspera/fasp/uri.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'aspera/log'
|
3
4
|
require 'aspera/command_line_builder'
|
4
5
|
|
@@ -7,38 +8,38 @@ module Aspera
|
|
7
8
|
# translates a "faspe:" URI (used in Faspex) into transfer spec hash
|
8
9
|
class Uri
|
9
10
|
def initialize(fasplink)
|
10
|
-
@fasp_uri=URI.parse(fasplink.gsub(' ','%20'))
|
11
|
+
@fasp_uri = URI.parse(fasplink.gsub(' ','%20'))
|
11
12
|
# TODO: check scheme is faspe
|
12
13
|
end
|
13
14
|
|
14
15
|
def transfer_spec
|
15
|
-
result_ts={}
|
16
|
-
result_ts['remote_host']
|
17
|
-
result_ts['remote_user']
|
18
|
-
result_ts['ssh_port']
|
19
|
-
result_ts['paths']=[{'source'=>URI.decode_www_form_component(@fasp_uri.path)}]
|
16
|
+
result_ts = {}
|
17
|
+
result_ts['remote_host'] = @fasp_uri.host
|
18
|
+
result_ts['remote_user'] = @fasp_uri.user
|
19
|
+
result_ts['ssh_port'] = @fasp_uri.port
|
20
|
+
result_ts['paths'] = [{'source' => URI.decode_www_form_component(@fasp_uri.path)}]
|
20
21
|
# faspex does not encode trailing base64 encoded tags, fix that
|
21
|
-
fixed_query = @fasp_uri.query.gsub(/(=+)$/){|x|'%3D'*x.length}
|
22
|
+
fixed_query = @fasp_uri.query.gsub(/(=+)$/){|x|'%3D' * x.length}
|
22
23
|
|
23
24
|
URI.decode_www_form(fixed_query).each do |i|
|
24
|
-
name=i[0]
|
25
|
-
value=i[1]
|
25
|
+
name = i[0]
|
26
|
+
value = i[1]
|
26
27
|
case name
|
27
|
-
when 'cookie' then result_ts['cookie']=value
|
28
|
-
when 'token' then result_ts['token']=value
|
29
|
-
when 'sshfp' then result_ts['sshfp']=value
|
30
|
-
when 'policy' then result_ts['rate_policy']=value
|
31
|
-
when 'httpport' then result_ts['http_fallback_port']=value.to_i
|
32
|
-
when 'targetrate' then result_ts['target_rate_kbps']=value.to_i
|
33
|
-
when 'minrate' then result_ts['min_rate_kbps']=value.to_i
|
34
|
-
when 'port' then result_ts['fasp_port']=value.to_i
|
35
|
-
when 'bwcap' then result_ts['target_rate_cap_kbps']=value.to_i
|
36
|
-
when 'enc' then result_ts['cipher']=value.gsub(/^aes/,'aes-').gsub(/cfb$/,'-cfb').gsub(/gcm$/,'-gcm').gsub(/--/,'-')
|
37
|
-
when 'tags64' then result_ts['tags']=JSON.parse(Base64.strict_decode64(value))
|
38
|
-
when 'createpath' then result_ts['create_dir']=CommandLineBuilder.yes_to_true(value)
|
39
|
-
when 'fallback' then result_ts['http_fallback']=CommandLineBuilder.yes_to_true(value)
|
40
|
-
when 'lockpolicy' then result_ts['lock_rate_policy']=CommandLineBuilder.yes_to_true(value)
|
41
|
-
when 'lockminrate' then result_ts['lock_min_rate']=CommandLineBuilder.yes_to_true(value)
|
28
|
+
when 'cookie' then result_ts['cookie'] = value
|
29
|
+
when 'token' then result_ts['token'] = value
|
30
|
+
when 'sshfp' then result_ts['sshfp'] = value
|
31
|
+
when 'policy' then result_ts['rate_policy'] = value
|
32
|
+
when 'httpport' then result_ts['http_fallback_port'] = value.to_i
|
33
|
+
when 'targetrate' then result_ts['target_rate_kbps'] = value.to_i
|
34
|
+
when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
|
35
|
+
when 'port' then result_ts['fasp_port'] = value.to_i
|
36
|
+
when 'bwcap' then result_ts['target_rate_cap_kbps'] = value.to_i
|
37
|
+
when 'enc' then result_ts['cipher'] = value.gsub(/^aes/,'aes-').gsub(/cfb$/,'-cfb').gsub(/gcm$/,'-gcm').gsub(/--/,'-')
|
38
|
+
when 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
|
39
|
+
when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
|
40
|
+
when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
|
41
|
+
when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
|
42
|
+
when 'lockminrate' then result_ts['lock_min_rate'] = CommandLineBuilder.yes_to_true(value)
|
42
43
|
when 'auth' then Log.log.debug("ignoring auth #{name}=#{value}") # TODO: translate into transfer spec ? yes/no
|
43
44
|
when 'v' then Log.log.debug("ignoring v #{name}=#{value}") # TODO: translate into transfer spec ? 2
|
44
45
|
when 'protect' then Log.log.debug("ignoring protect #{name}=#{value}") # TODO: translate into transfer spec ?
|