aspera-cli 4.13.0 → 4.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +28 -5
- data/CONTRIBUTING.md +17 -1
- data/README.md +782 -401
- data/examples/dascli +1 -1
- data/examples/rubyc +24 -0
- data/lib/aspera/aoc.rb +21 -32
- data/lib/aspera/ascmd.rb +1 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +6 -6
- data/lib/aspera/cli/formatter.rb +17 -25
- data/lib/aspera/cli/main.rb +21 -27
- data/lib/aspera/cli/manager.rb +128 -114
- data/lib/aspera/cli/plugin.rb +87 -38
- data/lib/aspera/cli/plugins/alee.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +216 -102
- data/lib/aspera/cli/plugins/ats.rb +16 -18
- data/lib/aspera/cli/plugins/bss.rb +3 -3
- data/lib/aspera/cli/plugins/config.rb +177 -367
- data/lib/aspera/cli/plugins/console.rb +4 -6
- data/lib/aspera/cli/plugins/cos.rb +12 -13
- data/lib/aspera/cli/plugins/faspex.rb +17 -18
- data/lib/aspera/cli/plugins/faspex5.rb +332 -216
- data/lib/aspera/cli/plugins/node.rb +171 -142
- data/lib/aspera/cli/plugins/orchestrator.rb +15 -18
- data/lib/aspera/cli/plugins/preview.rb +38 -60
- data/lib/aspera/cli/plugins/server.rb +22 -15
- data/lib/aspera/cli/plugins/shares.rb +24 -33
- data/lib/aspera/cli/plugins/sync.rb +3 -3
- data/lib/aspera/cli/transfer_agent.rb +29 -26
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +9 -7
- data/lib/aspera/data/6 +0 -0
- data/lib/aspera/environment.rb +7 -3
- data/lib/aspera/fasp/agent_connect.rb +5 -0
- data/lib/aspera/fasp/agent_direct.rb +5 -5
- data/lib/aspera/fasp/agent_httpgw.rb +138 -60
- data/lib/aspera/fasp/agent_trsdk.rb +2 -0
- data/lib/aspera/fasp/error_info.rb +2 -0
- data/lib/aspera/fasp/installation.rb +18 -19
- data/lib/aspera/fasp/parameters.rb +18 -17
- data/lib/aspera/fasp/parameters.yaml +2 -1
- data/lib/aspera/fasp/resume_policy.rb +3 -3
- data/lib/aspera/fasp/transfer_spec.rb +6 -5
- data/lib/aspera/fasp/uri.rb +23 -21
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/hash_ext.rb +12 -2
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/log.rb +1 -0
- data/lib/aspera/node.rb +62 -80
- data/lib/aspera/oauth.rb +1 -1
- data/lib/aspera/persistency_action_once.rb +1 -1
- data/lib/aspera/preview/terminal.rb +61 -15
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.js +2 -2
- data/lib/aspera/rest.rb +37 -0
- data/lib/aspera/secret_hider.rb +6 -1
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/sync.rb +2 -0
- data.tar.gz.sig +0 -0
- metadata +3 -4
- metadata.gz.sig +0 -0
- data/docs/test_env.conf +0 -186
- data/lib/aspera/data/7 +0 -0
@@ -72,15 +72,10 @@ module Aspera
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def register_node_options(env)
|
75
|
-
env[:options].
|
76
|
-
env[:options].
|
77
|
-
env[:options].
|
78
|
-
env[:options].
|
79
|
-
env[:options].add_opt_list(:token_type, %i[aspera basic hybrid], 'type of token used for transfers')
|
80
|
-
env[:options].add_opt_boolean(:default_ports, 'use standard FASP ports or get from node api (gen4)')
|
81
|
-
env[:options].set_option(:asperabrowserurl, 'https://asperabrowser.mybluemix.net')
|
82
|
-
env[:options].set_option(:token_type, :aspera)
|
83
|
-
env[:options].set_option(:default_ports, :yes)
|
75
|
+
env[:options].declare(:validator, 'Identifier of validator (optional for central)')
|
76
|
+
env[:options].declare(:asperabrowserurl, 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net')
|
77
|
+
env[:options].declare(:sync_name, 'Sync name')
|
78
|
+
env[:options].declare(:default_ports, 'Use standard FASP ports or get from node api (gen4)', values: :bool, default: :yes)
|
84
79
|
env[:options].parse_options!
|
85
80
|
Aspera::Node.use_standard_ports = env[:options].get_option(:default_ports)
|
86
81
|
end
|
@@ -117,7 +112,7 @@ module Aspera
|
|
117
112
|
NODE4_READ_ACTIONS = %i[bearer_token_node node_info browse find].freeze
|
118
113
|
|
119
114
|
# commands for execute_command_gen4
|
120
|
-
COMMANDS_GEN4 = %i[mkdir rename delete upload download sync http_node_download
|
115
|
+
COMMANDS_GEN4 = %i[mkdir rename delete upload download sync http_node_download show modify permission thumbnail v3].concat(NODE4_READ_ACTIONS).freeze
|
121
116
|
|
122
117
|
COMMANDS_COS = %i[upload download info access_key api_details transfer].freeze
|
123
118
|
COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
|
@@ -131,23 +126,23 @@ module Aspera
|
|
131
126
|
if env.key?(:node_api)
|
132
127
|
# this can be Aspera::Node or Aspera::Rest (shares)
|
133
128
|
env[:node_api]
|
134
|
-
elsif options.get_option(:password,
|
129
|
+
elsif options.get_option(:password, mandatory: true).start_with?('Bearer ')
|
135
130
|
# info is provided like node_info of aoc
|
136
131
|
Aspera::Node.new(params: {
|
137
|
-
base_url: options.get_option(:url,
|
132
|
+
base_url: options.get_option(:url, mandatory: true),
|
138
133
|
headers: {
|
139
|
-
Aspera::Node::HEADER_X_ASPERA_ACCESS_KEY => options.get_option(:username,
|
140
|
-
'Authorization' => options.get_option(:password,
|
134
|
+
Aspera::Node::HEADER_X_ASPERA_ACCESS_KEY => options.get_option(:username, mandatory: true),
|
135
|
+
'Authorization' => options.get_option(:password, mandatory: true)
|
141
136
|
}
|
142
137
|
})
|
143
138
|
else
|
144
139
|
# this is normal case
|
145
140
|
Aspera::Node.new(params: {
|
146
|
-
base_url: options.get_option(:url,
|
141
|
+
base_url: options.get_option(:url, mandatory: true),
|
147
142
|
auth: {
|
148
143
|
type: :basic,
|
149
|
-
username: options.get_option(:username,
|
150
|
-
password: options.get_option(:password,
|
144
|
+
username: options.get_option(:username, mandatory: true),
|
145
|
+
password: options.get_option(:password, mandatory: true)
|
151
146
|
}})
|
152
147
|
end
|
153
148
|
end
|
@@ -227,7 +222,7 @@ module Aspera
|
|
227
222
|
when :search
|
228
223
|
search_root = get_next_arg_add_prefix(prefix_path, 'search root')
|
229
224
|
parameters = {'path' => search_root}
|
230
|
-
other_options =
|
225
|
+
other_options = value_or_query(allowed_types: Hash)
|
231
226
|
parameters.merge!(other_options) unless other_options.nil?
|
232
227
|
resp = @api_node.create('files/search', parameters)
|
233
228
|
result = { type: :object_list, data: resp[:data]['items']}
|
@@ -285,40 +280,22 @@ module Aspera
|
|
285
280
|
node_sync = SyncSpecGen3.new(@api_node)
|
286
281
|
return Plugins::Sync.new(@agents, sync_spec: node_sync).execute_action
|
287
282
|
when :upload, :download
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
# set requested paths depending on direction
|
296
|
-
request_transfer_spec[:paths] = if command.eql?(:download)
|
297
|
-
transfer.ts_source_paths
|
298
|
-
else
|
299
|
-
[{ destination: transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND) }]
|
300
|
-
end
|
301
|
-
# add fixed parameters if any (for COS)
|
302
|
-
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
303
|
-
# prepare payload for single request
|
304
|
-
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
305
|
-
# only one request, so only one answer
|
306
|
-
transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)[:data]['transfer_specs'].first['transfer_spec']
|
307
|
-
# delete this part, as the returned value contains only destination, and not sources
|
308
|
-
transfer_spec.delete('paths') if command.eql?(:upload)
|
309
|
-
when :basic
|
310
|
-
raise 'shall have auth' unless @api_node.params[:auth].is_a?(Hash)
|
311
|
-
raise 'shall be basic auth' unless @api_node.params[:auth][:type].eql?(:basic)
|
312
|
-
transfer_spec = {}.merge(Aspera::Fasp::TransferSpec::AK_TSPEC_BASE)
|
313
|
-
transfer_spec['remote_host'] = URI.parse(@api_node.params[:base_url]).host
|
314
|
-
Fasp::TransferSpec.action_to_direction(transfer_spec, command)
|
315
|
-
transfer_spec['destination_root'] = transfer.destination_folder(transfer_spec['direction'])
|
316
|
-
@api_node.add_tspec_info(transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
317
|
-
else raise "ERROR: token_type #{tt}"
|
318
|
-
end
|
319
|
-
if %i[basic hybrid].include?(token_type)
|
320
|
-
@api_node.ts_basic_token(transfer_spec)
|
283
|
+
# empty transfer spec for authorization request
|
284
|
+
request_transfer_spec = {}
|
285
|
+
# set requested paths depending on direction
|
286
|
+
request_transfer_spec[:paths] = if command.eql?(:download)
|
287
|
+
transfer.ts_source_paths
|
288
|
+
else
|
289
|
+
[{ destination: transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND) }]
|
321
290
|
end
|
291
|
+
# add fixed parameters if any (for COS)
|
292
|
+
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
293
|
+
# prepare payload for single request
|
294
|
+
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
295
|
+
# only one request, so only one answer
|
296
|
+
transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)[:data]['transfer_specs'].first['transfer_spec']
|
297
|
+
# delete this part, as the returned value contains only destination, and not sources
|
298
|
+
transfer_spec.delete('paths') if command.eql?(:upload)
|
322
299
|
return Main.result_transfer(transfer.start(transfer_spec))
|
323
300
|
end
|
324
301
|
raise 'INTERNAL ERROR'
|
@@ -367,7 +344,7 @@ module Aspera
|
|
367
344
|
end
|
368
345
|
return nagios.result
|
369
346
|
when :events
|
370
|
-
events = @api_node.read('events',
|
347
|
+
events = @api_node.read('events', query_read_delete)[:data]
|
371
348
|
return { type: :object_list, data: events}
|
372
349
|
when :info
|
373
350
|
nd_info = @api_node.read('info')[:data]
|
@@ -383,66 +360,17 @@ module Aspera
|
|
383
360
|
return { type: :single_object, data: @api_node.params }
|
384
361
|
end
|
385
362
|
end
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
end
|
395
|
-
case command_node_file
|
396
|
-
when :show
|
397
|
-
items = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
398
|
-
return {type: :single_object, data: items}
|
399
|
-
when :modify
|
400
|
-
update_param = options.get_next_argument('update data', type: Hash)
|
401
|
-
apifid[:api].update("files/#{apifid[:file_id]}", update_param)[:data]
|
402
|
-
return Main.result_status('Done')
|
403
|
-
when :thumbnail
|
404
|
-
result = apifid[:api].call(
|
405
|
-
operation: 'GET',
|
406
|
-
subpath: "files/#{apifid[:file_id]}/preview",
|
407
|
-
headers: {'Accept' => 'image/png'}
|
408
|
-
)
|
409
|
-
require 'aspera/preview/terminal'
|
410
|
-
return Main.result_status(Preview::Terminal.build(result[:http].body, reserved_lines: 3))
|
411
|
-
when :permission
|
412
|
-
command_perm = options.get_next_command(%i[list create delete])
|
413
|
-
case command_perm
|
414
|
-
when :list
|
415
|
-
# generic options : TODO: as arg ? option_url_query
|
416
|
-
list_options ||= {'include' => [Rest::ARRAY_PARAMS, 'access_level', 'permission_count']}
|
417
|
-
# add which one to get
|
418
|
-
list_options['file_id'] = apifid[:file_id]
|
419
|
-
list_options['inherited'] ||= false
|
420
|
-
items = apifid[:api].read('permissions', list_options)[:data]
|
421
|
-
return {type: :object_list, data: items}
|
422
|
-
when :delete
|
423
|
-
perm_id = instance_identifier
|
424
|
-
return do_bulk_operation(perm_id, 'deleted') do |one_id|
|
425
|
-
# TODO: notify event ?
|
426
|
-
apifid[:api].delete("permissions/#{perm_id}")
|
427
|
-
{'id' => one_id}
|
428
|
-
end
|
429
|
-
when :create
|
430
|
-
create_param = options.get_next_argument('creation data', type: Hash)
|
431
|
-
raise 'no file_id' if create_param.key?('file_id')
|
432
|
-
create_param['file_id'] = apifid[:file_id]
|
433
|
-
create_param['access_levels'] = Aspera::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
434
|
-
# add application specific tags (AoC)
|
435
|
-
the_app = apifid[:api].app_info
|
436
|
-
the_app[:api].permissions_create_params(create_param: create_param, app_info: the_app) unless the_app.nil?
|
437
|
-
# create permission
|
438
|
-
created_data = apifid[:api].create('permissions', create_param)[:data]
|
439
|
-
# notify application of creation
|
440
|
-
the_app[:api].permissions_create_event(created_data: created_data, app_info: the_app) unless the_app.nil?
|
441
|
-
return { type: :single_object, data: created_data}
|
442
|
-
else raise "internal error:shall not reach here (#{command_perm})"
|
443
|
-
end
|
444
|
-
else raise "internal error:shall not reach here (#{command_node_file})"
|
363
|
+
|
364
|
+
# @return [Hash] api and main file id for given path or id
|
365
|
+
# Allows to specify a file by its path or by its id on the node
|
366
|
+
def apifid_from_next_arg(top_file_id)
|
367
|
+
file_path = instance_identifier(description: 'path or id') do |attribute, value|
|
368
|
+
raise 'Only selection "id" is supported (file id)' unless attribute.eql?('id')
|
369
|
+
# directly return result for method
|
370
|
+
return {api: @api_node, file_id: value}
|
445
371
|
end
|
372
|
+
# there was no selector, so it is a path
|
373
|
+
return @api_node.resolve_api_fid(top_file_id, file_path)
|
446
374
|
end
|
447
375
|
|
448
376
|
def execute_command_gen4(command_repo, top_file_id)
|
@@ -476,7 +404,7 @@ module Aspera
|
|
476
404
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
477
405
|
file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
478
406
|
if file_info['type'].eql?('folder')
|
479
|
-
result = apifid[:api].read("files/#{apifid[:file_id]}/files",
|
407
|
+
result = apifid[:api].read("files/#{apifid[:file_id]}/files", old_query_read_delete)
|
480
408
|
items = result[:data]
|
481
409
|
formatter.display_item_count(result[:data].length, result[:http]['X-Total-Count'])
|
482
410
|
else
|
@@ -485,7 +413,7 @@ module Aspera
|
|
485
413
|
return {type: :object_list, data: items, fields: %w[name type recursive_size size modified_time access_level]}
|
486
414
|
when :find
|
487
415
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
488
|
-
test_block = Aspera::Node.file_matcher(
|
416
|
+
test_block = Aspera::Node.file_matcher(value_or_query(allowed_types: String))
|
489
417
|
return {type: :object_list, data: @api_node.find_files(apifid[:file_id], test_block), fields: ['path']}
|
490
418
|
when :mkdir
|
491
419
|
containing_folder_path = options.get_next_argument('path').split(Aspera::Node::PATH_SEPARATOR)
|
@@ -495,10 +423,10 @@ module Aspera
|
|
495
423
|
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
496
424
|
when :rename
|
497
425
|
file_path = options.get_next_argument('source path')
|
498
|
-
newname = options.get_next_argument('new name')
|
499
426
|
apifid = @api_node.resolve_api_fid(top_file_id, file_path)
|
427
|
+
newname = options.get_next_argument('new name')
|
500
428
|
result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname})[:data]
|
501
|
-
return Main.result_status("renamed
|
429
|
+
return Main.result_status("renamed to #{newname}")
|
502
430
|
when :delete
|
503
431
|
return do_bulk_operation(options.get_next_argument('path'), 'deleted', id_result: 'path') do |l_path|
|
504
432
|
raise "expecting String (path), got #{l_path.class.name} (#{l_path})" unless l_path.is_a?(String)
|
@@ -555,9 +483,60 @@ module Aspera
|
|
555
483
|
subpath: "files/#{apifid[:file_id]}/content",
|
556
484
|
save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE), file_name))
|
557
485
|
return Main.result_status("downloaded: #{file_name}")
|
558
|
-
when :
|
559
|
-
|
560
|
-
|
486
|
+
when :show
|
487
|
+
apifid = apifid_from_next_arg(top_file_id)
|
488
|
+
items = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
489
|
+
return {type: :single_object, data: items}
|
490
|
+
when :modify
|
491
|
+
apifid = apifid_from_next_arg(top_file_id)
|
492
|
+
update_param = options.get_next_argument('update data', type: Hash)
|
493
|
+
apifid[:api].update("files/#{apifid[:file_id]}", update_param)[:data]
|
494
|
+
return Main.result_status('Done')
|
495
|
+
when :thumbnail
|
496
|
+
apifid = apifid_from_next_arg(top_file_id)
|
497
|
+
result = apifid[:api].call(
|
498
|
+
operation: 'GET',
|
499
|
+
subpath: "files/#{apifid[:file_id]}/preview",
|
500
|
+
headers: {'Accept' => 'image/png'}
|
501
|
+
)
|
502
|
+
require 'aspera/preview/terminal'
|
503
|
+
return Main.result_status(Preview::Terminal.build(result[:http].body, reserved_lines: 3))
|
504
|
+
when :permission
|
505
|
+
apifid = apifid_from_next_arg(top_file_id)
|
506
|
+
command_perm = options.get_next_command(%i[list create delete])
|
507
|
+
case command_perm
|
508
|
+
when :list
|
509
|
+
# generic options : TODO: as arg ? query_read_delete
|
510
|
+
list_options ||= {'include' => Rest.array_params(%w[access_level permission_count])}
|
511
|
+
# add which one to get
|
512
|
+
list_options['file_id'] = apifid[:file_id]
|
513
|
+
list_options['inherited'] ||= false
|
514
|
+
items = apifid[:api].read('permissions', list_options)[:data]
|
515
|
+
return {type: :object_list, data: items}
|
516
|
+
when :delete
|
517
|
+
perm_id = instance_identifier
|
518
|
+
return do_bulk_operation(perm_id, 'deleted') do |one_id|
|
519
|
+
# TODO: notify event ?
|
520
|
+
apifid[:api].delete("permissions/#{perm_id}")
|
521
|
+
# notify application of deletion
|
522
|
+
the_app[:api].permissions_send_event(created_data: created_data, app_info: the_app, types: ['permission.deleted']) unless the_app.nil?
|
523
|
+
{'id' => one_id}
|
524
|
+
end
|
525
|
+
when :create
|
526
|
+
create_param = options.get_next_argument('creation data', type: Hash)
|
527
|
+
raise 'no file_id' if create_param.key?('file_id')
|
528
|
+
create_param['file_id'] = apifid[:file_id]
|
529
|
+
create_param['access_levels'] = Aspera::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
530
|
+
# add application specific tags (AoC)
|
531
|
+
the_app = apifid[:api].app_info
|
532
|
+
the_app[:api].permissions_set_create_params(create_param: create_param, app_info: the_app) unless the_app.nil?
|
533
|
+
# create permission
|
534
|
+
created_data = apifid[:api].create('permissions', create_param)[:data]
|
535
|
+
# notify application of creation
|
536
|
+
the_app[:api].permissions_send_event(created_data: created_data, app_info: the_app) unless the_app.nil?
|
537
|
+
return { type: :single_object, data: created_data}
|
538
|
+
else raise "internal error:shall not reach here (#{command_perm})"
|
539
|
+
end
|
561
540
|
else raise "INTERNAL ERROR: no case for #{command_repo}"
|
562
541
|
end # command_repo
|
563
542
|
# raise 'INTERNAL ERROR: missing return'
|
@@ -610,21 +589,21 @@ module Aspera
|
|
610
589
|
# filename str
|
611
590
|
# skip int
|
612
591
|
# status int
|
613
|
-
filter =
|
592
|
+
filter = value_or_query(allowed_types: Hash)
|
614
593
|
post_data.merge!(filter) unless filter.nil?
|
615
594
|
resp = @api_node.create('async/files', post_data)[:data]
|
616
595
|
data = resp['sync_files']
|
617
596
|
data = data.first[async_id] unless data.empty?
|
618
597
|
iteration_data = []
|
619
598
|
skip_ids_persistency = nil
|
620
|
-
if options.get_option(:once_only,
|
599
|
+
if options.get_option(:once_only, mandatory: true)
|
621
600
|
skip_ids_persistency = PersistencyActionOnce.new(
|
622
601
|
manager: @agents[:persistency],
|
623
602
|
data: iteration_data,
|
624
603
|
id: IdGenerator.from_list([
|
625
604
|
'sync_files',
|
626
|
-
options.get_option(:url,
|
627
|
-
options.get_option(:username,
|
605
|
+
options.get_option(:url, mandatory: true),
|
606
|
+
options.get_option(:username, mandatory: true),
|
628
607
|
async_id]))
|
629
608
|
unless iteration_data.first.nil?
|
630
609
|
data.select!{|l| l['fnid'].to_i > iteration_data.first}
|
@@ -659,15 +638,18 @@ module Aspera
|
|
659
638
|
when :async then return execute_async # former API
|
660
639
|
when :ssync
|
661
640
|
# newer API
|
662
|
-
sync_command = options.get_next_command(%i[bandwidth counters files
|
641
|
+
sync_command = options.get_next_command(%i[start stop bandwidth counters files state summary].concat(Plugin::ALL_OPS) - %i[modify])
|
663
642
|
case sync_command
|
664
643
|
when *Plugin::ALL_OPS then return entity_command(sync_command, @api_node, 'asyncs', item_list_key: 'ids')
|
665
644
|
else
|
666
|
-
parameters = options.get_option(:value)
|
667
645
|
asyncs_id = instance_identifier
|
646
|
+
parameters = nil
|
668
647
|
if %i[start stop].include?(sync_command)
|
669
648
|
@api_node.create("asyncs/#{asyncs_id}/#{sync_command}", parameters)
|
670
|
-
return Main.result_status('
|
649
|
+
return Main.result_status('Done')
|
650
|
+
end
|
651
|
+
if %i[bandwidth counters files].include?(sync_command)
|
652
|
+
parameters = value_or_query(allowed_types: Hash, mandatory: false) || {}
|
671
653
|
end
|
672
654
|
return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters)[:data] }
|
673
655
|
end
|
@@ -675,16 +657,16 @@ module Aspera
|
|
675
657
|
command = options.get_next_command(%i[list create show modify cancel])
|
676
658
|
case command
|
677
659
|
when :list
|
678
|
-
resp = @api_node.read('ops/transfers',
|
660
|
+
resp = @api_node.read('ops/transfers', old_query_read_delete)
|
679
661
|
return { type: :object_list, data: resp[:data], fields: %w[id status] } # TODO: useful?
|
680
662
|
when :create
|
681
|
-
resp = @api_node.create('streams',
|
663
|
+
resp = @api_node.create('streams', value_create_modify(command: command, type: Hash))
|
682
664
|
return { type: :single_object, data: resp[:data] }
|
683
665
|
when :show
|
684
666
|
resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
|
685
667
|
return { type: :other_struct, data: resp[:data] }
|
686
668
|
when :modify
|
687
|
-
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}",
|
669
|
+
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command, type: Hash))
|
688
670
|
return { type: :other_struct, data: resp[:data] }
|
689
671
|
when :cancel
|
690
672
|
resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
|
@@ -693,21 +675,21 @@ module Aspera
|
|
693
675
|
raise 'error'
|
694
676
|
end
|
695
677
|
when :transfer
|
696
|
-
command = options.get_next_command(%i[list cancel show])
|
678
|
+
command = options.get_next_command(%i[list cancel show modify bandwidth_average])
|
697
679
|
res_class_path = 'ops/transfers'
|
698
|
-
if %i[cancel show].include?(command)
|
680
|
+
if %i[cancel show modify].include?(command)
|
699
681
|
one_res_id = instance_identifier
|
700
682
|
one_res_path = "#{res_class_path}/#{one_res_id}"
|
701
683
|
end
|
702
684
|
case command
|
703
685
|
when :list
|
704
686
|
# could use ? subpath: 'transfers'
|
705
|
-
query =
|
687
|
+
query = query_read_delete
|
706
688
|
raise 'Query must be a Hash' unless query.nil? || query.is_a?(Hash)
|
707
|
-
|
689
|
+
transfers_data = @api_node.read(res_class_path, query)[:data]
|
708
690
|
return {
|
709
691
|
type: :object_list,
|
710
|
-
data:
|
692
|
+
data: transfers_data,
|
711
693
|
fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
|
712
694
|
}
|
713
695
|
when :cancel
|
@@ -716,6 +698,54 @@ module Aspera
|
|
716
698
|
when :show
|
717
699
|
resp = @api_node.read(one_res_path)
|
718
700
|
return { type: :other_struct, data: resp[:data] }
|
701
|
+
when :modify
|
702
|
+
resp = @api_node.update(one_res_path, options.get_next_argument('update value', type: Hash))
|
703
|
+
return { type: :other_struct, data: resp[:data] }
|
704
|
+
when :bandwidth_average
|
705
|
+
transfers_data = @api_node.read(res_class_path, query)[:data]
|
706
|
+
# collect all key dates
|
707
|
+
bandwidth_period = {}
|
708
|
+
dir_info = %i[avg_kbps sessions].freeze
|
709
|
+
transfers_data.each do |transfer|
|
710
|
+
session = transfer
|
711
|
+
# transfer['sessions'].each do |session|
|
712
|
+
next if session['avg_rate_kbps'].zero?
|
713
|
+
bandwidth_period[session['start_time_usec']] = 0
|
714
|
+
bandwidth_period[session['end_time_usec']] = 0
|
715
|
+
# end
|
716
|
+
end
|
717
|
+
result = []
|
718
|
+
# all dates sorted numerically
|
719
|
+
all_dates = bandwidth_period.keys.sort
|
720
|
+
all_dates.each_with_index do |start_date, index|
|
721
|
+
end_date = all_dates[index + 1]
|
722
|
+
# do not process last one
|
723
|
+
break if end_date.nil?
|
724
|
+
# init data for this period
|
725
|
+
period_bandwidth = Fasp::TransferSpec::DIRECTION_ENUM_VALUES.map(&:to_sym).each_with_object({}) do |direction, h|
|
726
|
+
h[direction] = dir_info.each_with_object({}) do |k2, h2|
|
727
|
+
h2[k2] = 0
|
728
|
+
end
|
729
|
+
end
|
730
|
+
# find all transfers that were active at this time
|
731
|
+
transfers_data.each do |transfer|
|
732
|
+
session = transfer
|
733
|
+
# transfer['sessions'].each do |session|
|
734
|
+
# skip if not information for this period
|
735
|
+
next if session['avg_rate_kbps'].zero?
|
736
|
+
# skip if not in this period
|
737
|
+
next if session['start_time_usec'] >= end_date || session['end_time_usec'] <= start_date
|
738
|
+
info = period_bandwidth[transfer['start_spec']['direction'].to_sym]
|
739
|
+
info[:avg_kbps] += session['avg_rate_kbps']
|
740
|
+
info[:sessions] += 1
|
741
|
+
# end
|
742
|
+
end
|
743
|
+
next if Fasp::TransferSpec::DIRECTION_ENUM_VALUES.map(&:to_sym).all? do |dir|
|
744
|
+
period_bandwidth[dir][:sessions].zero?
|
745
|
+
end
|
746
|
+
result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
|
747
|
+
end
|
748
|
+
return { type: :object_list, data: result }
|
719
749
|
else
|
720
750
|
raise 'error'
|
721
751
|
end
|
@@ -749,15 +779,15 @@ module Aspera
|
|
749
779
|
@api_node.params[:headers]['X-aspera-WF-version'] = '2017_10_23'
|
750
780
|
case command
|
751
781
|
when :create
|
752
|
-
resp = @api_node.create(res_class_path,
|
782
|
+
resp = @api_node.create(res_class_path, value_create_modify(command: command, type: Hash))
|
753
783
|
return Main.result_status("#{resp[:data]['id']} created")
|
754
784
|
when :list
|
755
|
-
resp = @api_node.read(res_class_path,
|
785
|
+
resp = @api_node.read(res_class_path, old_query_read_delete)
|
756
786
|
return { type: :value_list, data: resp[:data]['ids'], name: 'id' }
|
757
787
|
when :show
|
758
788
|
return { type: :single_object, data: @api_node.read(one_res_path)[:data]}
|
759
789
|
when :modify
|
760
|
-
@api_node.update(one_res_path,
|
790
|
+
@api_node.update(one_res_path, value_or_query(mandatory: true, allowed_types: Hash))
|
761
791
|
return Main.result_status("#{one_res_id} updated")
|
762
792
|
when :delete
|
763
793
|
@api_node.delete(one_res_path)
|
@@ -769,8 +799,7 @@ module Aspera
|
|
769
799
|
command = options.get_next_command(%i[session file])
|
770
800
|
validator_id = options.get_option(:validator)
|
771
801
|
validation = {'validator_id' => validator_id} unless validator_id.nil?
|
772
|
-
request_data =
|
773
|
-
request_data ||= {}
|
802
|
+
request_data = value_create_modify(default: {}, type: Hash)
|
774
803
|
case command
|
775
804
|
when :session
|
776
805
|
command = options.get_next_command([:list])
|
@@ -801,16 +830,16 @@ module Aspera
|
|
801
830
|
end
|
802
831
|
when :asperabrowser
|
803
832
|
browse_params = {
|
804
|
-
'nodeUser' => options.get_option(:username,
|
805
|
-
'nodePW' => options.get_option(:password,
|
806
|
-
'nodeURL' => options.get_option(:url,
|
833
|
+
'nodeUser' => options.get_option(:username, mandatory: true),
|
834
|
+
'nodePW' => options.get_option(:password, mandatory: true),
|
835
|
+
'nodeURL' => options.get_option(:url, mandatory: true)
|
807
836
|
}
|
808
837
|
# encode parameters so that it looks good in url
|
809
838
|
encoded_params = Base64.strict_encode64(Zlib::Deflate.deflate(JSON.generate(browse_params))).gsub(/=+$/, '').tr('+/', '-_').reverse
|
810
839
|
OpenApplication.instance.uri(options.get_option(:asperabrowserurl) + '?goto=' + encoded_params)
|
811
840
|
return Main.result_status('done')
|
812
841
|
when :basic_token
|
813
|
-
return Main.result_status(Rest.basic_creds(options.get_option(:username,
|
842
|
+
return Main.result_status(Rest.basic_creds(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
|
814
843
|
end # case command
|
815
844
|
raise 'ERROR: shall not reach this line'
|
816
845
|
end # execute_action
|
@@ -9,15 +9,11 @@ module Aspera
|
|
9
9
|
class Orchestrator < Aspera::Cli::BasicAuthPlugin
|
10
10
|
def initialize(env)
|
11
11
|
super(env)
|
12
|
-
options.
|
13
|
-
options.
|
14
|
-
options.
|
15
|
-
options.
|
16
|
-
options.
|
17
|
-
options.set_option(:params, {})
|
18
|
-
options.set_option(:synchronous, :no)
|
19
|
-
options.set_option(:ret_style, :arg)
|
20
|
-
options.set_option(:auth_style, :head_basic)
|
12
|
+
options.declare(:params, 'Start parameters', types: Hash, default: {})
|
13
|
+
options.declare(:result, "Specify result value as: 'work step:parameter'")
|
14
|
+
options.declare(:synchronous, 'Work step:parameter expected as result', values: :bool, default: :no)
|
15
|
+
options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
|
16
|
+
options.declare(:auth_style, 'Authentication type', values: %i[arg_pass head_basic apikey], default: :head_basic)
|
21
17
|
options.parse_options!
|
22
18
|
end
|
23
19
|
|
@@ -49,7 +45,7 @@ module Aspera
|
|
49
45
|
call_args[:subpath] = "#{opt[:prefix]}/#{call_args[:subpath]}" unless opt[:prefix].nil?
|
50
46
|
# specify id if necessary
|
51
47
|
call_args[:subpath] = "#{call_args[:subpath]}/#{opt[:id]}" if opt.key?(:id)
|
52
|
-
call_type = options.get_option(:ret_style,
|
48
|
+
call_type = options.get_option(:ret_style, mandatory: true)
|
53
49
|
call_type = opt[:ret_style] if opt.key?(:ret_style)
|
54
50
|
format = 'json'
|
55
51
|
format = opt[:format] if opt.key?(:format)
|
@@ -73,19 +69,19 @@ module Aspera
|
|
73
69
|
end
|
74
70
|
|
75
71
|
def execute_action
|
76
|
-
rest_params = {base_url: options.get_option(:url,
|
77
|
-
case options.get_option(:auth_style,
|
72
|
+
rest_params = {base_url: options.get_option(:url, mandatory: true)}
|
73
|
+
case options.get_option(:auth_style, mandatory: true)
|
78
74
|
when :arg_pass
|
79
75
|
rest_params[:auth] = {
|
80
76
|
type: :url,
|
81
77
|
url_creds: {
|
82
|
-
'login' => options.get_option(:username,
|
83
|
-
'password' => options.get_option(:password,
|
78
|
+
'login' => options.get_option(:username, mandatory: true),
|
79
|
+
'password' => options.get_option(:password, mandatory: true) }}
|
84
80
|
when :head_basic
|
85
81
|
rest_params[:auth] = {
|
86
82
|
type: :basic,
|
87
|
-
username: options.get_option(:username,
|
88
|
-
password: options.get_option(:password,
|
83
|
+
username: options.get_option(:username, mandatory: true),
|
84
|
+
password: options.get_option(:password, mandatory: true) }
|
89
85
|
when :apikey
|
90
86
|
raise 'Not implemented'
|
91
87
|
end
|
@@ -150,11 +146,12 @@ module Aspera
|
|
150
146
|
call_params = {format: :json}
|
151
147
|
override_accept = nil
|
152
148
|
# set external parameters if any
|
153
|
-
|
149
|
+
# TODO: make not an option, but a parameter
|
150
|
+
self.options.get_option(:params, mandatory: true).each do |name, value|
|
154
151
|
call_params["external_parameters[#{name}]"] = value
|
155
152
|
end
|
156
153
|
# synchronous call ?
|
157
|
-
call_params['synchronous'] = true if self.options.get_option(:synchronous,
|
154
|
+
call_params['synchronous'] = true if self.options.get_option(:synchronous, mandatory: true)
|
158
155
|
# expected result for synchro call ?
|
159
156
|
expected = self.options.get_option(:result)
|
160
157
|
unless expected.nil?
|