aspera-cli 4.18.1 → 4.19.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 +13 -0
- data/CONTRIBUTING.md +5 -12
- data/README.md +60 -29
- data/examples/build_exec +85 -0
- data/lib/aspera/agent/base.rb +2 -0
- data/lib/aspera/agent/direct.rb +108 -104
- data/lib/aspera/api/aoc.rb +2 -2
- data/lib/aspera/api/httpgw.rb +91 -56
- data/lib/aspera/ascp/installation.rb +47 -32
- data/lib/aspera/ascp/management.rb +4 -1
- data/lib/aspera/ascp/products.rb +1 -7
- data/lib/aspera/cli/formatter.rb +24 -18
- data/lib/aspera/cli/manager.rb +10 -10
- data/lib/aspera/cli/plugin.rb +2 -2
- data/lib/aspera/cli/plugin_factory.rb +10 -1
- data/lib/aspera/cli/plugins/config.rb +15 -10
- data/lib/aspera/cli/plugins/node.rb +4 -3
- data/lib/aspera/cli/plugins/server.rb +1 -1
- data/lib/aspera/cli/plugins/shares.rb +11 -7
- data/lib/aspera/cli/sync_actions.rb +72 -31
- data/lib/aspera/cli/transfer_agent.rb +1 -0
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +43 -10
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +2 -0
- data/lib/aspera/log.rb +1 -0
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -0
- data/lib/aspera/oauth/web.rb +5 -4
- data/lib/aspera/secret_hider.rb +3 -2
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/faux_file.rb +7 -5
- data/lib/aspera/transfer/parameters.rb +27 -19
- data/lib/aspera/transfer/spec.rb +8 -10
- data/lib/aspera/transfer/sync.rb +52 -47
- data/lib/aspera/web_auth.rb +0 -1
- data/lib/aspera/web_server_simple.rb +24 -13
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
- data/examples/rubyc +0 -24
@@ -41,8 +41,11 @@ module Aspera
|
|
41
41
|
</CONF>
|
42
42
|
END_OF_CONFIG_FILE
|
43
43
|
# all ascp files (in SDK)
|
44
|
-
|
44
|
+
EXE_FILES = %i[ascp ascp4 async].freeze
|
45
|
+
FILES = %i[transferd ssh_private_dsa ssh_private_rsa aspera_license aspera_conf fallback_certificate fallback_private_key].unshift(*EXE_FILES).freeze
|
45
46
|
private_constant :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER, :DEFAULT_ASPERA_CONF, :FILES
|
47
|
+
# options for SSH client private key
|
48
|
+
CLIENT_SSH_KEY_OPTIONS = %i{dsa_rsa rsa per_client}.freeze
|
46
49
|
# set ascp executable path
|
47
50
|
def ascp_path=(v)
|
48
51
|
@path_to_ascp = v
|
@@ -110,14 +113,14 @@ module Aspera
|
|
110
113
|
def path(k)
|
111
114
|
file_is_optional = false
|
112
115
|
case k
|
113
|
-
when
|
116
|
+
when *EXE_FILES
|
117
|
+
file_is_optional = k.eql?(:async)
|
114
118
|
use_ascp_from_product(FIRST_FOUND) if @path_to_ascp.nil?
|
115
|
-
file = @path_to_ascp
|
116
119
|
# NOTE: that there might be a .exe at the end
|
117
|
-
file =
|
120
|
+
file = @path_to_ascp.gsub('ascp', k.to_s)
|
118
121
|
when :transferd
|
119
|
-
file = transferd_filepath
|
120
122
|
file_is_optional = true
|
123
|
+
file = transferd_filepath
|
121
124
|
when :ssh_private_dsa, :ssh_private_rsa
|
122
125
|
# assume last 3 letters are type
|
123
126
|
type = k.to_s[-3..-1].to_sym
|
@@ -151,8 +154,16 @@ module Aspera
|
|
151
154
|
return DataRepository.instance.item(:uuid)
|
152
155
|
end
|
153
156
|
|
154
|
-
|
155
|
-
|
157
|
+
# get paths of SSH keys to use for ascp client
|
158
|
+
# @param types [Symbol] types to use
|
159
|
+
def aspera_token_ssh_key_paths(types)
|
160
|
+
Aspera.assert_values(types, CLIENT_SSH_KEY_OPTIONS)
|
161
|
+
return case types
|
162
|
+
when :dsa_rsa, :rsa
|
163
|
+
types.to_s.split('_').map{|i|Installation.instance.path("ssh_private_#{i}".to_sym)}
|
164
|
+
when :per_client
|
165
|
+
raise 'Not yet implemented'
|
166
|
+
end
|
156
167
|
end
|
157
168
|
|
158
169
|
# use in plugin `config`
|
@@ -169,13 +180,14 @@ module Aspera
|
|
169
180
|
raise "An error occurred when testing #{ascp_filename}: #{cmd_out}" unless $CHILD_STATUS == 0
|
170
181
|
# get version from ascp, only after full extract, as windows requires DLLs (SSL/TLS/etc...)
|
171
182
|
m = cmd_out.match(/ version ([0-9.]+)/)
|
172
|
-
exe_version = m[1] unless m.nil?
|
183
|
+
exe_version = m[1].gsub(/\.$/, '') unless m.nil?
|
173
184
|
return exe_version
|
174
185
|
end
|
175
186
|
|
176
|
-
def
|
187
|
+
def ascp_pvcl_info
|
188
|
+
data = {}
|
177
189
|
# read PATHs from ascp directly, and pvcl modules as well
|
178
|
-
Open3.popen3(
|
190
|
+
Open3.popen3(ascp_path, '-DDL-') do |_stdin, _stdout, stderr, thread|
|
179
191
|
last_line = ''
|
180
192
|
while (line = stderr.gets)
|
181
193
|
line.chomp!
|
@@ -194,32 +206,32 @@ module Aspera
|
|
194
206
|
data['product_name'] = Regexp.last_match(1)
|
195
207
|
data['product_version'] = Regexp.last_match(2)
|
196
208
|
when /^LOG Initializing FASP version ([^,]+),/
|
197
|
-
data['
|
209
|
+
data['sdk_ascp_version'] = Regexp.last_match(1)
|
198
210
|
end
|
199
211
|
end
|
200
212
|
if !thread.value.exitstatus.eql?(1) && !data.key?('root')
|
201
213
|
raise last_line
|
202
214
|
end
|
203
215
|
end
|
216
|
+
return data
|
204
217
|
end
|
205
218
|
|
206
219
|
# extract some stings from ascp binary
|
207
|
-
def
|
208
|
-
|
209
|
-
File.binread(
|
220
|
+
def ascp_ssl_info
|
221
|
+
data = {}
|
222
|
+
File.binread(ascp_path).scan(/[\x20-\x7E]{10,}/) do |bin_string|
|
210
223
|
if (m = bin_string.match(/OPENSSLDIR.*"(.*)"/))
|
211
224
|
data['openssldir'] = m[1]
|
212
225
|
elsif (m = bin_string.match(/OpenSSL (\d[^ -]+)/))
|
213
226
|
data['openssl_version'] = m[1]
|
214
227
|
end
|
215
|
-
end if File.file?(
|
228
|
+
end if File.file?(ascp_path)
|
229
|
+
return data
|
216
230
|
end
|
217
231
|
|
218
232
|
def ascp_info
|
219
|
-
|
220
|
-
|
221
|
-
ascp_add_openssl(data)
|
222
|
-
return data
|
233
|
+
files = file_paths
|
234
|
+
return files.merge(ascp_pvcl_info).merge(ascp_ssl_info)
|
223
235
|
end
|
224
236
|
|
225
237
|
# download aspera SDK or use local file
|
@@ -263,19 +275,22 @@ module Aspera
|
|
263
275
|
# ensure license file are generated so that ascp invocation for version works
|
264
276
|
path(:aspera_license)
|
265
277
|
path(:aspera_conf)
|
266
|
-
|
267
|
-
|
268
|
-
raise "No #{
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
278
|
+
sdk_ascp_file = Products.ascp_filename
|
279
|
+
sdk_ascp_path = File.join(sdk_folder, sdk_ascp_file)
|
280
|
+
raise "No #{sdk_ascp_file} found in SDK archive" unless File.exist?(sdk_ascp_path)
|
281
|
+
EXE_FILES.each do |exe_sym|
|
282
|
+
exe_path = sdk_ascp_path.gsub('ascp', exe_sym.to_s)
|
283
|
+
Environment.restrict_file_access(exe_path, mode: 0o755) if File.exist?(exe_path)
|
284
|
+
end
|
285
|
+
sdk_ascp_version = get_ascp_version(sdk_ascp_path)
|
286
|
+
sdk_daemon_path = transferd_filepath
|
287
|
+
Log.log.warn{"No #{sdk_daemon_path} in SDK archive"} unless File.exist?(sdk_daemon_path)
|
288
|
+
Environment.restrict_file_access(sdk_daemon_path, mode: 0o755) if File.exist?(sdk_daemon_path)
|
289
|
+
transferd_version = get_exe_version(sdk_daemon_path, 'version')
|
290
|
+
sdk_name = 'IBM Aspera Transfer SDK'
|
291
|
+
sdk_version = transferd_version || sdk_ascp_version
|
292
|
+
File.write(File.join(sdk_folder, Products::INFO_META_FILE), "<product><name>#{sdk_name}</name><version>#{sdk_version}</version></product>")
|
293
|
+
return sdk_name, sdk_version
|
279
294
|
end
|
280
295
|
|
281
296
|
private
|
@@ -188,7 +188,7 @@ module Aspera
|
|
188
188
|
# empty line is separator to end event information
|
189
189
|
MGT_FRAME_SEPARATOR = ''
|
190
190
|
# fields description for JSON generation
|
191
|
-
#
|
191
|
+
# cspell: disable
|
192
192
|
INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
|
193
193
|
DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
|
194
194
|
ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
|
@@ -219,6 +219,9 @@ module Aspera
|
|
219
219
|
end
|
220
220
|
attr_reader :last_event
|
221
221
|
|
222
|
+
# process line of mgt port event
|
223
|
+
# @param line [String] line of mgt port event
|
224
|
+
# @return [Hash] event hash or nil if event is not yet complete
|
222
225
|
def process_line(line)
|
223
226
|
# Log.log.debug{"line=[#{line}]"}
|
224
227
|
case line
|
data/lib/aspera/ascp/products.rb
CHANGED
@@ -126,7 +126,7 @@ module Aspera
|
|
126
126
|
|
127
127
|
# filename for ascp with optional extension (Windows)
|
128
128
|
def ascp_filename
|
129
|
-
return
|
129
|
+
return "ascp#{Environment.exe_extension}"
|
130
130
|
end
|
131
131
|
|
132
132
|
# @return folder paths for specified applications
|
@@ -150,12 +150,6 @@ module Aspera
|
|
150
150
|
end
|
151
151
|
raise "no connect uri file found in #{folder}"
|
152
152
|
end
|
153
|
-
|
154
|
-
# @ return path to configuration file of aspera CLI
|
155
|
-
# def cli_conf_file
|
156
|
-
# connect = folders(PRODUCT_CLI_V1)
|
157
|
-
# return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
|
158
|
-
# end
|
159
153
|
end
|
160
154
|
end
|
161
155
|
end
|
data/lib/aspera/cli/formatter.rb
CHANGED
@@ -98,11 +98,12 @@ module Aspera
|
|
98
98
|
CSV_RECORD_SEPARATOR = "\n"
|
99
99
|
CSV_FIELD_SEPARATOR = ','
|
100
100
|
# supported output formats
|
101
|
-
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
|
101
|
+
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table multi csv image].freeze
|
102
102
|
# user output levels
|
103
103
|
DISPLAY_LEVELS = %i[info data error].freeze
|
104
|
+
FIELD_VALUE_HEADINGS = %i[key value].freeze
|
104
105
|
|
105
|
-
private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
|
106
|
+
private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR, :FIELD_VALUE_HEADINGS
|
106
107
|
# prefix to display error messages in user messages (terminal)
|
107
108
|
ERROR_FLASH = 'ERROR:'.bg_red.gray.blink.freeze
|
108
109
|
WARNING_FLASH = 'WARNING:'.bg_brown.black.blink.freeze
|
@@ -116,7 +117,7 @@ module Aspera
|
|
116
117
|
|
117
118
|
def tick(yes)
|
118
119
|
result =
|
119
|
-
if Environment.terminal_supports_unicode?
|
120
|
+
if Environment.instance.terminal_supports_unicode?
|
120
121
|
if yes
|
121
122
|
"\u2713"
|
122
123
|
else
|
@@ -150,16 +151,9 @@ module Aspera
|
|
150
151
|
end
|
151
152
|
|
152
153
|
# Highlight special values
|
153
|
-
def special_format(what
|
154
|
-
result =
|
155
|
-
|
156
|
-
result = if %w[null empty].any?{|s|what.include?(s)}
|
157
|
-
result.dim
|
158
|
-
else
|
159
|
-
result.reverse_color
|
160
|
-
end
|
161
|
-
end
|
162
|
-
return result
|
154
|
+
def special_format(what)
|
155
|
+
result = "<#{what}>"
|
156
|
+
return %w[null empty].any?{|s|what.include?(s)} ? result.dim : result.reverse_color
|
163
157
|
end
|
164
158
|
|
165
159
|
# call this after REST calls if several api calls are expected
|
@@ -198,7 +192,7 @@ module Aspera
|
|
198
192
|
end
|
199
193
|
|
200
194
|
def declare_options(options)
|
201
|
-
default_table_style = if Environment.terminal_supports_unicode?
|
195
|
+
default_table_style = if Environment.instance.terminal_supports_unicode?
|
202
196
|
{border: :unicode_round}
|
203
197
|
else
|
204
198
|
{}
|
@@ -326,16 +320,16 @@ module Aspera
|
|
326
320
|
display_message(:info, special_format('empty')) if @options[:format].eql?(:table)
|
327
321
|
return
|
328
322
|
end
|
323
|
+
# if table has only one element, and only one field, display the value
|
329
324
|
if object_array.length == 1 && fields.length == 1
|
330
325
|
display_message(:data, object_array.first[fields.first])
|
331
326
|
return
|
332
327
|
end
|
333
328
|
# Special case if only one row (it could be object_list or single_object)
|
334
329
|
if @options[:transpose_single] && object_array.length == 1
|
335
|
-
new_columns = %i[key value]
|
336
330
|
single = object_array.first
|
337
|
-
object_array = fields.map { |i|
|
338
|
-
fields =
|
331
|
+
object_array = fields.map { |i| FIELD_VALUE_HEADINGS.zip([i, single[i]]).to_h }
|
332
|
+
fields = FIELD_VALUE_HEADINGS
|
339
333
|
end
|
340
334
|
Log.log.debug{Log.dump(:object_array, object_array)}
|
341
335
|
# convert data to string, and keep only display fields
|
@@ -348,8 +342,18 @@ module Aspera
|
|
348
342
|
headings: fields,
|
349
343
|
rows: final_table_rows,
|
350
344
|
style: @options[:table_style]&.symbolize_keys))
|
345
|
+
when :multi
|
346
|
+
final_table_rows.each do |row|
|
347
|
+
Log.log.debug{Log.dump(:row, row)}
|
348
|
+
display_message(:data, Terminal::Table.new(
|
349
|
+
headings: FIELD_VALUE_HEADINGS,
|
350
|
+
rows: fields.zip(row),
|
351
|
+
style: @options[:table_style]&.symbolize_keys))
|
352
|
+
end
|
351
353
|
when :csv
|
352
354
|
display_message(:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
|
355
|
+
else
|
356
|
+
raise "not expected: #{@options[:format]}"
|
353
357
|
end
|
354
358
|
end
|
355
359
|
|
@@ -420,7 +424,7 @@ module Aspera
|
|
420
424
|
end
|
421
425
|
raise "not url: #{url.class} #{url}" unless url.is_a?(String)
|
422
426
|
display_message(:data, status_image(url))
|
423
|
-
when :table, :csv
|
427
|
+
when :table, :csv, :multi
|
424
428
|
case type
|
425
429
|
when :config_over
|
426
430
|
display_table(Flattener.new(self).config_over(data), CONF_OVERVIEW_KEYS)
|
@@ -452,6 +456,8 @@ module Aspera
|
|
452
456
|
else
|
453
457
|
raise "unknown data type: #{type}"
|
454
458
|
end
|
459
|
+
else
|
460
|
+
raise "not expected: #{@options[:format]}"
|
455
461
|
end
|
456
462
|
end
|
457
463
|
end
|
data/lib/aspera/cli/manager.rb
CHANGED
@@ -20,7 +20,7 @@ module Aspera
|
|
20
20
|
@method = method_name
|
21
21
|
@option_name = option_name
|
22
22
|
@has_writer = @object.respond_to?(writer_method)
|
23
|
-
Log.log.
|
23
|
+
Log.log.trace1{"AttrAccessor: #{@option_name}: #{@object.class}.#{@method}: writer=#{@has_writer}"}
|
24
24
|
Aspera.assert(@object.respond_to?(@method)) {"#{object} does not respond to #{method_name}"}
|
25
25
|
end
|
26
26
|
|
@@ -328,7 +328,7 @@ module Aspera
|
|
328
328
|
if opt[:read_write].eql?(:accessor)
|
329
329
|
Aspera.assert_type(handler, Hash)
|
330
330
|
Aspera.assert(handler.keys.sort.eql?(%i[m o]))
|
331
|
-
Log.log.
|
331
|
+
Log.log.trace1{"set attr obj: #{option_symbol} (#{handler[:o]},#{handler[:m]})"}
|
332
332
|
opt[:accessor] = AttrAccessor.new(handler[:o], handler[:m], option_symbol)
|
333
333
|
end
|
334
334
|
set_option(option_symbol, default, where: 'default') unless default.nil?
|
@@ -372,7 +372,7 @@ module Aspera
|
|
372
372
|
@parser.on(*on_args, &block)
|
373
373
|
else Aspera.error_unexpected_value(values)
|
374
374
|
end
|
375
|
-
Log.log.
|
375
|
+
Log.log.trace1{"on_args=#{on_args}"}
|
376
376
|
end
|
377
377
|
|
378
378
|
# Adds each of the keys of specified hash as an option
|
@@ -435,7 +435,7 @@ module Aspera
|
|
435
435
|
|
436
436
|
# removes already known options from the list
|
437
437
|
def parse_options!
|
438
|
-
Log.log.
|
438
|
+
Log.log.trace1('parse_options!'.red)
|
439
439
|
# first conf file, then env var
|
440
440
|
consume_option_pairs(@option_pairs_batch, 'set')
|
441
441
|
consume_option_pairs(@option_pairs_env, 'env')
|
@@ -443,16 +443,16 @@ module Aspera
|
|
443
443
|
unknown_options = []
|
444
444
|
begin
|
445
445
|
# remove known options one by one, exception if unknown
|
446
|
-
Log.log.
|
446
|
+
Log.log.trace1('before parse'.red)
|
447
447
|
@parser.parse!(@unprocessed_cmd_line_options)
|
448
|
-
Log.log.
|
448
|
+
Log.log.trace1('After parse'.red)
|
449
449
|
rescue OptionParser::InvalidOption => e
|
450
|
-
Log.log.
|
450
|
+
Log.log.trace1{"InvalidOption #{e}".red}
|
451
451
|
# save for later processing
|
452
452
|
unknown_options.push(e.args.first)
|
453
453
|
retry
|
454
454
|
end
|
455
|
-
Log.log.
|
455
|
+
Log.log.trace1{"remains: #{unknown_options}"}
|
456
456
|
# set unprocessed options for next time
|
457
457
|
@unprocessed_cmd_line_options = unknown_options
|
458
458
|
end
|
@@ -538,7 +538,7 @@ module Aspera
|
|
538
538
|
# @param unprocessed_options [Array] list of options to apply (key_sym,value)
|
539
539
|
# @param where [String] where the options come from
|
540
540
|
def consume_option_pairs(unprocessed_options, where)
|
541
|
-
Log.log.
|
541
|
+
Log.log.trace1{"consume_option_pairs: #{where}"}
|
542
542
|
options_to_set = {}
|
543
543
|
unprocessed_options.each do |k, v|
|
544
544
|
if @declared_options.key?(k)
|
@@ -548,7 +548,7 @@ module Aspera
|
|
548
548
|
end
|
549
549
|
options_to_set[k] = v
|
550
550
|
else
|
551
|
-
Log.log.
|
551
|
+
Log.log.trace1{"unprocessed: #{k}: #{v}"}
|
552
552
|
end
|
553
553
|
end
|
554
554
|
options_to_set.each do |k, v|
|
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -5,7 +5,7 @@ require 'aspera/assert'
|
|
5
5
|
|
6
6
|
module Aspera
|
7
7
|
module Cli
|
8
|
-
#
|
8
|
+
# Base class for plugins
|
9
9
|
class Plugin
|
10
10
|
# operations without id
|
11
11
|
GLOBAL_OPS = %i[create list].freeze
|
@@ -53,8 +53,8 @@ module Aspera
|
|
53
53
|
options.parser.separator('OPTIONS:')
|
54
54
|
end
|
55
55
|
|
56
|
+
# @return a hash of instance variables
|
56
57
|
def init_params
|
57
|
-
# return a hash of instance variables
|
58
58
|
INIT_PARAMS.map{|p| [p, instance_variable_get("@#{p}".to_sym)]}.to_h
|
59
59
|
end
|
60
60
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'singleton'
|
4
4
|
module Aspera
|
5
5
|
module Cli
|
6
|
-
#
|
6
|
+
# Instantiate plugin from well-known locations
|
7
7
|
class PluginFactory
|
8
8
|
include Singleton
|
9
9
|
|
@@ -19,14 +19,17 @@ module Aspera
|
|
19
19
|
@plugins = {}
|
20
20
|
end
|
21
21
|
|
22
|
+
# @return list of registered plugins
|
22
23
|
def plugin_list
|
23
24
|
@plugins.keys
|
24
25
|
end
|
25
26
|
|
27
|
+
# @return path to source file of plugin
|
26
28
|
def plugin_source(plugin_name_sym)
|
27
29
|
@plugins[plugin_name_sym][:source]
|
28
30
|
end
|
29
31
|
|
32
|
+
# add a folder to the list of folders to look for plugins
|
30
33
|
def add_lookup_folder(folder)
|
31
34
|
@lookup_folders.unshift(folder)
|
32
35
|
end
|
@@ -43,6 +46,7 @@ module Aspera
|
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
49
|
+
# @return Class object for plugin
|
46
50
|
def plugin_class(plugin_name_sym)
|
47
51
|
raise "ERROR: plugin not found: #{plugin_name_sym}" unless @plugins.key?(plugin_name_sym)
|
48
52
|
require @plugins[plugin_name_sym][:require_stanza]
|
@@ -50,6 +54,9 @@ module Aspera
|
|
50
54
|
return Object.const_get("#{Module.nesting[1]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
|
51
55
|
end
|
52
56
|
|
57
|
+
# Create specified plugin
|
58
|
+
# @param plugin_name_sym [Symbol] name of plugin
|
59
|
+
# @param args [Hash] arguments to pass to plugin constructor
|
53
60
|
def create(plugin_name_sym, **args)
|
54
61
|
# TODO: check that ancestor is Plugin?
|
55
62
|
plugin_class(plugin_name_sym).new(**args)
|
@@ -57,6 +64,8 @@ module Aspera
|
|
57
64
|
|
58
65
|
private
|
59
66
|
|
67
|
+
# add plugin information to list
|
68
|
+
# @param path [String] path to plugin source file
|
60
69
|
def add_plugin_info(path)
|
61
70
|
raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
|
62
71
|
plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
|
@@ -281,6 +281,8 @@ module Aspera
|
|
281
281
|
attr_reader :option_ignore_cert_host_port, :progress_bar
|
282
282
|
|
283
283
|
# add files, folders or default locations to the certificate store
|
284
|
+
# @param path_list [Array<String>] list of paths to add
|
285
|
+
# @return the list of paths
|
284
286
|
def trusted_cert_locations=(path_list)
|
285
287
|
path_list = [path_list] unless path_list.is_a?(Array)
|
286
288
|
Aspera.assert_type(path_list, Array){'cert locations'}
|
@@ -296,10 +298,10 @@ module Aspera
|
|
296
298
|
Log.log.debug{"Adding cert location: #{path}"}
|
297
299
|
if path.eql?(SpecialValues::DEF)
|
298
300
|
@certificate_store.set_default_paths
|
299
|
-
paths_to_add = [
|
300
|
-
|
301
|
-
|
302
|
-
|
301
|
+
paths_to_add = [OpenSSL::X509::DEFAULT_CERT_DIR]
|
302
|
+
# JRuby cert file seems not to be PEM
|
303
|
+
paths_to_add.push(OpenSSL::X509::DEFAULT_CERT_FILE) unless defined?(JRUBY_VERSION)
|
304
|
+
paths_to_add.select!{|f|File.exist?(f)}
|
303
305
|
elsif File.file?(path)
|
304
306
|
@certificate_store.add_file(path)
|
305
307
|
elsif File.directory?(path)
|
@@ -578,7 +580,7 @@ module Aspera
|
|
578
580
|
@config_checksum_on_disk = config_checksum
|
579
581
|
end
|
580
582
|
files_to_copy = []
|
581
|
-
Log.log.
|
583
|
+
Log.log.trace1{Log.dump('Available_presets', @config_presets)}
|
582
584
|
Aspera.assert_type(@config_presets, Hash){'config file YAML'}
|
583
585
|
# check there is at least the config section
|
584
586
|
Aspera.assert(@config_presets.key?(CONF_PRESET_CONFIG)){"Cannot find key: #{CONF_PRESET_CONFIG}"}
|
@@ -699,8 +701,7 @@ module Aspera
|
|
699
701
|
return execute_connect_action
|
700
702
|
when :use
|
701
703
|
ascp_path = options.get_next_argument('path to ascp')
|
702
|
-
|
703
|
-
formatter.display_status("ascp version: #{ascp_version}")
|
704
|
+
formatter.display_status("ascp version: #{Ascp::Installation.instance.get_ascp_version(ascp_path)}")
|
704
705
|
set_global_default(:ascp_path, ascp_path)
|
705
706
|
return Main.result_nothing
|
706
707
|
when :show
|
@@ -729,8 +730,8 @@ module Aspera
|
|
729
730
|
when :install
|
730
731
|
# reset to default location, if older default was used
|
731
732
|
Ascp::Installation.instance.sdk_folder = self.class.default_app_main_folder(app_name: APP_NAME_SDK) if @sdk_default_location
|
732
|
-
v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
|
733
|
-
return Main.result_status("Installed version #{v}")
|
733
|
+
n, v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
|
734
|
+
return Main.result_status("Installed #{n} version #{v}")
|
734
735
|
when :spec
|
735
736
|
return {
|
736
737
|
type: :object_list,
|
@@ -871,7 +872,9 @@ module Aspera
|
|
871
872
|
check_update
|
872
873
|
initdemo
|
873
874
|
vault
|
874
|
-
throw
|
875
|
+
throw
|
876
|
+
platform
|
877
|
+
].freeze
|
875
878
|
|
876
879
|
# Main action procedure for plugin
|
877
880
|
def execute_action
|
@@ -1015,6 +1018,8 @@ module Aspera
|
|
1015
1018
|
exception_class = Object.const_get(exception_class_name)
|
1016
1019
|
Aspera.assert(exception_class <= Exception){"#{exception_class} is not an exception: #{exception_class.class}"}
|
1017
1020
|
raise exception_class, exception_text
|
1021
|
+
when :platform
|
1022
|
+
return Main.result_status(Environment.architecture)
|
1018
1023
|
else Aspera.error_unreachable_line
|
1019
1024
|
end
|
1020
1025
|
end
|
@@ -531,16 +531,17 @@ module Aspera
|
|
531
531
|
# if a single file: split into folder and path
|
532
532
|
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
533
533
|
if source_paths.empty?
|
534
|
+
# get precise info in this element
|
534
535
|
file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
535
536
|
case file_info['type']
|
536
537
|
when 'file'
|
537
538
|
# if the single source is a file, we need to split into folder path and filename
|
538
539
|
src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
|
539
|
-
# filename is the last one
|
540
|
+
# filename is the last one, source folder is what remains
|
540
541
|
source_paths = [{'source' => src_dir_elements.pop}]
|
541
|
-
#
|
542
|
+
# add trailing / so that link is resolved, if it's a shared folder
|
543
|
+
src_dir_elements.push('')
|
542
544
|
source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
|
543
|
-
# TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
|
544
545
|
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
545
546
|
when 'link', 'folder'
|
546
547
|
# single source is 'folder' or 'link'
|
@@ -176,7 +176,7 @@ module Aspera
|
|
176
176
|
def execute_transfer(command, transfer_spec)
|
177
177
|
case command
|
178
178
|
when :upload, :download
|
179
|
-
Transfer::Spec.
|
179
|
+
transfer_spec['direction'] = Transfer::Spec.transfer_type_to_direction(command)
|
180
180
|
return Main.result_transfer(transfer.start(transfer_spec))
|
181
181
|
when :sync
|
182
182
|
# lets ignore the arguments provided by execute_sync_action, we just give the transfer spec
|
@@ -7,7 +7,10 @@ module Aspera
|
|
7
7
|
module Plugins
|
8
8
|
# Plugin for Aspera Shares v1
|
9
9
|
class Shares < Cli::BasicAuthPlugin
|
10
|
-
|
10
|
+
# path for node API after base url
|
11
|
+
NODE_API_PATH = 'node_api'
|
12
|
+
# path for node admin after base url
|
13
|
+
ADMIN_API_PATH = 'api/v1'
|
11
14
|
class << self
|
12
15
|
def detect(address_or_url)
|
13
16
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
@@ -16,7 +19,7 @@ module Aspera
|
|
16
19
|
begin
|
17
20
|
# shall fail: shares requires auth, but we check error message
|
18
21
|
# TODO: use ping instead ?
|
19
|
-
api.read("#{
|
22
|
+
api.read("#{NODE_API_PATH}/app")
|
20
23
|
rescue RestCallError => e
|
21
24
|
if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
22
25
|
found = true
|
@@ -65,7 +68,7 @@ module Aspera
|
|
65
68
|
nagios = Nagios.new
|
66
69
|
begin
|
67
70
|
res = Rest
|
68
|
-
.new(base_url: "#{options.get_option(:url, mandatory: true)}/#{
|
71
|
+
.new(base_url: "#{options.get_option(:url, mandatory: true)}/#{NODE_API_PATH}")
|
69
72
|
.call(
|
70
73
|
operation: 'GET',
|
71
74
|
subpath: 'ping',
|
@@ -77,13 +80,13 @@ module Aspera
|
|
77
80
|
end
|
78
81
|
return nagios.result
|
79
82
|
when :repository, :files
|
80
|
-
api_shares_node = basic_auth_api(
|
83
|
+
api_shares_node = basic_auth_api(NODE_API_PATH)
|
81
84
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
82
85
|
return Node
|
83
86
|
.new(**init_params, api: api_shares_node)
|
84
87
|
.execute_action(repo_command)
|
85
88
|
when :admin
|
86
|
-
api_shares_admin = basic_auth_api(
|
89
|
+
api_shares_admin = basic_auth_api(ADMIN_API_PATH)
|
87
90
|
admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
|
88
91
|
case admin_command
|
89
92
|
when :node
|
@@ -92,8 +95,9 @@ module Aspera
|
|
92
95
|
share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
|
93
96
|
case share_command
|
94
97
|
when *Plugin::ALL_OPS
|
95
|
-
return entity_command(
|
96
|
-
|
98
|
+
return entity_command(
|
99
|
+
share_command, api_shares_admin, 'data/shares',
|
100
|
+
display_fields: %w[id name node_id directory percent_free])
|
97
101
|
when :user_permissions, :group_permissions
|
98
102
|
share_id = instance_identifier
|
99
103
|
return entity_action(api_shares_admin, "data/shares/#{share_id}/#{share_command}")
|