aspera-cli 4.18.1 → 4.20.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/CHANGELOG.md +33 -0
- data/CONTRIBUTING.md +17 -12
- data/README.md +396 -185
- data/bin/asession +26 -19
- data/examples/build_exec +74 -0
- data/examples/{rubyc → build_exec_rubyc} +18 -2
- data/examples/get_proto_file.rb +7 -0
- data/lib/aspera/agent/alpha.rb +8 -8
- data/lib/aspera/agent/base.rb +4 -18
- data/lib/aspera/agent/connect.rb +14 -13
- data/lib/aspera/agent/direct.rb +123 -120
- data/lib/aspera/agent/httpgw.rb +2 -3
- data/lib/aspera/agent/node.rb +10 -10
- data/lib/aspera/agent/trsdk.rb +17 -20
- data/lib/aspera/api/alee.rb +15 -0
- data/lib/aspera/api/aoc.rb +128 -99
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/httpgw.rb +104 -64
- data/lib/aspera/api/node.rb +33 -12
- data/lib/aspera/ascmd.rb +56 -48
- data/lib/aspera/ascp/installation.rb +142 -70
- data/lib/aspera/ascp/management.rb +7 -3
- data/lib/aspera/ascp/products.rb +13 -7
- data/lib/aspera/assert.rb +10 -5
- data/lib/aspera/cli/formatter.rb +42 -26
- data/lib/aspera/cli/hints.rb +2 -1
- data/lib/aspera/cli/info.rb +12 -10
- data/lib/aspera/cli/main.rb +16 -13
- data/lib/aspera/cli/manager.rb +15 -10
- data/lib/aspera/cli/plugin.rb +17 -31
- data/lib/aspera/cli/plugin_factory.rb +10 -1
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +222 -194
- data/lib/aspera/cli/plugins/ats.rb +16 -14
- data/lib/aspera/cli/plugins/config.rb +66 -53
- data/lib/aspera/cli/plugins/console.rb +3 -3
- data/lib/aspera/cli/plugins/faspex.rb +11 -21
- data/lib/aspera/cli/plugins/faspex5.rb +44 -42
- data/lib/aspera/cli/plugins/faspio.rb +2 -2
- data/lib/aspera/cli/plugins/httpgw.rb +1 -1
- data/lib/aspera/cli/plugins/node.rb +155 -96
- data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
- data/lib/aspera/cli/plugins/preview.rb +8 -9
- data/lib/aspera/cli/plugins/server.rb +6 -10
- data/lib/aspera/cli/plugins/shares.rb +13 -9
- data/lib/aspera/cli/sync_actions.rb +72 -31
- data/lib/aspera/cli/transfer_agent.rb +13 -14
- data/lib/aspera/cli/transfer_progress.rb +36 -18
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +3 -4
- data/lib/aspera/coverage.rb +13 -1
- data/lib/aspera/environment.rb +59 -10
- data/lib/aspera/faspex_gw.rb +3 -3
- data/lib/aspera/json_rpc.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +2 -0
- data/lib/aspera/keychain/macos_security.rb +7 -12
- data/lib/aspera/log.rb +4 -4
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/base.rb +39 -45
- data/lib/aspera/oauth/factory.rb +11 -4
- data/lib/aspera/oauth/generic.rb +4 -8
- data/lib/aspera/oauth/jwt.rb +4 -4
- data/lib/aspera/oauth/url_json.rb +3 -2
- data/lib/aspera/oauth/web.rb +10 -6
- data/lib/aspera/persistency_action_once.rb +16 -8
- data/lib/aspera/preview/utils.rb +5 -16
- data/lib/aspera/rest.rb +100 -76
- data/lib/aspera/secret_hider.rb +3 -2
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/faux_file.rb +7 -5
- data/lib/aspera/transfer/parameters.rb +41 -35
- data/lib/aspera/transfer/spec.rb +16 -18
- data/lib/aspera/transfer/sync.rb +51 -50
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/aspera/web_auth.rb +166 -18
- data/lib/aspera/web_server_simple.rb +27 -15
- data/lib/transfer_pb.rb +84 -0
- data/lib/transfer_services_pb.rb +82 -0
- data.tar.gz.sig +0 -0
- metadata +25 -6
- metadata.gz.sig +0 -0
@@ -22,6 +22,10 @@ module Aspera
|
|
22
22
|
class Node < Cli::BasicAuthPlugin
|
23
23
|
include SyncActions
|
24
24
|
class << self
|
25
|
+
# directory: node, container: shares
|
26
|
+
FOLDER_TYPES = %w[directory container].freeze
|
27
|
+
private_constant :FOLDER_TYPES
|
28
|
+
|
25
29
|
def application_name
|
26
30
|
'HSTS Node API'
|
27
31
|
end
|
@@ -43,9 +47,9 @@ module Aspera
|
|
43
47
|
test_endpoint = 'ping'
|
44
48
|
result = api.call(operation: 'GET', subpath: test_endpoint)
|
45
49
|
next unless result[:http].body.eql?('')
|
46
|
-
|
50
|
+
url_end = -2 - test_endpoint.length
|
47
51
|
return {
|
48
|
-
url: result[:http].uri.to_s[0..
|
52
|
+
url: result[:http].uri.to_s[0..url_end],
|
49
53
|
version: 'requires authentication'
|
50
54
|
}
|
51
55
|
rescue StandardError => e
|
@@ -69,16 +73,25 @@ module Aspera
|
|
69
73
|
end
|
70
74
|
|
71
75
|
def declare_options(options)
|
76
|
+
return if @options_declared
|
77
|
+
@options_declared = true
|
72
78
|
options.declare(:validator, 'Identifier of validator (optional for central)')
|
73
79
|
options.declare(:asperabrowserurl, 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net')
|
74
80
|
options.declare(:sync_name, 'Sync name')
|
75
81
|
options.declare(
|
76
82
|
:default_ports, 'Use standard FASP ports or get from node api (gen4)', values: :bool, default: :yes,
|
77
83
|
handler: {o: Api::Node, m: :use_standard_ports})
|
78
|
-
options.declare(
|
84
|
+
options.declare(
|
85
|
+
:node_cache, 'Set to no to force actual file system read (gen4)', values: :bool,
|
86
|
+
handler: {o: Api::Node, m: :use_node_cache})
|
87
|
+
options.declare(:root_id, 'File id of top folder when using access key (override AK root id)')
|
79
88
|
SyncActions.declare_options(options)
|
80
89
|
options.parse_options!
|
81
90
|
end
|
91
|
+
|
92
|
+
def gen3_entry_folder?(entry)
|
93
|
+
FOLDER_TYPES.include?(entry['type'])
|
94
|
+
end
|
82
95
|
end
|
83
96
|
|
84
97
|
# spellchecker: disable
|
@@ -164,7 +177,7 @@ module Aspera
|
|
164
177
|
def c_result_translate_rem_prefix(response, type, success_msg, path_prefix)
|
165
178
|
errors = []
|
166
179
|
final_result = {type: :object_list, data: [], fields: [type, 'result']}
|
167
|
-
|
180
|
+
response['paths'].each do |p|
|
168
181
|
result = success_msg
|
169
182
|
if p.key?('error')
|
170
183
|
Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
|
@@ -180,9 +193,6 @@ module Aspera
|
|
180
193
|
return c_result_remove_prefix_path(final_result, type, path_prefix)
|
181
194
|
end
|
182
195
|
|
183
|
-
# directory: node, container: shares
|
184
|
-
FOLDER_TYPE = %w[directory container].freeze
|
185
|
-
|
186
196
|
def browse_gen3(prefix_path)
|
187
197
|
folders_to_process = [get_one_argument_with_prefix(prefix_path, 'path')]
|
188
198
|
query = options.get_option(:query, default: {})
|
@@ -206,26 +216,21 @@ module Aspera
|
|
206
216
|
result = nil
|
207
217
|
loop do
|
208
218
|
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
209
|
-
response = @api_node.
|
210
|
-
operation: 'POST',
|
211
|
-
subpath: 'files/browse',
|
212
|
-
headers: {'Accept' => 'application/json'},
|
213
|
-
body: query,
|
214
|
-
body_type: :json)
|
219
|
+
response = @api_node.create('files/browse', query)
|
215
220
|
# 'file','symbolic_link'
|
216
|
-
if
|
217
|
-
result = { type: :single_object, data: response[
|
221
|
+
if !Node.gen3_entry_folder?(response['self']) || only_path
|
222
|
+
result = { type: :single_object, data: response['self']}
|
218
223
|
break
|
219
224
|
end
|
220
|
-
items = response[
|
221
|
-
total_count ||= response[
|
225
|
+
items = response['items']
|
226
|
+
total_count ||= response['total_count']
|
222
227
|
all_items.concat(items)
|
223
228
|
if single_call
|
224
|
-
formatter.display_item_count(response[
|
229
|
+
formatter.display_item_count(response['item_count'], total_count)
|
225
230
|
break
|
226
231
|
end
|
227
232
|
if recursive
|
228
|
-
folders_to_process.concat(items.select{|i|
|
233
|
+
folders_to_process.concat(items.select{|i|Node.gen3_entry_folder?(i)}.map{|i|i['path']})
|
229
234
|
end
|
230
235
|
if !max_items.nil? && (all_items.count >= max_items)
|
231
236
|
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
@@ -239,6 +244,7 @@ module Aspera
|
|
239
244
|
query.delete('skip')
|
240
245
|
end
|
241
246
|
result ||= {type: :object_list, data: all_items}
|
247
|
+
formatter.long_operation_terminated
|
242
248
|
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
243
249
|
end
|
244
250
|
|
@@ -253,19 +259,19 @@ module Aspera
|
|
253
259
|
when :search
|
254
260
|
search_root = get_one_argument_with_prefix(prefix_path, 'search root')
|
255
261
|
parameters = {'path' => search_root}
|
256
|
-
other_options =
|
262
|
+
other_options = options.get_option(:query)
|
257
263
|
parameters.merge!(other_options) unless other_options.nil?
|
258
264
|
resp = @api_node.create('files/search', parameters)
|
259
|
-
result = { type: :object_list, data: resp[
|
265
|
+
result = { type: :object_list, data: resp['items']}
|
260
266
|
return Main.result_empty if result[:data].empty?
|
261
267
|
result[:fields] = result[:data].first.keys.reject{|i|SEARCH_REMOVE_FIELDS.include?(i)}
|
262
|
-
formatter.display_item_count(resp[
|
263
|
-
formatter.display_status("params: #{resp[
|
268
|
+
formatter.display_item_count(resp['item_count'], resp['total_count'])
|
269
|
+
formatter.display_status("params: #{resp['parameters'].keys.map{|k|"#{k}:#{resp['parameters'][k]}"}.join(',')}")
|
264
270
|
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
265
271
|
when :space
|
266
272
|
path_list = get_all_arguments_with_prefix(prefix_path, 'folder path or ext.val. list')
|
267
273
|
resp = @api_node.create('space', { 'paths' => path_list.map {|i| { path: i} } })
|
268
|
-
result = { type: :object_list, data: resp[
|
274
|
+
result = { type: :object_list, data: resp['paths']}
|
269
275
|
# return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
270
276
|
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
271
277
|
when :mkdir
|
@@ -311,7 +317,7 @@ module Aspera
|
|
311
317
|
# prepare payload for single request
|
312
318
|
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
313
319
|
# only one request, so only one answer
|
314
|
-
transfer_spec = @api_node.create('files/sync_setup', setup_payload)[
|
320
|
+
transfer_spec = @api_node.create('files/sync_setup', setup_payload)['transfer_specs'].first['transfer_spec']
|
315
321
|
# API returns null tag... but async does not like it
|
316
322
|
transfer_spec.delete_if{ |_k, v| v.nil? }
|
317
323
|
# delete this part, as the returned value contains only destination, and not sources
|
@@ -333,7 +339,7 @@ module Aspera
|
|
333
339
|
# prepare payload for single request
|
334
340
|
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
335
341
|
# only one request, so only one answer
|
336
|
-
transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)[
|
342
|
+
transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)['transfer_specs'].first['transfer_spec']
|
337
343
|
# delete this part, as the returned value contains only destination, and not sources
|
338
344
|
transfer_spec.delete('paths') if command.eql?(:upload)
|
339
345
|
return Main.result_transfer(transfer.start(transfer_spec))
|
@@ -363,13 +369,13 @@ module Aspera
|
|
363
369
|
when *Plugin::ALL_OPS
|
364
370
|
return entity_command(ak_command, @api_node, 'access_keys') do |field, value|
|
365
371
|
raise 'only selector: %id:self' unless field.eql?('id') && value.eql?('self')
|
366
|
-
@api_node.read('access_keys/self')[
|
372
|
+
@api_node.read('access_keys/self')['id']
|
367
373
|
end
|
368
374
|
when :do
|
369
375
|
access_key_id = options.get_next_argument('access key id')
|
370
376
|
root_file_id = options.get_option(:root_id)
|
371
377
|
if root_file_id.nil?
|
372
|
-
ak_info = @api_node.read("access_keys/#{access_key_id}")
|
378
|
+
ak_info = @api_node.read("access_keys/#{access_key_id}")
|
373
379
|
# change API credentials if different access key
|
374
380
|
if !access_key_id.eql?('self')
|
375
381
|
@api_node.auth_params[:username] = ak_info['id']
|
@@ -381,7 +387,7 @@ module Aspera
|
|
381
387
|
return execute_command_gen4(command_repo, root_file_id)
|
382
388
|
when :set_bearer_key
|
383
389
|
access_key_id = options.get_next_argument('access key id')
|
384
|
-
access_key_id = @api_node.read('access_keys/self')[
|
390
|
+
access_key_id = @api_node.read('access_keys/self')['id'] if access_key_id.eql?('self')
|
385
391
|
bearer_key_pem = options.get_next_argument('public or private RSA key PEM value', validation: String)
|
386
392
|
key = OpenSSL::PKey.read(bearer_key_pem)
|
387
393
|
key = key.public_key if key.private?
|
@@ -392,7 +398,7 @@ module Aspera
|
|
392
398
|
when :health
|
393
399
|
nagios = Nagios.new
|
394
400
|
begin
|
395
|
-
info = @api_node.read('info')
|
401
|
+
info = @api_node.read('info')
|
396
402
|
nagios.add_ok('node api', 'accessible')
|
397
403
|
nagios.check_time_offset(info['current_time'], 'node api')
|
398
404
|
nagios.check_product_version('node api', 'entsrv', info['version'])
|
@@ -412,17 +418,17 @@ module Aspera
|
|
412
418
|
end
|
413
419
|
return nagios.result
|
414
420
|
when :events
|
415
|
-
events = @api_node.read('events', query_read_delete)
|
421
|
+
events = @api_node.read('events', query_read_delete)
|
416
422
|
return { type: :object_list, data: events, fields: ->(f){!f.start_with?('data')} }
|
417
423
|
when :info
|
418
|
-
nd_info = @api_node.read('info')
|
424
|
+
nd_info = @api_node.read('info')
|
419
425
|
return { type: :single_object, data: nd_info}
|
420
426
|
when :slash
|
421
|
-
nd_info = @api_node.read('')
|
427
|
+
nd_info = @api_node.read('')
|
422
428
|
return { type: :single_object, data: nd_info}
|
423
429
|
when :license
|
424
430
|
# requires: asnodeadmin -mu <node user> --acl-add=internal --internal
|
425
|
-
node_license = @api_node.read('license')
|
431
|
+
node_license = @api_node.read('license')
|
426
432
|
if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
427
433
|
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
|
428
434
|
end
|
@@ -432,8 +438,8 @@ module Aspera
|
|
432
438
|
end
|
433
439
|
end
|
434
440
|
|
435
|
-
#
|
436
|
-
#
|
441
|
+
# Allows to specify a file by its path or by its id on the node in command line
|
442
|
+
# @return [Hash] api and main file id for given path or id in next argument
|
437
443
|
def apifid_from_next_arg(top_file_id)
|
438
444
|
file_path = instance_identifier(description: 'path or %id:<id>') do |attribute, value|
|
439
445
|
raise 'Only selection "id" is supported (file id)' unless attribute.eql?('id')
|
@@ -445,6 +451,9 @@ module Aspera
|
|
445
451
|
end
|
446
452
|
|
447
453
|
def execute_command_gen4(command_repo, top_file_id)
|
454
|
+
override_file_id = options.get_option(:root_id)
|
455
|
+
top_file_id = override_file_id unless override_file_id.nil?
|
456
|
+
raise 'Specify root file id with option root_id' if top_file_id.nil?
|
448
457
|
case command_repo
|
449
458
|
when :v3
|
450
459
|
# NOTE: other common actions are unauthorized with user scope
|
@@ -453,7 +462,7 @@ module Aspera
|
|
453
462
|
apifid = @api_node.resolve_api_fid(top_file_id, '')
|
454
463
|
return Node.new(**init_params, api: apifid[:api]).execute_action(command_legacy)
|
455
464
|
when :node_info, :bearer_token_node
|
456
|
-
apifid =
|
465
|
+
apifid = apifid_from_next_arg(top_file_id)
|
457
466
|
result = {
|
458
467
|
url: apifid[:api].base_url,
|
459
468
|
root_id: apifid[:file_id]
|
@@ -473,10 +482,14 @@ module Aspera
|
|
473
482
|
OAuth::Factory.bearer_extract(result[:password])
|
474
483
|
return Main.result_status(result[:password])
|
475
484
|
when :browse
|
476
|
-
apifid =
|
477
|
-
file_info = apifid[:api].
|
485
|
+
apifid = apifid_from_next_arg(top_file_id)
|
486
|
+
file_info = apifid[:api].read_with_cache("files/#{apifid[:file_id]}")
|
478
487
|
if file_info['type'].eql?('folder')
|
479
|
-
result = apifid[:api].
|
488
|
+
result = apifid[:api].call(
|
489
|
+
operation: 'GET',
|
490
|
+
subpath: "files/#{apifid[:file_id]}/files",
|
491
|
+
headers: Api::Node.cache_control_headers,
|
492
|
+
query: query_read_delete)
|
480
493
|
items = result[:data]
|
481
494
|
formatter.display_item_count(result[:data].length, result[:http]['X-Total-Count'])
|
482
495
|
else
|
@@ -484,25 +497,33 @@ module Aspera
|
|
484
497
|
end
|
485
498
|
return {type: :object_list, data: items, fields: %w[name type recursive_size size modified_time access_level]}
|
486
499
|
when :find
|
487
|
-
apifid =
|
500
|
+
apifid = apifid_from_next_arg(top_file_id)
|
488
501
|
test_block = Api::Node.file_matcher_from_argument(options)
|
489
502
|
return {type: :object_list, data: @api_node.find_files(apifid[:file_id], test_block), fields: ['path']}
|
490
503
|
when :mkdir
|
491
504
|
containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
|
492
505
|
new_folder = containing_folder_path.pop
|
493
|
-
|
494
|
-
|
506
|
+
# add trailing slash to force last link to be resolved
|
507
|
+
apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Api::Node::PATH_SEPARATOR), true)
|
508
|
+
result = apifid[:api].create("files/#{apifid[:file_id]}/files", {name: new_folder, type: :folder})
|
495
509
|
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
496
510
|
when :rename
|
497
511
|
file_path = options.get_next_argument('source path')
|
498
512
|
apifid = @api_node.resolve_api_fid(top_file_id, file_path)
|
499
513
|
newname = options.get_next_argument('new name')
|
500
|
-
result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname})
|
514
|
+
result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname})
|
501
515
|
return Main.result_status("renamed to #{newname}")
|
502
516
|
when :delete
|
503
517
|
return do_bulk_operation(command: command_repo, descr: 'path', values: String, id_result: 'path') do |l_path|
|
504
|
-
apifid =
|
505
|
-
|
518
|
+
apifid = if (m = l_path.match(REGEX_LOOKUP_ID_BY_FIELD))
|
519
|
+
{
|
520
|
+
api: @api_node,
|
521
|
+
file_id: m[2]
|
522
|
+
}
|
523
|
+
else
|
524
|
+
@api_node.resolve_api_fid(top_file_id, l_path)
|
525
|
+
end
|
526
|
+
result = apifid[:api].delete("files/#{apifid[:file_id]}")
|
506
527
|
{'path' => l_path}
|
507
528
|
end
|
508
529
|
when :sync
|
@@ -522,26 +543,24 @@ module Aspera
|
|
522
543
|
transfer_spec
|
523
544
|
end
|
524
545
|
when :upload
|
525
|
-
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND))
|
546
|
+
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND), true)
|
526
547
|
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_SEND)))
|
527
548
|
when :download
|
528
549
|
source_paths = transfer.ts_source_paths
|
529
550
|
# special case for AoC : all files must be in same folder
|
530
551
|
source_folder = source_paths.shift['source']
|
531
552
|
# if a single file: split into folder and path
|
532
|
-
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
553
|
+
apifid = @api_node.resolve_api_fid(top_file_id, source_folder, true)
|
533
554
|
if source_paths.empty?
|
534
|
-
|
555
|
+
# get precise info in this element
|
556
|
+
file_info = apifid[:api].read("files/#{apifid[:file_id]}")
|
535
557
|
case file_info['type']
|
536
558
|
when 'file'
|
537
559
|
# if the single source is a file, we need to split into folder path and filename
|
538
560
|
src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
|
539
|
-
# filename is the last one
|
561
|
+
# filename is the last one, source folder is what remains
|
540
562
|
source_paths = [{'source' => src_dir_elements.pop}]
|
541
|
-
|
542
|
-
source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
|
543
|
-
# TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
|
544
|
-
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
563
|
+
apifid = @api_node.resolve_api_fid(top_file_id, src_dir_elements.join(Api::Node::PATH_SEPARATOR), true)
|
545
564
|
when 'link', 'folder'
|
546
565
|
# single source is 'folder' or 'link'
|
547
566
|
# TODO: add this ? , 'destination'=>file_info['name']
|
@@ -569,12 +588,12 @@ module Aspera
|
|
569
588
|
return Main.result_status("downloaded: #{file_name}")
|
570
589
|
when :show
|
571
590
|
apifid = apifid_from_next_arg(top_file_id)
|
572
|
-
items = apifid[:api].read("files/#{apifid[:file_id]}")
|
591
|
+
items = apifid[:api].read("files/#{apifid[:file_id]}")
|
573
592
|
return {type: :single_object, data: items}
|
574
593
|
when :modify
|
575
594
|
apifid = apifid_from_next_arg(top_file_id)
|
576
595
|
update_param = options.get_next_argument('update data', validation: Hash)
|
577
|
-
apifid[:api].update("files/#{apifid[:file_id]}", update_param)
|
596
|
+
apifid[:api].update("files/#{apifid[:file_id]}", update_param)
|
578
597
|
return Main.result_status('Done')
|
579
598
|
when :thumbnail
|
580
599
|
apifid = apifid_from_next_arg(top_file_id)
|
@@ -594,13 +613,14 @@ module Aspera
|
|
594
613
|
# add which one to get
|
595
614
|
list_options['file_id'] = apifid[:file_id]
|
596
615
|
list_options['inherited'] ||= false
|
597
|
-
items = apifid[:api].read('permissions', list_options)
|
616
|
+
items = apifid[:api].read('permissions', list_options)
|
598
617
|
return {type: :object_list, data: items}
|
599
618
|
when :delete
|
600
619
|
return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
|
601
620
|
apifid[:api].delete("permissions/#{one_id}")
|
602
621
|
# notify application of deletion
|
603
|
-
the_app[:api].
|
622
|
+
the_app = apifid[:api].app_info
|
623
|
+
the_app&.[](:api)&.permissions_send_event(event_data: {}, app_info: the_app, types: ['permission.deleted'])
|
604
624
|
{'id' => one_id}
|
605
625
|
end
|
606
626
|
when :create
|
@@ -610,11 +630,11 @@ module Aspera
|
|
610
630
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
611
631
|
# add application specific tags (AoC)
|
612
632
|
the_app = apifid[:api].app_info
|
613
|
-
the_app[:api
|
633
|
+
the_app&.[](:api)&.permissions_set_create_params(perm_data: create_param, app_info: the_app)
|
614
634
|
# create permission
|
615
|
-
created_data = apifid[:api].create('permissions', create_param)
|
635
|
+
created_data = apifid[:api].create('permissions', create_param)
|
616
636
|
# notify application of creation
|
617
|
-
the_app[:api
|
637
|
+
the_app&.[](:api)&.permissions_send_event(event_data: created_data, app_info: the_app)
|
618
638
|
return { type: :single_object, data: created_data}
|
619
639
|
else Aspera.error_unreachable_line
|
620
640
|
end
|
@@ -631,14 +651,14 @@ module Aspera
|
|
631
651
|
if async_name.nil?
|
632
652
|
async_id = instance_identifier
|
633
653
|
if async_id.eql?(SpecialValues::ALL) && %i[show delete].include?(command)
|
634
|
-
async_ids = @api_node.read('async/list')[
|
654
|
+
async_ids = @api_node.read('async/list')['sync_ids']
|
635
655
|
else
|
636
656
|
Integer(async_id) # must be integer
|
637
657
|
async_ids = [async_id]
|
638
658
|
end
|
639
659
|
else
|
640
|
-
async_ids = @api_node.read('async/list')[
|
641
|
-
summaries = @api_node.create('async/summary', {'syncs' => async_ids})[
|
660
|
+
async_ids = @api_node.read('async/list')['sync_ids']
|
661
|
+
summaries = @api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
642
662
|
selected = summaries.find{|s|s['name'].eql?(async_name)}
|
643
663
|
raise "no such sync: #{async_name}" if selected.nil?
|
644
664
|
async_id = selected['snid']
|
@@ -648,19 +668,19 @@ module Aspera
|
|
648
668
|
end
|
649
669
|
case command
|
650
670
|
when :list
|
651
|
-
resp = @api_node.read('async/list')[
|
671
|
+
resp = @api_node.read('async/list')['sync_ids']
|
652
672
|
return { type: :value_list, data: resp, name: 'id' }
|
653
673
|
when :show
|
654
|
-
resp = @api_node.create('async/summary', post_data)[
|
674
|
+
resp = @api_node.create('async/summary', post_data)['sync_summaries']
|
655
675
|
return Main.result_empty if resp.empty?
|
656
676
|
return { type: :object_list, data: resp, fields: %w[snid name local_dir remote_dir] } if async_id.eql?(SpecialValues::ALL)
|
657
677
|
return { type: :single_object, data: resp.first }
|
658
678
|
when :delete
|
659
|
-
resp = @api_node.create('async/delete', post_data)
|
679
|
+
resp = @api_node.create('async/delete', post_data)
|
660
680
|
return { type: :single_object, data: resp, name: 'id' }
|
661
681
|
when :bandwidth
|
662
682
|
post_data['seconds'] = 100 # TODO: as parameter with --value
|
663
|
-
resp = @api_node.create('async/bandwidth', post_data)
|
683
|
+
resp = @api_node.create('async/bandwidth', post_data)
|
664
684
|
data = resp['bandwidth_data']
|
665
685
|
return Main.result_empty if data.empty?
|
666
686
|
data = data.first[async_id]['data']
|
@@ -670,9 +690,9 @@ module Aspera
|
|
670
690
|
# filename str
|
671
691
|
# skip int
|
672
692
|
# status int
|
673
|
-
filter =
|
693
|
+
filter = options.get_option(:query)
|
674
694
|
post_data.merge!(filter) unless filter.nil?
|
675
|
-
resp = @api_node.create('async/files', post_data)
|
695
|
+
resp = @api_node.create('async/files', post_data)
|
676
696
|
data = resp['sync_files']
|
677
697
|
data = data.first[async_id] unless data.empty?
|
678
698
|
iteration_data = []
|
@@ -695,7 +715,7 @@ module Aspera
|
|
695
715
|
skip_ids_persistency&.save
|
696
716
|
return { type: :object_list, data: data, name: 'id' }
|
697
717
|
when :counters
|
698
|
-
resp = @api_node.create('async/counters', post_data)[
|
718
|
+
resp = @api_node.create('async/counters', post_data)['sync_counters'].first[async_id].last
|
699
719
|
return Main.result_empty if resp.nil?
|
700
720
|
return { type: :single_object, data: resp }
|
701
721
|
end
|
@@ -707,8 +727,8 @@ module Aspera
|
|
707
727
|
# @param [String] value value of the field to search
|
708
728
|
def ssync_lookup(field, value)
|
709
729
|
raise Cli::BadArgument, "Only search by name is supported (#{field})" unless field.eql?('name')
|
710
|
-
@api_node.read('asyncs')[
|
711
|
-
sync_info = @api_node.read("asyncs/#{id}")[
|
730
|
+
@api_node.read('asyncs')['ids'].each do |id|
|
731
|
+
sync_info = @api_node.read("asyncs/#{id}")['configuration']
|
712
732
|
# name is unique, so we can return
|
713
733
|
return id if sync_info[field].eql?(value)
|
714
734
|
end
|
@@ -749,27 +769,27 @@ module Aspera
|
|
749
769
|
return Main.result_status('Done')
|
750
770
|
end
|
751
771
|
parameters = nil
|
752
|
-
parameters =
|
753
|
-
return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters)
|
772
|
+
parameters = options.get_option(:query, default: {}) if %i[bandwidth counters files].include?(sync_command)
|
773
|
+
return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters) }
|
754
774
|
end
|
755
775
|
when :stream
|
756
776
|
command = options.get_next_command(%i[list create show modify cancel])
|
757
777
|
case command
|
758
778
|
when :list
|
759
779
|
resp = @api_node.read('ops/transfers', query_read_delete)
|
760
|
-
return { type: :object_list, data: resp
|
780
|
+
return { type: :object_list, data: resp, fields: %w[id status] } # TODO: useful?
|
761
781
|
when :create
|
762
782
|
resp = @api_node.create('streams', value_create_modify(command: command))
|
763
|
-
return { type: :single_object, data: resp
|
783
|
+
return { type: :single_object, data: resp }
|
764
784
|
when :show
|
765
785
|
resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
|
766
|
-
return { type: :other_struct, data: resp
|
786
|
+
return { type: :other_struct, data: resp }
|
767
787
|
when :modify
|
768
788
|
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command))
|
769
|
-
return { type: :other_struct, data: resp
|
789
|
+
return { type: :other_struct, data: resp }
|
770
790
|
when :cancel
|
771
791
|
resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
|
772
|
-
return { type: :other_struct, data: resp
|
792
|
+
return { type: :other_struct, data: resp }
|
773
793
|
else
|
774
794
|
raise 'error'
|
775
795
|
end
|
@@ -782,14 +802,50 @@ module Aspera
|
|
782
802
|
end
|
783
803
|
case command
|
784
804
|
when :list
|
785
|
-
|
805
|
+
iteration_persistency = nil
|
806
|
+
iteration_data = []
|
807
|
+
if options.get_option(:once_only, mandatory: true)
|
808
|
+
iteration_persistency = PersistencyActionOnce.new(
|
809
|
+
manager: persistency,
|
810
|
+
data: iteration_data,
|
811
|
+
id: IdGenerator.from_list([
|
812
|
+
'node_transfers',
|
813
|
+
options.get_option(:url, mandatory: true),
|
814
|
+
options.get_option(:username, mandatory: true)
|
815
|
+
]))
|
816
|
+
end
|
817
|
+
transfer_filter = query_read_delete(default: {})
|
818
|
+
if transfer_filter.delete('reset')
|
819
|
+
iteration_data.clear
|
820
|
+
iteration_persistency&.save
|
821
|
+
return Main.result_status('Persistency reset')
|
822
|
+
end
|
823
|
+
max_items = transfer_filter.delete(MAX_ITEMS)
|
824
|
+
transfer_filter['iteration_token'] = iteration_persistency.data[0] unless iteration_data.empty?
|
825
|
+
transfers_data = []
|
826
|
+
loop do
|
827
|
+
result = @api_node.call(operation: 'GET', subpath: res_class_path, query: transfer_filter)
|
828
|
+
data = result[:data]
|
829
|
+
transfers_data.concat(data)
|
830
|
+
if !max_items.nil? && (transfers_data.length >= max_items)
|
831
|
+
transfers_data = transfers_data.slice(0, max_items)
|
832
|
+
break
|
833
|
+
end
|
834
|
+
link_info = result[:http]['Link']
|
835
|
+
break if iteration_persistency.nil? || data.empty? || link_info.nil?
|
836
|
+
m = link_info.match(/<([^>]+)>/)
|
837
|
+
raise "Problem with iteration: #{link_info}" if m.nil?
|
838
|
+
iteration_token = CGI.parse(URI.parse(m[1]).query)['iteration_token']&.first
|
839
|
+
iteration_data[0] = transfer_filter['iteration_token'] = iteration_token
|
840
|
+
end
|
841
|
+
iteration_persistency&.save
|
786
842
|
return {
|
787
843
|
type: :object_list,
|
788
844
|
data: transfers_data,
|
789
845
|
fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
|
790
846
|
}
|
791
847
|
when :sessions
|
792
|
-
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
848
|
+
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
793
849
|
sessions = transfers_data.map{|t|t['sessions']}.flatten
|
794
850
|
sessions.each do |session|
|
795
851
|
session['start_time'] = Time.at(session['start_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
@@ -802,15 +858,15 @@ module Aspera
|
|
802
858
|
}
|
803
859
|
when :cancel
|
804
860
|
resp = @api_node.cancel(one_res_path)
|
805
|
-
return { type: :other_struct, data: resp
|
861
|
+
return { type: :other_struct, data: resp }
|
806
862
|
when :show
|
807
863
|
resp = @api_node.read(one_res_path)
|
808
|
-
return { type: :other_struct, data: resp
|
864
|
+
return { type: :other_struct, data: resp }
|
809
865
|
when :modify
|
810
866
|
resp = @api_node.update(one_res_path, options.get_next_argument('update value', validation: Hash))
|
811
|
-
return { type: :other_struct, data: resp
|
867
|
+
return { type: :other_struct, data: resp }
|
812
868
|
when :bandwidth_average
|
813
|
-
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
869
|
+
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
814
870
|
# collect all key dates
|
815
871
|
bandwidth_period = {}
|
816
872
|
dir_info = %i[avg_kbps sessions].freeze
|
@@ -865,12 +921,12 @@ module Aspera
|
|
865
921
|
case command
|
866
922
|
when :list
|
867
923
|
resp = @api_node.read('rund/services')
|
868
|
-
return { type: :object_list, data: resp[
|
924
|
+
return { type: :object_list, data: resp['services'] }
|
869
925
|
when :create
|
870
926
|
# @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
|
871
927
|
params = options.get_next_argument('creation data', validation: Hash)
|
872
928
|
resp = @api_node.create('rund/services', params)
|
873
|
-
return Main.result_status("#{resp[
|
929
|
+
return Main.result_status("#{resp['id']} created")
|
874
930
|
when :delete
|
875
931
|
@api_node.delete("rund/services/#{service_id}")
|
876
932
|
return Main.result_status("#{service_id} deleted")
|
@@ -888,36 +944,37 @@ module Aspera
|
|
888
944
|
case command
|
889
945
|
when :create
|
890
946
|
resp = @api_node.create(res_class_path, value_create_modify(command: command))
|
891
|
-
return Main.result_status("#{resp[
|
947
|
+
return Main.result_status("#{resp['id']} created")
|
892
948
|
when :list
|
893
949
|
resp = @api_node.read(res_class_path, query_read_delete)
|
894
|
-
return { type: :value_list, data: resp[
|
950
|
+
return { type: :value_list, data: resp['ids'], name: 'id' }
|
895
951
|
when :show
|
896
|
-
return { type: :single_object, data: @api_node.read(one_res_path)
|
952
|
+
return { type: :single_object, data: @api_node.read(one_res_path)}
|
897
953
|
when :modify
|
898
|
-
@api_node.update(one_res_path,
|
954
|
+
@api_node.update(one_res_path, options.get_option(:query, mandatory: true))
|
899
955
|
return Main.result_status("#{one_res_id} updated")
|
900
956
|
when :delete
|
901
957
|
@api_node.delete(one_res_path)
|
902
958
|
return Main.result_status("#{one_res_id} deleted")
|
903
959
|
when :state
|
904
|
-
return { type: :single_object, data: @api_node.read("#{one_res_path}/state")
|
960
|
+
return { type: :single_object, data: @api_node.read("#{one_res_path}/state") }
|
905
961
|
end
|
906
962
|
when :central
|
907
963
|
command = options.get_next_command(%i[session file])
|
908
964
|
validator_id = options.get_option(:validator)
|
909
965
|
validation = {'validator_id' => validator_id} unless validator_id.nil?
|
910
|
-
request_data =
|
966
|
+
request_data = options.get_option(:query, default: {})
|
911
967
|
case command
|
912
968
|
when :session
|
913
969
|
command = options.get_next_command([:list])
|
914
970
|
case command
|
915
971
|
when :list
|
972
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
916
973
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
917
974
|
resp = @api_node.create('services/rest/transfers/v1/sessions', request_data)
|
918
975
|
return {
|
919
976
|
type: :object_list,
|
920
|
-
data: resp[
|
977
|
+
data: resp['session_info_result']['session_info'],
|
921
978
|
fields: %w[session_uuid status transport direction bytes_transferred]
|
922
979
|
}
|
923
980
|
end
|
@@ -925,12 +982,14 @@ module Aspera
|
|
925
982
|
command = options.get_next_command(%i[list modify])
|
926
983
|
case command
|
927
984
|
when :list
|
985
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
928
986
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
929
|
-
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
987
|
+
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
930
988
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
931
989
|
Log.log.debug{Log.dump(:resp, resp)}
|
932
990
|
return { type: :object_list, data: resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path]}
|
933
991
|
when :modify
|
992
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
934
993
|
request_data.deep_merge!(validation) unless validation.nil?
|
935
994
|
@api_node.update('services/rest/transfers/v1/files', request_data)
|
936
995
|
return Main.result_status('updated')
|