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
|
@@ -7,18 +7,20 @@ require 'aspera/preview/options'
|
|
|
7
7
|
require 'aspera/preview/utils'
|
|
8
8
|
require 'aspera/preview/file_types'
|
|
9
9
|
require 'aspera/preview/terminal'
|
|
10
|
-
require 'aspera/
|
|
10
|
+
require 'aspera/transfer/spec'
|
|
11
11
|
require 'aspera/persistency_action_once'
|
|
12
|
-
require 'aspera/node'
|
|
12
|
+
require 'aspera/api/node'
|
|
13
13
|
require 'aspera/hash_ext'
|
|
14
14
|
require 'aspera/timer_limiter'
|
|
15
15
|
require 'aspera/id_generator'
|
|
16
|
+
require 'aspera/log'
|
|
17
|
+
require 'aspera/assert'
|
|
16
18
|
require 'securerandom'
|
|
17
19
|
|
|
18
20
|
module Aspera
|
|
19
21
|
module Cli
|
|
20
22
|
module Plugins
|
|
21
|
-
class Preview <
|
|
23
|
+
class Preview < Cli::BasicAuthPlugin
|
|
22
24
|
# special tag to identify transfers related to generator
|
|
23
25
|
PREV_GEN_TAG = 'preview_generator'
|
|
24
26
|
# defined by node API: suffix for folder containing previews
|
|
@@ -47,8 +49,8 @@ module Aspera
|
|
|
47
49
|
attr_accessor :option_previews_folder
|
|
48
50
|
attr_accessor :option_folder_reset_cache, :option_skip_folders, :option_overwrite, :option_file_access
|
|
49
51
|
|
|
50
|
-
def initialize(env)
|
|
51
|
-
super
|
|
52
|
+
def initialize(**env)
|
|
53
|
+
super
|
|
52
54
|
@skip_types = []
|
|
53
55
|
@default_transfer_spec = nil
|
|
54
56
|
# by default generate all supported formats (clone, as altered by options)
|
|
@@ -94,7 +96,7 @@ module Aspera
|
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
options.parse_options!
|
|
97
|
-
|
|
99
|
+
Aspera.assert_type(@option_skip_folders, Array){'skip_folder'}
|
|
98
100
|
@tmp_folder = File.join(options.get_option(:temp_folder, mandatory: true), "#{TMP_DIR_PREFIX}.#{SecureRandom.uuid}")
|
|
99
101
|
FileUtils.mkdir_p(@tmp_folder)
|
|
100
102
|
Log.log.debug{"tmpdir: #{@tmp_folder}"}
|
|
@@ -104,7 +106,7 @@ module Aspera
|
|
|
104
106
|
@skip_types = []
|
|
105
107
|
value.split(',').each do |v|
|
|
106
108
|
s = v.to_sym
|
|
107
|
-
|
|
109
|
+
Aspera.assert_values(s, Aspera::Preview::FileTypes::CONVERSION_TYPES){'skip_types'}
|
|
108
110
|
@skip_types.push(s)
|
|
109
111
|
end
|
|
110
112
|
end
|
|
@@ -126,7 +128,7 @@ module Aspera
|
|
|
126
128
|
def get_folder_entries(file_id, request_args=nil)
|
|
127
129
|
headers = {'Accept' => 'application/json'}
|
|
128
130
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
|
129
|
-
return @api_node.call(
|
|
131
|
+
return @api_node.call(operation: 'GET', subpath: "files/#{file_id}/files", headers: headers, url_params: request_args)[:data]
|
|
130
132
|
# return @api_node.read("files/#{file_id}/files",request_args)[:data]
|
|
131
133
|
end
|
|
132
134
|
|
|
@@ -151,11 +153,11 @@ module Aspera
|
|
|
151
153
|
end
|
|
152
154
|
return if events.empty?
|
|
153
155
|
events.each do |event|
|
|
154
|
-
if event['data']['direction'].eql?(
|
|
156
|
+
if event['data']['direction'].eql?(Transfer::Spec::DIRECTION_RECEIVE) &&
|
|
155
157
|
event['data']['status'].eql?('completed') &&
|
|
156
158
|
event['data']['error_code'].eql?(0) &&
|
|
157
|
-
event['data'].dig('tags',
|
|
158
|
-
folder_id = event.dig('data', 'tags',
|
|
159
|
+
event['data'].dig('tags', Transfer::Spec::TAG_RESERVED, PREV_GEN_TAG).nil?
|
|
160
|
+
folder_id = event.dig('data', 'tags', Transfer::Spec::TAG_RESERVED, 'node', 'file_id')
|
|
159
161
|
folder_id ||= event.dig('data', 'file_id')
|
|
160
162
|
if !folder_id.nil?
|
|
161
163
|
folder_entry = @api_node.read("files/#{folder_id}")[:data] rescue nil
|
|
@@ -189,7 +191,7 @@ module Aspera
|
|
|
189
191
|
if event.dig('data', 'type').eql?('file')
|
|
190
192
|
file_entry = @api_node.read("files/#{event['data']['id']}")[:data] rescue nil
|
|
191
193
|
if !file_entry.nil? &&
|
|
192
|
-
@option_skip_folders.
|
|
194
|
+
@option_skip_folders.none?{|d|file_entry['path'].start_with?(d)}
|
|
193
195
|
file_entry['parent_file_id'] = event['data']['parent_file_id']
|
|
194
196
|
if event['types'].include?('file.deleted')
|
|
195
197
|
Log.log.error('TODO'.red)
|
|
@@ -211,10 +213,10 @@ module Aspera
|
|
|
211
213
|
end
|
|
212
214
|
|
|
213
215
|
def do_transfer(direction, folder_id, source_filename, destination='/')
|
|
214
|
-
|
|
216
|
+
Aspera.assert(!(destination.nil? && direction.eql?(Transfer::Spec::DIRECTION_RECEIVE)))
|
|
215
217
|
t_spec = @api_node.transfer_spec_gen4(folder_id, direction, {
|
|
216
218
|
'paths' => [{'source' => source_filename}],
|
|
217
|
-
'tags' => {
|
|
219
|
+
'tags' => {Transfer::Spec::TAG_RESERVED => {PREV_GEN_TAG => true}}
|
|
218
220
|
})
|
|
219
221
|
# force destination, need to set this in transfer agent else it gets overwritten, not do: t_spec['destination_root']=destination
|
|
220
222
|
transfer.option_transfer_spec_deep_merge({'destination_root' => destination})
|
|
@@ -316,7 +318,7 @@ module Aspera
|
|
|
316
318
|
if @access_remote
|
|
317
319
|
raise 'missing parent_file_id in entry' if entry['parent_file_id'].nil?
|
|
318
320
|
# download original file to temp folder
|
|
319
|
-
do_transfer(
|
|
321
|
+
do_transfer(Transfer::Spec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
|
|
320
322
|
end
|
|
321
323
|
Log.log.info{"source: #{entry['id']}: #{entry['path']}"}
|
|
322
324
|
gen_infos.each do |gen_info|
|
|
@@ -324,7 +326,7 @@ module Aspera
|
|
|
324
326
|
end
|
|
325
327
|
if @access_remote
|
|
326
328
|
# upload
|
|
327
|
-
do_transfer(
|
|
329
|
+
do_transfer(Transfer::Spec::DIRECTION_SEND, @previews_folder_entry['id'], local_entry_preview_dir)
|
|
328
330
|
# cleanup after upload
|
|
329
331
|
FileUtils.rm_rf(local_entry_preview_dir)
|
|
330
332
|
File.delete(File.join(@tmp_folder, entry['name']))
|
|
@@ -401,8 +403,8 @@ module Aspera
|
|
|
401
403
|
command = options.get_next_command(ACTIONS)
|
|
402
404
|
unless %i[check test show].include?(command)
|
|
403
405
|
# this will use node api
|
|
404
|
-
@api_node =
|
|
405
|
-
@transfer_server_address = URI.parse(@api_node.
|
|
406
|
+
@api_node = Api::Node.new(**basic_auth_params)
|
|
407
|
+
@transfer_server_address = URI.parse(@api_node.base_url).host
|
|
406
408
|
# get current access key
|
|
407
409
|
@access_key_self = @api_node.read('access_keys/self')[:data]
|
|
408
410
|
# TODO: check events is activated here:
|
|
@@ -420,13 +422,13 @@ module Aspera
|
|
|
420
422
|
raise Cli::Error, "Folder #{@option_previews_folder} does not exist on node. " \
|
|
421
423
|
'Please create it in the storage root, or specify an alternate name.' if @previews_folder_entry.nil?
|
|
422
424
|
else
|
|
423
|
-
|
|
425
|
+
Aspera.assert(@access_key_self['storage']['type'].eql?('local')){'only local storage allowed in this mode'}
|
|
424
426
|
@local_storage_root = @access_key_self['storage']['path']
|
|
425
427
|
# TODO: option to override @local_storage_root='xxx'
|
|
426
428
|
@local_storage_root = @local_storage_root[PVCL_LOCAL_STORAGE.length..-1] if @local_storage_root.start_with?(PVCL_LOCAL_STORAGE)
|
|
427
429
|
# TODO: windows could have "C:" ?
|
|
428
|
-
|
|
429
|
-
|
|
430
|
+
Aspera.assert(@local_storage_root.start_with?('/')){"not local storage: #{@local_storage_root}"}
|
|
431
|
+
Aspera.assert(File.directory?(@local_storage_root), exception_class: Cli::Error){"Local storage root folder #{@local_storage_root} does not exist."}
|
|
430
432
|
@local_preview_folder = File.join(@local_storage_root, @option_previews_folder)
|
|
431
433
|
raise Cli::Error, "Folder #{@local_preview_folder} does not exist locally. " \
|
|
432
434
|
'Please create it, or specify an alternate name.' unless File.directory?(@local_preview_folder)
|
|
@@ -435,7 +437,7 @@ module Aspera
|
|
|
435
437
|
Log.log.debug{"marker file: #{marker_file}"}
|
|
436
438
|
if File.exist?(marker_file)
|
|
437
439
|
ak = File.read(marker_file).chomp
|
|
438
|
-
|
|
440
|
+
Aspera.assert(@access_key_self['id'].eql?(ak)){"mismatch access key in #{marker_file}: contains #{ak}, using #{@access_key_self['id']}"}
|
|
439
441
|
else
|
|
440
442
|
File.write(marker_file, @access_key_self['id'])
|
|
441
443
|
end
|
|
@@ -459,15 +461,15 @@ module Aspera
|
|
|
459
461
|
else
|
|
460
462
|
@api_node.read("files/#{scan_id}")[:data]
|
|
461
463
|
end
|
|
462
|
-
@filter_block =
|
|
464
|
+
@filter_block = Api::Node.file_matcher_from_argument(options)
|
|
463
465
|
scan_folder_files(folder_info, scan_path)
|
|
464
466
|
return Main.result_status('scan finished')
|
|
465
467
|
when :events, :trevents
|
|
466
|
-
@filter_block =
|
|
468
|
+
@filter_block = Api::Node.file_matcher_from_argument(options)
|
|
467
469
|
iteration_persistency = nil
|
|
468
470
|
if options.get_option(:once_only, mandatory: true)
|
|
469
471
|
iteration_persistency = PersistencyActionOnce.new(
|
|
470
|
-
manager:
|
|
472
|
+
manager: persistency,
|
|
471
473
|
data: [],
|
|
472
474
|
id: IdGenerator.from_list([
|
|
473
475
|
'preview_iteration',
|
|
@@ -477,7 +479,7 @@ module Aspera
|
|
|
477
479
|
]))
|
|
478
480
|
end
|
|
479
481
|
# call processing method specified by command line command
|
|
480
|
-
send("process_#{command}", iteration_persistency)
|
|
482
|
+
send(:"process_#{command}", iteration_persistency)
|
|
481
483
|
return Main.result_status("#{command} finished")
|
|
482
484
|
when :check
|
|
483
485
|
return Main.result_status('Tools validated')
|
|
@@ -499,8 +501,8 @@ module Aspera
|
|
|
499
501
|
ensure
|
|
500
502
|
Log.log.debug{"cleaning up temp folder #{@tmp_folder}"}
|
|
501
503
|
FileUtils.rm_rf(@tmp_folder)
|
|
502
|
-
end
|
|
503
|
-
end
|
|
504
|
-
end
|
|
505
|
-
end
|
|
506
|
-
end
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
end
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
# cspell:ignore ascmd zmode zuid zgid fasping
|
|
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/ascmd'
|
|
8
8
|
require 'aspera/ssh'
|
|
9
9
|
require 'aspera/nagios'
|
|
10
|
+
require 'aspera/log'
|
|
11
|
+
require 'aspera/assert'
|
|
10
12
|
require 'tempfile'
|
|
11
13
|
require 'open3'
|
|
12
14
|
|
|
@@ -14,7 +16,7 @@ module Aspera
|
|
|
14
16
|
module Cli
|
|
15
17
|
module Plugins
|
|
16
18
|
# implement basic remote access with FASP/SSH
|
|
17
|
-
class Server <
|
|
19
|
+
class Server < Cli::BasicAuthPlugin
|
|
18
20
|
include SyncActions
|
|
19
21
|
SSH_SCHEME = 'ssh'
|
|
20
22
|
LOCAL_SCHEME = 'local'
|
|
@@ -51,27 +53,27 @@ module Aspera
|
|
|
51
53
|
[address_or_url]
|
|
52
54
|
else
|
|
53
55
|
[
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
+
"#{SSH_SCHEME}://#{address_or_url}:33001",
|
|
57
|
+
"#{SSH_SCHEME}://#{address_or_url}:22"
|
|
56
58
|
]
|
|
57
59
|
# wss not practical as it requires a token
|
|
58
60
|
end
|
|
59
|
-
|
|
61
|
+
error = nil
|
|
60
62
|
urls.each do |base_url|
|
|
61
63
|
server_uri = URI.parse(base_url)
|
|
62
64
|
Log.log.debug{"URI=#{server_uri}, host=#{server_uri.hostname}, port=#{server_uri.port}, scheme=#{server_uri.scheme}"}
|
|
63
65
|
next unless server_uri.scheme.eql?(SSH_SCHEME)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url}
|
|
70
|
-
end
|
|
71
|
-
rescue StandardError => e
|
|
72
|
-
Log.log.debug{"detect error: #{e}"}
|
|
66
|
+
socket = TCPSocket.new(server_uri.hostname, server_uri.port)
|
|
67
|
+
socket.puts('SSH-2.0-Ascli_0.0')
|
|
68
|
+
version = socket.gets.chomp
|
|
69
|
+
if version.match?(/^SSH-2.0-/)
|
|
70
|
+
return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url}
|
|
73
71
|
end
|
|
72
|
+
rescue StandardError => e
|
|
73
|
+
error = e
|
|
74
|
+
Log.log.debug{"detect error: #{e}"}
|
|
74
75
|
end
|
|
76
|
+
raise error if error
|
|
75
77
|
return nil
|
|
76
78
|
end
|
|
77
79
|
|
|
@@ -88,8 +90,8 @@ module Aspera
|
|
|
88
90
|
end
|
|
89
91
|
end
|
|
90
92
|
|
|
91
|
-
def initialize(env)
|
|
92
|
-
super
|
|
93
|
+
def initialize(**env)
|
|
94
|
+
super
|
|
93
95
|
options.declare(:ssh_keys, 'SSH key path list (Array or single)')
|
|
94
96
|
options.declare(:passphrase, 'SSH private key passphrase')
|
|
95
97
|
options.declare(:ssh_options, 'SSH options', types: Hash, default: {})
|
|
@@ -125,14 +127,14 @@ module Aspera
|
|
|
125
127
|
if !server_uri.scheme.eql?(SSH_SCHEME)
|
|
126
128
|
Log.log.warn('URL scheme is https but no token was provided in transfer spec.')
|
|
127
129
|
Log.log.warn("If you want to access the server, not using WSS for session, then use a URL with scheme \"#{SSH_SCHEME}\" and proper SSH port")
|
|
128
|
-
assumed_url = "#{SSH_SCHEME}://#{server_transfer_spec['remote_host']}:#{
|
|
130
|
+
assumed_url = "#{SSH_SCHEME}://#{server_transfer_spec['remote_host']}:#{Transfer::Spec::SSH_PORT}"
|
|
129
131
|
Log.log.warn{"Assuming proper URL is: #{assumed_url}"}
|
|
130
132
|
server_uri = URI.parse(assumed_url)
|
|
131
133
|
end
|
|
132
134
|
# Scheme is SSH
|
|
133
135
|
if options.get_option(:username).nil?
|
|
134
|
-
options.set_option(:username,
|
|
135
|
-
Log.log.info{"No username provided: Assuming default transfer user: #{
|
|
136
|
+
options.set_option(:username, Transfer::Spec::ACCESS_KEY_TRANSFER_USER)
|
|
137
|
+
Log.log.info{"No username provided: Assuming default transfer user: #{Transfer::Spec::ACCESS_KEY_TRANSFER_USER}"}
|
|
136
138
|
end
|
|
137
139
|
server_transfer_spec['remote_user'] = options.get_option(:username, mandatory: true)
|
|
138
140
|
if !server_uri.port.nil?
|
|
@@ -148,16 +150,15 @@ module Aspera
|
|
|
148
150
|
end
|
|
149
151
|
ssh_key_list = options.get_option(:ssh_keys)
|
|
150
152
|
if !ssh_key_list.nil?
|
|
151
|
-
raise 'Expecting single value or array for ssh_keys' unless ssh_key_list.is_a?(Array) || ssh_key_list.is_a?(String)
|
|
152
153
|
ssh_key_list = [ssh_key_list] if ssh_key_list.is_a?(String)
|
|
154
|
+
Aspera.assert_type(ssh_key_list, Array){'ssh_keys'}
|
|
155
|
+
Aspera.assert(ssh_key_list.all?(String))
|
|
153
156
|
ssh_key_list.map!{|p|File.expand_path(p)}
|
|
154
157
|
Log.log.debug{"SSH keys=#{ssh_key_list}"}
|
|
155
158
|
if !ssh_key_list.empty?
|
|
156
159
|
@ssh_opts[:keys] = ssh_key_list
|
|
157
|
-
server_transfer_spec['
|
|
158
|
-
|
|
159
|
-
Log.log.warn{"No such key file: #{k}"} unless File.exist?(k)
|
|
160
|
-
end
|
|
160
|
+
server_transfer_spec['ssh_private_key'] = File.read(ssh_key_list.first)
|
|
161
|
+
Log.log.warn{'Using only first SSH key for transfers'} unless ssh_key_list.length.eql?(1)
|
|
161
162
|
cred_set = true
|
|
162
163
|
end
|
|
163
164
|
end
|
|
@@ -175,7 +176,7 @@ module Aspera
|
|
|
175
176
|
def execute_transfer(command, transfer_spec)
|
|
176
177
|
case command
|
|
177
178
|
when :upload, :download
|
|
178
|
-
|
|
179
|
+
Transfer::Spec.action_to_direction(transfer_spec, command)
|
|
179
180
|
return Main.result_transfer(transfer.start(transfer_spec))
|
|
180
181
|
when :sync
|
|
181
182
|
# lets ignore the arguments provided by execute_sync_action, we just give the transfer spec
|
|
@@ -186,7 +187,7 @@ module Aspera
|
|
|
186
187
|
# actions without ascmd
|
|
187
188
|
BASE_ACTIONS = %i[health].concat(TRANSFER_COMMANDS).freeze
|
|
188
189
|
# all actions
|
|
189
|
-
ACTIONS = [BASE_ACTIONS,
|
|
190
|
+
ACTIONS = [BASE_ACTIONS, AsCmd::OPERATIONS, ASCMD_ALIASES.keys].flatten.freeze
|
|
190
191
|
|
|
191
192
|
def execute_action
|
|
192
193
|
server_transfer_spec = options_to_base_transfer_spec
|
|
@@ -225,16 +226,16 @@ module Aspera
|
|
|
225
226
|
else
|
|
226
227
|
nagios.add_critical('transfer', statuses.reject{|i|i.eql?(:success)}.first.to_s)
|
|
227
228
|
end
|
|
228
|
-
else
|
|
229
|
+
else Aspera.error_unexpected_value(command_nagios)
|
|
229
230
|
end
|
|
230
231
|
return nagios.result
|
|
231
232
|
when *TRANSFER_COMMANDS
|
|
232
233
|
return execute_transfer(command, server_transfer_spec)
|
|
233
|
-
when *
|
|
234
|
+
when *AsCmd::OPERATIONS
|
|
234
235
|
command_arguments = options.get_next_argument('ascmd command arguments', expected: :multiple, mandatory: false)
|
|
235
|
-
ascmd =
|
|
236
|
+
ascmd = AsCmd.new(ascmd_executor)
|
|
236
237
|
begin
|
|
237
|
-
result = ascmd.
|
|
238
|
+
result = ascmd.execute_single(command, command_arguments)
|
|
238
239
|
case command
|
|
239
240
|
when :mkdir, :mv, :cp, :rm
|
|
240
241
|
return Main.result_success
|
|
@@ -245,10 +246,10 @@ module Aspera
|
|
|
245
246
|
when :du, :md5sum, :info
|
|
246
247
|
return {type: :single_object, data: result.stringify_keys}
|
|
247
248
|
end
|
|
248
|
-
rescue
|
|
249
|
+
rescue AsCmd::Error => e
|
|
249
250
|
raise Cli::BadArgument, e.extended_message
|
|
250
251
|
end
|
|
251
|
-
else
|
|
252
|
+
else Aspera.error_unreachable_line
|
|
252
253
|
end
|
|
253
254
|
end # execute_action
|
|
254
255
|
end # Server
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'aspera/cli/plugins/node'
|
|
4
|
-
|
|
4
|
+
require 'aspera/assert'
|
|
5
5
|
module Aspera
|
|
6
6
|
module Cli
|
|
7
7
|
module Plugins
|
|
8
8
|
# Plugin for Aspera Shares v1
|
|
9
|
-
class Shares <
|
|
9
|
+
class Shares < Cli::BasicAuthPlugin
|
|
10
10
|
API_BASE = 'node_api'
|
|
11
11
|
class << self
|
|
12
12
|
def detect(address_or_url)
|
|
@@ -24,7 +24,7 @@ module Aspera
|
|
|
24
24
|
end
|
|
25
25
|
return nil unless found
|
|
26
26
|
version = 'unknown'
|
|
27
|
-
test_page = api.call(
|
|
27
|
+
test_page = api.call(operation: 'GET', subpath: 'login')
|
|
28
28
|
if (m = test_page[:http].body.match(/\(v(1\..*)\)/))
|
|
29
29
|
version = m[1]
|
|
30
30
|
end
|
|
@@ -47,10 +47,8 @@ module Aspera
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def initialize(env)
|
|
51
|
-
super
|
|
52
|
-
options.declare(:type, 'Type of user/group for operations', values: %i[any local ldap saml], default: :any)
|
|
53
|
-
options.parse_options!
|
|
50
|
+
def initialize(**env)
|
|
51
|
+
super
|
|
54
52
|
end
|
|
55
53
|
|
|
56
54
|
SAML_IMPORT_MANDATORY = %w[id name_id].freeze
|
|
@@ -81,66 +79,74 @@ module Aspera
|
|
|
81
79
|
when :repository, :files
|
|
82
80
|
api_shares_node = basic_auth_api(API_BASE)
|
|
83
81
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
|
84
|
-
return Node.new(
|
|
82
|
+
return Node.new(**init_params, api: api_shares_node).execute_action(repo_command)
|
|
85
83
|
when :admin
|
|
86
84
|
api_shares_admin = basic_auth_api('api/v1')
|
|
87
|
-
admin_command = options.get_next_command(%i[user group
|
|
85
|
+
admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
|
|
88
86
|
case admin_command
|
|
89
87
|
when :node
|
|
90
88
|
return entity_action(api_shares_admin, 'data/nodes')
|
|
89
|
+
when :share
|
|
90
|
+
share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
|
|
91
|
+
case share_command
|
|
92
|
+
when *Plugin::ALL_OPS
|
|
93
|
+
return entity_command(share_command, api_shares_admin, 'data/shares')
|
|
94
|
+
# return {type: :object_list, data: all_shares, fields: %w[id name status status_message]}
|
|
95
|
+
when :user_permissions, :group_permissions
|
|
96
|
+
share_id = instance_identifier
|
|
97
|
+
return entity_action(api_shares_admin, "data/shares/#{share_id}/#{share_command}")
|
|
98
|
+
end
|
|
99
|
+
when :transfer_settings
|
|
100
|
+
xfer_settings_command = options.get_next_command(%i[show modify])
|
|
101
|
+
return entity_command(xfer_settings_command, api_shares_admin, 'data/transfer_settings', is_singleton: true)
|
|
91
102
|
when :user, :group
|
|
92
103
|
entity_type = admin_command
|
|
93
|
-
entities_location = options.
|
|
94
|
-
|
|
104
|
+
entities_location = options.get_next_command(%i[all local ldap saml])
|
|
105
|
+
entities_prefix = entities_location.eql?(:all) ? '' : "#{entities_location}_"
|
|
106
|
+
entities_path = "data/#{entities_prefix}#{entity_type}s"
|
|
95
107
|
entity_action = nil
|
|
96
108
|
case entities_location
|
|
97
|
-
when :
|
|
98
|
-
entities_path = "data/#{entity_type}s"
|
|
109
|
+
when :all
|
|
99
110
|
entity_action = %i[list show delete]
|
|
100
111
|
entity_action.concat(USR_GRP_SETTINGS)
|
|
101
112
|
entity_action.push(:users) if entity_type.eql?(:group)
|
|
102
113
|
entity_action.freeze
|
|
103
114
|
when :local
|
|
104
|
-
entity_action = %i[list show create modify
|
|
115
|
+
entity_action = %i[list show delete create modify]
|
|
116
|
+
entity_action.push(:users) if entity_type.eql?(:group)
|
|
117
|
+
entity_action.freeze
|
|
105
118
|
when :ldap
|
|
106
119
|
entity_action = %i[add].freeze
|
|
107
120
|
when :saml
|
|
108
121
|
entity_action = %i[import].freeze
|
|
109
122
|
end
|
|
110
123
|
entity_verb = options.get_next_command(entity_action)
|
|
111
|
-
# entity_path = "#{entities_path}/#{instance_identifier}" if %i[app_authorizations share_permissions].include?(entity_verb)
|
|
112
124
|
case entity_verb
|
|
113
|
-
when *Plugin::ALL_OPS
|
|
125
|
+
when *Plugin::ALL_OPS # list, show, delete, create, modify
|
|
114
126
|
display_fields = entity_type.eql?(:user) ? %w[id username first_name last_name email] : nil
|
|
115
|
-
display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:
|
|
127
|
+
display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:all)
|
|
116
128
|
return entity_command(entity_verb, api_shares_admin, entities_path, display_fields: display_fields)
|
|
117
|
-
when
|
|
129
|
+
when *USR_GRP_SETTINGS # transfer_settings, app_authorizations, share_permissions
|
|
130
|
+
group_id = instance_identifier
|
|
131
|
+
entities_path = "#{entities_path}/#{group_id}/#{entity_verb}"
|
|
132
|
+
return entity_action(api_shares_admin, entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
|
|
133
|
+
when :import # saml
|
|
118
134
|
return do_bulk_operation(command: entity_verb, descr: 'user information') do |entity_parameters|
|
|
119
135
|
entity_parameters = entity_parameters.transform_keys{|k|k.gsub(/\s+/, '_').downcase}
|
|
120
|
-
|
|
136
|
+
Aspera.assert_type(entity_parameters, Hash)
|
|
121
137
|
SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if entity_parameters[p].nil?}
|
|
122
138
|
entity_parameters.each_key do |p|
|
|
123
139
|
raise "unsupported field: #{p}, use: #{SAML_IMPORT_ALLOWED.join(',')}" unless SAML_IMPORT_ALLOWED.include?(p)
|
|
124
140
|
end
|
|
125
141
|
api_shares_admin.create("#{entities_path}/import", entity_parameters)[:data]
|
|
126
142
|
end
|
|
127
|
-
when :add
|
|
143
|
+
when :add # ldap
|
|
128
144
|
return do_bulk_operation(command: entity_verb, descr: "#{entity_type} name", values: String) do |entity_name|
|
|
129
145
|
api_shares_admin.create(entities_path, {entity_type=>entity_name})[:data]
|
|
130
146
|
end
|
|
131
|
-
when
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return entity_action(api_shares_admin, entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
|
|
135
|
-
end
|
|
136
|
-
when :share
|
|
137
|
-
share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
|
|
138
|
-
case share_command
|
|
139
|
-
when *Plugin::ALL_OPS
|
|
140
|
-
return entity_command(share_command, api_shares_admin, 'data/shares')
|
|
141
|
-
# return {type: :object_list, data: all_shares, fields: %w[id name status status_message]}
|
|
142
|
-
when :user_permissions, :group_permissions
|
|
143
|
-
return entity_action(api_shares_admin, "data/shares/#{instance_identifier}/#{share_command}")
|
|
147
|
+
when :users # group
|
|
148
|
+
return entity_action(api_shares_admin, "#{entities_path}/#{instance_identifier}/#{entities_prefix}users")
|
|
149
|
+
else Aspera.error_unexpected_value(entity_verb)
|
|
144
150
|
end
|
|
145
151
|
end
|
|
146
152
|
end
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'aspera/sync'
|
|
3
|
+
require 'aspera/transfer/sync'
|
|
4
|
+
require 'aspera/assert'
|
|
4
5
|
|
|
5
6
|
module Aspera
|
|
6
7
|
module Cli
|
|
7
8
|
# Module for sync actions
|
|
8
9
|
module SyncActions
|
|
9
10
|
SIMPLE_ARGUMENTS_SYNC = {
|
|
10
|
-
direction:
|
|
11
|
+
direction: Transfer::Sync::DIRECTIONS,
|
|
11
12
|
local_dir: String,
|
|
12
13
|
remote_dir: String
|
|
13
14
|
}.stringify_keys.freeze
|
|
@@ -19,8 +20,7 @@ module Aspera
|
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def execute_sync_action(&block)
|
|
22
|
-
|
|
23
|
-
raise 'Internal Error: No block given' unless block
|
|
23
|
+
Aspera.assert(block){'No block given'}
|
|
24
24
|
command = options.get_next_command(%i[start admin])
|
|
25
25
|
# try to get 3 arguments as simple arguments
|
|
26
26
|
case command
|
|
@@ -45,13 +45,13 @@ module Aspera
|
|
|
45
45
|
:sync_info,
|
|
46
46
|
mandatory: false,
|
|
47
47
|
default: {'sessions' => [{'name' => File.basename(simple_session_args['local_dir'])}]})
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
Aspera.assert_type(async_params, Hash){'sync_info'}
|
|
49
|
+
Aspera.assert_type(async_params['sessions'], Array){'sync_info[sessions]'}
|
|
50
|
+
Aspera.assert_type(async_params['sessions'].first, Hash){'sync_info[sessions][0]'}
|
|
51
51
|
async_params['sessions'].first.merge!(simple_session_args)
|
|
52
52
|
end
|
|
53
53
|
Log.log.debug{Log.dump('async_params', async_params)}
|
|
54
|
-
|
|
54
|
+
Transfer::Sync.start(async_params, &block)
|
|
55
55
|
return Main.result_success
|
|
56
56
|
when :admin
|
|
57
57
|
command2 = options.get_next_command([:status])
|
|
@@ -59,7 +59,7 @@ module Aspera
|
|
|
59
59
|
when :status
|
|
60
60
|
sync_session_name = options.get_next_argument('name of sync session', mandatory: false, type: String)
|
|
61
61
|
async_params = options.get_option(:sync_info, mandatory: true)
|
|
62
|
-
return {type: :single_object, data:
|
|
62
|
+
return {type: :single_object, data: Transfer::Sync.admin_status(async_params, sync_session_name)}
|
|
63
63
|
end # command2
|
|
64
64
|
end # command
|
|
65
65
|
end # execute_action
|