aspera-cli 4.1.0 → 4.3.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
- data/README.md +455 -229
- data/docs/Makefile +4 -4
- data/docs/README.erb.md +457 -126
- data/docs/test_env.conf +19 -2
- data/examples/aoc.rb +14 -3
- data/examples/faspex4.rb +89 -0
- data/lib/aspera/aoc.rb +38 -40
- data/lib/aspera/cli/main.rb +65 -33
- data/lib/aspera/cli/plugins/aoc.rb +54 -65
- data/lib/aspera/cli/plugins/ats.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +158 -137
- data/lib/aspera/cli/plugins/faspex.rb +111 -64
- data/lib/aspera/cli/plugins/faspex5.rb +35 -48
- data/lib/aspera/cli/plugins/node.rb +3 -2
- data/lib/aspera/cli/plugins/preview.rb +88 -55
- data/lib/aspera/cli/transfer_agent.rb +98 -62
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +48 -31
- data/lib/aspera/cos_node.rb +34 -28
- data/lib/aspera/environment.rb +2 -2
- data/lib/aspera/fasp/aoc.rb +1 -1
- data/lib/aspera/fasp/installation.rb +68 -45
- data/lib/aspera/fasp/local.rb +89 -45
- data/lib/aspera/fasp/manager.rb +3 -0
- data/lib/aspera/fasp/node.rb +23 -1
- data/lib/aspera/fasp/parameters.rb +57 -86
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/resume_policy.rb +13 -12
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/id_generator.rb +22 -0
- data/lib/aspera/node.rb +14 -3
- data/lib/aspera/oauth.rb +135 -129
- data/lib/aspera/persistency_action_once.rb +11 -7
- data/lib/aspera/persistency_folder.rb +6 -26
- data/lib/aspera/rest.rb +3 -12
- data/lib/aspera/secrets.rb +20 -0
- data/lib/aspera/sync.rb +40 -35
- data/lib/aspera/timer_limiter.rb +22 -0
- data/lib/aspera/web_auth.rb +105 -0
- metadata +22 -3
- data/docs/transfer_spec.html +0 -99
data/lib/aspera/fasp/local.rb
CHANGED
|
@@ -21,16 +21,25 @@ module Aspera
|
|
|
21
21
|
ACCESS_KEY_TRANSFER_USER='xfer'
|
|
22
22
|
# executes a local "ascp", connects mgt port, equivalent of "Fasp Manager"
|
|
23
23
|
class Local < Manager
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
# options for initialize (same as values in option transfer_info)
|
|
25
|
+
DEFAULT_OPTIONS = {
|
|
26
|
+
:spawn_timeout_sec => 3,
|
|
27
|
+
:spawn_delay_sec => 2,
|
|
28
|
+
:wss => false,
|
|
29
|
+
:multi_incr_udp => true,
|
|
30
|
+
:resume => {}
|
|
31
|
+
}
|
|
32
|
+
DEFAULT_UDP_PORT=33001
|
|
33
|
+
private_constant :DEFAULT_OPTIONS
|
|
34
|
+
# set to false to keep ascp progress bar display ("true" adds ascp's option -q)
|
|
27
35
|
attr_accessor :quiet
|
|
36
|
+
|
|
28
37
|
# start ascp transfer (non blocking), single or multi-session
|
|
29
38
|
# job information added to @jobs
|
|
30
39
|
# @param transfer_spec [Hash] aspera transfer specification
|
|
31
40
|
# @param options [Hash] :resumer, :regenerate_token
|
|
32
41
|
def start_transfer(transfer_spec,options={})
|
|
33
|
-
raise
|
|
42
|
+
raise 'option: must be hash (or nil)' unless options.is_a?(Hash)
|
|
34
43
|
job_options = options.clone
|
|
35
44
|
job_options[:resumer] ||= @resume_policy
|
|
36
45
|
job_options[:job_id] ||= SecureRandom.uuid
|
|
@@ -56,23 +65,34 @@ module Aspera
|
|
|
56
65
|
transfer_spec['EX_ssh_key_paths'] = Installation.instance.bypass_keys
|
|
57
66
|
end
|
|
58
67
|
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
multi_session_number=nil
|
|
68
|
+
# Compute this before using transfer spec because it potentially modifies the transfer spec
|
|
69
|
+
# (even if the var is not used in single session)
|
|
70
|
+
multi_session_info=nil
|
|
63
71
|
if transfer_spec.has_key?('multi_session')
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
multi_session_info={
|
|
73
|
+
count: transfer_spec['multi_session'].to_i,
|
|
74
|
+
}
|
|
75
|
+
# Managed by multi-session, so delete from transfer spec
|
|
67
76
|
transfer_spec.delete('multi_session')
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
if multi_session_info[:count] < 0
|
|
78
|
+
Log.log.error("multi_session(#{transfer_spec['multi_session']}) shall be integer >= 0")
|
|
79
|
+
multi_session_info = nil
|
|
80
|
+
elsif multi_session_info[:count].eql?(0)
|
|
81
|
+
Log.log.debug("multi_session count is zero: no multisession")
|
|
82
|
+
multi_session_info = nil
|
|
83
|
+
else # multi_session_info[:count] > 0
|
|
84
|
+
# if option not true: keep default udp port for all sessions
|
|
85
|
+
if @options[:multi_incr_udp]
|
|
86
|
+
# override if specified, else use default value
|
|
87
|
+
multi_session_info[:udp_base]=transfer_spec.has_key?('fasp_port') ? transfer_spec['fasp_port'] : DEFAULT_UDP_PORT
|
|
88
|
+
# delete from original transfer spec, as we will increment values
|
|
89
|
+
transfer_spec.delete('fasp_port')
|
|
90
|
+
end
|
|
71
91
|
end
|
|
72
92
|
end
|
|
73
93
|
|
|
74
94
|
# compute known args
|
|
75
|
-
env_args=Parameters.ts_to_env_args(transfer_spec,wss: @
|
|
95
|
+
env_args=Parameters.ts_to_env_args(transfer_spec,wss: @options[:wss])
|
|
76
96
|
|
|
77
97
|
# add fallback cert and key as arguments if needed
|
|
78
98
|
if ['1','force'].include?(transfer_spec['http_fallback'])
|
|
@@ -98,25 +118,28 @@ module Aspera
|
|
|
98
118
|
:options => job_options # [Hash]
|
|
99
119
|
}
|
|
100
120
|
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
if multi_session_info.nil?
|
|
122
|
+
Log.log.debug('Starting single session thread')
|
|
103
123
|
# single session for transfer : simple
|
|
104
124
|
session[:thread] = Thread.new(session) {|s|transfer_thread_entry(s)}
|
|
105
125
|
xfer_job[:sessions].push(session)
|
|
106
126
|
else
|
|
107
|
-
|
|
127
|
+
Log.log.debug('Starting multi session threads')
|
|
128
|
+
1.upto(multi_session_info[:count]) do |i|
|
|
129
|
+
# do not delay the first session
|
|
130
|
+
sleep(@options[:spawn_delay_sec]) unless i.eql?(1)
|
|
108
131
|
# do deep copy (each thread has its own copy because it is modified here below and in thread)
|
|
109
132
|
this_session=session.clone()
|
|
110
133
|
this_session[:env_args]=this_session[:env_args].clone()
|
|
111
134
|
this_session[:env_args][:args]=this_session[:env_args][:args].clone()
|
|
112
|
-
this_session[:env_args][:args].unshift("-C#{i}:#{
|
|
113
|
-
#
|
|
114
|
-
this_session[:env_args][:args].unshift(
|
|
135
|
+
this_session[:env_args][:args].unshift("-C#{i}:#{multi_session_info[:count]}")
|
|
136
|
+
# option: increment (default as per ascp manual) or not (cluster on other side ?)
|
|
137
|
+
this_session[:env_args][:args].unshift('-O',"#{multi_session_info[:udp_base]+i-1}") if @options[:multi_incr_udp]
|
|
115
138
|
this_session[:thread] = Thread.new(this_session) {|s|transfer_thread_entry(s)}
|
|
116
139
|
xfer_job[:sessions].push(this_session)
|
|
117
140
|
end
|
|
118
141
|
end
|
|
119
|
-
Log.log.debug(
|
|
142
|
+
Log.log.debug('started session thread(s)')
|
|
120
143
|
|
|
121
144
|
# add job to list of jobs
|
|
122
145
|
@jobs[job_options[:job_id]]=xfer_job
|
|
@@ -128,7 +151,7 @@ module Aspera
|
|
|
128
151
|
# wait for completion of all jobs started
|
|
129
152
|
# @return list of :success or error message
|
|
130
153
|
def wait_for_transfers_completion
|
|
131
|
-
Log.log.debug(
|
|
154
|
+
Log.log.debug('wait_for_transfers_completion')
|
|
132
155
|
# set to non-nil to exit loop
|
|
133
156
|
result=[]
|
|
134
157
|
@jobs.each do |id,job|
|
|
@@ -138,7 +161,7 @@ module Aspera
|
|
|
138
161
|
result.push(session[:error] ? session[:error] : :success)
|
|
139
162
|
end
|
|
140
163
|
end
|
|
141
|
-
Log.log.debug(
|
|
164
|
+
Log.log.debug('all transfers joined')
|
|
142
165
|
# since all are finished and we return the result, clear statuses
|
|
143
166
|
@jobs.clear
|
|
144
167
|
return result
|
|
@@ -146,7 +169,7 @@ module Aspera
|
|
|
146
169
|
|
|
147
170
|
# used by asession (to be removed ?)
|
|
148
171
|
def shutdown
|
|
149
|
-
Log.log.debug(
|
|
172
|
+
Log.log.debug('fasp local shutdown')
|
|
150
173
|
end
|
|
151
174
|
|
|
152
175
|
# This is the low level method to start the "ascp" process
|
|
@@ -158,8 +181,10 @@ module Aspera
|
|
|
158
181
|
# @param session this session information
|
|
159
182
|
# could be private method
|
|
160
183
|
def start_transfer_with_args_env(env_args,session)
|
|
161
|
-
raise
|
|
162
|
-
raise
|
|
184
|
+
raise 'env_args must be Hash' unless env_args.is_a?(Hash)
|
|
185
|
+
raise 'session must be Hash' unless session.is_a?(Hash)
|
|
186
|
+
# by default we assume an exception will be raised (for ensure block)
|
|
187
|
+
exception_raised=true
|
|
163
188
|
begin
|
|
164
189
|
Log.log.debug("env_args=#{env_args.inspect}")
|
|
165
190
|
# get location of ascp executable
|
|
@@ -182,7 +207,7 @@ module Aspera
|
|
|
182
207
|
Log.log.debug("before accept for pid (#{ascp_pid})")
|
|
183
208
|
# init management socket
|
|
184
209
|
ascp_mgt_io=nil
|
|
185
|
-
Timeout.timeout(
|
|
210
|
+
Timeout.timeout(@options[:spawn_timeout_sec]) do
|
|
186
211
|
ascp_mgt_io = mgt_sock.accept
|
|
187
212
|
# management messages include file names which may be utf8
|
|
188
213
|
# by default socket is US-ASCII
|
|
@@ -216,7 +241,7 @@ module Aspera
|
|
|
216
241
|
current_event_data[$1] = $2
|
|
217
242
|
when ''
|
|
218
243
|
# empty line is separator to end event information
|
|
219
|
-
raise
|
|
244
|
+
raise 'unexpected empty line' if current_event_data.nil?
|
|
220
245
|
current_event_data[Manager::LISTENER_SESSION_ID_B]=ascp_pid
|
|
221
246
|
notify_listeners(current_event_text,current_event_data)
|
|
222
247
|
case current_event_data['Type']
|
|
@@ -232,26 +257,28 @@ module Aspera
|
|
|
232
257
|
end # case
|
|
233
258
|
end # loop (process mgt port lines)
|
|
234
259
|
# check that last status was received before process exit
|
|
235
|
-
if last_status_event.
|
|
236
|
-
Log.log.warn("no status read from ascp mgt port")
|
|
237
|
-
else
|
|
260
|
+
if last_status_event.is_a?(Hash)
|
|
238
261
|
case last_status_event['Type']
|
|
239
262
|
when 'DONE'
|
|
240
|
-
#
|
|
241
|
-
|
|
263
|
+
# all went well
|
|
264
|
+
exception_raised=false
|
|
242
265
|
when 'ERROR'
|
|
243
266
|
Log.log.error("code: #{last_status_event['Code']}")
|
|
244
267
|
if last_status_event['Description'] =~ /bearer token/i
|
|
245
|
-
Log.log.error(
|
|
268
|
+
Log.log.error('need to regenerate token'.red)
|
|
246
269
|
if session[:options].is_a?(Hash) and session[:options].has_key?(:regenerate_token)
|
|
247
270
|
# regenerate token here, expired, or error on it
|
|
271
|
+
# Note: in multi-session, each session will have a different one.
|
|
248
272
|
env_args[:env]['ASPERA_SCP_TOKEN']=session[:options][:regenerate_token].call(true)
|
|
249
273
|
end
|
|
250
274
|
end
|
|
251
275
|
raise Fasp::Error.new(last_status_event['Description'],last_status_event['Code'].to_i)
|
|
252
|
-
else
|
|
276
|
+
else # case
|
|
253
277
|
raise "unexpected last event type: #{last_status_event['Type']}"
|
|
254
278
|
end
|
|
279
|
+
else
|
|
280
|
+
exception_raised=false
|
|
281
|
+
Log.log.debug('no status read from ascp mgt port')
|
|
255
282
|
end
|
|
256
283
|
rescue SystemCallError => e
|
|
257
284
|
# Process.spawn
|
|
@@ -269,7 +296,13 @@ module Aspera
|
|
|
269
296
|
ascp_pid=nil
|
|
270
297
|
session.delete(:io)
|
|
271
298
|
if !status.success?
|
|
272
|
-
|
|
299
|
+
message="ascp failed with code #{status.exitstatus}"
|
|
300
|
+
if exception_raised
|
|
301
|
+
# just debug, as main exception is already here
|
|
302
|
+
Log.log.debug(message)
|
|
303
|
+
else
|
|
304
|
+
raise Fasp::Error.new(message)
|
|
305
|
+
end
|
|
273
306
|
end
|
|
274
307
|
end
|
|
275
308
|
end # begin-ensure
|
|
@@ -283,9 +316,9 @@ module Aspera
|
|
|
283
316
|
# {'type'=>'DONE'}
|
|
284
317
|
def send_command(job_id,session_index,data)
|
|
285
318
|
job=@jobs[job_id]
|
|
286
|
-
raise
|
|
319
|
+
raise 'no such job' if job.nil?
|
|
287
320
|
session=job[:sessions][session_index]
|
|
288
|
-
raise
|
|
321
|
+
raise 'no such session' if session.nil?
|
|
289
322
|
Log.log.debug("command: #{data}")
|
|
290
323
|
# build command
|
|
291
324
|
command=data.
|
|
@@ -299,8 +332,8 @@ module Aspera
|
|
|
299
332
|
|
|
300
333
|
private
|
|
301
334
|
|
|
302
|
-
|
|
303
|
-
|
|
335
|
+
# @param options : keys(symbol): see DEFAULT_OPTIONS
|
|
336
|
+
def initialize(options=nil)
|
|
304
337
|
super()
|
|
305
338
|
# by default no interactive progress bar
|
|
306
339
|
@quiet=true
|
|
@@ -308,9 +341,20 @@ module Aspera
|
|
|
308
341
|
@jobs={}
|
|
309
342
|
# mutex protects global data accessed by threads
|
|
310
343
|
@mutex=Mutex.new
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
344
|
+
# set default options and override if specified
|
|
345
|
+
@options=DEFAULT_OPTIONS.clone
|
|
346
|
+
if !options.nil?
|
|
347
|
+
raise "expecting Hash (or nil), but have #{options.class}" unless options.is_a?(Hash)
|
|
348
|
+
options.each do |k,v|
|
|
349
|
+
if DEFAULT_OPTIONS.has_key?(k)
|
|
350
|
+
@options[k]=v
|
|
351
|
+
else
|
|
352
|
+
raise "Unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map{|i|i.to_s}.join(",")}"
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
Log.log.debug("local options= #{options}")
|
|
357
|
+
@resume_policy=ResumePolicy.new(@options[:resume].symbolize_keys)
|
|
314
358
|
end
|
|
315
359
|
|
|
316
360
|
# transfer thread entry
|
|
@@ -318,7 +362,7 @@ module Aspera
|
|
|
318
362
|
def transfer_thread_entry(session)
|
|
319
363
|
begin
|
|
320
364
|
# set name for logging
|
|
321
|
-
Thread.current[:name]=
|
|
365
|
+
Thread.current[:name]='transfer'
|
|
322
366
|
Log.log.debug("ENTER (#{Thread.current[:name]})")
|
|
323
367
|
# start transfer with selected resumer policy
|
|
324
368
|
session[:options][:resumer].process do
|
data/lib/aspera/fasp/manager.rb
CHANGED
|
@@ -72,6 +72,9 @@ module Aspera
|
|
|
72
72
|
# start_transfer(transfer_spec,options) : start and wait for completion
|
|
73
73
|
# wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
|
|
74
74
|
# optional: shutdown
|
|
75
|
+
|
|
76
|
+
# This checks the validity of the value returned by wait_for_transfers_completion
|
|
77
|
+
# it must be a list of :success or exception
|
|
75
78
|
def self.validate_status_list(statuses)
|
|
76
79
|
raise "internal error: bad statuses type: #{statuses.class}" unless statuses.is_a?(Array)
|
|
77
80
|
raise "internal error: bad statuses content: #{statuses}" unless statuses.select{|i|!i.eql?(:success) and !i.is_a?(StandardError)}.empty?
|
data/lib/aspera/fasp/node.rb
CHANGED
|
@@ -7,9 +7,12 @@ module Aspera
|
|
|
7
7
|
# this singleton class is used by the CLI to provide a common interface to start a transfer
|
|
8
8
|
# before using it, the use must set the `node_api` member.
|
|
9
9
|
class Node < Manager
|
|
10
|
-
|
|
10
|
+
# option include: root_id if the node is an access key
|
|
11
|
+
attr_writer :options
|
|
12
|
+
def initialize(node_api,options={})
|
|
11
13
|
super()
|
|
12
14
|
@node_api=node_api
|
|
15
|
+
@options=options
|
|
13
16
|
# TODO: currently only supports one transfer. This is bad shortcut. but ok for CLI.
|
|
14
17
|
@transfer_id=nil
|
|
15
18
|
end
|
|
@@ -32,6 +35,25 @@ module Aspera
|
|
|
32
35
|
|
|
33
36
|
# generic method
|
|
34
37
|
def start_transfer(transfer_spec,options=nil)
|
|
38
|
+
# add root id if access key
|
|
39
|
+
if @options.has_key?(:root_id)
|
|
40
|
+
case transfer_spec['direction']
|
|
41
|
+
when 'send';transfer_spec['source_root_id']=@options[:root_id]
|
|
42
|
+
when 'receive';transfer_spec['destination_root_id']=@options[:root_id]
|
|
43
|
+
else raise "unexpected direction in ts: #{transfer_spec['direction']}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
# manage special additional parameter
|
|
47
|
+
if transfer_spec.has_key?('EX_ssh_key_paths') and transfer_spec['EX_ssh_key_paths'].is_a?(Array) and !transfer_spec['EX_ssh_key_paths'].empty?
|
|
48
|
+
# not standard, so place standard field
|
|
49
|
+
if transfer_spec.has_key?('ssh_private_key')
|
|
50
|
+
Log.log.warn('Both ssh_private_key and EX_ssh_key_paths are present, using ssh_private_key')
|
|
51
|
+
else
|
|
52
|
+
Log.log.warn('EX_ssh_key_paths has multiple keys, using first one only') unless transfer_spec['EX_ssh_key_paths'].length.eql?(1)
|
|
53
|
+
transfer_spec['ssh_private_key']=File.read(transfer_spec['EX_ssh_key_paths'].first)
|
|
54
|
+
transfer_spec.delete('EX_ssh_key_paths')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
35
57
|
if transfer_spec['tags'].is_a?(Hash) and transfer_spec['tags']['aspera'].is_a?(Hash)
|
|
36
58
|
transfer_spec['tags']['aspera']['xfer_retry']||=150
|
|
37
59
|
end
|
|
@@ -4,6 +4,7 @@ require 'aspera/temp_file_manager'
|
|
|
4
4
|
require 'securerandom'
|
|
5
5
|
require 'base64'
|
|
6
6
|
require 'json'
|
|
7
|
+
require 'yaml'
|
|
7
8
|
require 'securerandom'
|
|
8
9
|
require 'fileutils'
|
|
9
10
|
|
|
@@ -12,96 +13,67 @@ module Aspera
|
|
|
12
13
|
# translate transfer specification to ascp parameter list
|
|
13
14
|
class Parameters
|
|
14
15
|
private
|
|
15
|
-
#
|
|
16
|
+
# Temp folder for file lists, must contain only file lists
|
|
16
17
|
# because of garbage collection takes any file there
|
|
17
18
|
# this could be refined, as , for instance, on macos, temp folder is already user specific
|
|
18
19
|
@@file_list_folder=TempFileManager.instance.new_file_path_global('asession_filelists')
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
'EX_apply_local_docroot' => { :type => :opt_without_arg, :option_switch=>'--apply-local-docroot'},
|
|
72
|
-
# TODO: manage those parameters, some are for connect only ? node api ?
|
|
73
|
-
'target_rate_cap_kbps' => { :type => :ignore, :accepted_types=>Integer},
|
|
74
|
-
'target_rate_percentage' => { :type => :ignore, :accepted_types=>String}, # -wf -l<rate>p
|
|
75
|
-
'min_rate_cap_kbps' => { :type => :ignore, :accepted_types=>Integer},
|
|
76
|
-
'rate_policy_allowed' => { :type => :ignore, :accepted_types=>String},
|
|
77
|
-
'fasp_url' => { :type => :ignore, :accepted_types=>String},
|
|
78
|
-
'lock_rate_policy' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
|
79
|
-
'lock_min_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
|
80
|
-
'lock_target_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
|
81
|
-
#'authentication' => { :type => :ignore, :accepted_types=>String}, # = token
|
|
82
|
-
'https_fallback_port' => { :type => :ignore, :accepted_types=>Integer}, # same as http fallback, option -t ?
|
|
83
|
-
'content_protection' => { :type => :ignore, :accepted_types=>String},
|
|
84
|
-
'cipher_allowed' => { :type => :ignore, :accepted_types=>String},
|
|
85
|
-
'multi_session' => { :type => :ignore, :accepted_types=>Integer}, # managed
|
|
86
|
-
# optional tags ( additional option to generate: {:space=>' ',:object_nl=>' ',:space_before=>'+',:array_nl=>'1'} )
|
|
87
|
-
'tags' => { :type => :opt_with_arg, :option_switch=>'--tags64',:accepted_types=>Hash,:encode=>lambda{|tags|Base64.strict_encode64(JSON.generate(tags))}},
|
|
88
|
-
# special processing @builder.process_param( called individually
|
|
89
|
-
'use_ascp4' => { :type => :defer, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
|
90
|
-
'paths' => { :type => :defer, :accepted_types=>Array},
|
|
91
|
-
'EX_file_list' => { :type => :defer, :option_switch=>'--file-list', :accepted_types=>String},
|
|
92
|
-
'EX_file_pair_list' => { :type => :defer, :option_switch=>'--file-pair-list', :accepted_types=>String},
|
|
93
|
-
'EX_ascp_args' => { :type => :defer, :accepted_types=>Array},
|
|
94
|
-
'destination_root' => { :type => :defer, :accepted_types=>String},
|
|
95
|
-
'wss_enabled' => { :type => :defer, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
|
96
|
-
'wss_port' => { :type => :defer, :accepted_types=>Integer},
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private_constant :PARAM_DEFINITION
|
|
20
|
+
@@param_description_cache=nil
|
|
21
|
+
# @return normaiwed description of transfer spec parameters
|
|
22
|
+
def self.description
|
|
23
|
+
return @@param_description_cache unless @@param_description_cache.nil?
|
|
24
|
+
# config file in same folder with same name as this source
|
|
25
|
+
@@param_description_cache=YAML.load_file("#{__FILE__[0..-3]}yaml")
|
|
26
|
+
Aspera::CommandLineBuilder.normalize_description(@@param_description_cache)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Agents shown in manual
|
|
30
|
+
SUPPORTED_AGENTS=[:direct,:node,:connect]
|
|
31
|
+
# Short names of columns in manual
|
|
32
|
+
SUPPORTED_AGENTS_SHORT=SUPPORTED_AGENTS.map{|a|a.to_s[0].to_sym}
|
|
33
|
+
|
|
34
|
+
# @return a table suitable to display a manual
|
|
35
|
+
def self.man_table
|
|
36
|
+
result=[]
|
|
37
|
+
description.keys.map do |k|
|
|
38
|
+
i=description[k]
|
|
39
|
+
param={name: k, type: [i[:accepted_types]].flatten.join(','),description: i[:desc]}
|
|
40
|
+
SUPPORTED_AGENTS.each do |a|
|
|
41
|
+
param[a.to_s[0].to_sym]=i[:context].nil? || i[:context].include?(a) ? 'Y' : ''
|
|
42
|
+
end
|
|
43
|
+
# only keep lines that are usable in supported agents
|
|
44
|
+
next if SUPPORTED_AGENTS_SHORT.inject(true){|m,i|m and param[i].empty?}
|
|
45
|
+
param[:cli]=case i[:cltype]
|
|
46
|
+
when :envvar; 'env:'+i[:clvarname]
|
|
47
|
+
when :opt_without_arg,:opt_with_arg; i[:option_switch]
|
|
48
|
+
else ''
|
|
49
|
+
end
|
|
50
|
+
if i.has_key?(:enum)
|
|
51
|
+
param[:description] << "\nAllowed values: #{i[:enum].join(', ')}"
|
|
52
|
+
end
|
|
53
|
+
result.push(param)
|
|
54
|
+
end
|
|
55
|
+
return result
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# special encoding methods used in YAML (key: :encode)
|
|
59
|
+
def self.encode_cipher(v)
|
|
60
|
+
v.tr('-','')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# special encoding methods used in YAML (key: :encode)
|
|
64
|
+
def self.encode_source_root(v)
|
|
65
|
+
Base64.strict_encode64(v)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# special encoding methods used in YAML (key: :encode)
|
|
69
|
+
def self.encode_tags(v)
|
|
70
|
+
Base64.strict_encode64(JSON.generate(v))
|
|
71
|
+
end
|
|
100
72
|
|
|
101
73
|
def initialize(job_spec,options)
|
|
102
74
|
@job_spec=job_spec
|
|
103
|
-
@builder=Aspera::CommandLineBuilder.new(@job_spec,PARAM_DEFINITION)
|
|
104
75
|
@options=options
|
|
76
|
+
@builder=Aspera::CommandLineBuilder.new(@job_spec,self.class.description)
|
|
105
77
|
end
|
|
106
78
|
|
|
107
79
|
public
|
|
@@ -124,7 +96,7 @@ module Aspera
|
|
|
124
96
|
# special cases
|
|
125
97
|
@job_spec.delete('source_root') if @job_spec.has_key?('source_root') and @job_spec['source_root'].empty?
|
|
126
98
|
|
|
127
|
-
# use web socket initiation ?
|
|
99
|
+
# use web socket session initiation ?
|
|
128
100
|
if @builder.process_param('wss_enabled',:get_value) and @options[:wss]
|
|
129
101
|
# by default use web socket session if available, unless removed by user
|
|
130
102
|
@builder.add_command_line_options(['--ws-connect'])
|
|
@@ -150,8 +122,7 @@ module Aspera
|
|
|
150
122
|
# destination will be base64 encoded, put before path arguments
|
|
151
123
|
@builder.add_command_line_options(['--dest64'])
|
|
152
124
|
end
|
|
153
|
-
|
|
154
|
-
PARAM_DEFINITION['paths'][:mandatory]=!@job_spec.has_key?('keepalive')
|
|
125
|
+
@builder.params_definition['paths'][:mandatory]=!@job_spec.has_key?('keepalive')
|
|
155
126
|
paths_array=@builder.process_param('paths',:get_value)
|
|
156
127
|
unless paths_array.nil?
|
|
157
128
|
# use file list if there is storage defined for it.
|