aspera-cli 4.23.0 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +32 -1
- data/CONTRIBUTING.md +86 -29
- data/README.md +1651 -856
- data/bin/ascli +2 -1
- data/bin/asession +4 -4
- data/lib/aspera/agent/base.rb +4 -0
- data/lib/aspera/agent/connect.rb +20 -18
- data/lib/aspera/agent/desktop.rb +14 -11
- data/lib/aspera/agent/direct.rb +39 -31
- data/lib/aspera/agent/httpgw.rb +2 -2
- data/lib/aspera/agent/node.rb +9 -11
- data/lib/aspera/agent/transferd.rb +18 -11
- data/lib/aspera/api/aoc.rb +44 -31
- data/lib/aspera/api/cos_node.rb +7 -5
- data/lib/aspera/api/httpgw.rb +15 -18
- data/lib/aspera/api/node.rb +104 -22
- data/lib/aspera/ascmd.rb +22 -16
- data/lib/aspera/ascp/installation.rb +37 -40
- data/lib/aspera/ascp/management.rb +5 -4
- data/lib/aspera/assert.rb +54 -23
- data/lib/aspera/cli/basic_auth_plugin.rb +8 -7
- data/lib/aspera/cli/error.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +28 -29
- data/lib/aspera/cli/formatter.rb +191 -168
- data/lib/aspera/cli/hints.rb +29 -3
- data/lib/aspera/cli/main.rb +138 -107
- data/lib/aspera/cli/manager.rb +50 -30
- data/lib/aspera/cli/plugin.rb +148 -77
- data/lib/aspera/cli/plugin_factory.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +189 -70
- data/lib/aspera/cli/plugins/ats.rb +15 -13
- data/lib/aspera/cli/plugins/config.rb +86 -213
- data/lib/aspera/cli/plugins/console.rb +49 -18
- data/lib/aspera/cli/plugins/cos.rb +4 -4
- data/lib/aspera/cli/plugins/faspex.rb +45 -51
- data/lib/aspera/cli/plugins/faspex5.rb +162 -163
- data/lib/aspera/cli/plugins/faspio.rb +6 -5
- data/lib/aspera/cli/plugins/httpgw.rb +2 -2
- data/lib/aspera/cli/plugins/node.rb +144 -162
- data/lib/aspera/cli/plugins/orchestrator.rb +10 -14
- data/lib/aspera/cli/plugins/preview.rb +26 -29
- data/lib/aspera/cli/plugins/server.rb +28 -28
- data/lib/aspera/cli/plugins/shares.rb +40 -28
- data/lib/aspera/cli/sync_actions.rb +101 -80
- data/lib/aspera/cli/transfer_agent.rb +51 -50
- data/lib/aspera/cli/transfer_progress.rb +29 -20
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +160 -0
- data/lib/aspera/colors.rb +13 -8
- data/lib/aspera/command_line_builder.rb +28 -22
- data/lib/aspera/command_line_converter.rb +31 -0
- data/lib/aspera/environment.rb +144 -101
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +3 -2
- data/lib/aspera/hash_ext.rb +1 -1
- data/lib/aspera/id_generator.rb +10 -10
- data/lib/aspera/keychain/base.rb +18 -0
- data/lib/aspera/keychain/encrypted_hash.rb +6 -12
- data/lib/aspera/keychain/factory.rb +9 -3
- data/lib/aspera/keychain/hashicorp_vault.rb +9 -6
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/log.rb +69 -20
- data/lib/aspera/nagios.rb +5 -6
- data/lib/aspera/node_simulator.rb +12 -7
- data/lib/aspera/oauth/base.rb +5 -3
- data/lib/aspera/oauth/factory.rb +24 -18
- data/lib/aspera/oauth/jwt.rb +13 -1
- data/lib/aspera/oauth/url_json.rb +3 -3
- data/lib/aspera/oauth/web.rb +5 -3
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -3
- data/lib/aspera/preview/generator.rb +25 -12
- data/lib/aspera/preview/terminal.rb +10 -7
- data/lib/aspera/preview/utils.rb +11 -9
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +2 -2
- data/lib/aspera/products/transferd.rb +8 -6
- data/lib/aspera/proxy_auto_config.rb +1 -1
- data/lib/aspera/rest.rb +29 -22
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +46 -40
- data/lib/aspera/ssh.rb +13 -3
- data/lib/aspera/sync/args.schema.yaml +102 -0
- data/lib/aspera/sync/conf.schema.yaml +701 -0
- data/lib/aspera/sync/database.rb +83 -0
- data/lib/aspera/{transfer/sync.rb → sync/operations.rb} +132 -65
- data/lib/aspera/temp_file_manager.rb +3 -2
- data/lib/aspera/transfer/error.rb +1 -1
- data/lib/aspera/transfer/error_info.rb +1 -2
- data/lib/aspera/transfer/faux_file.rb +11 -10
- data/lib/aspera/transfer/parameters.rb +6 -5
- data/lib/aspera/transfer/spec.rb +15 -1
- data/lib/aspera/transfer/spec.schema.yaml +316 -293
- data/lib/aspera/transfer/spec_doc.rb +34 -16
- data/lib/aspera/transfer/uri.rb +5 -5
- data/lib/aspera/uri_reader.rb +14 -10
- data/lib/aspera/web_auth.rb +2 -2
- data/lib/aspera/web_server_simple.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +15 -13
- metadata.gz.sig +2 -2
- data/lib/aspera/transfer/async_conf.schema.yaml +0 -716
- data/lib/aspera/transfer/convert.rb +0 -29
- data/lib/aspera/transfer/sync_instance.schema.yaml +0 -20
- data/lib/aspera/transfer/sync_session.schema.yaml +0 -86
@@ -35,10 +35,10 @@ module Aspera
|
|
35
35
|
Log.log.debug{"detect error: #{e}"}
|
36
36
|
end
|
37
37
|
raise error if error
|
38
|
-
return
|
38
|
+
return
|
39
39
|
end
|
40
40
|
|
41
|
-
def wizard(object
|
41
|
+
def wizard(object:)
|
42
42
|
options = object.options
|
43
43
|
return {
|
44
44
|
preset_value: {
|
@@ -51,8 +51,9 @@ module Aspera
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def initialize(**
|
54
|
+
def initialize(**_)
|
55
55
|
super
|
56
|
+
@api_orch = nil
|
56
57
|
options.declare(:result, "Specify result value as: 'work_step:parameter'")
|
57
58
|
options.declare(:synchronous, 'Wait for completion', values: :bool, default: :no)
|
58
59
|
options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
|
@@ -89,7 +90,7 @@ module Aspera
|
|
89
90
|
result = @api_orch.call(**call_args)
|
90
91
|
return result[:http] if http
|
91
92
|
result = format.eql?('xml') ? XmlSimple.xml_in(result[:http].body, {'ForceArray' => xml_arrays}) : result[:data]
|
92
|
-
Log.
|
93
|
+
Log.dump(:data, result)
|
93
94
|
return result
|
94
95
|
end
|
95
96
|
|
@@ -101,7 +102,8 @@ module Aspera
|
|
101
102
|
type: :url,
|
102
103
|
url_query: {
|
103
104
|
'login' => options.get_option(:username, mandatory: true),
|
104
|
-
'password' => options.get_option(:password, mandatory: true)
|
105
|
+
'password' => options.get_option(:password, mandatory: true)
|
106
|
+
}
|
105
107
|
}
|
106
108
|
when :head_basic
|
107
109
|
{
|
@@ -110,7 +112,7 @@ module Aspera
|
|
110
112
|
password: options.get_option(:password, mandatory: true)
|
111
113
|
}
|
112
114
|
when :apikey
|
113
|
-
|
115
|
+
Aspera.error_not_implemented
|
114
116
|
end
|
115
117
|
|
116
118
|
@api_orch = Rest.new(
|
@@ -150,11 +152,7 @@ module Aspera
|
|
150
152
|
return Main.result_object_list(result['workflows']['workflow'])
|
151
153
|
when :list
|
152
154
|
result = call_ao('workflows_list/0')
|
153
|
-
return
|
154
|
-
type: :object_list,
|
155
|
-
data: result['workflows']['workflow'],
|
156
|
-
fields: %w[id portable_id name published_status published_revision_id latest_revision_id last_modification]
|
157
|
-
}
|
155
|
+
return Main.result_object_list(result['workflows']['workflow'], fields: %w[id portable_id name published_status published_revision_id latest_revision_id last_modification])
|
158
156
|
when :details
|
159
157
|
result = call_ao("workflow_details/#{instance_identifier}")
|
160
158
|
return Main.result_object_list(result['workflows']['workflow']['statuses'])
|
@@ -188,9 +186,7 @@ module Aspera
|
|
188
186
|
# implicitly, call is synchronous
|
189
187
|
call_params['synchronous'] = true
|
190
188
|
end
|
191
|
-
if call_params['synchronous']
|
192
|
-
result[:type] = :text
|
193
|
-
end
|
189
|
+
result[:type] = :text if call_params['synchronous']
|
194
190
|
result[:data] = call_ao("initiate/#{wf_id}", args: call_params)
|
195
191
|
return result
|
196
192
|
end
|
@@ -49,7 +49,7 @@ module Aspera
|
|
49
49
|
attr_accessor :option_previews_folder
|
50
50
|
attr_accessor :option_folder_reset_cache, :option_skip_folders, :option_overwrite, :option_file_access
|
51
51
|
|
52
|
-
def initialize(**
|
52
|
+
def initialize(**_)
|
53
53
|
super
|
54
54
|
@skip_types = []
|
55
55
|
@default_transfer_spec = nil
|
@@ -64,12 +64,14 @@ module Aspera
|
|
64
64
|
# link CLI options to gen_info attributes
|
65
65
|
options.declare(
|
66
66
|
:skip_format, 'Skip this preview format (multiple possible)', values: Aspera::Preview::Generator::PREVIEW_FORMATS,
|
67
|
-
handler: {o: self, m: :option_skip_format}, default: []
|
67
|
+
handler: {o: self, m: :option_skip_format}, default: []
|
68
|
+
)
|
68
69
|
options.declare(
|
69
70
|
:folder_reset_cache, 'Force detection of generated preview by refresh cache',
|
70
71
|
values: %i[no header read],
|
71
72
|
handler: {o: self, m: :option_folder_reset_cache},
|
72
|
-
default: :no
|
73
|
+
default: :no
|
74
|
+
)
|
73
75
|
options.declare(:skip_types, 'Skip types in comma separated list', handler: {o: self, m: :option_skip_types})
|
74
76
|
options.declare(:previews_folder, 'Preview folder in storage root', handler: {o: self, m: :option_previews_folder}, default: DEFAULT_PREVIEWS_FOLDER)
|
75
77
|
options.declare(:temp_folder, 'Path to temp folder', default: Dir.tmpdir)
|
@@ -83,7 +85,8 @@ module Aspera
|
|
83
85
|
:file_access, 'How to read and write files in repository',
|
84
86
|
values: %i[local remote],
|
85
87
|
handler: {o: self, m: :option_file_access},
|
86
|
-
default: :local
|
88
|
+
default: :local
|
89
|
+
)
|
87
90
|
|
88
91
|
# add other options for generator (and set default values)
|
89
92
|
Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
|
@@ -125,14 +128,15 @@ module Aspera
|
|
125
128
|
|
126
129
|
# /files/id/files is normally cached in redis, but we can discard the cache
|
127
130
|
# but /files/id is not cached
|
128
|
-
def get_folder_entries(file_id, request_args=nil)
|
131
|
+
def get_folder_entries(file_id, request_args = nil)
|
129
132
|
headers = {'Accept' => Rest::MIME_JSON}
|
130
133
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
131
134
|
return @api_node.call(
|
132
135
|
operation: 'GET',
|
133
136
|
subpath: "files/#{file_id}/files",
|
134
137
|
headers: headers,
|
135
|
-
query: request_args
|
138
|
+
query: request_args
|
139
|
+
)[:data]
|
136
140
|
end
|
137
141
|
|
138
142
|
# old version based on folders
|
@@ -196,12 +200,8 @@ module Aspera
|
|
196
200
|
if !file_entry.nil? &&
|
197
201
|
@option_skip_folders.none?{ |d| file_entry['path'].start_with?(d)}
|
198
202
|
file_entry['parent_file_id'] = event['data']['parent_file_id']
|
199
|
-
if event['types'].include?('file.deleted')
|
200
|
-
|
201
|
-
end
|
202
|
-
if event['types'].include?('file.deleted')
|
203
|
-
generate_preview(file_entry)
|
204
|
-
end
|
203
|
+
Log.log.error('TODO'.red) if event['types'].include?('file.deleted')
|
204
|
+
generate_preview(file_entry) if event['types'].include?('file.deleted')
|
205
205
|
end
|
206
206
|
end
|
207
207
|
# log/persist periodically or last one
|
@@ -215,7 +215,7 @@ module Aspera
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
218
|
-
def do_transfer(direction, folder_id, source_filename, destination='/')
|
218
|
+
def do_transfer(direction, folder_id, source_filename, destination = '/')
|
219
219
|
Aspera.assert(!(destination.nil? && direction.eql?(Transfer::Spec::DIRECTION_RECEIVE)))
|
220
220
|
t_spec = @api_node.transfer_spec_gen4(folder_id, direction, {
|
221
221
|
'paths' => [{'source' => source_filename}],
|
@@ -268,7 +268,7 @@ module Aspera
|
|
268
268
|
end
|
269
269
|
|
270
270
|
# Generate a file name based on basename and format (extension)
|
271
|
-
def preview_filename(preview_format, base_name=nil)
|
271
|
+
def preview_filename(preview_format, base_name = nil)
|
272
272
|
base_name ||= PREVIEW_BASENAME
|
273
273
|
return "#{base_name}.#{preview_format}"
|
274
274
|
end
|
@@ -319,7 +319,7 @@ module Aspera
|
|
319
319
|
# create folder if needed
|
320
320
|
FileUtils.mkdir_p(local_entry_preview_dir)
|
321
321
|
if @access_remote
|
322
|
-
|
322
|
+
Aspera.assert(!entry['parent_file_id'].nil?){'missing parent_file_id in entry'}
|
323
323
|
# download original file to temp folder
|
324
324
|
do_transfer(Transfer::Spec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
|
325
325
|
end
|
@@ -335,9 +335,7 @@ module Aspera
|
|
335
335
|
File.delete(File.join(@tmp_folder, entry['name']))
|
336
336
|
end
|
337
337
|
# force read file updated previews
|
338
|
-
if @option_folder_reset_cache.eql?(:read)
|
339
|
-
@api_node.read("files/#{entry['id']}")
|
340
|
-
end
|
338
|
+
@api_node.read("files/#{entry['id']}") if @option_folder_reset_cache.eql?(:read)
|
341
339
|
rescue StandardError => e
|
342
340
|
Log.log.error{"Ignore: #{e.message}"}
|
343
341
|
Log.log.debug(e.backtrace.join("\n").red)
|
@@ -345,10 +343,10 @@ module Aspera
|
|
345
343
|
|
346
344
|
# scan all files in provided folder entry
|
347
345
|
# @param top_path subpath to start folder scan inside
|
348
|
-
def scan_folder_files(top_entry, top_path=nil)
|
346
|
+
def scan_folder_files(top_entry, top_path = nil)
|
349
347
|
unless top_path.nil?
|
350
348
|
# canonical path: start with / and ends with /
|
351
|
-
top_path =
|
349
|
+
top_path = "/#{top_path.split('/').reject(&:empty?).join('/')}/"
|
352
350
|
end
|
353
351
|
Log.log.debug{"scan: #{top_entry} : #{top_path}".green}
|
354
352
|
# don't use recursive call, use list instead
|
@@ -384,9 +382,7 @@ module Aspera
|
|
384
382
|
# process all items in current folder
|
385
383
|
folder_entries.each do |folder_entry|
|
386
384
|
# add path for older versions of ES
|
387
|
-
if !folder_entry.key?('path')
|
388
|
-
folder_entry['path'] = entry_path_with_slash + folder_entry['name']
|
389
|
-
end
|
385
|
+
folder_entry['path'] = entry_path_with_slash + folder_entry['name'] if !folder_entry.key?('path')
|
390
386
|
folder_entry['parent_file_id'] = entry['id']
|
391
387
|
entries_to_process.push(folder_entry)
|
392
388
|
end
|
@@ -418,7 +414,7 @@ module Aspera
|
|
418
414
|
Log.log.debug{"remote: #{@access_remote}"}
|
419
415
|
Log.log.debug{"access key info: #{@access_key_self}"}
|
420
416
|
# TODO: can the previews folder parameter be read from node api ?
|
421
|
-
@option_skip_folders.push(
|
417
|
+
@option_skip_folders.push("/#{@option_previews_folder}")
|
422
418
|
if @access_remote
|
423
419
|
# NOTE: the filter "name", it's why we take the first one
|
424
420
|
@previews_folder_entry = get_folder_entries(@access_key_self['root_file_id'], {name: @option_previews_folder}).first
|
@@ -431,7 +427,7 @@ module Aspera
|
|
431
427
|
@local_storage_root = @local_storage_root[PVCL_LOCAL_STORAGE.length..-1] if @local_storage_root.start_with?(PVCL_LOCAL_STORAGE)
|
432
428
|
# TODO: windows could have "C:" ?
|
433
429
|
Aspera.assert(@local_storage_root.start_with?('/')){"not local storage: #{@local_storage_root}"}
|
434
|
-
Aspera.assert(File.directory?(@local_storage_root),
|
430
|
+
Aspera.assert(File.directory?(@local_storage_root), type: Cli::Error){"Local storage root folder #{@local_storage_root} does not exist."}
|
435
431
|
@local_preview_folder = File.join(@local_storage_root, @option_previews_folder)
|
436
432
|
raise Cli::Error, "Folder #{@local_preview_folder} does not exist locally. " \
|
437
433
|
'Please create it, or specify an alternate name.' unless File.directory?(@local_preview_folder)
|
@@ -460,7 +456,8 @@ module Aspera
|
|
460
456
|
'id' => @access_key_self['root_file_id'],
|
461
457
|
'name' => '/',
|
462
458
|
'type' => 'folder',
|
463
|
-
'path' => '/'
|
459
|
+
'path' => '/'
|
460
|
+
}
|
464
461
|
else
|
465
462
|
@api_node.read("files/#{scan_id}")
|
466
463
|
end
|
@@ -479,7 +476,8 @@ module Aspera
|
|
479
476
|
command.to_s,
|
480
477
|
options.get_option(:url, mandatory: true),
|
481
478
|
options.get_option(:username, mandatory: true)
|
482
|
-
])
|
479
|
+
])
|
480
|
+
)
|
483
481
|
end
|
484
482
|
# call processing method specified by command line command
|
485
483
|
send(:"process_#{command}", iteration_persistency)
|
@@ -498,8 +496,7 @@ module Aspera
|
|
498
496
|
formatter.display_status(Aspera::Preview::Terminal.build(File.read(generated_file_path), **terminal_options))
|
499
497
|
end
|
500
498
|
return Main.result_status("generated: #{generated_file_path}")
|
501
|
-
else
|
502
|
-
raise 'error'
|
499
|
+
else Aspera.error_unexpected_value(command)
|
503
500
|
end
|
504
501
|
ensure
|
505
502
|
Log.log.debug{"cleaning up temp folder #{@tmp_folder}"}
|
@@ -10,13 +10,10 @@ require 'aspera/nagios'
|
|
10
10
|
require 'aspera/log'
|
11
11
|
require 'aspera/assert'
|
12
12
|
require 'aspera/environment'
|
13
|
-
require 'tempfile'
|
14
|
-
require 'open3'
|
15
|
-
|
16
13
|
module Aspera
|
17
14
|
module Cli
|
18
15
|
module Plugins
|
19
|
-
#
|
16
|
+
# Operations on HSTS with SSH/FASP (ascmd/ascp)
|
20
17
|
class Server < Cli::BasicAuthPlugin
|
21
18
|
include SyncActions
|
22
19
|
|
@@ -34,8 +31,8 @@ module Aspera
|
|
34
31
|
private_constant :SSH_SCHEME, :URI_SCHEMES, :ASCMD_ALIASES, :TRANSFER_COMMANDS
|
35
32
|
|
36
33
|
class LocalExecutor
|
37
|
-
def execute(ascmd_path,
|
38
|
-
return Environment.secure_capture(exec: ascmd_path, stdin_data:
|
34
|
+
def execute(ascmd_path, input:)
|
35
|
+
return Environment.secure_capture(exec: ascmd_path, stdin_data: input, binmode: true, exception: false)
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
@@ -62,18 +59,16 @@ module Aspera
|
|
62
59
|
socket = TCPSocket.new(server_uri.hostname, server_uri.port)
|
63
60
|
socket.puts('SSH-2.0-Ascli_0.0')
|
64
61
|
version = socket.gets.chomp
|
65
|
-
if version.match?(/^SSH-2.0-/)
|
66
|
-
return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url}
|
67
|
-
end
|
62
|
+
return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url} if version.match?(/^SSH-2.0-/)
|
68
63
|
rescue StandardError => e
|
69
64
|
error = e
|
70
65
|
Log.log.debug{"detect error: #{e}"}
|
71
66
|
end
|
72
67
|
raise error if error
|
73
|
-
return
|
68
|
+
return
|
74
69
|
end
|
75
70
|
|
76
|
-
def wizard(object
|
71
|
+
def wizard(object:)
|
77
72
|
options = object.options
|
78
73
|
return {
|
79
74
|
preset_value: {
|
@@ -86,14 +81,23 @@ module Aspera
|
|
86
81
|
end
|
87
82
|
end
|
88
83
|
|
89
|
-
def initialize(**
|
84
|
+
def initialize(**_)
|
90
85
|
super
|
86
|
+
@ssh_opts = {}
|
87
|
+
@connection_type = :ssh
|
91
88
|
options.declare(:ssh_keys, 'SSH key path list (Array or single)')
|
92
89
|
options.declare(:passphrase, 'SSH private key passphrase')
|
93
|
-
options.declare(:ssh_options, 'SSH options', types: Hash,
|
90
|
+
options.declare(:ssh_options, 'SSH options', types: Hash, handler: {o: self, m: :option_ssh_opts})
|
94
91
|
SyncActions.declare_options(options)
|
95
92
|
options.parse_options!
|
96
|
-
|
93
|
+
end
|
94
|
+
|
95
|
+
def option_ssh_opts; @ssh_opts; end
|
96
|
+
|
97
|
+
# multiple option are merged
|
98
|
+
def option_ssh_opts=(value)
|
99
|
+
Aspera.assert_type(value, Hash)
|
100
|
+
@ssh_opts.deep_merge!(value.compact.symbolize_keys)
|
97
101
|
end
|
98
102
|
|
99
103
|
# Read command line options
|
@@ -111,12 +115,14 @@ module Aspera
|
|
111
115
|
if server_uri.scheme.eql?(LOCAL_SCHEME)
|
112
116
|
# Using local execution (mostly for testing)
|
113
117
|
server_transfer_spec['remote_host'] = 'localhost'
|
114
|
-
# simulate SSH environment, else
|
118
|
+
# simulate SSH environment, else ascmd will fail
|
115
119
|
ENV['SSH_CLIENT'] = 'local 0 0'
|
120
|
+
@connection_type = :local
|
116
121
|
return server_transfer_spec
|
117
122
|
elsif transfer.option_transfer_spec['token'].is_a?(String) && server_uri.scheme.eql?(HTTPS_SCHEME)
|
118
123
|
server_transfer_spec['wss_enabled'] = true
|
119
124
|
server_transfer_spec['wss_port'] = server_uri.port
|
125
|
+
@connection_type = :wss
|
120
126
|
# Using WSS
|
121
127
|
return server_transfer_spec
|
122
128
|
end
|
@@ -166,7 +172,7 @@ module Aspera
|
|
166
172
|
end
|
167
173
|
# if user provided transfer spec has a token, we will use bypass keys
|
168
174
|
cred_set = true if transfer.option_transfer_spec['token'].is_a?(String)
|
169
|
-
|
175
|
+
Aspera.assert(cred_set, type: BadArgument){'Either password, key , or transfer spec token must be provided'}
|
170
176
|
return server_transfer_spec
|
171
177
|
end
|
172
178
|
|
@@ -188,12 +194,11 @@ module Aspera
|
|
188
194
|
|
189
195
|
def execute_action
|
190
196
|
server_transfer_spec = options_to_base_transfer_spec
|
191
|
-
ascmd_executor =
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
else
|
196
|
-
LocalExecutor.new
|
197
|
+
ascmd_executor = case @connection_type
|
198
|
+
when :local then LocalExecutor.new
|
199
|
+
when :wss then nil
|
200
|
+
when :ssh then Ssh.new(server_transfer_spec['remote_host'], server_transfer_spec['remote_user'], @ssh_opts)
|
201
|
+
else Aspera.error_unexpected_value(@connection_type){'connection type'}
|
197
202
|
end
|
198
203
|
# the set of available commands depends on SSH executor availability (i.e. no WSS)
|
199
204
|
available_commands = ascmd_executor.nil? ? BASE_ACTIONS : ACTIONS
|
@@ -206,18 +211,13 @@ module Aspera
|
|
206
211
|
command_nagios = options.get_next_command(%i[transfer])
|
207
212
|
case command_nagios
|
208
213
|
when :transfer
|
209
|
-
file = Tempfile.new('transfer_test')
|
210
|
-
filepath = file.path
|
211
|
-
file.write('This is a test file for transfer test')
|
212
|
-
file.close
|
213
214
|
probe_ts = server_transfer_spec.merge({
|
214
215
|
'direction' => 'send',
|
215
216
|
'cookie' => 'aspera.sync', # hide in console
|
216
217
|
'resume_policy' => 'none',
|
217
|
-
'paths' => [{'source' =>
|
218
|
+
'paths' => [{'source' => 'faux:///pingfile?1k', 'destination' => '.fasping'}]
|
218
219
|
})
|
219
220
|
statuses = transfer.start(probe_ts)
|
220
|
-
file.unlink
|
221
221
|
if TransferAgent.session_status(statuses).eql?(:success)
|
222
222
|
nagios.add_ok('transfer', 'ok')
|
223
223
|
else
|
@@ -21,11 +21,9 @@ module Aspera
|
|
21
21
|
# TODO: use ping instead ?
|
22
22
|
api.read("#{NODE_API_PATH}/app")
|
23
23
|
rescue RestCallError => e
|
24
|
-
if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
25
|
-
found = true
|
26
|
-
end
|
24
|
+
found = true if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
27
25
|
end
|
28
|
-
return
|
26
|
+
return unless found
|
29
27
|
version = 'unknown'
|
30
28
|
test_page = api.call(operation: 'GET', subpath: 'login')
|
31
29
|
if (m = test_page[:http].body.match(/\(v(1\..*)\)/))
|
@@ -37,7 +35,7 @@ module Aspera
|
|
37
35
|
}
|
38
36
|
end
|
39
37
|
|
40
|
-
def wizard(object
|
38
|
+
def wizard(object:)
|
41
39
|
options = object.options
|
42
40
|
return {
|
43
41
|
preset_value: {
|
@@ -72,8 +70,9 @@ module Aspera
|
|
72
70
|
.call(
|
73
71
|
operation: 'GET',
|
74
72
|
subpath: 'ping',
|
75
|
-
headers: {'content-type': Rest::MIME_JSON}
|
76
|
-
|
73
|
+
headers: {'content-type': Rest::MIME_JSON}
|
74
|
+
)
|
75
|
+
raise Error, 'Shares not detected' unless res[:http].body.eql?(' ')
|
77
76
|
nagios.add_ok('shares api', 'accessible')
|
78
77
|
rescue StandardError => e
|
79
78
|
nagios.add_critical('API', e.to_s)
|
@@ -83,59 +82,72 @@ module Aspera
|
|
83
82
|
api_shares_node = basic_auth_api(NODE_API_PATH)
|
84
83
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
85
84
|
return Node
|
86
|
-
.new(
|
85
|
+
.new(context: context, api: api_shares_node)
|
87
86
|
.execute_action(repo_command)
|
88
87
|
when :admin
|
89
88
|
api_shares_admin = basic_auth_api(ADMIN_API_PATH)
|
90
89
|
admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
|
91
90
|
case admin_command
|
92
91
|
when :node
|
93
|
-
return
|
92
|
+
return entity_execute(api: api_shares_admin, entity: 'data/nodes')
|
94
93
|
when :share
|
95
94
|
share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
|
96
95
|
case share_command
|
97
96
|
when *Plugin::ALL_OPS
|
98
|
-
return
|
99
|
-
|
100
|
-
|
97
|
+
return entity_execute(
|
98
|
+
api: api_shares_admin,
|
99
|
+
entity: 'data/shares',
|
100
|
+
command: share_command,
|
101
|
+
display_fields: %w[id name node_id directory percent_free]
|
102
|
+
)
|
101
103
|
when :user_permissions, :group_permissions
|
102
104
|
share_id = instance_identifier
|
103
|
-
return
|
105
|
+
return entity_execute(api: api_shares_admin, entity: "data/shares/#{share_id}/#{share_command}")
|
104
106
|
end
|
105
107
|
when :transfer_settings
|
106
108
|
xfer_settings_command = options.get_next_command(%i[show modify])
|
107
|
-
return
|
109
|
+
return entity_execute(
|
110
|
+
api: api_shares_admin,
|
111
|
+
entity: 'data/transfer_settings',
|
112
|
+
command: xfer_settings_command,
|
113
|
+
is_singleton: true
|
114
|
+
)
|
108
115
|
when :user, :group
|
109
116
|
entity_type = admin_command
|
110
117
|
entities_location = options.get_next_command(%i[all local ldap saml])
|
111
118
|
entities_prefix = entities_location.eql?(:all) ? '' : "#{entities_location}_"
|
112
119
|
entities_path = "data/#{entities_prefix}#{entity_type}s"
|
113
|
-
|
120
|
+
entity_commands = nil
|
114
121
|
case entities_location
|
115
122
|
when :all
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
123
|
+
entity_commands = %i[list show delete]
|
124
|
+
entity_commands.concat(USR_GRP_SETTINGS)
|
125
|
+
entity_commands.push(:users) if entity_type.eql?(:group)
|
126
|
+
entity_commands.freeze
|
120
127
|
when :local
|
121
|
-
|
122
|
-
|
123
|
-
|
128
|
+
entity_commands = %i[list show delete create modify]
|
129
|
+
entity_commands.push(:users) if entity_type.eql?(:group)
|
130
|
+
entity_commands.freeze
|
124
131
|
when :ldap
|
125
|
-
|
132
|
+
entity_commands = %i[add].freeze
|
126
133
|
when :saml
|
127
|
-
|
134
|
+
entity_commands = %i[import].freeze
|
128
135
|
end
|
129
|
-
entity_verb = options.get_next_command(
|
136
|
+
entity_verb = options.get_next_command(entity_commands)
|
130
137
|
case entity_verb
|
131
138
|
when *Plugin::ALL_OPS # list, show, delete, create, modify
|
132
139
|
display_fields = entity_type.eql?(:user) ? %w[id username first_name last_name email] : nil
|
133
140
|
display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:all)
|
134
|
-
return
|
141
|
+
return entity_execute(
|
142
|
+
api: api_shares_admin,
|
143
|
+
entity: entities_path,
|
144
|
+
command: entity_verb,
|
145
|
+
display_fields: display_fields
|
146
|
+
)
|
135
147
|
when *USR_GRP_SETTINGS # transfer_settings, app_authorizations, share_permissions
|
136
148
|
group_id = instance_identifier
|
137
149
|
entities_path = "#{entities_path}/#{group_id}/#{entity_verb}"
|
138
|
-
return
|
150
|
+
return entity_execute(api: api_shares_admin, entity: entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
|
139
151
|
when :import # saml
|
140
152
|
return do_bulk_operation(command: entity_verb, descr: 'user information') do |entity_parameters|
|
141
153
|
entity_parameters = entity_parameters.transform_keys{ |k| k.gsub(/\s+/, '_').downcase}
|
@@ -151,7 +163,7 @@ module Aspera
|
|
151
163
|
api_shares_admin.create(entities_path, {entity_type=>entity_name})
|
152
164
|
end
|
153
165
|
when :users # group
|
154
|
-
return
|
166
|
+
return entity_execute(api: api_shares_admin, entity: "#{entities_path}/#{instance_identifier}/#{entities_prefix}users")
|
155
167
|
else Aspera.error_unexpected_value(entity_verb)
|
156
168
|
end
|
157
169
|
end
|