aspera-cli 4.18.1 → 4.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +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}")
|