aspera-cli 4.19.0 → 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 +20 -0
- data/CONTRIBUTING.md +16 -4
- data/README.md +344 -164
- data/bin/asession +26 -19
- data/examples/build_exec +65 -76
- data/examples/build_exec_rubyc +40 -0
- data/examples/get_proto_file.rb +7 -0
- data/lib/aspera/agent/alpha.rb +8 -8
- data/lib/aspera/agent/base.rb +2 -18
- data/lib/aspera/agent/connect.rb +14 -13
- data/lib/aspera/agent/direct.rb +23 -24
- 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 +126 -97
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/httpgw.rb +15 -10
- data/lib/aspera/api/node.rb +33 -12
- data/lib/aspera/ascmd.rb +56 -48
- data/lib/aspera/ascp/installation.rb +99 -42
- data/lib/aspera/ascp/management.rb +3 -2
- data/lib/aspera/ascp/products.rb +12 -0
- data/lib/aspera/assert.rb +10 -5
- data/lib/aspera/cli/formatter.rb +27 -17
- 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 +5 -0
- data/lib/aspera/cli/plugin.rb +15 -29
- 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 +53 -45
- 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 +153 -95
- 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 +5 -9
- data/lib/aspera/cli/plugins/shares.rb +2 -2
- data/lib/aspera/cli/sync_actions.rb +2 -2
- data/lib/aspera/cli/transfer_agent.rb +12 -14
- data/lib/aspera/cli/transfer_progress.rb +35 -17
- 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 +34 -18
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/json_rpc.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +7 -12
- data/lib/aspera/log.rb +3 -4
- 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 +3 -3
- data/lib/aspera/oauth/url_json.rb +1 -2
- data/lib/aspera/oauth/web.rb +5 -2
- 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/transfer/faux_file.rb +4 -4
- data/lib/aspera/transfer/parameters.rb +14 -16
- data/lib/aspera/transfer/spec.rb +12 -12
- data/lib/aspera/transfer/sync.rb +1 -5
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/aspera/web_auth.rb +166 -17
- data/lib/aspera/web_server_simple.rb +4 -3
- data/lib/transfer_pb.rb +84 -0
- data/lib/transfer_services_pb.rb +82 -0
- data.tar.gz.sig +0 -0
- metadata +24 -5
- 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,27 +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
|
535
|
-
file_info = apifid[:api].read("files/#{apifid[:file_id]}")
|
556
|
+
file_info = apifid[:api].read("files/#{apifid[:file_id]}")
|
536
557
|
case file_info['type']
|
537
558
|
when 'file'
|
538
559
|
# if the single source is a file, we need to split into folder path and filename
|
539
560
|
src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
|
540
561
|
# filename is the last one, source folder is what remains
|
541
562
|
source_paths = [{'source' => src_dir_elements.pop}]
|
542
|
-
|
543
|
-
src_dir_elements.push('')
|
544
|
-
source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
|
545
|
-
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)
|
546
564
|
when 'link', 'folder'
|
547
565
|
# single source is 'folder' or 'link'
|
548
566
|
# TODO: add this ? , 'destination'=>file_info['name']
|
@@ -570,12 +588,12 @@ module Aspera
|
|
570
588
|
return Main.result_status("downloaded: #{file_name}")
|
571
589
|
when :show
|
572
590
|
apifid = apifid_from_next_arg(top_file_id)
|
573
|
-
items = apifid[:api].read("files/#{apifid[:file_id]}")
|
591
|
+
items = apifid[:api].read("files/#{apifid[:file_id]}")
|
574
592
|
return {type: :single_object, data: items}
|
575
593
|
when :modify
|
576
594
|
apifid = apifid_from_next_arg(top_file_id)
|
577
595
|
update_param = options.get_next_argument('update data', validation: Hash)
|
578
|
-
apifid[:api].update("files/#{apifid[:file_id]}", update_param)
|
596
|
+
apifid[:api].update("files/#{apifid[:file_id]}", update_param)
|
579
597
|
return Main.result_status('Done')
|
580
598
|
when :thumbnail
|
581
599
|
apifid = apifid_from_next_arg(top_file_id)
|
@@ -595,13 +613,14 @@ module Aspera
|
|
595
613
|
# add which one to get
|
596
614
|
list_options['file_id'] = apifid[:file_id]
|
597
615
|
list_options['inherited'] ||= false
|
598
|
-
items = apifid[:api].read('permissions', list_options)
|
616
|
+
items = apifid[:api].read('permissions', list_options)
|
599
617
|
return {type: :object_list, data: items}
|
600
618
|
when :delete
|
601
619
|
return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
|
602
620
|
apifid[:api].delete("permissions/#{one_id}")
|
603
621
|
# notify application of deletion
|
604
|
-
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'])
|
605
624
|
{'id' => one_id}
|
606
625
|
end
|
607
626
|
when :create
|
@@ -611,11 +630,11 @@ module Aspera
|
|
611
630
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
612
631
|
# add application specific tags (AoC)
|
613
632
|
the_app = apifid[:api].app_info
|
614
|
-
the_app[:api
|
633
|
+
the_app&.[](:api)&.permissions_set_create_params(perm_data: create_param, app_info: the_app)
|
615
634
|
# create permission
|
616
|
-
created_data = apifid[:api].create('permissions', create_param)
|
635
|
+
created_data = apifid[:api].create('permissions', create_param)
|
617
636
|
# notify application of creation
|
618
|
-
the_app[:api
|
637
|
+
the_app&.[](:api)&.permissions_send_event(event_data: created_data, app_info: the_app)
|
619
638
|
return { type: :single_object, data: created_data}
|
620
639
|
else Aspera.error_unreachable_line
|
621
640
|
end
|
@@ -632,14 +651,14 @@ module Aspera
|
|
632
651
|
if async_name.nil?
|
633
652
|
async_id = instance_identifier
|
634
653
|
if async_id.eql?(SpecialValues::ALL) && %i[show delete].include?(command)
|
635
|
-
async_ids = @api_node.read('async/list')[
|
654
|
+
async_ids = @api_node.read('async/list')['sync_ids']
|
636
655
|
else
|
637
656
|
Integer(async_id) # must be integer
|
638
657
|
async_ids = [async_id]
|
639
658
|
end
|
640
659
|
else
|
641
|
-
async_ids = @api_node.read('async/list')[
|
642
|
-
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']
|
643
662
|
selected = summaries.find{|s|s['name'].eql?(async_name)}
|
644
663
|
raise "no such sync: #{async_name}" if selected.nil?
|
645
664
|
async_id = selected['snid']
|
@@ -649,19 +668,19 @@ module Aspera
|
|
649
668
|
end
|
650
669
|
case command
|
651
670
|
when :list
|
652
|
-
resp = @api_node.read('async/list')[
|
671
|
+
resp = @api_node.read('async/list')['sync_ids']
|
653
672
|
return { type: :value_list, data: resp, name: 'id' }
|
654
673
|
when :show
|
655
|
-
resp = @api_node.create('async/summary', post_data)[
|
674
|
+
resp = @api_node.create('async/summary', post_data)['sync_summaries']
|
656
675
|
return Main.result_empty if resp.empty?
|
657
676
|
return { type: :object_list, data: resp, fields: %w[snid name local_dir remote_dir] } if async_id.eql?(SpecialValues::ALL)
|
658
677
|
return { type: :single_object, data: resp.first }
|
659
678
|
when :delete
|
660
|
-
resp = @api_node.create('async/delete', post_data)
|
679
|
+
resp = @api_node.create('async/delete', post_data)
|
661
680
|
return { type: :single_object, data: resp, name: 'id' }
|
662
681
|
when :bandwidth
|
663
682
|
post_data['seconds'] = 100 # TODO: as parameter with --value
|
664
|
-
resp = @api_node.create('async/bandwidth', post_data)
|
683
|
+
resp = @api_node.create('async/bandwidth', post_data)
|
665
684
|
data = resp['bandwidth_data']
|
666
685
|
return Main.result_empty if data.empty?
|
667
686
|
data = data.first[async_id]['data']
|
@@ -671,9 +690,9 @@ module Aspera
|
|
671
690
|
# filename str
|
672
691
|
# skip int
|
673
692
|
# status int
|
674
|
-
filter =
|
693
|
+
filter = options.get_option(:query)
|
675
694
|
post_data.merge!(filter) unless filter.nil?
|
676
|
-
resp = @api_node.create('async/files', post_data)
|
695
|
+
resp = @api_node.create('async/files', post_data)
|
677
696
|
data = resp['sync_files']
|
678
697
|
data = data.first[async_id] unless data.empty?
|
679
698
|
iteration_data = []
|
@@ -696,7 +715,7 @@ module Aspera
|
|
696
715
|
skip_ids_persistency&.save
|
697
716
|
return { type: :object_list, data: data, name: 'id' }
|
698
717
|
when :counters
|
699
|
-
resp = @api_node.create('async/counters', post_data)[
|
718
|
+
resp = @api_node.create('async/counters', post_data)['sync_counters'].first[async_id].last
|
700
719
|
return Main.result_empty if resp.nil?
|
701
720
|
return { type: :single_object, data: resp }
|
702
721
|
end
|
@@ -708,8 +727,8 @@ module Aspera
|
|
708
727
|
# @param [String] value value of the field to search
|
709
728
|
def ssync_lookup(field, value)
|
710
729
|
raise Cli::BadArgument, "Only search by name is supported (#{field})" unless field.eql?('name')
|
711
|
-
@api_node.read('asyncs')[
|
712
|
-
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']
|
713
732
|
# name is unique, so we can return
|
714
733
|
return id if sync_info[field].eql?(value)
|
715
734
|
end
|
@@ -750,27 +769,27 @@ module Aspera
|
|
750
769
|
return Main.result_status('Done')
|
751
770
|
end
|
752
771
|
parameters = nil
|
753
|
-
parameters =
|
754
|
-
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) }
|
755
774
|
end
|
756
775
|
when :stream
|
757
776
|
command = options.get_next_command(%i[list create show modify cancel])
|
758
777
|
case command
|
759
778
|
when :list
|
760
779
|
resp = @api_node.read('ops/transfers', query_read_delete)
|
761
|
-
return { type: :object_list, data: resp
|
780
|
+
return { type: :object_list, data: resp, fields: %w[id status] } # TODO: useful?
|
762
781
|
when :create
|
763
782
|
resp = @api_node.create('streams', value_create_modify(command: command))
|
764
|
-
return { type: :single_object, data: resp
|
783
|
+
return { type: :single_object, data: resp }
|
765
784
|
when :show
|
766
785
|
resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
|
767
|
-
return { type: :other_struct, data: resp
|
786
|
+
return { type: :other_struct, data: resp }
|
768
787
|
when :modify
|
769
788
|
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command))
|
770
|
-
return { type: :other_struct, data: resp
|
789
|
+
return { type: :other_struct, data: resp }
|
771
790
|
when :cancel
|
772
791
|
resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
|
773
|
-
return { type: :other_struct, data: resp
|
792
|
+
return { type: :other_struct, data: resp }
|
774
793
|
else
|
775
794
|
raise 'error'
|
776
795
|
end
|
@@ -783,14 +802,50 @@ module Aspera
|
|
783
802
|
end
|
784
803
|
case command
|
785
804
|
when :list
|
786
|
-
|
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
|
787
842
|
return {
|
788
843
|
type: :object_list,
|
789
844
|
data: transfers_data,
|
790
845
|
fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
|
791
846
|
}
|
792
847
|
when :sessions
|
793
|
-
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
848
|
+
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
794
849
|
sessions = transfers_data.map{|t|t['sessions']}.flatten
|
795
850
|
sessions.each do |session|
|
796
851
|
session['start_time'] = Time.at(session['start_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
@@ -803,15 +858,15 @@ module Aspera
|
|
803
858
|
}
|
804
859
|
when :cancel
|
805
860
|
resp = @api_node.cancel(one_res_path)
|
806
|
-
return { type: :other_struct, data: resp
|
861
|
+
return { type: :other_struct, data: resp }
|
807
862
|
when :show
|
808
863
|
resp = @api_node.read(one_res_path)
|
809
|
-
return { type: :other_struct, data: resp
|
864
|
+
return { type: :other_struct, data: resp }
|
810
865
|
when :modify
|
811
866
|
resp = @api_node.update(one_res_path, options.get_next_argument('update value', validation: Hash))
|
812
|
-
return { type: :other_struct, data: resp
|
867
|
+
return { type: :other_struct, data: resp }
|
813
868
|
when :bandwidth_average
|
814
|
-
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
869
|
+
transfers_data = @api_node.read(res_class_path, query_read_delete)
|
815
870
|
# collect all key dates
|
816
871
|
bandwidth_period = {}
|
817
872
|
dir_info = %i[avg_kbps sessions].freeze
|
@@ -866,12 +921,12 @@ module Aspera
|
|
866
921
|
case command
|
867
922
|
when :list
|
868
923
|
resp = @api_node.read('rund/services')
|
869
|
-
return { type: :object_list, data: resp[
|
924
|
+
return { type: :object_list, data: resp['services'] }
|
870
925
|
when :create
|
871
926
|
# @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
|
872
927
|
params = options.get_next_argument('creation data', validation: Hash)
|
873
928
|
resp = @api_node.create('rund/services', params)
|
874
|
-
return Main.result_status("#{resp[
|
929
|
+
return Main.result_status("#{resp['id']} created")
|
875
930
|
when :delete
|
876
931
|
@api_node.delete("rund/services/#{service_id}")
|
877
932
|
return Main.result_status("#{service_id} deleted")
|
@@ -889,36 +944,37 @@ module Aspera
|
|
889
944
|
case command
|
890
945
|
when :create
|
891
946
|
resp = @api_node.create(res_class_path, value_create_modify(command: command))
|
892
|
-
return Main.result_status("#{resp[
|
947
|
+
return Main.result_status("#{resp['id']} created")
|
893
948
|
when :list
|
894
949
|
resp = @api_node.read(res_class_path, query_read_delete)
|
895
|
-
return { type: :value_list, data: resp[
|
950
|
+
return { type: :value_list, data: resp['ids'], name: 'id' }
|
896
951
|
when :show
|
897
|
-
return { type: :single_object, data: @api_node.read(one_res_path)
|
952
|
+
return { type: :single_object, data: @api_node.read(one_res_path)}
|
898
953
|
when :modify
|
899
|
-
@api_node.update(one_res_path,
|
954
|
+
@api_node.update(one_res_path, options.get_option(:query, mandatory: true))
|
900
955
|
return Main.result_status("#{one_res_id} updated")
|
901
956
|
when :delete
|
902
957
|
@api_node.delete(one_res_path)
|
903
958
|
return Main.result_status("#{one_res_id} deleted")
|
904
959
|
when :state
|
905
|
-
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") }
|
906
961
|
end
|
907
962
|
when :central
|
908
963
|
command = options.get_next_command(%i[session file])
|
909
964
|
validator_id = options.get_option(:validator)
|
910
965
|
validation = {'validator_id' => validator_id} unless validator_id.nil?
|
911
|
-
request_data =
|
966
|
+
request_data = options.get_option(:query, default: {})
|
912
967
|
case command
|
913
968
|
when :session
|
914
969
|
command = options.get_next_command([:list])
|
915
970
|
case command
|
916
971
|
when :list
|
972
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
917
973
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
918
974
|
resp = @api_node.create('services/rest/transfers/v1/sessions', request_data)
|
919
975
|
return {
|
920
976
|
type: :object_list,
|
921
|
-
data: resp[
|
977
|
+
data: resp['session_info_result']['session_info'],
|
922
978
|
fields: %w[session_uuid status transport direction bytes_transferred]
|
923
979
|
}
|
924
980
|
end
|
@@ -926,12 +982,14 @@ module Aspera
|
|
926
982
|
command = options.get_next_command(%i[list modify])
|
927
983
|
case command
|
928
984
|
when :list
|
985
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
929
986
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
930
|
-
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
987
|
+
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
931
988
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
932
989
|
Log.log.debug{Log.dump(:resp, resp)}
|
933
990
|
return { type: :object_list, data: resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path]}
|
934
991
|
when :modify
|
992
|
+
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
935
993
|
request_data.deep_merge!(validation) unless validation.nil?
|
936
994
|
@api_node.update('services/rest/transfers/v1/files', request_data)
|
937
995
|
return Main.result_status('updated')
|