aspera-cli 4.4.0 → 4.5.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 +1042 -787
- data/bin/ascli +1 -1
- data/bin/asession +3 -5
- data/docs/Makefile +4 -7
- data/docs/README.erb.md +988 -740
- data/examples/faspex4.rb +4 -6
- data/examples/transfer.rb +2 -2
- data/lib/aspera/aoc.rb +139 -118
- data/lib/aspera/cli/listener/progress_multi.rb +5 -5
- data/lib/aspera/cli/main.rb +64 -34
- data/lib/aspera/cli/manager.rb +19 -20
- data/lib/aspera/cli/plugin.rb +9 -1
- data/lib/aspera/cli/plugins/aoc.rb +156 -143
- data/lib/aspera/cli/plugins/ats.rb +11 -10
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +236 -112
- data/lib/aspera/cli/plugins/faspex.rb +29 -7
- data/lib/aspera/cli/plugins/faspex5.rb +21 -8
- data/lib/aspera/cli/plugins/node.rb +21 -9
- data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
- data/lib/aspera/cli/plugins/preview.rb +2 -2
- data/lib/aspera/cli/plugins/server.rb +3 -3
- data/lib/aspera/cli/plugins/shares.rb +17 -0
- data/lib/aspera/cli/transfer_agent.rb +47 -85
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +4 -4
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +14 -17
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +4 -4
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +25 -8
- data/lib/aspera/fasp/agent_trsdk.rb +106 -0
- data/lib/aspera/fasp/default.rb +17 -0
- data/lib/aspera/fasp/installation.rb +64 -48
- data/lib/aspera/fasp/parameters.rb +7 -3
- data/lib/aspera/faspex_gw.rb +6 -6
- data/lib/aspera/keychain/encrypted_hash.rb +120 -0
- data/lib/aspera/keychain/macos_security.rb +94 -0
- data/lib/aspera/log.rb +45 -32
- data/lib/aspera/node.rb +3 -6
- data/lib/aspera/rest.rb +65 -49
- metadata +68 -27
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/secrets.rb +0 -20
@@ -32,6 +32,20 @@ module Aspera
|
|
32
32
|
private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES,
|
33
33
|
:ATOM_PARAMS,:ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
|
34
34
|
|
35
|
+
class << self
|
36
|
+
def detect(base_url)
|
37
|
+
api=Rest.new({:base_url=>base_url})
|
38
|
+
result=api.call({:operation=>'POST',:subpath=>'aspera/faspex',:headers=>{'Accept'=>'application/xrds+xml'},:text_body_params=>''})
|
39
|
+
# 4.x
|
40
|
+
if result[:http].body.start_with?('<?xml')
|
41
|
+
res_s=XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
|
42
|
+
version=res_s['XRD']['application']['version']
|
43
|
+
return {version: version}
|
44
|
+
end
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
35
49
|
def initialize(env)
|
36
50
|
@api_v3=nil
|
37
51
|
@api_v4=nil
|
@@ -136,6 +150,8 @@ module Aspera
|
|
136
150
|
mailbox_query.delete(MAX_PAGES)
|
137
151
|
end
|
138
152
|
loop do
|
153
|
+
# get a batch of package information
|
154
|
+
# order: first batch is latest packages, and then in a batch ids are increasing
|
139
155
|
atom_xml=api_v3.call({operation: 'GET',subpath: "#{mailbox}.atom",headers: {'Accept'=>'application/xml'},url_params: mailbox_query})[:http].body
|
140
156
|
box_data=XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
|
141
157
|
Log.dump(:box_data,box_data)
|
@@ -143,7 +159,8 @@ module Aspera
|
|
143
159
|
Log.log.debug("new items: #{items.count}")
|
144
160
|
# it is the end if page is empty
|
145
161
|
break if items.empty?
|
146
|
-
|
162
|
+
# results will be sorted in reverse id
|
163
|
+
items.reverse.each do |package|
|
147
164
|
package[PACKAGE_MATCH_FIELD]=case mailbox
|
148
165
|
when :inbox,:archive
|
149
166
|
recipient=package['to'].select{|i|i['name'].first.eql?(recipient_name)}.first
|
@@ -151,12 +168,16 @@ module Aspera
|
|
151
168
|
else # :sent
|
152
169
|
package['delivery_id'].first
|
153
170
|
end
|
154
|
-
# keep only those for the specified recipient
|
171
|
+
# keep only those for the specified recipient,
|
155
172
|
result.push(package) unless package[PACKAGE_MATCH_FIELD].nil?
|
156
173
|
end
|
174
|
+
#result.push({PACKAGE_MATCH_FIELD=>'======'})
|
157
175
|
Log.log.debug("total items: #{result.count}")
|
158
176
|
# reach the limit ?
|
159
|
-
|
177
|
+
if !max_items.nil? and result.count >= max_items
|
178
|
+
result=result.slice(0,max_items) if result.count > max_items
|
179
|
+
break
|
180
|
+
end
|
160
181
|
link=box_data['link'].select{|i|i['rel'].eql?('next')}.first
|
161
182
|
Log.log.debug("link: #{link}")
|
162
183
|
# no next link
|
@@ -267,10 +288,11 @@ module Aspera
|
|
267
288
|
id: IdGenerator.from_list(['faspex_recv',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory),self.options.get_option(:box,:mandatory).to_s]))
|
268
289
|
end
|
269
290
|
# get command line parameters
|
270
|
-
delivid=self.
|
291
|
+
delivid=self.instance_identifier()
|
292
|
+
raise "empty id" if delivid.empty?
|
271
293
|
if delivid.eql?(VAL_ALL)
|
272
294
|
pkg_id_uri=mailbox_all_entries.map{|i|{:id=>i[PACKAGE_MATCH_FIELD],:uri=>self.class.get_fasp_uri_from_entry(i)}}
|
273
|
-
# TODO : remove ids from skip not present in inbox
|
295
|
+
# TODO : remove ids from skip not present in inbox to avoid growing too big
|
274
296
|
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
275
297
|
pkg_id_uri.select!{|i|!skip_ids_data.include?(i[:id])}
|
276
298
|
else
|
@@ -294,7 +316,7 @@ module Aspera
|
|
294
316
|
if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
|
295
317
|
raise CliBadArgument,"Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
|
296
318
|
end
|
297
|
-
# Note: unauthenticated API (
|
319
|
+
# Note: unauthenticated API (authorization is in url params)
|
298
320
|
api_public_link=Rest.new({:base_url=>link_data[:base_url]})
|
299
321
|
pkgdatares=api_public_link.call({:operation=>'GET',:subpath=>link_data[:subpath],:url_params=>{:passcode=>link_data[:query]['passcode']},:headers=>{'Accept'=>'application/xml'}})
|
300
322
|
if !pkgdatares[:http].body.start_with?('<?xml ')
|
@@ -400,7 +422,7 @@ module Aspera
|
|
400
422
|
return self.entity_action(api_v4,'metadata_profiles',nil,:id)
|
401
423
|
when :package
|
402
424
|
pkg_box_type=self.options.get_next_command([:users])
|
403
|
-
pkg_box_id=self.
|
425
|
+
pkg_box_id=self.instance_identifier()
|
404
426
|
return self.entity_action(api_v4,"#{pkg_box_type}/#{pkg_box_id}/packages",nil,:id)
|
405
427
|
end
|
406
428
|
when :address_book
|
@@ -7,14 +7,27 @@ module Aspera
|
|
7
7
|
module Cli
|
8
8
|
module Plugins
|
9
9
|
class Faspex5 < BasicAuthPlugin
|
10
|
+
class << self
|
11
|
+
def detect(base_url)
|
12
|
+
api=Rest.new({:base_url=>base_url})
|
13
|
+
result=api.read('api/v5/configuration/ping')
|
14
|
+
if result[:http].code.start_with?('2') and result[:http].body.strip.empty?
|
15
|
+
return {version: '5'}
|
16
|
+
end
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
10
21
|
VAL_ALL='ALL'
|
22
|
+
private_constant :VAL_ALL
|
23
|
+
|
11
24
|
def initialize(env)
|
12
25
|
super(env)
|
13
|
-
options.add_opt_simple(:client_id,'
|
14
|
-
options.add_opt_simple(:client_secret,'
|
15
|
-
options.add_opt_simple(:redirect_uri,'
|
16
|
-
options.add_opt_list(:auth,Oauth.auth_types.clone.push(:boot),'type of
|
17
|
-
options.add_opt_simple(:private_key,'RSA private key PEM value for JWT (prefix file path with @val:@file:)')
|
26
|
+
options.add_opt_simple(:client_id,'OAuth client identifier')
|
27
|
+
options.add_opt_simple(:client_secret,'OAuth client secret')
|
28
|
+
options.add_opt_simple(:redirect_uri,'OAuth redirect URI')
|
29
|
+
options.add_opt_list(:auth,Oauth.auth_types.clone.push(:boot),'OAuth type of authentication')
|
30
|
+
options.add_opt_simple(:private_key,'Oauth RSA private key PEM value for JWT (prefix file path with @val:@file:)')
|
18
31
|
options.set_option(:auth,:jwt)
|
19
32
|
options.parse_options!
|
20
33
|
end
|
@@ -43,7 +56,7 @@ module Aspera
|
|
43
56
|
:redirect_uri => options.get_option(:redirect_uri,:mandatory),
|
44
57
|
}})
|
45
58
|
when :jwt
|
46
|
-
# currently Faspex 5 beta
|
59
|
+
# currently Faspex 5 beta 4 only supports non-user based apis (e.g. jobs)
|
47
60
|
app_client_id=options.get_option(:client_id,:mandatory)
|
48
61
|
@api_v5=Rest.new({
|
49
62
|
:base_url => faxpex5_api_v5_url,
|
@@ -85,7 +98,7 @@ module Aspera
|
|
85
98
|
parameters=options.get_option(:value,:optional)
|
86
99
|
return {:type => :object_list, :data=>@api_v5.read('packages',parameters)[:data]['packages']}
|
87
100
|
when :show
|
88
|
-
id=
|
101
|
+
id=instance_identifier()
|
89
102
|
return {:type => :single_object, :data=>@api_v5.read("packages/#{id}")[:data]}
|
90
103
|
when :send
|
91
104
|
parameters=options.get_option(:value,:mandatory)
|
@@ -96,7 +109,7 @@ module Aspera
|
|
96
109
|
return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
|
97
110
|
when :receive
|
98
111
|
pkg_type='received'
|
99
|
-
pack_id=
|
112
|
+
pack_id=instance_identifier()
|
100
113
|
package_ids=[pack_id]
|
101
114
|
skip_ids_data=[]
|
102
115
|
skip_ids_persistency=nil
|
@@ -2,6 +2,7 @@ require 'aspera/cli/basic_auth_plugin'
|
|
2
2
|
require 'aspera/nagios'
|
3
3
|
require 'aspera/hash_ext'
|
4
4
|
require 'aspera/id_generator'
|
5
|
+
require 'aspera/node'
|
5
6
|
require 'base64'
|
6
7
|
require 'zlib'
|
7
8
|
|
@@ -9,8 +10,19 @@ module Aspera
|
|
9
10
|
module Cli
|
10
11
|
module Plugins
|
11
12
|
class Node < BasicAuthPlugin
|
13
|
+
class << self
|
14
|
+
def detect(base_url)
|
15
|
+
api=Rest.new({:base_url=>base_url})
|
16
|
+
result=api.call({:operation=>'GET',:subpath=>'ping'})
|
17
|
+
if result[:http].body.eql?('')
|
18
|
+
return {:product=>:node,:version=>'unknown'}
|
19
|
+
end
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
12
23
|
SAMPLE_SOAP_CALL='<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="urn:Aspera:XML:FASPSessionNET:2009/11:Types"><soapenv:Header></soapenv:Header><soapenv:Body><typ:GetSessionInfoRequest><SessionFilter><SessionStatus>running</SessionStatus></SessionFilter></typ:GetSessionInfoRequest></soapenv:Body></soapenv:Envelope>'
|
13
24
|
private_constant :SAMPLE_SOAP_CALL
|
25
|
+
|
14
26
|
def initialize(env)
|
15
27
|
super(env)
|
16
28
|
# this is added to some requests , for instance to add tags (COS)
|
@@ -165,7 +177,7 @@ module Aspera
|
|
165
177
|
when :mkdir
|
166
178
|
path_list=get_next_arg_add_prefix(prefix_path,"folder path or ext.val. list")
|
167
179
|
path_list=[path_list] unless path_list.is_a?(Array)
|
168
|
-
#TODO
|
180
|
+
#TODO: a command for that ?
|
169
181
|
#resp=@api_node.create('space',{ "paths" => path_list.map {|i| {:type=>:directory,:path=>i} } } )
|
170
182
|
resp=@api_node.create('files/create',{ "paths" => [{ :type => :directory, :path => path_list } ] } )
|
171
183
|
return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
@@ -224,9 +236,9 @@ module Aspera
|
|
224
236
|
raise "shall be basic auth" unless @api_node.params[:auth][:type].eql?(:basic)
|
225
237
|
transfer_spec={
|
226
238
|
'remote_host'=>URI.parse(@api_node.params[:base_url]).host,
|
227
|
-
'remote_user'=>Aspera::
|
228
|
-
'ssh_port'=>Aspera::
|
229
|
-
'direction'=>case command;when :upload;'send';when :download;'recv';else raise "Error";end
|
239
|
+
'remote_user'=>Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER,
|
240
|
+
'ssh_port' =>Aspera::Fasp::Default::SSH_PORT,
|
241
|
+
'direction' =>case command;when :upload;'send';when :download;'recv';else raise "Error";end
|
230
242
|
}
|
231
243
|
else raise "ERROR: token_type #{tt}"
|
232
244
|
end
|
@@ -244,7 +256,7 @@ module Aspera
|
|
244
256
|
unless command.eql?(:list)
|
245
257
|
asyncname=self.options.get_option(:name,:optional)
|
246
258
|
if asyncname.nil?
|
247
|
-
asyncid=self.
|
259
|
+
asyncid=self.instance_identifier()
|
248
260
|
if asyncid.eql?('ALL') and [:show,:delete].include?(command)
|
249
261
|
asyncids=@api_node.read('async/list')[:data]['sync_ids']
|
250
262
|
else
|
@@ -327,7 +339,7 @@ module Aspera
|
|
327
339
|
case command
|
328
340
|
when :list
|
329
341
|
resp=@api_node.read('ops/transfers',self.options.get_option(:value,:optional))
|
330
|
-
return { :type => :object_list, :data => resp[:data], :fields=>['id','status'] } # TODO
|
342
|
+
return { :type => :object_list, :data => resp[:data], :fields=>['id','status'] } # TODO: useful?
|
331
343
|
when :create
|
332
344
|
resp=@api_node.create('streams',self.options.get_option(:value,:mandatory))
|
333
345
|
return { :type => :single_object, :data => resp[:data] }
|
@@ -350,7 +362,7 @@ module Aspera
|
|
350
362
|
command=self.options.get_next_command([ :list, :cancel, :show ])
|
351
363
|
res_class_path='ops/transfers'
|
352
364
|
if [:cancel, :show].include?(command)
|
353
|
-
one_res_id=self.
|
365
|
+
one_res_id=self.instance_identifier()
|
354
366
|
one_res_path="#{res_class_path}/#{one_res_id}"
|
355
367
|
end
|
356
368
|
case command
|
@@ -372,7 +384,7 @@ module Aspera
|
|
372
384
|
when :service
|
373
385
|
command=self.options.get_next_command([ :list, :create, :delete])
|
374
386
|
if [:delete].include?(command)
|
375
|
-
svcid=self.
|
387
|
+
svcid=self.instance_identifier()
|
376
388
|
end
|
377
389
|
case command
|
378
390
|
when :list
|
@@ -392,7 +404,7 @@ module Aspera
|
|
392
404
|
#return entity_action(@api_node,'v3/watchfolders',nil,:id)
|
393
405
|
command=self.options.get_next_command([ :create, :list, :show, :modify, :delete, :state])
|
394
406
|
if [:show,:modify,:delete,:state].include?(command)
|
395
|
-
one_res_id=self.
|
407
|
+
one_res_id=self.instance_identifier()
|
396
408
|
one_res_path="#{res_class_path}/#{one_res_id}"
|
397
409
|
end
|
398
410
|
# hum, to avoid: Unable to convert 2016_09_14 configuration
|
@@ -110,12 +110,14 @@ module Aspera
|
|
110
110
|
return {:type=>:object_list,:data=>result['Plugin']}
|
111
111
|
when :workflow
|
112
112
|
command=self.options.get_next_command([:list, :status, :inputs, :details, :start, :export])
|
113
|
-
unless [:list
|
114
|
-
wf_id=self.
|
113
|
+
unless [:list].include?(command)
|
114
|
+
wf_id=self.instance_identifier()
|
115
115
|
end
|
116
116
|
case command
|
117
117
|
when :status
|
118
|
-
|
118
|
+
options={}
|
119
|
+
options[:id]=wf_id unless wf_id.eql?('ALL')
|
120
|
+
result=call_API('workflows_status',options)[:data]
|
119
121
|
return {:type=>:object_list,:data=>result['workflows']['workflow']}
|
120
122
|
when :list
|
121
123
|
result=call_API('workflows_list',id: 0)[:data]
|
@@ -205,9 +205,9 @@ module Aspera
|
|
205
205
|
template_ts=res[:data]['transfer_specs'].first['transfer_spec']
|
206
206
|
# get ports, anyway that should be 33001 for both. add remote_user ?
|
207
207
|
@default_transfer_spec=['ssh_port','fasp_port'].inject({}){|h,e|h[e]=template_ts[e];h}
|
208
|
-
if ! @default_transfer_spec['remote_user'].eql?(Aspera::
|
208
|
+
if ! @default_transfer_spec['remote_user'].eql?(Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER)
|
209
209
|
Log.log.warn("remote_user shall be xfer")
|
210
|
-
@default_transfer_spec['remote_user']=Aspera::
|
210
|
+
@default_transfer_spec['remote_user']=Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER
|
211
211
|
end
|
212
212
|
Aspera::Node::set_ak_basic_token(@default_transfer_spec,@access_key_self['id'],self.options.get_option(:password,:mandatory))
|
213
213
|
# note: we use the same address for ascp than for node api instead of the one from upload_setup
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'aspera/cli/basic_auth_plugin'
|
2
2
|
require 'aspera/ascmd'
|
3
|
-
require 'aspera/
|
3
|
+
require 'aspera/fasp/default'
|
4
4
|
require 'aspera/ssh'
|
5
5
|
require 'aspera/nagios'
|
6
6
|
require 'tempfile'
|
@@ -73,8 +73,8 @@ module Aspera
|
|
73
73
|
case server_uri.scheme
|
74
74
|
when 'ssh'
|
75
75
|
if self.options.get_option(:username,:optional).nil?
|
76
|
-
self.options.set_option(:username,Aspera::
|
77
|
-
Log.log.info("Using default transfer user: #{Aspera::
|
76
|
+
self.options.set_option(:username,Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER)
|
77
|
+
Log.log.info("Using default transfer user: #{Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER}")
|
78
78
|
end
|
79
79
|
server_transfer_spec['remote_user']=self.options.get_option(:username,:mandatory)
|
80
80
|
ssh_options=self.options.get_option(:ssh_options,:optional)
|
@@ -4,6 +4,23 @@ module Aspera
|
|
4
4
|
module Cli
|
5
5
|
module Plugins
|
6
6
|
class Shares < BasicAuthPlugin
|
7
|
+
class << self
|
8
|
+
def detect(base_url)
|
9
|
+
api=Rest.new({:base_url=>base_url})
|
10
|
+
# Shares
|
11
|
+
begin
|
12
|
+
# shall fail: shares requires auth, but we check error message
|
13
|
+
api.read('node_api/app')
|
14
|
+
rescue RestCallError => e
|
15
|
+
if e.response.code.to_s.eql?('401') and e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
16
|
+
return {:version=>'unknown'}
|
17
|
+
end
|
18
|
+
rescue
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
7
24
|
def initialize(env)
|
8
25
|
super(env)
|
9
26
|
#self.options.parse_options!
|
@@ -1,8 +1,4 @@
|
|
1
|
-
require 'aspera/fasp/local'
|
2
1
|
require 'aspera/fasp/parameters'
|
3
|
-
require 'aspera/fasp/connect'
|
4
|
-
require 'aspera/fasp/node'
|
5
|
-
require 'aspera/fasp/http_gw'
|
6
2
|
require 'aspera/cli/listener/logger'
|
7
3
|
require 'aspera/cli/listener/progress_multi'
|
8
4
|
|
@@ -25,12 +21,14 @@ Transfer is: <%=global_transfer_status%>
|
|
25
21
|
|
26
22
|
<%=ts.to_yaml%>
|
27
23
|
END_OF_TEMPLATE
|
28
|
-
#%
|
24
|
+
#% (formating bug in eclipse)
|
29
25
|
private_constant :FILE_LIST_FROM_ARGS,:FILE_LIST_FROM_TRANSFER_SPEC,:DEFAULT_TRANSFER_NOTIF_TMPL
|
26
|
+
TRANSFER_AGENTS=[:direct,:node,:connect,:httpgw,:trsdk]
|
27
|
+
|
30
28
|
# @param env external objects: option manager, config file manager
|
31
|
-
def initialize(
|
32
|
-
|
33
|
-
@
|
29
|
+
def initialize(opt_mgr,config)
|
30
|
+
@opt_mgr=opt_mgr
|
31
|
+
@config=config
|
34
32
|
# command line can override transfer spec
|
35
33
|
@transfer_spec_cmdline={'create_dir'=>true}
|
36
34
|
# the currently selected transfer agent
|
@@ -38,25 +36,21 @@ END_OF_TEMPLATE
|
|
38
36
|
@progress_listener=Listener::ProgressMulti.new
|
39
37
|
# source/destination pair, like "paths" of transfer spec
|
40
38
|
@transfer_paths=nil
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
39
|
+
@opt_mgr.set_obj_attr(:ts,self,:option_transfer_spec)
|
40
|
+
@opt_mgr.add_opt_simple(:ts,"override transfer spec values (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:ts,:optional)}")
|
41
|
+
@opt_mgr.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:local_resume,:optional)}")
|
42
|
+
@opt_mgr.add_opt_simple(:to_folder,"destination folder for downloaded files")
|
43
|
+
@opt_mgr.add_opt_simple(:sources,"list of source files (see doc)")
|
44
|
+
@opt_mgr.add_opt_simple(:transfer_info,"parameters for transfer agent")
|
45
|
+
@opt_mgr.add_opt_list(:src_type,[:list,:pair],"type of file list")
|
46
|
+
@opt_mgr.add_opt_list(:transfer,TRANSFER_AGENTS,"type of transfer agent")
|
47
|
+
@opt_mgr.add_opt_list(:progress,[:none,:native,:multi],"type of progress bar")
|
48
|
+
@opt_mgr.set_option(:transfer,:direct)
|
49
|
+
@opt_mgr.set_option(:src_type,:list)
|
50
|
+
@opt_mgr.set_option(:progress,:native) # use native ascp progress bar as it is more reliable
|
51
|
+
@opt_mgr.parse_options!
|
54
52
|
end
|
55
53
|
|
56
|
-
def options; @env[:options];end
|
57
|
-
|
58
|
-
def config; @env[:config];end
|
59
|
-
|
60
54
|
def option_transfer_spec; @transfer_spec_cmdline; end
|
61
55
|
|
62
56
|
# multiple option are merged
|
@@ -68,8 +62,8 @@ END_OF_TEMPLATE
|
|
68
62
|
@agent=instance
|
69
63
|
@agent.add_listener(Listener::Logger.new)
|
70
64
|
# use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
|
71
|
-
if
|
72
|
-
(
|
65
|
+
if @opt_mgr.get_option(:progress,:mandatory).eql?(:multi) or
|
66
|
+
(@opt_mgr.get_option(:progress,:mandatory).eql?(:native) and ! instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
|
73
67
|
@agent.add_listener(@progress_listener)
|
74
68
|
end
|
75
69
|
end
|
@@ -77,56 +71,24 @@ END_OF_TEMPLATE
|
|
77
71
|
# analyze options and create new agent if not already created or set
|
78
72
|
def set_agent_by_options
|
79
73
|
return nil unless @agent.nil?
|
80
|
-
agent_type
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
new_agent=Fasp::HttpGW.new(httpgw_config)
|
90
|
-
when :connect
|
91
|
-
new_agent=Fasp::Connect.new
|
92
|
-
when :node
|
93
|
-
# way for code to setup alternate node api in advance
|
94
|
-
# support: @preset:<name>
|
95
|
-
# support extended values
|
96
|
-
node_config=options.get_option(:transfer_info,:optional)
|
97
|
-
# if not specified: use default node
|
98
|
-
if node_config.nil?
|
99
|
-
param_set_name=config.get_plugin_default_config_name(:node)
|
100
|
-
raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.gsub('_','-')}" if param_set_name.nil?
|
101
|
-
node_config=config.preset_by_name(param_set_name)
|
102
|
-
end
|
103
|
-
Log.log.debug("node=#{node_config}")
|
104
|
-
raise CliBadArgument,"the node configuration shall be Hash, not #{node_config.class} (#{node_config}), use either @json:<json> or @preset:<parameter set name>" unless node_config.is_a?(Hash)
|
105
|
-
# here, node_config is a Hash
|
106
|
-
node_config=node_config.symbolize_keys
|
107
|
-
# Check mandatory params
|
108
|
-
[:url,:username,:password].each { |k| raise CliBadArgument,"missing parameter [#{k}] in node specification: #{node_config}" unless node_config.has_key?(k) }
|
109
|
-
if node_config[:password].match(/^Bearer /)
|
110
|
-
node_api=Rest.new({
|
111
|
-
base_url: node_config[:url],
|
112
|
-
headers: {
|
113
|
-
'X-Aspera-AccessKey'=>node_config[:username],
|
114
|
-
'Authorization' =>node_config[:password]}})
|
115
|
-
else
|
116
|
-
node_api=Rest.new({
|
117
|
-
base_url: node_config[:url],
|
118
|
-
auth: {
|
119
|
-
type: :basic,
|
120
|
-
username: node_config[:username],
|
121
|
-
password: node_config[:password]
|
122
|
-
}})
|
123
|
-
end
|
124
|
-
new_agent=Fasp::Node.new(node_api)
|
125
|
-
# add root id if it's an access key
|
126
|
-
new_agent.options={root_id: node_config[:root_id]} if node_config.has_key?(:root_id)
|
127
|
-
else
|
128
|
-
raise "Unexpected transfer agent type: #{agent_type}"
|
74
|
+
agent_type=@opt_mgr.get_option(:transfer,:mandatory)
|
75
|
+
require "aspera/fasp/agent_#{agent_type}"
|
76
|
+
agent_options=@opt_mgr.get_option(:transfer_info,:optional)
|
77
|
+
raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), use either @json:<json> or @preset:<parameter set name>" unless [Hash,NilClass].include?(agent_options.class)
|
78
|
+
# special case
|
79
|
+
if agent_type.eql?(:node) and agent_options.nil?
|
80
|
+
param_set_name=@config.get_plugin_default_config_name(:node)
|
81
|
+
raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.gsub('_','-')}" if param_set_name.nil?
|
82
|
+
agent_options=@config.preset_by_name(param_set_name)
|
129
83
|
end
|
84
|
+
# special case
|
85
|
+
if agent_type.eql?(:direct) and @opt_mgr.get_option(:progress,:mandatory).eql?(:native)
|
86
|
+
agent_options={} if agent_options.nil?
|
87
|
+
agent_options[:quiet]=false
|
88
|
+
end
|
89
|
+
agent_options=agent_options.symbolize_keys if agent_options.is_a?(Hash)
|
90
|
+
# get agent instance
|
91
|
+
new_agent=Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
|
130
92
|
set_agent_instance(new_agent)
|
131
93
|
return nil
|
132
94
|
end
|
@@ -135,8 +97,8 @@ END_OF_TEMPLATE
|
|
135
97
|
# sets default if needed
|
136
98
|
# param: 'send' or 'receive'
|
137
99
|
def destination_folder(direction)
|
138
|
-
dest_folder
|
139
|
-
return dest_folder unless dest_folder.nil?
|
100
|
+
dest_folder=@opt_mgr.get_option(:to_folder,:optional)
|
101
|
+
return File.expand_path(dest_folder) unless dest_folder.nil?
|
140
102
|
dest_folder=@transfer_spec_cmdline['destination_root']
|
141
103
|
return dest_folder unless dest_folder.nil?
|
142
104
|
# default: / on remote, . on local
|
@@ -158,16 +120,16 @@ END_OF_TEMPLATE
|
|
158
120
|
# start with lower priority : get paths from transfer spec on command line
|
159
121
|
@transfer_paths=@transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.has_key?('paths')
|
160
122
|
# is there a source list option ?
|
161
|
-
file_list
|
123
|
+
file_list=@opt_mgr.get_option(:sources,:optional)
|
162
124
|
case file_list
|
163
125
|
when nil,FILE_LIST_FROM_ARGS
|
164
126
|
Log.log.debug("getting file list as parameters")
|
165
127
|
# get remaining arguments
|
166
|
-
file_list
|
128
|
+
file_list=@opt_mgr.get_next_argument("source file list",:multiple)
|
167
129
|
raise CliBadArgument,"specify at least one file on command line or use --sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) or file_list.empty?
|
168
130
|
when FILE_LIST_FROM_TRANSFER_SPEC
|
169
131
|
Log.log.debug("assume list provided in transfer spec")
|
170
|
-
special_case_direct_with_list
|
132
|
+
special_case_direct_with_list=@opt_mgr.get_option(:transfer,:mandatory).eql?(:direct) and Fasp::Parameters.ts_has_file_list(@transfer_spec_cmdline)
|
171
133
|
raise CliBadArgument,"transfer spec on command line must have sources" if @transfer_paths.nil? and !special_case_direct_with_list
|
172
134
|
# here we assume check of sources is made in transfer agent
|
173
135
|
return @transfer_paths
|
@@ -181,7 +143,7 @@ END_OF_TEMPLATE
|
|
181
143
|
if !@transfer_paths.nil?
|
182
144
|
Log.log.warn("--sources overrides paths from --ts")
|
183
145
|
end
|
184
|
-
case
|
146
|
+
case @opt_mgr.get_option(:src_type,:mandatory)
|
185
147
|
when :list
|
186
148
|
# when providing a list, just specify source
|
187
149
|
@transfer_paths=file_list.map{|i|{'source'=>i}}
|
@@ -237,13 +199,13 @@ END_OF_TEMPLATE
|
|
237
199
|
@agent.start_transfer(transfer_spec,tr_opts)
|
238
200
|
result=@agent.wait_for_transfers_completion
|
239
201
|
@progress_listener.reset
|
240
|
-
Fasp::
|
202
|
+
Fasp::AgentBase.validate_status_list(result)
|
241
203
|
send_email_transfer_notification(transfer_spec,result)
|
242
204
|
return result
|
243
205
|
end
|
244
206
|
|
245
207
|
def send_email_transfer_notification(transfer_spec,statuses)
|
246
|
-
return if
|
208
|
+
return if @opt_mgr.get_option(:notif_to,:optional).nil?
|
247
209
|
global_status=self.class.session_status(statuses)
|
248
210
|
email_vars={
|
249
211
|
global_transfer_status: global_status,
|
@@ -251,7 +213,7 @@ END_OF_TEMPLATE
|
|
251
213
|
body: "Transfer is: #{global_status}",
|
252
214
|
ts: transfer_spec
|
253
215
|
}
|
254
|
-
@
|
216
|
+
@config.send_email_template(email_vars,DEFAULT_TRANSFER_NOTIF_TMPL)
|
255
217
|
end
|
256
218
|
|
257
219
|
# @return :success if all sessions statuses returned by "start" are success
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/environment.rb
CHANGED
@@ -33,12 +33,12 @@ module Aspera
|
|
33
33
|
def self.cpu
|
34
34
|
case RbConfig::CONFIG['host_cpu']
|
35
35
|
when /x86_64/,/x64/
|
36
|
-
return
|
36
|
+
return CPU_X86_64
|
37
37
|
when /powerpc/
|
38
|
-
return
|
39
|
-
return
|
38
|
+
return CPU_PPC64LE if os.eql?(OS_LINUX)
|
39
|
+
return CPU_PPC64
|
40
40
|
when /s390/
|
41
|
-
return
|
41
|
+
return CPU_S390
|
42
42
|
else # other
|
43
43
|
raise "Unknown CPU: #{RbConfig::CONFIG['host_cpu']}"
|
44
44
|
end
|
@@ -2,7 +2,7 @@ module Aspera
|
|
2
2
|
module Fasp
|
3
3
|
# Base class for FASP transfer agents
|
4
4
|
# sub classes shall implement start_transfer and shutdown
|
5
|
-
class
|
5
|
+
class AgentBase
|
6
6
|
|
7
7
|
private
|
8
8
|
|
@@ -68,17 +68,18 @@ module Aspera
|
|
68
68
|
self
|
69
69
|
end
|
70
70
|
|
71
|
-
# the following methods must be implemented by subclass:
|
72
|
-
# start_transfer(transfer_spec,options) : start and wait for completion
|
73
|
-
# wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
|
74
|
-
# optional: shutdown
|
75
|
-
|
76
71
|
# This checks the validity of the value returned by wait_for_transfers_completion
|
77
72
|
# it must be a list of :success or exception
|
78
73
|
def self.validate_status_list(statuses)
|
79
74
|
raise "internal error: bad statuses type: #{statuses.class}" unless statuses.is_a?(Array)
|
80
75
|
raise "internal error: bad statuses content: #{statuses}" unless statuses.select{|i|!i.eql?(:success) and !i.is_a?(StandardError)}.empty?
|
81
76
|
end
|
77
|
+
|
78
|
+
# the following methods must be implemented by subclass:
|
79
|
+
# start_transfer(transfer_spec,options) : start and wait for completion
|
80
|
+
# wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
|
81
|
+
# optional: shutdown
|
82
|
+
|
82
83
|
end
|
83
84
|
end
|
84
85
|
end
|