aspera-cli 4.2.2 → 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 +104 -36
- data/docs/README.erb.md +107 -41
- data/docs/test_env.conf +1 -0
- data/lib/aspera/aoc.rb +20 -19
- data/lib/aspera/cli/plugins/aoc.rb +25 -14
- data/lib/aspera/cli/plugins/config.rb +2 -1
- data/lib/aspera/cli/plugins/faspex.rb +3 -2
- data/lib/aspera/cli/plugins/faspex5.rb +3 -2
- data/lib/aspera/cli/plugins/node.rb +3 -2
- data/lib/aspera/cli/plugins/preview.rb +56 -36
- data/lib/aspera/cli/transfer_agent.rb +21 -13
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +0 -1
- data/lib/aspera/cos_node.rb +4 -3
- data/lib/aspera/fasp/aoc.rb +1 -1
- data/lib/aspera/fasp/local.rb +31 -22
- data/lib/aspera/fasp/node.rb +23 -1
- data/lib/aspera/id_generator.rb +22 -0
- data/lib/aspera/node.rb +2 -4
- data/lib/aspera/oauth.rb +112 -96
- data/lib/aspera/persistency_action_once.rb +11 -7
- data/lib/aspera/persistency_folder.rb +6 -26
- data/lib/aspera/rest.rb +1 -1
- data/lib/aspera/timer_limiter.rb +22 -0
- metadata +4 -2
data/lib/aspera/aoc.rb
CHANGED
@@ -273,7 +273,7 @@ module Aspera
|
|
273
273
|
transfer_spec['remote_host']=node_file[:node_info]['host']
|
274
274
|
else
|
275
275
|
# retrieve values from API
|
276
|
-
std_t_spec=get_node_api(node_file[:node_info],SCOPE_NODE_USER).create('files/download_setup',{:transfer_requests => [ { :transfer_request => {:paths => [ {"source"=>'/'} ] } } ] } )[:data]['transfer_specs'].first['transfer_spec']
|
276
|
+
std_t_spec=get_node_api(node_file[:node_info],scope: SCOPE_NODE_USER).create('files/download_setup',{:transfer_requests => [ { :transfer_request => {:paths => [ {"source"=>'/'} ] } } ] } )[:data]['transfer_specs'].first['transfer_spec']
|
277
277
|
['remote_host','remote_user','ssh_port','fasp_port'].each {|i| transfer_spec[i]=std_t_spec[i]}
|
278
278
|
end
|
279
279
|
# add caller provided transfer spec
|
@@ -290,26 +290,27 @@ module Aspera
|
|
290
290
|
# @param scope e.g. SCOPE_NODE_USER
|
291
291
|
# no scope: requires secret
|
292
292
|
# if secret provided beforehand: use it
|
293
|
-
def get_node_api(node_info,
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
ak_secret=@key_chain.get_secret(node_info['access_key'],false)
|
300
|
-
if ak_secret.nil? and node_scope.nil?
|
293
|
+
def get_node_api(node_info,options={})
|
294
|
+
raise "INTERNAL ERROR: method parameters: options must ne hash" unless options.is_a?(Hash)
|
295
|
+
options.keys.each {|k| raise "INTERNAL ERROR: not valid option: #{k}" unless [:scope,:use_secret].include?(k)}
|
296
|
+
# get optional secret unless :use_secret is false (default is true)
|
297
|
+
ak_secret=@key_chain.get_secret(node_info['access_key'],false) if !options.has_key?(:use_secret) or options[:use_secret]
|
298
|
+
if ak_secret.nil? and !options.has_key?(:scope)
|
301
299
|
raise "There must be at least one of: 'secret' or 'scope' for access key #{node_info['access_key']}"
|
302
300
|
end
|
303
|
-
|
304
|
-
if
|
301
|
+
node_rest_params={base_url: node_info['url']}
|
302
|
+
# if secret is available
|
303
|
+
if !ak_secret.nil?
|
305
304
|
node_rest_params[:auth]={
|
306
|
-
:
|
307
|
-
:
|
308
|
-
:
|
305
|
+
type: :basic,
|
306
|
+
username: node_info['access_key'],
|
307
|
+
password: ak_secret
|
309
308
|
}
|
310
309
|
else
|
310
|
+
# X-Aspera-AccessKey required for bearer token only
|
311
|
+
node_rest_params[:headers]= {'X-Aspera-AccessKey'=>node_info['access_key']}
|
311
312
|
node_rest_params[:auth]=self.params[:auth].clone
|
312
|
-
node_rest_params[:auth][:scope]=self.class.node_scope(node_info['access_key'],
|
313
|
+
node_rest_params[:auth][:scope]=self.class.node_scope(node_info['access_key'],options[:scope])
|
313
314
|
end
|
314
315
|
return Node.new(node_rest_params)
|
315
316
|
end
|
@@ -336,7 +337,7 @@ module Aspera
|
|
336
337
|
if entry[:type].eql?('link')
|
337
338
|
sub_node_info=self.read("nodes/#{entry['target_node_id']}")[:data]
|
338
339
|
sub_opt={method: process_find_files, top_file_id: entry['target_id'], top_file_path: path}
|
339
|
-
get_node_api(sub_node_info,SCOPE_NODE_USER).crawl(self,sub_opt)
|
340
|
+
get_node_api(sub_node_info,scope: SCOPE_NODE_USER).crawl(self,sub_opt)
|
340
341
|
end
|
341
342
|
rescue => e
|
342
343
|
Log.log.error("#{path}: #{e.message}")
|
@@ -349,7 +350,7 @@ module Aspera
|
|
349
350
|
top_node_info,top_file_id=check_get_node_file(top_node_file)
|
350
351
|
Log.log.debug("find_files: node_info=#{top_node_info}, fileid=#{top_file_id}")
|
351
352
|
@find_state={found: [], test_block: test_block}
|
352
|
-
get_node_api(top_node_info,SCOPE_NODE_USER).crawl(self,{method: :process_find_files, top_file_id: top_file_id})
|
353
|
+
get_node_api(top_node_info,scope: SCOPE_NODE_USER).crawl(self,{method: :process_find_files, top_file_id: top_file_id})
|
353
354
|
result=@find_state[:found]
|
354
355
|
@find_state=nil
|
355
356
|
return result
|
@@ -370,7 +371,7 @@ module Aspera
|
|
370
371
|
if @resolve_state[:path].empty?
|
371
372
|
@resolve_state[:result][:file_id]=entry['target_id']
|
372
373
|
else
|
373
|
-
get_node_api(@resolve_state[:result][:node_info],SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: entry['target_id']})
|
374
|
+
get_node_api(@resolve_state[:result][:node_info],scope: SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: entry['target_id']})
|
374
375
|
end
|
375
376
|
when 'folder'
|
376
377
|
if @resolve_state[:path].empty?
|
@@ -397,7 +398,7 @@ module Aspera
|
|
397
398
|
result[:file_id]=top_file_id
|
398
399
|
else
|
399
400
|
@resolve_state={path: path_elements, result: result}
|
400
|
-
get_node_api(top_node_info,SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: top_file_id})
|
401
|
+
get_node_api(top_node_info,scope: SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: top_file_id})
|
401
402
|
not_found=@resolve_state[:path]
|
402
403
|
@resolve_state=nil
|
403
404
|
raise "entry not found: #{not_found}" if result[:file_id].nil?
|
@@ -5,6 +5,7 @@ require 'aspera/cli/transfer_agent'
|
|
5
5
|
require 'aspera/aoc'
|
6
6
|
require 'aspera/node'
|
7
7
|
require 'aspera/persistency_action_once'
|
8
|
+
require 'aspera/id_generator'
|
8
9
|
require 'securerandom'
|
9
10
|
require 'resolv'
|
10
11
|
require 'date'
|
@@ -82,19 +83,29 @@ module Aspera
|
|
82
83
|
return self.transfer.start(*@api_aoc.tr_spec(app,direction,node_file,ts_add))
|
83
84
|
end
|
84
85
|
|
85
|
-
NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node ]
|
86
|
+
NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node, :node_info ]
|
86
87
|
|
87
88
|
def execute_node_gen4_command(command_repo,top_node_file)
|
88
89
|
case command_repo
|
89
90
|
when :bearer_token_node
|
90
91
|
thepath=self.options.get_next_argument('path')
|
91
92
|
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
92
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
93
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER, use_secret: false)
|
93
94
|
return Main.result_status(node_api.oauth_token)
|
95
|
+
when :node_info
|
96
|
+
thepath=self.options.get_next_argument('path')
|
97
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
98
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER, use_secret: false)
|
99
|
+
return {:type=>:single_object,:data=>{
|
100
|
+
url: node_file[:node_info]['url'],
|
101
|
+
username: node_file[:node_info]['access_key'],
|
102
|
+
password: node_api.oauth_token,
|
103
|
+
root_id: node_file[:file_id]
|
104
|
+
}}
|
94
105
|
when :browse
|
95
106
|
thepath=self.options.get_next_argument('path')
|
96
107
|
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
97
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
108
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
98
109
|
file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
|
99
110
|
if file_info['type'].eql?('folder')
|
100
111
|
result=node_api.read("files/#{node_file[:file_id]}/files",self.options.get_option(:value,:optional))
|
@@ -114,14 +125,14 @@ module Aspera
|
|
114
125
|
containing_folder_path = thepath.split(AoC::PATH_SEPARATOR)
|
115
126
|
new_folder=containing_folder_path.pop
|
116
127
|
node_file = @api_aoc.resolve_node_file(top_node_file,containing_folder_path.join(AoC::PATH_SEPARATOR))
|
117
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
128
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
118
129
|
result=node_api.create("files/#{node_file[:file_id]}/files",{:name=>new_folder,:type=>:folder})[:data]
|
119
130
|
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
120
131
|
when :rename
|
121
132
|
thepath=self.options.get_next_argument('source path')
|
122
133
|
newname=self.options.get_next_argument('new name')
|
123
134
|
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
124
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
135
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
125
136
|
result=node_api.update("files/#{node_file[:file_id]}",{:name=>newname})[:data]
|
126
137
|
return Main.result_status("renamed #{thepath} to #{newname}")
|
127
138
|
when :delete
|
@@ -129,7 +140,7 @@ module Aspera
|
|
129
140
|
return do_bulk_operation(thepath,'deleted','path') do |l_path|
|
130
141
|
raise "expecting String (path), got #{l_path.class.name} (#{l_path})" unless l_path.is_a?(String)
|
131
142
|
node_file = @api_aoc.resolve_node_file(top_node_file,l_path)
|
132
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
143
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
133
144
|
result=node_api.delete("files/#{node_file[:file_id]}")[:data]
|
134
145
|
{'path'=>l_path}
|
135
146
|
end
|
@@ -152,7 +163,7 @@ module Aspera
|
|
152
163
|
client_node_file = @api_aoc.resolve_node_file(client_home_node_file,client_folder)
|
153
164
|
server_node_file = @api_aoc.resolve_node_file(server_home_node_file,server_folder)
|
154
165
|
# force node as transfer agent
|
155
|
-
@agents[:transfer].set_agent_instance(Fasp::Node.new(@api_aoc.get_node_api(client_node_file[:node_info],AoC::SCOPE_NODE_USER)))
|
166
|
+
@agents[:transfer].set_agent_instance(Fasp::Node.new(@api_aoc.get_node_api(client_node_file[:node_info],scope: AoC::SCOPE_NODE_USER)))
|
156
167
|
# additional node to node TS info
|
157
168
|
add_ts={
|
158
169
|
'remote_access_key' => server_node_file[:node_info]['access_key'],
|
@@ -190,14 +201,14 @@ module Aspera
|
|
190
201
|
raise CliBadArgument,'one file at a time only in HTTP mode' if source_paths.length > 1
|
191
202
|
file_name = source_paths.first['source']
|
192
203
|
node_file = @api_aoc.resolve_node_file(top_node_file,File.join(source_folder,file_name))
|
193
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
204
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
194
205
|
node_api.call({:operation=>'GET',:subpath=>"files/#{node_file[:file_id]}/content",:save_to_file=>File.join(self.transfer.destination_folder('receive'),file_name)})
|
195
206
|
return Main.result_status("downloaded: #{file_name}")
|
196
207
|
when :v3
|
197
208
|
# Note: other "common" actions are unauthorized with user scope
|
198
209
|
command_legacy=self.options.get_next_command(Node::SIMPLE_ACTIONS)
|
199
210
|
# TODO: shall we support all methods here ? what if there is a link ?
|
200
|
-
node_api=@api_aoc.get_node_api(top_node_file[:node_info],AoC::SCOPE_NODE_USER)
|
211
|
+
node_api=@api_aoc.get_node_api(top_node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
201
212
|
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: node_api)).execute_action(command_legacy)
|
202
213
|
when :file
|
203
214
|
file_path=self.options.get_option(:path,:optional)
|
@@ -206,7 +217,7 @@ module Aspera
|
|
206
217
|
else
|
207
218
|
{node_info: top_node_file[:node_info],file_id: self.options.get_option(:id,:mandatory)}
|
208
219
|
end
|
209
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
220
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
210
221
|
command_node_file=self.options.get_next_command([:show,:permission,:modify])
|
211
222
|
case command_node_file
|
212
223
|
when :show
|
@@ -517,7 +528,7 @@ module Aspera
|
|
517
528
|
startdate_persistency=PersistencyActionOnce.new(
|
518
529
|
manager: @agents[:persistency],
|
519
530
|
data: saved_date,
|
520
|
-
ids:
|
531
|
+
ids: IdGenerator.from_list(['aoc_ana_date',self.options.get_option(:url,:mandatory),@workspace_name].push(filter_resource,filter_id)))
|
521
532
|
start_datetime=saved_date.first
|
522
533
|
stop_datetime=Time.now.utc.strftime('%FT%T.%LZ')
|
523
534
|
#Log.log().error("start: #{start_datetime}")
|
@@ -653,7 +664,7 @@ module Aspera
|
|
653
664
|
res_data=@api_aoc.read(resource_instance_path)[:data]
|
654
665
|
node_file = @api_aoc.resolve_node_file({node_info: res_data, file_id: ak_data['root_file_id']},folder_path)
|
655
666
|
|
656
|
-
#node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
667
|
+
#node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
657
668
|
#file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
|
658
669
|
|
659
670
|
access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
|
@@ -781,7 +792,7 @@ module Aspera
|
|
781
792
|
skip_ids_persistency=PersistencyActionOnce.new(
|
782
793
|
manager: @agents[:persistency],
|
783
794
|
data: skip_ids_data,
|
784
|
-
|
795
|
+
id: IdGenerator.from_list(['aoc_recv',self.options.get_option(:url,:mandatory),@workspace_id].push(*@persist_ids)))
|
785
796
|
end
|
786
797
|
if ids_to_download.eql?(VAL_ALL)
|
787
798
|
# get list of packages in inbox
|
@@ -875,7 +886,7 @@ module Aspera
|
|
875
886
|
end
|
876
887
|
result=self.entity_action(@api_aoc,'short_links',nil,:id,'self')
|
877
888
|
if result[:data].is_a?(Hash) and result[:data].has_key?('created_at') and result[:data]['resource_type'].eql?('UrlToken')
|
878
|
-
node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
|
889
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],scope: AoC::SCOPE_NODE_USER)
|
879
890
|
# TODO: access level as arg
|
880
891
|
access_levels=Aspera::Node::ACCESS_LEVELS #['delete','list','mkdir','preview','read','rename','write']
|
881
892
|
perm_data={
|
@@ -9,6 +9,7 @@ require 'aspera/proxy_auto_config'
|
|
9
9
|
require 'aspera/uri_reader'
|
10
10
|
require 'aspera/rest'
|
11
11
|
require 'aspera/persistency_action_once'
|
12
|
+
require 'aspera/id_generator'
|
12
13
|
require 'xmlsimple'
|
13
14
|
require 'base64'
|
14
15
|
require 'net/smtp'
|
@@ -148,7 +149,7 @@ END_OF_TEMPLATE
|
|
148
149
|
check_date_persist=PersistencyActionOnce.new(
|
149
150
|
manager: persistency,
|
150
151
|
data: last_check_array,
|
151
|
-
|
152
|
+
id: 'version_last_check')
|
152
153
|
# get persisted date or nil
|
153
154
|
last_check_date = begin
|
154
155
|
Date.strptime(last_check_array.first, '%Y/%m/%d')
|
@@ -7,6 +7,7 @@ require 'aspera/persistency_action_once'
|
|
7
7
|
require 'aspera/open_application'
|
8
8
|
require 'aspera/fasp/uri'
|
9
9
|
require 'aspera/nagios'
|
10
|
+
require 'aspera/id_generator'
|
10
11
|
require 'xmlsimple'
|
11
12
|
require 'json'
|
12
13
|
require 'cgi'
|
@@ -260,8 +261,8 @@ module Aspera
|
|
260
261
|
if self.options.get_option(:once_only,:mandatory)
|
261
262
|
skip_ids_persistency=PersistencyActionOnce.new(
|
262
263
|
manager: @agents[:persistency],
|
263
|
-
data:
|
264
|
-
|
264
|
+
data: skip_ids_data,
|
265
|
+
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]))
|
265
266
|
end
|
266
267
|
# get command line parameters
|
267
268
|
delivid=self.options.get_option(:id,:mandatory)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'aspera/cli/basic_auth_plugin'
|
2
2
|
require 'aspera/persistency_action_once'
|
3
|
+
require 'aspera/id_generator'
|
3
4
|
require 'securerandom'
|
4
5
|
|
5
6
|
module Aspera
|
@@ -103,8 +104,8 @@ module Aspera
|
|
103
104
|
# read ids from persistency
|
104
105
|
skip_ids_persistency=PersistencyActionOnce.new(
|
105
106
|
manager: @agents[:persistency],
|
106
|
-
data:
|
107
|
-
|
107
|
+
data: skip_ids_data,
|
108
|
+
id: IdGenerator.from_list(['faspex_recv',options.get_option(:url,:mandatory),options.get_option(:username,:mandatory),pkg_type]))
|
108
109
|
end
|
109
110
|
if pack_id.eql?(VAL_ALL)
|
110
111
|
# TODO: if packages have same name, they will overwrite
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'aspera/cli/basic_auth_plugin'
|
2
2
|
require 'aspera/nagios'
|
3
3
|
require 'aspera/hash_ext'
|
4
|
+
require 'aspera/id_generator'
|
4
5
|
require 'base64'
|
5
6
|
require 'zlib'
|
6
7
|
|
@@ -271,8 +272,8 @@ module Aspera
|
|
271
272
|
if self.options.get_option(:once_only,:mandatory)
|
272
273
|
skip_ids_persistency=PersistencyActionOnce.new(
|
273
274
|
manager: @agents[:persistency],
|
274
|
-
data:
|
275
|
-
|
275
|
+
data: iteration_data,
|
276
|
+
id: IdGenerator.from_list(['sync_files',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory),asyncid]))
|
276
277
|
unless iteration_data.first.nil?
|
277
278
|
data.select!{|l| l['fnid'].to_i>iteration_data.first}
|
278
279
|
end
|
@@ -6,6 +6,8 @@ require 'aspera/preview/file_types'
|
|
6
6
|
require 'aspera/persistency_action_once'
|
7
7
|
require 'aspera/node'
|
8
8
|
require 'aspera/hash_ext'
|
9
|
+
require 'aspera/timer_limiter'
|
10
|
+
require 'aspera/id_generator'
|
9
11
|
require 'date'
|
10
12
|
require 'securerandom'
|
11
13
|
|
@@ -24,7 +26,8 @@ module Aspera
|
|
24
26
|
DEFAULT_PREVIEWS_FOLDER='previews'
|
25
27
|
AK_MARKER_FILE='.aspera_access_key'
|
26
28
|
LOCAL_STORAGE_PCVL='file:///'
|
27
|
-
|
29
|
+
LOG_LIMITER_SEC=30.0
|
30
|
+
private_constant :PREV_GEN_TAG, :PREVIEW_FOLDER_SUFFIX, :PREVIEW_BASENAME, :TMP_DIR_PREFIX, :DEFAULT_PREVIEWS_FOLDER, :LOCAL_STORAGE_PCVL, :AK_MARKER_FILE, :LOG_LIMITER_SEC
|
28
31
|
|
29
32
|
# option_skip_format has special accessors
|
30
33
|
attr_accessor :option_previews_folder
|
@@ -40,6 +43,8 @@ module Aspera
|
|
40
43
|
@preview_formats_to_generate=Aspera::Preview::Generator::PREVIEW_FORMATS.clone
|
41
44
|
# options for generation
|
42
45
|
@gen_options=Aspera::Preview::Options.new
|
46
|
+
# used to trigger periodic processing
|
47
|
+
@periodic=TimerLimiter.new(LOG_LIMITER_SEC)
|
43
48
|
# link CLI options to gen_info attributes
|
44
49
|
self.options.set_obj_attr(:skip_format,self,:option_skip_format,[]) # no skip
|
45
50
|
self.options.set_obj_attr(:folder_reset_cache,self,:option_folder_reset_cache,:no)
|
@@ -113,13 +118,14 @@ module Aspera
|
|
113
118
|
end
|
114
119
|
|
115
120
|
# old version based on folders
|
116
|
-
|
121
|
+
# @param iteration_persistency can be nil
|
122
|
+
def process_trevents(iteration_persistency)
|
117
123
|
events_filter={
|
118
124
|
'access_key'=>@access_key_self['id'],
|
119
125
|
'type'=>'download.ended'
|
120
126
|
}
|
121
|
-
# optionally
|
122
|
-
events_filter['iteration_token']=
|
127
|
+
# optionally add iteration token from persistency
|
128
|
+
events_filter['iteration_token']=iteration_persistency.data.first unless iteration_persistency.nil?
|
123
129
|
begin
|
124
130
|
events=@api_node.read('events',events_filter)[:data]
|
125
131
|
rescue RestCallError => e
|
@@ -132,47 +138,63 @@ module Aspera
|
|
132
138
|
end
|
133
139
|
return if events.empty?
|
134
140
|
events.each do |event|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
141
|
+
if event['data']['direction'].eql?('receive') and
|
142
|
+
event['data']['status'].eql?('completed') and
|
143
|
+
event['data']['error_code'].eql?(0) and
|
144
|
+
event['data'].dig('tags','aspera',PREV_GEN_TAG).nil?
|
145
|
+
folder_id=event.dig('data','tags','aspera','node','file_id')
|
146
|
+
folder_id||=event.dig('data','file_id')
|
147
|
+
if !folder_id.nil?
|
148
|
+
folder_entry=@api_node.read("files/#{folder_id}")[:data] rescue nil
|
149
|
+
scan_folder_files(folder_entry) unless folder_entry.nil?
|
150
|
+
end
|
151
|
+
end
|
152
|
+
if @periodic.trigger? or event.equal?(events.last)
|
153
|
+
Log.log.info("Processed event #{event['id']}")
|
154
|
+
# save checkpoint to avoid losing processing in case of error
|
155
|
+
if !iteration_persistency.nil?
|
156
|
+
iteration_persistency.data[0]=event['id'].to_s
|
157
|
+
iteration_persistency.save
|
158
|
+
end
|
159
|
+
end
|
145
160
|
end
|
146
|
-
return events.last['id'].to_s
|
147
161
|
end
|
148
162
|
|
149
163
|
# requests recent events on node api and process newly modified folders
|
150
|
-
def process_events(
|
164
|
+
def process_events(iteration_persistency)
|
151
165
|
# get new file creation by access key (TODO: what if file already existed?)
|
152
166
|
events_filter={
|
153
167
|
'access_key'=>@access_key_self['id'],
|
154
168
|
'type'=>'file.*'
|
155
169
|
}
|
156
|
-
#
|
157
|
-
events_filter['iteration_token']=
|
170
|
+
# optionally add iteration token from persistency
|
171
|
+
events_filter['iteration_token']=iteration_persistency.data.first unless iteration_persistency.nil?
|
158
172
|
events=@api_node.read('events',events_filter)[:data]
|
159
173
|
return if events.empty?
|
160
174
|
events.each do |event|
|
161
175
|
# process only files
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
176
|
+
if event.dig('data','type').eql?('file')
|
177
|
+
file_entry=@api_node.read("files/#{event['data']['id']}")[:data] rescue nil
|
178
|
+
if !file_entry.nil? and
|
179
|
+
@option_skip_folders.select{|d|file_entry['path'].start_with?(d)}.empty?
|
180
|
+
file_entry['parent_file_id']=event['data']['parent_file_id']
|
181
|
+
if event['types'].include?('file.deleted')
|
182
|
+
Log.log.error('TODO'.red)
|
183
|
+
end
|
184
|
+
if event['types'].include?('file.deleted')
|
185
|
+
generate_preview(file_entry)
|
186
|
+
end
|
187
|
+
end
|
169
188
|
end
|
170
|
-
if event
|
171
|
-
|
189
|
+
if @periodic.trigger? or event.equal?(events.last)
|
190
|
+
Log.log.info("Processing event #{event['id']}")
|
191
|
+
# save checkpoint to avoid losing processing in case of error
|
192
|
+
if !iteration_persistency.nil?
|
193
|
+
iteration_persistency.data[0]=event['id'].to_s
|
194
|
+
iteration_persistency.save
|
195
|
+
end
|
172
196
|
end
|
173
197
|
end
|
174
|
-
# write new iteration file
|
175
|
-
return events.last['id'].to_s
|
176
198
|
end
|
177
199
|
|
178
200
|
def do_transfer(direction,folder_id,source_filename,destination='/')
|
@@ -338,6 +360,7 @@ module Aspera
|
|
338
360
|
entry=entries_to_process.shift
|
339
361
|
# process this entry only if it is within the scan_start
|
340
362
|
entry_path_with_slash=entry['path']
|
363
|
+
Log.log.info("processing entry #{entry_path_with_slash}") if @periodic.trigger?
|
341
364
|
entry_path_with_slash="#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
|
342
365
|
if !scan_start.nil? and !scan_start.start_with?(entry_path_with_slash) and !entry_path_with_slash.start_with?(scan_start)
|
343
366
|
Log.log.debug("#{entry['path']} folder (skip start)".bg_red)
|
@@ -441,18 +464,15 @@ module Aspera
|
|
441
464
|
scan_folder_files(folder_info,scan_path)
|
442
465
|
return Main.result_status('scan finished')
|
443
466
|
when :events,:trevents
|
444
|
-
iteration_data=[]
|
445
467
|
iteration_persistency=nil
|
446
468
|
if self.options.get_option(:once_only,:mandatory)
|
447
469
|
iteration_persistency=PersistencyActionOnce.new(
|
448
470
|
manager: @agents[:persistency],
|
449
|
-
data:
|
450
|
-
|
471
|
+
data: [],
|
472
|
+
id: IdGenerator.from_list(['preview_iteration',command.to_s,self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory)]))
|
451
473
|
end
|
452
|
-
|
453
|
-
#
|
454
|
-
iteration_data[0]=send("process_#{command}",iteration_data[0])
|
455
|
-
iteration_persistency.save unless iteration_persistency.nil?
|
474
|
+
# call processing method specified by command line command
|
475
|
+
send("process_#{command}",iteration_persistency)
|
456
476
|
return Main.result_status("#{command} finished")
|
457
477
|
when :check
|
458
478
|
Aspera::Preview::Utils.check_tools(@skip_types)
|
@@ -101,21 +101,29 @@ END_OF_TEMPLATE
|
|
101
101
|
node_config=config.preset_by_name(param_set_name)
|
102
102
|
end
|
103
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>"
|
105
|
-
#
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
+
}})
|
110
123
|
end
|
111
|
-
node_api=Rest.new({
|
112
|
-
:base_url => sym_config[:url],
|
113
|
-
:auth => {
|
114
|
-
:type =>:basic,
|
115
|
-
:username => sym_config[:username],
|
116
|
-
:password => sym_config[:password]
|
117
|
-
}})
|
118
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)
|
119
127
|
when :aoc
|
120
128
|
aoc_config=options.get_option(:transfer_info,:optional)
|
121
129
|
if aoc_config.nil?
|
data/lib/aspera/cli/version.rb
CHANGED
@@ -16,7 +16,6 @@ module Aspera
|
|
16
16
|
# Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
|
17
17
|
def self.normalize_description(d)
|
18
18
|
d.each do |param_name,options|
|
19
|
-
Log.log.debug("def: #{param_name}")
|
20
19
|
raise "Expecting Hash, but have #{options.class} in #{param_name}" unless options.is_a?(Hash)
|
21
20
|
#options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
|
22
21
|
# by default : not mandatory
|
data/lib/aspera/cos_node.rb
CHANGED
@@ -6,6 +6,7 @@ module Aspera
|
|
6
6
|
class CosNode < Rest
|
7
7
|
attr_reader :add_ts
|
8
8
|
IBM_CLOUD_TOKEN_URL='https://iam.cloud.ibm.com/identity'
|
9
|
+
TOKEN_FIELD='delegated_refresh_token'
|
9
10
|
def initialize(bucket_name,storage_endpoint,instance_id,api_key,auth_url=IBM_CLOUD_TOKEN_URL)
|
10
11
|
@auth_url=auth_url
|
11
12
|
@api_key=api_key
|
@@ -32,7 +33,7 @@ module Aspera
|
|
32
33
|
# prepare transfer spec addition
|
33
34
|
@add_ts={'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>{
|
34
35
|
'type' => 'token',
|
35
|
-
'token' => {
|
36
|
+
'token' => {TOKEN_FIELD=>nil}
|
36
37
|
}}}}}
|
37
38
|
generate_token
|
38
39
|
end
|
@@ -45,10 +46,10 @@ module Aspera
|
|
45
46
|
:base_url => @auth_url,
|
46
47
|
:grant => :delegated_refresh,
|
47
48
|
:api_key => @api_key,
|
48
|
-
:token_field=>
|
49
|
+
:token_field=> TOKEN_FIELD
|
49
50
|
})
|
50
51
|
# get delagated token to be placed in rest call header and in transfer tags
|
51
|
-
@add_ts['tags']['aspera']['node']['storage_credentials']['token'][
|
52
|
+
@add_ts['tags']['aspera']['node']['storage_credentials']['token'][TOKEN_FIELD]=delegated_oauth.get_authorization().gsub(/^Bearer /,'')
|
52
53
|
@params[:headers]={'X-Aspera-Storage-Credentials'=>JSON.generate(@add_ts['tags']['aspera']['node']['storage_credentials'])}
|
53
54
|
end
|
54
55
|
end
|
data/lib/aspera/fasp/aoc.rb
CHANGED
@@ -11,7 +11,7 @@ module Aspera
|
|
11
11
|
Log.log.warn("Under Development")
|
12
12
|
server_node_file = @api_aoc.resolve_node_file(server_home_node_file,server_folder)
|
13
13
|
# force node as transfer agent
|
14
|
-
node_api=Fasp::Node.new(@api_aoc.get_node_api(client_node_file[:node_info],AoC::SCOPE_NODE_USER))
|
14
|
+
node_api=Fasp::Node.new(@api_aoc.get_node_api(client_node_file[:node_info],scope: AoC::SCOPE_NODE_USER))
|
15
15
|
super(node_api)
|
16
16
|
# additional node to node TS info
|
17
17
|
@add_ts={
|