aspera-cli 4.15.0 → 4.17.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/BUGS.md +29 -3
- data/CHANGELOG.md +375 -280
- data/CONTRIBUTING.md +71 -18
- data/README.md +1978 -1656
- data/bin/ascli +13 -31
- data/bin/asession +32 -22
- data/examples/dascli +2 -2
- data/lib/aspera/agent/alpha.rb +117 -0
- data/lib/aspera/agent/base.rb +61 -0
- data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
- data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +116 -116
- data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +21 -19
- data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +21 -33
- data/lib/aspera/agent/trsdk.rb +188 -0
- data/lib/aspera/api/aoc.rb +586 -0
- data/lib/aspera/api/ats.rb +46 -0
- data/lib/aspera/api/cos_node.rb +95 -0
- data/lib/aspera/api/node.rb +344 -0
- data/lib/aspera/ascmd.rb +47 -14
- data/lib/aspera/{fasp → ascp}/installation.rb +54 -15
- data/lib/aspera/{fasp → ascp}/management.rb +14 -14
- data/lib/aspera/{fasp → ascp}/products.rb +1 -1
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
- data/lib/aspera/cli/extended_value.rb +5 -5
- data/lib/aspera/cli/formatter.rb +27 -14
- data/lib/aspera/cli/hints.rb +7 -6
- data/lib/aspera/cli/main.rb +49 -29
- data/lib/aspera/cli/manager.rb +46 -36
- data/lib/aspera/cli/plugin.rb +34 -20
- data/lib/aspera/cli/plugin_factory.rb +61 -0
- data/lib/aspera/cli/plugins/alee.rb +7 -7
- data/lib/aspera/cli/plugins/aoc.rb +168 -132
- data/lib/aspera/cli/plugins/ats.rb +33 -33
- data/lib/aspera/cli/plugins/bss.rb +3 -4
- data/lib/aspera/cli/plugins/config.rb +250 -272
- data/lib/aspera/cli/plugins/console.rb +8 -6
- data/lib/aspera/cli/plugins/cos.rb +20 -19
- data/lib/aspera/cli/plugins/faspex.rb +71 -60
- data/lib/aspera/cli/plugins/faspex5.rb +212 -133
- data/lib/aspera/cli/plugins/node.rb +83 -75
- data/lib/aspera/cli/plugins/orchestrator.rb +36 -44
- data/lib/aspera/cli/plugins/preview.rb +33 -31
- data/lib/aspera/cli/plugins/server.rb +33 -32
- data/lib/aspera/cli/plugins/shares.rb +39 -33
- data/lib/aspera/cli/sync_actions.rb +9 -9
- data/lib/aspera/cli/transfer_agent.rb +45 -25
- data/lib/aspera/cli/transfer_progress.rb +2 -3
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +5 -0
- data/lib/aspera/command_line_builder.rb +16 -14
- data/lib/aspera/coverage.rb +21 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +5 -4
- data/lib/aspera/faspex_gw.rb +13 -11
- data/lib/aspera/faspex_postproc.rb +6 -5
- data/lib/aspera/id_generator.rb +4 -2
- data/lib/aspera/json_rpc.rb +10 -8
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +29 -22
- data/lib/aspera/log.rb +5 -4
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node_simulator.rb +213 -0
- data/lib/aspera/oauth/base.rb +143 -0
- data/lib/aspera/oauth/factory.rb +124 -0
- data/lib/aspera/oauth/generic.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +51 -0
- data/lib/aspera/oauth/url_json.rb +31 -0
- data/lib/aspera/oauth/web.rb +50 -0
- data/lib/aspera/oauth.rb +5 -328
- data/lib/aspera/open_application.rb +7 -7
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +3 -2
- data/lib/aspera/preview/file_types.rb +53 -267
- data/lib/aspera/preview/generator.rb +7 -5
- data/lib/aspera/preview/terminal.rb +17 -7
- data/lib/aspera/preview/utils.rb +8 -7
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +187 -140
- data/lib/aspera/rest_error_analyzer.rb +1 -0
- data/lib/aspera/rest_errors_aspera.rb +5 -3
- data/lib/aspera/resumer.rb +77 -0
- data/lib/aspera/secret_hider.rb +5 -2
- data/lib/aspera/ssh.rb +15 -8
- data/lib/aspera/temp_file_manager.rb +1 -1
- data/lib/aspera/{fasp → transfer}/error.rb +3 -3
- data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
- data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
- data/lib/aspera/{fasp → transfer}/parameters.rb +95 -120
- data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +23 -19
- data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
- data/lib/aspera/transfer/sync.rb +273 -0
- data/lib/aspera/{fasp → transfer}/uri.rb +10 -9
- data/lib/aspera/web_server_simple.rb +12 -3
- data.tar.gz.sig +0 -0
- metadata +92 -68
- metadata.gz.sig +0 -0
- data/lib/aspera/aoc.rb +0 -606
- data/lib/aspera/ats_api.rb +0 -47
- data/lib/aspera/cos_node.rb +0 -93
- data/lib/aspera/fasp/agent_aspera.rb +0 -126
- data/lib/aspera/fasp/agent_base.rb +0 -48
- data/lib/aspera/fasp/agent_trsdk.rb +0 -146
- data/lib/aspera/fasp/resume_policy.rb +0 -77
- data/lib/aspera/node.rb +0 -338
- data/lib/aspera/sync.rb +0 -219
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
# cspell:ignore snid fnid bidi ssync asyncs rund asnodeadmin mkfile mklink asperabrowser asperabrowserurl watchfolders watchfolderd entsrv
|
|
4
4
|
require 'aspera/cli/basic_auth_plugin'
|
|
5
5
|
require 'aspera/cli/sync_actions'
|
|
6
|
-
require 'aspera/
|
|
6
|
+
require 'aspera/transfer/spec'
|
|
7
7
|
require 'aspera/nagios'
|
|
8
8
|
require 'aspera/hash_ext'
|
|
9
9
|
require 'aspera/id_generator'
|
|
10
|
-
require 'aspera/node'
|
|
11
|
-
require 'aspera/aoc'
|
|
12
|
-
require 'aspera/sync'
|
|
10
|
+
require 'aspera/api/node'
|
|
11
|
+
require 'aspera/api/aoc'
|
|
13
12
|
require 'aspera/oauth'
|
|
13
|
+
require 'aspera/node_simulator'
|
|
14
|
+
require 'aspera/assert'
|
|
14
15
|
require 'base64'
|
|
15
16
|
require 'zlib'
|
|
16
17
|
|
|
17
18
|
module Aspera
|
|
18
19
|
module Cli
|
|
19
20
|
module Plugins
|
|
20
|
-
class Node <
|
|
21
|
+
class Node < Cli::BasicAuthPlugin
|
|
21
22
|
include SyncActions
|
|
22
23
|
class << self
|
|
23
|
-
@@node_options_declared = false # rubocop:disable Style/ClassVars
|
|
24
24
|
def application_name
|
|
25
25
|
'HSTS Node API'
|
|
26
26
|
end
|
|
@@ -35,7 +35,7 @@ module Aspera
|
|
|
35
35
|
"http://#{address_or_url}:9091"
|
|
36
36
|
]
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
error = nil
|
|
39
39
|
urls.each do |base_url|
|
|
40
40
|
next unless base_url.match?('https?://')
|
|
41
41
|
api = Rest.new(base_url: base_url)
|
|
@@ -47,8 +47,10 @@ module Aspera
|
|
|
47
47
|
url: result[:http].uri.to_s[0..url_length]
|
|
48
48
|
}
|
|
49
49
|
rescue StandardError => e
|
|
50
|
+
error = e
|
|
50
51
|
Log.log.debug{"detect error: #{e}"}
|
|
51
52
|
end
|
|
53
|
+
raise error if error
|
|
52
54
|
return nil
|
|
53
55
|
end
|
|
54
56
|
|
|
@@ -64,15 +66,13 @@ module Aspera
|
|
|
64
66
|
}
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
def declare_options(options
|
|
68
|
-
return if @@node_options_declared && !force
|
|
69
|
-
@@node_options_declared = true # rubocop:disable Style/ClassVars
|
|
69
|
+
def declare_options(options)
|
|
70
70
|
options.declare(:validator, 'Identifier of validator (optional for central)')
|
|
71
71
|
options.declare(:asperabrowserurl, 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net')
|
|
72
72
|
options.declare(:sync_name, 'Sync name')
|
|
73
73
|
options.declare(
|
|
74
74
|
:default_ports, 'Use standard FASP ports or get from node api (gen4)', values: :bool, default: :yes,
|
|
75
|
-
handler: {o:
|
|
75
|
+
handler: {o: Api::Node, m: :use_standard_ports})
|
|
76
76
|
options.declare(:root_id, 'File id of top folder if using bearer tokens')
|
|
77
77
|
SyncActions.declare_options(options)
|
|
78
78
|
options.parse_options!
|
|
@@ -116,28 +116,29 @@ module Aspera
|
|
|
116
116
|
COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
|
|
117
117
|
COMMANDS_FASPEX = COMMON_ACTIONS
|
|
118
118
|
|
|
119
|
-
def initialize(
|
|
120
|
-
super(env)
|
|
121
|
-
Node.declare_options(options
|
|
119
|
+
def initialize(api: nil, **env)
|
|
120
|
+
super(**env, basic_options: api.nil?)
|
|
121
|
+
Node.declare_options(options) if api.nil?
|
|
122
|
+
return if only_manual
|
|
122
123
|
@api_node =
|
|
123
|
-
if !api.nil?
|
|
124
|
-
# this can be
|
|
124
|
+
if !api.nil?
|
|
125
|
+
# this can be Api::Node or Rest (shares)
|
|
125
126
|
api
|
|
126
|
-
elsif
|
|
127
|
+
elsif OAuth::Factory.bearer?(options.get_option(:password, mandatory: true))
|
|
127
128
|
# info is provided like node_info of aoc
|
|
128
|
-
|
|
129
|
+
Api::Node.new(
|
|
129
130
|
base_url: options.get_option(:url, mandatory: true),
|
|
130
|
-
headers:
|
|
131
|
-
|
|
131
|
+
headers: Api::Node.bearer_headers(options.get_option(:password, mandatory: true))
|
|
132
|
+
)
|
|
132
133
|
else
|
|
133
134
|
# this is normal case
|
|
134
|
-
|
|
135
|
+
Api::Node.new(
|
|
135
136
|
base_url: options.get_option(:url, mandatory: true),
|
|
136
137
|
auth: {
|
|
137
138
|
type: :basic,
|
|
138
139
|
username: options.get_option(:username, mandatory: true),
|
|
139
140
|
password: options.get_option(:password, mandatory: true)
|
|
140
|
-
}
|
|
141
|
+
})
|
|
141
142
|
end
|
|
142
143
|
end
|
|
143
144
|
|
|
@@ -165,7 +166,7 @@ module Aspera
|
|
|
165
166
|
result = success_msg
|
|
166
167
|
if p.key?('error')
|
|
167
168
|
Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
|
|
168
|
-
result =
|
|
169
|
+
result = "ERROR: #{p['error']['user_message']}"
|
|
169
170
|
errors.push([p['path'], p['error']['user_message']])
|
|
170
171
|
end
|
|
171
172
|
final_result[:data].push({type => p['path'], 'result' => result})
|
|
@@ -191,7 +192,7 @@ module Aspera
|
|
|
191
192
|
case command
|
|
192
193
|
when :delete
|
|
193
194
|
paths_to_delete = get_next_arg_add_prefix(prefix_path, 'file list', :multiple)
|
|
194
|
-
resp = @api_node.create('files/delete', { paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i :
|
|
195
|
+
resp = @api_node.create('files/delete', { paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i : "/#{i}"} }})
|
|
195
196
|
return c_result_translate_rem_prefix(resp, 'file', 'deleted', prefix_path)
|
|
196
197
|
when :search
|
|
197
198
|
search_root = get_next_arg_add_prefix(prefix_path, 'search root')
|
|
@@ -283,7 +284,7 @@ module Aspera
|
|
|
283
284
|
request_transfer_spec[:paths] = if command.eql?(:download)
|
|
284
285
|
transfer.ts_source_paths
|
|
285
286
|
else
|
|
286
|
-
[{ destination: transfer.destination_folder(
|
|
287
|
+
[{ destination: transfer.destination_folder(Transfer::Spec::DIRECTION_SEND) }]
|
|
287
288
|
end
|
|
288
289
|
# add fixed parameters if any (for COS)
|
|
289
290
|
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
|
@@ -300,10 +301,10 @@ module Aspera
|
|
|
300
301
|
@api_node.call(
|
|
301
302
|
operation: 'GET',
|
|
302
303
|
subpath: "files/#{URI.encode_www_form_component(remote_path)}/contents",
|
|
303
|
-
save_to_file: File.join(transfer.destination_folder(
|
|
304
|
+
save_to_file: File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_name))
|
|
304
305
|
return Main.result_status("downloaded: #{file_name}")
|
|
305
306
|
end
|
|
306
|
-
|
|
307
|
+
Aspera.error_unreachable_line
|
|
307
308
|
end
|
|
308
309
|
|
|
309
310
|
# common API to node and Shares
|
|
@@ -327,8 +328,8 @@ module Aspera
|
|
|
327
328
|
ak_info = @api_node.read("access_keys/#{access_key_id}")[:data]
|
|
328
329
|
# change API credentials if different access key
|
|
329
330
|
if !access_key_id.eql?('self')
|
|
330
|
-
@api_node.
|
|
331
|
-
@api_node.
|
|
331
|
+
@api_node.auth_params[:username] = ak_info['id']
|
|
332
|
+
@api_node.auth_params[:password] = config.lookup_secret(url: @api_node.base_url, username: ak_info['id'], mandatory: true)
|
|
332
333
|
end
|
|
333
334
|
root_file_id = ak_info['root_file_id']
|
|
334
335
|
end
|
|
@@ -380,9 +381,9 @@ module Aspera
|
|
|
380
381
|
if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
|
381
382
|
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
|
|
382
383
|
end
|
|
383
|
-
return {
|
|
384
|
+
return {type: :single_object, data: node_license}
|
|
384
385
|
when :api_details
|
|
385
|
-
return {
|
|
386
|
+
return {type: :single_object, data: {base_url: @api_node.base_url}.merge(@api_node.params)}
|
|
386
387
|
end
|
|
387
388
|
end
|
|
388
389
|
|
|
@@ -405,26 +406,26 @@ module Aspera
|
|
|
405
406
|
command_legacy = options.get_next_command(V3_IN_V4_ACTIONS)
|
|
406
407
|
# TODO: shall we support all methods here ? what if there is a link ?
|
|
407
408
|
apifid = @api_node.resolve_api_fid(top_file_id, '')
|
|
408
|
-
return Node.new(
|
|
409
|
+
return Node.new(**init_params, api: apifid[:api]).execute_action(command_legacy)
|
|
409
410
|
when :node_info, :bearer_token_node
|
|
410
411
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
|
411
412
|
result = {
|
|
412
|
-
url: apifid[:api].
|
|
413
|
+
url: apifid[:api].base_url,
|
|
413
414
|
root_id: apifid[:file_id]
|
|
414
415
|
}
|
|
415
|
-
|
|
416
|
-
case apifid[:api].
|
|
416
|
+
Aspera.assert_values(apifid[:api].auth_params[:type], %i[basic oauth2])
|
|
417
|
+
case apifid[:api].auth_params[:type]
|
|
417
418
|
when :basic
|
|
418
|
-
result[:username] = apifid[:api].
|
|
419
|
-
result[:password] = apifid[:api].
|
|
419
|
+
result[:username] = apifid[:api].auth_params[:username]
|
|
420
|
+
result[:password] = apifid[:api].auth_params[:password]
|
|
420
421
|
when :oauth2
|
|
421
|
-
result[:username] = apifid[:api].params[:headers][
|
|
422
|
+
result[:username] = apifid[:api].params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
|
|
422
423
|
result[:password] = apifid[:api].oauth_token
|
|
423
|
-
else
|
|
424
|
+
else Aspera.error_unreachable_line
|
|
424
425
|
end
|
|
425
426
|
return {type: :single_object, data: result} if command_repo.eql?(:node_info)
|
|
426
427
|
# check format of bearer token
|
|
427
|
-
|
|
428
|
+
OAuth::Factory.bearer_extract(result[:password])
|
|
428
429
|
return Main.result_status(result[:password])
|
|
429
430
|
when :browse
|
|
430
431
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
|
@@ -439,12 +440,12 @@ module Aspera
|
|
|
439
440
|
return {type: :object_list, data: items, fields: %w[name type recursive_size size modified_time access_level]}
|
|
440
441
|
when :find
|
|
441
442
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
|
442
|
-
test_block =
|
|
443
|
+
test_block = Api::Node.file_matcher_from_argument(options)
|
|
443
444
|
return {type: :object_list, data: @api_node.find_files(apifid[:file_id], test_block), fields: ['path']}
|
|
444
445
|
when :mkdir
|
|
445
|
-
containing_folder_path = options.get_next_argument('path').split(
|
|
446
|
+
containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
|
|
446
447
|
new_folder = containing_folder_path.pop
|
|
447
|
-
apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(
|
|
448
|
+
apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Api::Node::PATH_SEPARATOR))
|
|
448
449
|
result = apifid[:api].create("files/#{apifid[:file_id]}/files", {name: new_folder, type: :folder})[:data]
|
|
449
450
|
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
|
450
451
|
when :rename
|
|
@@ -463,10 +464,11 @@ module Aspera
|
|
|
463
464
|
return execute_sync_action do |sync_direction, _local_path, remote_path|
|
|
464
465
|
# Gen4 API
|
|
465
466
|
# direction is push pull, bidi
|
|
467
|
+
Aspera.assert_values(sync_direction, %i[push pull bidi])
|
|
466
468
|
ts_direction = case sync_direction
|
|
467
|
-
when :push, :bidi then
|
|
468
|
-
when :pull then
|
|
469
|
-
else
|
|
469
|
+
when :push, :bidi then Transfer::Spec::DIRECTION_SEND
|
|
470
|
+
when :pull then Transfer::Spec::DIRECTION_RECEIVE
|
|
471
|
+
else Aspera.error_unreachable_line
|
|
470
472
|
end
|
|
471
473
|
# remote is specified by option to_folder
|
|
472
474
|
apifid = @api_node.resolve_api_fid(top_file_id, remote_path)
|
|
@@ -475,8 +477,8 @@ module Aspera
|
|
|
475
477
|
transfer_spec
|
|
476
478
|
end
|
|
477
479
|
when :upload
|
|
478
|
-
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(
|
|
479
|
-
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id],
|
|
480
|
+
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND))
|
|
481
|
+
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_SEND)))
|
|
480
482
|
when :download
|
|
481
483
|
source_paths = transfer.ts_source_paths
|
|
482
484
|
# special case for AoC : all files must be in same folder
|
|
@@ -488,11 +490,11 @@ module Aspera
|
|
|
488
490
|
case file_info['type']
|
|
489
491
|
when 'file'
|
|
490
492
|
# if the single source is a file, we need to split into folder path and filename
|
|
491
|
-
src_dir_elements = source_folder.split(
|
|
493
|
+
src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
|
|
492
494
|
# filename is the last one
|
|
493
495
|
source_paths = [{'source' => src_dir_elements.pop}]
|
|
494
496
|
# source folder is what remains
|
|
495
|
-
source_folder = src_dir_elements.join(
|
|
497
|
+
source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
|
|
496
498
|
# TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
|
|
497
499
|
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
|
498
500
|
when 'link', 'folder'
|
|
@@ -503,14 +505,14 @@ module Aspera
|
|
|
503
505
|
raise "Unknown source type: #{file_info['type']}"
|
|
504
506
|
end
|
|
505
507
|
end
|
|
506
|
-
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id],
|
|
508
|
+
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
|
|
507
509
|
when :http_node_download
|
|
508
510
|
source_paths = transfer.ts_source_paths
|
|
509
511
|
source_folder = source_paths.shift['source']
|
|
510
512
|
if source_paths.empty?
|
|
511
|
-
source_folder = source_folder.split(
|
|
513
|
+
source_folder = source_folder.split(Api::Node::PATH_SEPARATOR)
|
|
512
514
|
source_paths = [{'source' => source_folder.pop}]
|
|
513
|
-
source_folder = source_folder.join(
|
|
515
|
+
source_folder = source_folder.join(Api::Node::PATH_SEPARATOR)
|
|
514
516
|
end
|
|
515
517
|
raise Cli::BadArgument, 'one file at a time only in HTTP mode' if source_paths.length > 1
|
|
516
518
|
file_name = source_paths.first['source']
|
|
@@ -518,7 +520,7 @@ module Aspera
|
|
|
518
520
|
apifid[:api].call(
|
|
519
521
|
operation: 'GET',
|
|
520
522
|
subpath: "files/#{apifid[:file_id]}/content",
|
|
521
|
-
save_to_file: File.join(transfer.destination_folder(
|
|
523
|
+
save_to_file: File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_name))
|
|
522
524
|
return Main.result_status("downloaded: #{file_name}")
|
|
523
525
|
when :show
|
|
524
526
|
apifid = apifid_from_next_arg(top_file_id)
|
|
@@ -536,12 +538,7 @@ module Aspera
|
|
|
536
538
|
subpath: "files/#{apifid[:file_id]}/preview",
|
|
537
539
|
headers: {'Accept' => 'image/png'}
|
|
538
540
|
)
|
|
539
|
-
|
|
540
|
-
terminal_options = options.get_option(:query, default: {}).symbolize_keys
|
|
541
|
-
allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
|
|
542
|
-
unknown_options = terminal_options.keys - allowed_options
|
|
543
|
-
raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
|
|
544
|
-
return Main.result_status(Preview::Terminal.build(result[:http].body, **terminal_options))
|
|
541
|
+
return Main.result_picture_in_terminal(options, result[:http].body)
|
|
545
542
|
when :permission
|
|
546
543
|
apifid = apifid_from_next_arg(top_file_id)
|
|
547
544
|
command_perm = options.get_next_command(%i[list create delete])
|
|
@@ -565,7 +562,7 @@ module Aspera
|
|
|
565
562
|
create_param = options.get_next_argument('creation data', type: Hash)
|
|
566
563
|
raise 'no file_id' if create_param.key?('file_id')
|
|
567
564
|
create_param['file_id'] = apifid[:file_id]
|
|
568
|
-
create_param['access_levels'] =
|
|
565
|
+
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
|
569
566
|
# add application specific tags (AoC)
|
|
570
567
|
the_app = apifid[:api].app_info
|
|
571
568
|
the_app[:api].permissions_set_create_params(create_param: create_param, app_info: the_app) unless the_app.nil?
|
|
@@ -574,11 +571,11 @@ module Aspera
|
|
|
574
571
|
# notify application of creation
|
|
575
572
|
the_app[:api].permissions_send_event(created_data: created_data, app_info: the_app) unless the_app.nil?
|
|
576
573
|
return { type: :single_object, data: created_data}
|
|
577
|
-
else
|
|
574
|
+
else Aspera.error_unreachable_line
|
|
578
575
|
end
|
|
579
|
-
else
|
|
576
|
+
else Aspera.error_unreachable_line
|
|
580
577
|
end # command_repo
|
|
581
|
-
|
|
578
|
+
Aspera.error_unreachable_line
|
|
582
579
|
end # execute_command_gen4
|
|
583
580
|
|
|
584
581
|
# This is older API
|
|
@@ -637,7 +634,7 @@ module Aspera
|
|
|
637
634
|
skip_ids_persistency = nil
|
|
638
635
|
if options.get_option(:once_only, mandatory: true)
|
|
639
636
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
640
|
-
manager:
|
|
637
|
+
manager: persistency,
|
|
641
638
|
data: iteration_data,
|
|
642
639
|
id: IdGenerator.from_list([
|
|
643
640
|
'sync_files',
|
|
@@ -683,7 +680,8 @@ module Aspera
|
|
|
683
680
|
central
|
|
684
681
|
asperabrowser
|
|
685
682
|
basic_token
|
|
686
|
-
bearer_token
|
|
683
|
+
bearer_token
|
|
684
|
+
simulator].concat(COMMON_ACTIONS).freeze
|
|
687
685
|
|
|
688
686
|
def execute_action(command=nil, prefix_path=nil)
|
|
689
687
|
command ||= options.get_next_command(ACTIONS)
|
|
@@ -783,7 +781,7 @@ module Aspera
|
|
|
783
781
|
# do not process last one
|
|
784
782
|
break if end_date.nil?
|
|
785
783
|
# init data for this period
|
|
786
|
-
period_bandwidth =
|
|
784
|
+
period_bandwidth = Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).each_with_object({}) do |direction, h|
|
|
787
785
|
h[direction] = dir_info.each_with_object({}) do |k2, h2|
|
|
788
786
|
h2[k2] = 0
|
|
789
787
|
end
|
|
@@ -801,7 +799,7 @@ module Aspera
|
|
|
801
799
|
info[:sessions] += 1
|
|
802
800
|
# end
|
|
803
801
|
end
|
|
804
|
-
next if
|
|
802
|
+
next if Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).all? do |dir|
|
|
805
803
|
period_bandwidth[dir][:sessions].zero?
|
|
806
804
|
end
|
|
807
805
|
result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
|
|
@@ -897,7 +895,7 @@ module Aspera
|
|
|
897
895
|
}
|
|
898
896
|
# encode parameters so that it looks good in url
|
|
899
897
|
encoded_params = Base64.strict_encode64(Zlib::Deflate.deflate(JSON.generate(browse_params))).gsub(/=+$/, '').tr('+/', '-_').reverse
|
|
900
|
-
OpenApplication.instance.uri(options.get_option(:asperabrowserurl)
|
|
898
|
+
OpenApplication.instance.uri("#{options.get_option(:asperabrowserurl)}?goto=#{encoded_params}")
|
|
901
899
|
return Main.result_status('done')
|
|
902
900
|
when :basic_token
|
|
903
901
|
return Main.result_status(Rest.basic_token(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
|
|
@@ -905,11 +903,21 @@ module Aspera
|
|
|
905
903
|
private_key = OpenSSL::PKey::RSA.new(options.get_next_argument('private RSA key PEM value', type: String))
|
|
906
904
|
token_info = options.get_next_argument('user and group identification', type: Hash)
|
|
907
905
|
access_key = options.get_option(:username, mandatory: true)
|
|
908
|
-
return Main.result_status(
|
|
906
|
+
return Main.result_status(Api::Node.bearer_token(payload: token_info, access_key: access_key, private_key: private_key))
|
|
907
|
+
when :simulator
|
|
908
|
+
require 'aspera/node_simulator'
|
|
909
|
+
parameters = value_create_modify(command: command)
|
|
910
|
+
parameters = parameters.symbolize_keys
|
|
911
|
+
raise 'Missing key: url' unless parameters.key?(:url)
|
|
912
|
+
uri = URI.parse(parameters[:url])
|
|
913
|
+
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
|
914
|
+
server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], transfer)
|
|
915
|
+
server.start
|
|
916
|
+
return Main.result_status('Simulator terminated')
|
|
909
917
|
end # case command
|
|
910
918
|
raise 'ERROR: shall not reach this line'
|
|
911
|
-
end
|
|
912
|
-
end
|
|
913
|
-
end
|
|
914
|
-
end
|
|
915
|
-
end
|
|
919
|
+
end
|
|
920
|
+
end
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
end
|
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
require 'aspera/cli/basic_auth_plugin'
|
|
4
4
|
require 'aspera/nagios'
|
|
5
|
+
require 'aspera/log'
|
|
6
|
+
require 'aspera/assert'
|
|
5
7
|
require 'xmlsimple'
|
|
6
8
|
|
|
7
9
|
module Aspera
|
|
8
10
|
module Cli
|
|
9
11
|
module Plugins
|
|
10
|
-
class Orchestrator <
|
|
12
|
+
class Orchestrator < Cli::BasicAuthPlugin
|
|
11
13
|
class << self
|
|
12
14
|
STANDARD_PATH = '/aspera/orchestrator'
|
|
13
15
|
def detect(address_or_url)
|
|
14
16
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
15
17
|
urls = [address_or_url]
|
|
16
18
|
urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
|
|
19
|
+
error = nil
|
|
17
20
|
urls.each do |base_url|
|
|
18
21
|
next unless base_url.match?('https?://')
|
|
19
22
|
api = Rest.new(base_url: base_url)
|
|
@@ -26,8 +29,10 @@ module Aspera
|
|
|
26
29
|
url: url[0..url.index(test_endpoint) - 2]
|
|
27
30
|
}
|
|
28
31
|
rescue StandardError => e
|
|
32
|
+
error = e
|
|
29
33
|
Log.log.debug{"detect error: #{e}"}
|
|
30
34
|
end
|
|
35
|
+
raise error if error
|
|
31
36
|
return nil
|
|
32
37
|
end
|
|
33
38
|
|
|
@@ -44,8 +49,8 @@ module Aspera
|
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
|
|
47
|
-
def initialize(env)
|
|
48
|
-
super
|
|
52
|
+
def initialize(**env)
|
|
53
|
+
super
|
|
49
54
|
options.declare(:result, "Specify result value as: 'work_step:parameter'")
|
|
50
55
|
options.declare(:synchronous, 'Wait for completion', values: :bool, default: :no)
|
|
51
56
|
options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
|
|
@@ -55,24 +60,6 @@ module Aspera
|
|
|
55
60
|
|
|
56
61
|
ACTIONS = %i[health info workflow plugins processes].freeze
|
|
57
62
|
|
|
58
|
-
# for JSON format: add extension ".json" or add url parameter: format=json or Accept: application/json
|
|
59
|
-
# id can be: a parameter id=x, or at the end of url /id, for workflows: work_order[workflow_id]=wf_id
|
|
60
|
-
# def call_API_orig(endpoint,id=nil,url_params={format: :json},accept=nil)
|
|
61
|
-
# # calls are GET
|
|
62
|
-
# call_args={operation: 'GET',subpath: endpoint}
|
|
63
|
-
# # specify id if necessary
|
|
64
|
-
# call_args[:subpath]=call_args[:subpath]+'/'+id unless id.nil?
|
|
65
|
-
# unless url_params.nil?
|
|
66
|
-
# if url_params.has_key?(:format)
|
|
67
|
-
# call_args[:headers]={'Accept'=>'application/'+url_params[:format].to_s}
|
|
68
|
-
# end
|
|
69
|
-
# call_args[:headers]={'Accept'=>accept} unless accept.nil?
|
|
70
|
-
# # add params if necessary
|
|
71
|
-
# call_args[:url_params]=url_params
|
|
72
|
-
# end
|
|
73
|
-
# return @api_orch.call(call_args)
|
|
74
|
-
# end
|
|
75
|
-
|
|
76
63
|
def call_ao(endpoint, opt={})
|
|
77
64
|
opt[:prefix] = 'api' unless opt.key?(:prefix)
|
|
78
65
|
# calls are GET
|
|
@@ -89,40 +76,45 @@ module Aspera
|
|
|
89
76
|
unless format.nil?
|
|
90
77
|
case call_type
|
|
91
78
|
when :header
|
|
92
|
-
call_args[:headers] = {'Accept' =>
|
|
79
|
+
call_args[:headers] = {'Accept' => "application/#{format}" }
|
|
93
80
|
when :arg
|
|
94
81
|
call_args[:url_params] ||= {}
|
|
95
82
|
call_args[:url_params][:format] = format
|
|
96
83
|
when :ext
|
|
97
84
|
call_args[:subpath] = "#{call_args[:subpath]}.#{format}"
|
|
98
|
-
else
|
|
85
|
+
else Aspera.error_unexpected_value(call_type)
|
|
99
86
|
end
|
|
100
87
|
end
|
|
101
|
-
result = @api_orch.call(call_args)
|
|
88
|
+
result = @api_orch.call(**call_args)
|
|
102
89
|
result[:data] = XmlSimple.xml_in(result[:http].body, opt[:xml_opt] || {'ForceArray' => true}) if format.eql?('xml')
|
|
103
90
|
Log.log.debug{Log.dump(:data, result[:data])}
|
|
104
91
|
return result
|
|
105
92
|
end
|
|
106
93
|
|
|
107
94
|
def execute_action
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
95
|
+
auth_params =
|
|
96
|
+
case options.get_option(:auth_style, mandatory: true)
|
|
97
|
+
when :arg_pass
|
|
98
|
+
{
|
|
99
|
+
type: :url,
|
|
100
|
+
url_query: {
|
|
101
|
+
'login' => options.get_option(:username, mandatory: true),
|
|
102
|
+
'password' => options.get_option(:password, mandatory: true) }
|
|
103
|
+
}
|
|
104
|
+
when :head_basic
|
|
105
|
+
{
|
|
106
|
+
type: :basic,
|
|
107
|
+
username: options.get_option(:username, mandatory: true),
|
|
108
|
+
password: options.get_option(:password, mandatory: true)
|
|
109
|
+
}
|
|
110
|
+
when :apikey
|
|
111
|
+
raise 'Not implemented'
|
|
112
|
+
end
|
|
124
113
|
|
|
125
|
-
@api_orch = Rest.new(
|
|
114
|
+
@api_orch = Rest.new(
|
|
115
|
+
base_url: options.get_option(:url, mandatory: true),
|
|
116
|
+
auth: auth_params
|
|
117
|
+
)
|
|
126
118
|
|
|
127
119
|
command1 = options.get_next_command(ACTIONS)
|
|
128
120
|
case command1
|
|
@@ -140,11 +132,11 @@ module Aspera
|
|
|
140
132
|
result = call_ao('remote_node_ping', format: 'xml', xml_opt: {'ForceArray' => false})[:data]
|
|
141
133
|
return {type: :single_object, data: result}
|
|
142
134
|
when :processes
|
|
143
|
-
# TODO:
|
|
135
|
+
# TODO: Bug ? API has only XML format
|
|
144
136
|
result = call_ao('processes_status', format: 'xml')[:data]
|
|
145
137
|
return {type: :object_list, data: result['process']}
|
|
146
138
|
when :plugins
|
|
147
|
-
# TODO:
|
|
139
|
+
# TODO: Bug ? only json format on url
|
|
148
140
|
result = call_ao('plugin_version')[:data]
|
|
149
141
|
return {type: :object_list, data: result['Plugin']}
|
|
150
142
|
when :workflow
|
|
@@ -205,7 +197,7 @@ module Aspera
|
|
|
205
197
|
result[:data] = call_ao('initiate', id: wf_id, args: call_params, accept: override_accept)[:data]
|
|
206
198
|
return result
|
|
207
199
|
end # wf command
|
|
208
|
-
else
|
|
200
|
+
else Aspera.error_unexpected_value(command)
|
|
209
201
|
end # case command
|
|
210
202
|
end # execute_action
|
|
211
203
|
end # Orchestrator
|