aspera-cli 4.22.0 → 4.23.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 +374 -364
- data/README.md +255 -155
- data/lib/aspera/agent/direct.rb +1 -1
- data/lib/aspera/api/aoc.rb +9 -12
- data/lib/aspera/api/httpgw.rb +8 -4
- data/lib/aspera/ascmd.rb +14 -6
- data/lib/aspera/ascp/installation.rb +6 -3
- data/lib/aspera/assert.rb +3 -3
- data/lib/aspera/cli/hints.rb +9 -1
- data/lib/aspera/cli/main.rb +1 -1
- data/lib/aspera/cli/manager.rb +1 -1
- data/lib/aspera/cli/plugin.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +33 -23
- data/lib/aspera/cli/plugins/config.rb +20 -15
- data/lib/aspera/cli/plugins/node.rb +96 -92
- data/lib/aspera/cli/plugins/server.rb +1 -0
- data/lib/aspera/cli/transfer_agent.rb +7 -11
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +1 -0
- data/lib/aspera/log.rb +1 -0
- data/lib/aspera/oauth/base.rb +2 -0
- data/lib/aspera/oauth/factory.rb +1 -0
- data/lib/aspera/preview/file_types.rb +40 -33
- data/lib/aspera/preview/generator.rb +1 -1
- data/lib/aspera/products/connect.rb +1 -0
- data/lib/aspera/rest.rb +18 -7
- data/lib/aspera/rest_error_analyzer.rb +1 -0
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/temp_file_manager.rb +1 -0
- data/lib/aspera/timer_limiter.rb +7 -5
- data/lib/aspera/transfer/async_conf.schema.yaml +716 -0
- data/lib/aspera/transfer/sync.rb +14 -4
- data/lib/aspera/transfer/sync_instance.schema.yaml +7 -0
- data/lib/aspera/transfer/sync_session.schema.yaml +7 -0
- data.tar.gz.sig +0 -0
- metadata +3 -5
- metadata.gz.sig +0 -0
- data/examples/dascli +0 -30
- data/examples/get_proto_file.rb +0 -8
- data/examples/proxy.pac +0 -60
data/lib/aspera/agent/direct.rb
CHANGED
@@ -325,7 +325,7 @@ module Aspera
|
|
325
325
|
session.delete(:io)
|
326
326
|
# if command was successfully started, check its status
|
327
327
|
unless command_pid.nil?
|
328
|
-
Process.kill(:INT, command_pid) if @monitor
|
328
|
+
Process.kill(:INT, command_pid) if @monitor && !Environment.os.eql?(Environment::OS_WINDOWS)
|
329
329
|
# collect process exit status or wait for termination
|
330
330
|
_, status = Process.wait2(command_pid)
|
331
331
|
# process stderr of ascp
|
data/lib/aspera/api/aoc.rb
CHANGED
@@ -34,6 +34,8 @@ module Aspera
|
|
34
34
|
# types of events for shared folder creation
|
35
35
|
# Node events: permission.created permission.modified permission.deleted
|
36
36
|
PERMISSIONS_CREATED = ['permission.created'].freeze
|
37
|
+
# Special name when creating workspace shared folders
|
38
|
+
ID_AK_ADMIN = 'ASPERA_ACCESS_KEY_ADMIN'
|
37
39
|
|
38
40
|
private_constant :MAX_AOC_URL_REDIRECT,
|
39
41
|
:CLIENT_ID_PREFIX,
|
@@ -43,7 +45,8 @@ module Aspera
|
|
43
45
|
:JWT_AUDIENCE,
|
44
46
|
:OAUTH_API_SUBPATH,
|
45
47
|
:USER_INFO_FIELDS_MIN,
|
46
|
-
:PERMISSIONS_CREATED
|
48
|
+
:PERMISSIONS_CREATED,
|
49
|
+
:ID_AK_ADMIN
|
47
50
|
|
48
51
|
# various API scopes supported
|
49
52
|
SCOPE_FILES_SELF = 'self'
|
@@ -546,17 +549,12 @@ module Aspera
|
|
546
549
|
transfer_spec['tags'][Transfer::Spec::TAG_RESERVED]['app'] = app_info[:app]
|
547
550
|
end
|
548
551
|
|
549
|
-
ID_AK_ADMIN = 'ASPERA_ACCESS_KEY_ADMIN'
|
550
552
|
# Callback from Plugins::Node
|
551
553
|
# add application specific tags to permissions creation
|
552
554
|
# @param perm_data [Hash] parameters for creating permissions
|
553
555
|
# @param app_info [Hash] application information
|
554
556
|
def permissions_set_create_params(perm_data:, app_info:)
|
555
|
-
# workspace shared folder:
|
556
|
-
# access_id = "#{ID_AK_ADMIN}_WS_#{app_info[:workspace_id]}"
|
557
557
|
defaults = {
|
558
|
-
# 'access_type' => 'user', # mandatory: user or group
|
559
|
-
# 'access_id' => access_id, # id of user or group or special
|
560
558
|
'tags' => {
|
561
559
|
Transfer::Spec::TAG_RESERVED => {
|
562
560
|
'files' => {
|
@@ -567,8 +565,6 @@ module Aspera
|
|
567
565
|
'shared_by_user_id' => current_user_info['id'],
|
568
566
|
'shared_by_name' => current_user_info['name'],
|
569
567
|
'shared_by_email' => current_user_info['email'],
|
570
|
-
# 'shared_with_name' => access_id,
|
571
|
-
# 'share_as' => new_name_for_folder,
|
572
568
|
'access_key' => app_info[:node_info]['access_key'],
|
573
569
|
'node' => app_info[:node_info]['name']
|
574
570
|
}
|
@@ -578,19 +574,20 @@ module Aspera
|
|
578
574
|
}
|
579
575
|
perm_data.deep_merge!(defaults)
|
580
576
|
tag_workspace = perm_data['tags'][Transfer::Spec::TAG_RESERVED]['files']['workspace']
|
581
|
-
|
577
|
+
shared_with = perm_data.delete('with')
|
578
|
+
case shared_with
|
582
579
|
when NilClass
|
583
580
|
when ''
|
581
|
+
# workspace shared folder
|
584
582
|
perm_data['access_type'] = 'user'
|
585
583
|
perm_data['access_id'] = "#{ID_AK_ADMIN}_WS_#{app_info[:workspace_id]}"
|
586
584
|
tag_workspace['shared_with_name'] = perm_data['access_id']
|
587
585
|
else
|
588
|
-
entity_info = lookup_by_name('contacts',
|
586
|
+
entity_info = lookup_by_name('contacts', shared_with, query: {'current_workspace_id' => app_info[:workspace_id]})
|
589
587
|
perm_data['access_type'] = entity_info['source_type']
|
590
588
|
perm_data['access_id'] = entity_info['source_id']
|
591
|
-
tag_workspace['shared_with_name'] = entity_info['email']
|
589
|
+
tag_workspace['shared_with_name'] = entity_info['email'] # TODO: check that ???
|
592
590
|
end
|
593
|
-
perm_data.delete('with')
|
594
591
|
if perm_data.key?('as')
|
595
592
|
tag_workspace['share_as'] = perm_data['as']
|
596
593
|
perm_data.delete('as')
|
data/lib/aspera/api/httpgw.rb
CHANGED
@@ -244,18 +244,22 @@ module Aspera
|
|
244
244
|
end
|
245
245
|
|
246
246
|
def download(transfer_spec)
|
247
|
-
transfer_spec['zip_required'] ||= false
|
248
247
|
transfer_spec['source_root'] ||= '/'
|
248
|
+
default_file_name = transfer_spec['paths'].first['source']
|
249
|
+
source_is_folder = %w[. /].include?(default_file_name)
|
250
|
+
default_file_name = 'http_download' if source_is_folder
|
251
|
+
transfer_spec['zip_required'] ||= source_is_folder || transfer_spec['paths'].length > 1
|
249
252
|
# is normally provided by application, like package name
|
250
253
|
if !transfer_spec.key?('download_name')
|
251
254
|
# by default it is the name of first file
|
252
|
-
download_name = File.basename(
|
253
|
-
#
|
255
|
+
download_name = File.basename(default_file_name, '.*')
|
256
|
+
# add indication of number of files if there is more than one
|
254
257
|
if transfer_spec['paths'].length > 1
|
255
258
|
download_name += " #{transfer_spec['paths'].length} Files"
|
256
259
|
end
|
257
260
|
transfer_spec['download_name'] = download_name
|
258
261
|
end
|
262
|
+
# start transfer session on httpgw
|
259
263
|
creation = create('download', {'transfer_spec' => transfer_spec})
|
260
264
|
transfer_uuid = creation['url'].split('/').last
|
261
265
|
file_name =
|
@@ -264,7 +268,7 @@ module Aspera
|
|
264
268
|
transfer_spec['download_name'] + '.zip'
|
265
269
|
else
|
266
270
|
# it is a plain file if we don't require zip and there is only one file
|
267
|
-
File.basename(
|
271
|
+
File.basename(default_file_name)
|
268
272
|
end
|
269
273
|
file_path = File.join(transfer_spec['destination_root'], file_name)
|
270
274
|
call(operation: 'GET', subpath: "download/#{transfer_uuid}", save_to_file: file_path)
|
data/lib/aspera/ascmd.rb
CHANGED
@@ -10,7 +10,7 @@ module Aspera
|
|
10
10
|
# execute: "ascmd -h" to get syntax
|
11
11
|
# Note: "ls" can take filters: as_ls -f *.txt -f *.bin /
|
12
12
|
class AsCmd
|
13
|
-
# number of arguments for each operation
|
13
|
+
# number of arguments for each operation (to allow splitting into batches)
|
14
14
|
OPS_ARGS = {
|
15
15
|
cp: 2,
|
16
16
|
df: 0,
|
@@ -23,11 +23,11 @@ module Aspera
|
|
23
23
|
rm: 1
|
24
24
|
}.freeze
|
25
25
|
|
26
|
-
#
|
27
|
-
#
|
26
|
+
# Protocol is based on Type-Length-Value
|
27
|
+
# Type start at one, but array index start at zero
|
28
28
|
ENUM_START = 1
|
29
29
|
|
30
|
-
#
|
30
|
+
# Description of result structures (see ascmdtypes.h).
|
31
31
|
# Base types are big endian
|
32
32
|
# key = name of type
|
33
33
|
# index in array `fields` is the type (minus ENUM_START)
|
@@ -79,17 +79,25 @@ module Aspera
|
|
79
79
|
end
|
80
80
|
|
81
81
|
# execute an "as" command on a remote server
|
82
|
+
# Version 2 allows use of reverse proxy with multiple addresses.
|
82
83
|
# @param [Symbol] one of OPERATIONS
|
83
84
|
# @param [Array] parameters for "as" command
|
84
85
|
# @return result of command, type depends on command (bool, array, hash)
|
85
|
-
def execute_single(action_sym, arguments)
|
86
|
+
def execute_single(action_sym, arguments, version: 1, host: nil)
|
86
87
|
arguments = [] if arguments.nil?
|
87
88
|
Log.log.debug{"execute_single:#{action_sym}:#{arguments}"}
|
88
89
|
Aspera.assert_type(action_sym, Symbol)
|
89
90
|
Aspera.assert_type(arguments, Array)
|
90
91
|
Aspera.assert(arguments.all?(String), 'arguments must be strings')
|
92
|
+
remote_cmd = 'ascmd'
|
91
93
|
# lines of commands (String's)
|
92
94
|
command_lines = []
|
95
|
+
if version.eql?(2)
|
96
|
+
cmd = "as_session_init --protocol=#{version}"
|
97
|
+
cmd += " --host=#{host}" if host
|
98
|
+
command_lines.push(cmd)
|
99
|
+
remote_cmd += ' -V2'
|
100
|
+
end
|
93
101
|
# add "as_" command
|
94
102
|
main_command = "as_#{action_sym}"
|
95
103
|
arg_batches =
|
@@ -114,7 +122,7 @@ module Aspera
|
|
114
122
|
stdin_input = command_lines.join("\n")
|
115
123
|
Log.log.trace1{"execute_single:#{stdin_input}"}
|
116
124
|
# execute, get binary output
|
117
|
-
byte_buffer = @command_executor.execute(
|
125
|
+
byte_buffer = @command_executor.execute(remote_cmd, stdin_input).unpack('C*')
|
118
126
|
raise 'ERROR: empty answer from server' if byte_buffer.empty?
|
119
127
|
# get hash or table result
|
120
128
|
result = self.class.parse(byte_buffer, :result)
|
@@ -32,6 +32,7 @@ module Aspera
|
|
32
32
|
# Installation.instance.ascp_path=""
|
33
33
|
class Installation
|
34
34
|
include Singleton
|
35
|
+
|
35
36
|
DEFAULT_ASPERA_CONF = <<~END_OF_CONFIG_FILE
|
36
37
|
<?xml version='1.0' encoding='UTF-8'?>
|
37
38
|
<CONF version="2">
|
@@ -196,6 +197,8 @@ module Aspera
|
|
196
197
|
last_line = ''
|
197
198
|
while (line = stderr.gets)
|
198
199
|
line.chomp!
|
200
|
+
# skip lines that may have accents
|
201
|
+
next unless line.valid_encoding?
|
199
202
|
last_line = line
|
200
203
|
case line
|
201
204
|
when /^DBG Path ([^ ]+) (dir|file) +: (.*)$/
|
@@ -211,7 +214,7 @@ module Aspera
|
|
211
214
|
data['product_name'] = Regexp.last_match(1)
|
212
215
|
data['product_version'] = Regexp.last_match(2)
|
213
216
|
when /^LOG Initializing FASP version ([^,]+),/
|
214
|
-
data['
|
217
|
+
data['ascp_version'] = Regexp.last_match(1)
|
215
218
|
end
|
216
219
|
end
|
217
220
|
if !thread.value.exitstatus.eql?(1) && !data.key?('root')
|
@@ -226,9 +229,9 @@ module Aspera
|
|
226
229
|
data = {}
|
227
230
|
File.binread(ascp_path).scan(/[\x20-\x7E]{10,}/) do |bin_string|
|
228
231
|
if (m = bin_string.match(/OPENSSLDIR.*"(.*)"/))
|
229
|
-
data['
|
232
|
+
data['ascp_openssl_dir'] = m[1]
|
230
233
|
elsif (m = bin_string.match(/OpenSSL (\d[^ -]+)/))
|
231
|
-
data['
|
234
|
+
data['ascp_openssl_version'] = m[1]
|
232
235
|
end
|
233
236
|
end if File.file?(ascp_path)
|
234
237
|
return data
|
data/lib/aspera/assert.rb
CHANGED
@@ -22,7 +22,7 @@ module Aspera
|
|
22
22
|
# @param value [Object] the value to check
|
23
23
|
# @param type [Class] the expected type
|
24
24
|
def assert_type(value, type, exception_class: AssertError)
|
25
|
-
assert(value.is_a?(type), exception_class: exception_class){"#{
|
25
|
+
assert(value.is_a?(type), exception_class: exception_class){"#{"#{yield}: " if block_given?}expecting #{type}, but have #{value.inspect}"}
|
26
26
|
end
|
27
27
|
|
28
28
|
# assert that value is one of the given values
|
@@ -33,7 +33,7 @@ module Aspera
|
|
33
33
|
assert(values.include?(value), exception_class: exception_class) do
|
34
34
|
val_list = values.inspect
|
35
35
|
val_list = "one of #{val_list}" if values.is_a?(Array)
|
36
|
-
"#{
|
36
|
+
"#{"#{yield}: " if block_given?}expecting #{val_list}, but have #{value.inspect}"
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -47,7 +47,7 @@ module Aspera
|
|
47
47
|
# @param exception_class exception to raise
|
48
48
|
# @param block additional description in front
|
49
49
|
def error_unexpected_value(value, exception_class: InternalError)
|
50
|
-
raise exception_class, "#{
|
50
|
+
raise exception_class, "#{"#{yield}: " if block_given?}unexpected value: #{value.inspect}"
|
51
51
|
end
|
52
52
|
|
53
53
|
def require_method!(name)
|
data/lib/aspera/cli/hints.rb
CHANGED
@@ -64,7 +64,15 @@ module Aspera
|
|
64
64
|
remediation: [
|
65
65
|
'If remote node is Cloud Pak For Integration',
|
66
66
|
'Make sure that a LoadBalancer is active on cluster',
|
67
|
-
'Check the external address of Aspera tcp-proxy
|
67
|
+
'Check the external address of Aspera tcp-proxy Pod'
|
68
|
+
]
|
69
|
+
},
|
70
|
+
{
|
71
|
+
exception: Aspera::RestCallError,
|
72
|
+
match: /Invalid subject\./,
|
73
|
+
remediation: [
|
74
|
+
'It seems that this user name is not registered on the server',
|
75
|
+
'Check the user name and try again'
|
68
76
|
]
|
69
77
|
}
|
70
78
|
]
|
data/lib/aspera/cli/main.rb
CHANGED
@@ -198,7 +198,7 @@ module Aspera
|
|
198
198
|
rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true}
|
199
199
|
rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'}
|
200
200
|
rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
|
201
|
-
rescue Cli::BadIdentifier => e;
|
201
|
+
rescue Cli::BadIdentifier => e; exception_info = {e: e, t: 'Identifier'}
|
202
202
|
rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
|
203
203
|
rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'}
|
204
204
|
rescue RestCallError => e; exception_info = {e: e, t: 'Rest'}
|
data/lib/aspera/cli/manager.rb
CHANGED
@@ -112,7 +112,7 @@ module Aspera
|
|
112
112
|
value_list = check_array ? to_check : [to_check]
|
113
113
|
value_list.each do |value|
|
114
114
|
raise Cli::BadArgument,
|
115
|
-
"#{what.to_s.capitalize} #{descr} is a #{value.class} but must be #{
|
115
|
+
"#{what.to_s.capitalize} #{descr} is a #{value.class} but must be #{'one of: ' if type_list.length > 1}#{type_list.map(&:name).join(', ')}" unless
|
116
116
|
type_list.any?{ |t| value.is_a?(t)}
|
117
117
|
end
|
118
118
|
end
|
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -240,7 +240,7 @@ module Aspera
|
|
240
240
|
# @param default [Object] default value if not provided
|
241
241
|
def value_create_modify(command:, description: nil, type: Hash, bulk: false, default: nil)
|
242
242
|
value = options.get_next_argument(
|
243
|
-
"parameters for #{command}#{
|
243
|
+
"parameters for #{command}#{" (#{description})" unless description.nil?}", mandatory: default.nil?,
|
244
244
|
validation: bulk ? Array : type)
|
245
245
|
value = default if value.nil?
|
246
246
|
unless type.nil?
|
@@ -50,10 +50,11 @@ module Aspera
|
|
50
50
|
'archived' => false,
|
51
51
|
'has_content' => true,
|
52
52
|
'received' => true,
|
53
|
-
'completed' => true
|
53
|
+
'completed' => true
|
54
|
+
}.freeze
|
55
|
+
PACKAGE_LIST_DEFAULT_FIELDS = %w[id name created_at files_completed bytes_transferred].freeze
|
54
56
|
# options and parameters for Api::AoC.new
|
55
57
|
OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
|
56
|
-
PACKAGE_LIST_DEFAULT_FIELDS = %w[id name created_at files_completed bytes_transferred].freeze
|
57
58
|
|
58
59
|
private_constant :REDIRECT_LOCALHOST, :STD_AUTH_TYPES, :ADMIN_OBJECTS, :PACKAGE_RECEIVED_BASE_QUERY, :OPTIONS_NEW, :PACKAGE_LIST_DEFAULT_FIELDS
|
59
60
|
class << self
|
@@ -191,22 +192,28 @@ module Aspera
|
|
191
192
|
options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
|
192
193
|
options.declare(:client_id, 'OAuth API client identifier')
|
193
194
|
options.declare(:client_secret, 'OAuth API client secret')
|
194
|
-
options.declare(:scope, 'OAuth scope for AoC API calls'
|
195
|
+
options.declare(:scope, 'OAuth scope for AoC API calls')
|
195
196
|
options.declare(:redirect_uri, 'OAuth API client redirect URI')
|
196
197
|
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
197
198
|
options.declare(:passphrase, 'RSA private key passphrase', types: String)
|
198
199
|
options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Api::AoC::DEFAULT_WORKSPACE)
|
199
200
|
options.declare(:new_user_option, 'New user creation option for unknown package recipients', types: Hash)
|
200
201
|
options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
|
202
|
+
options.declare(:package_folder, 'Field of package to use as folder name, or @none:', types: [String, NilClass])
|
201
203
|
options.parse_options!
|
202
204
|
# add node plugin options (for manual)
|
203
205
|
Node.declare_options(options)
|
204
206
|
end
|
205
207
|
|
206
|
-
def api_from_options(
|
207
|
-
create_values = {
|
208
|
+
def api_from_options(aoc_base_path)
|
209
|
+
create_values = OPTIONS_NEW.each_with_object({
|
210
|
+
subpath: aoc_base_path,
|
211
|
+
secret_finder: config}) do |i, m|
|
212
|
+
m[i] = options.get_option(i) unless options.get_option(i).nil?
|
213
|
+
end
|
214
|
+
create_values[:scope] = Api::AoC::SCOPE_FILES_USER if create_values[:scope].nil?
|
208
215
|
# create an API object with the same options, but with a different subpath
|
209
|
-
return Api::AoC.new(**
|
216
|
+
return Api::AoC.new(**create_values)
|
210
217
|
rescue ArgumentError => e
|
211
218
|
if (m = e.message.match(/missing keyword: :(.*)$/))
|
212
219
|
raise Cli::Error, "Missing option: #{m[1]}"
|
@@ -443,7 +450,9 @@ module Aspera
|
|
443
450
|
default_fields.push('app_type', 'app_name', 'available', 'direct_authorizations_allowed', 'workspace_authorizations_allowed')
|
444
451
|
when :client, :client_access_key, :dropbox, :group, :package, :saml_configuration, :workspace then default_fields.push('name')
|
445
452
|
when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
|
446
|
-
when :contact
|
453
|
+
when :contact
|
454
|
+
default_fields = %w[source_type source_id name email]
|
455
|
+
default_query = {'include_only_user_personal_contacts' => true} if aoc_api.oauth.scope == Api::AoC::SCOPE_FILES_USER
|
447
456
|
when :node then default_fields.push('name', 'host', 'access_key')
|
448
457
|
when :operation then default_fields = nil
|
449
458
|
when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
|
@@ -486,8 +495,8 @@ module Aspera
|
|
486
495
|
ADMIN_ACTIONS = %i[ats resource usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
|
487
496
|
|
488
497
|
def execute_admin_action
|
489
|
-
#
|
490
|
-
aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
|
498
|
+
# default scope to admin
|
499
|
+
aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN if options.get_option(:scope).nil?
|
491
500
|
command_admin = options.get_next_command(ADMIN_ACTIONS)
|
492
501
|
case command_admin
|
493
502
|
when :resource
|
@@ -801,7 +810,9 @@ module Aspera
|
|
801
810
|
when :tier_restrictions
|
802
811
|
return Main.result_single_object(aoc_api.read('tier_restrictions'))
|
803
812
|
when :user
|
804
|
-
case options.get_next_command(%i[workspaces profile preferences])
|
813
|
+
case options.get_next_command(%i[workspaces profile preferences contacts])
|
814
|
+
when :contacts
|
815
|
+
return execute_resource_action(:contact)
|
805
816
|
# when :settings
|
806
817
|
# return Main.result_object_list(aoc_api.read('client_settings/'))
|
807
818
|
when :workspaces
|
@@ -890,31 +901,30 @@ module Aspera
|
|
890
901
|
# remove from list the ones already downloaded
|
891
902
|
reject_packages_from_persistency(all_packages, skip_ids_persistency)
|
892
903
|
ids_to_download = all_packages.map{ |e| e['id']}
|
904
|
+
formatter.display_status("Found #{ids_to_download.length} package(s).")
|
893
905
|
else
|
894
906
|
# single id to array
|
895
907
|
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
896
908
|
end
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
[{'source' => '.'}]
|
902
|
-
end
|
903
|
-
# list here
|
909
|
+
# download all files, or specified list only
|
910
|
+
ts_paths = transfer.ts_source_paths(default: ['.'])
|
911
|
+
per_package_field = options.get_option(:package_folder)
|
912
|
+
destination_folder = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
|
904
913
|
result_transfer = []
|
905
|
-
formatter.display_status("Found #{ids_to_download.length} package(s).")
|
906
914
|
ids_to_download.each do |package_id|
|
907
915
|
package_info = aoc_api.read("packages/#{package_id}")
|
908
|
-
formatter.display_status("downloading package: [#{package_info['id']}] #{package_info['name']}")
|
909
916
|
package_node_api = aoc_api.node_api_from(
|
910
917
|
node_id: package_info['node_id'],
|
911
918
|
package_info: package_info,
|
912
919
|
**workspace_id_hash(name: true))
|
920
|
+
transfer_spec = package_node_api.transfer_spec_gen4(
|
921
|
+
package_info['contents_file_id'],
|
922
|
+
Transfer::Spec::DIRECTION_RECEIVE,
|
923
|
+
{'paths'=> ts_paths})
|
924
|
+
transfer.option_transfer_spec['destination_root'] = File.join(destination_folder, package_info[per_package_field]) unless per_package_field.nil?
|
925
|
+
formatter.display_status(%Q{Downloading package: [#{package_info['id']}] "#{package_info['name']}" to [#{transfer.option_transfer_spec['destination_root']}]})
|
913
926
|
statuses = transfer.start(
|
914
|
-
|
915
|
-
package_info['contents_file_id'],
|
916
|
-
Transfer::Spec::DIRECTION_RECEIVE,
|
917
|
-
{'paths'=> file_list}),
|
927
|
+
transfer_spec,
|
918
928
|
rest_token: package_node_api)
|
919
929
|
result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
|
920
930
|
# update skip list only if all transfer sessions completed
|
@@ -210,23 +210,23 @@ module Aspera
|
|
210
210
|
options.declare(:test_mode, 'Wizard: skip private key check step', values: :bool, default: false)
|
211
211
|
options.declare(:key_path, 'Wizard: path to private key for JWT')
|
212
212
|
# Transfer SDK options
|
213
|
-
options.declare(:ascp_path, 'Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
|
214
|
-
options.declare(:use_product, 'Use ascp from specified product', handler: {o: self, m: :option_use_product})
|
215
|
-
options.declare(:sdk_url, 'URL to get Aspera Transfer
|
216
|
-
options.declare(:locations_url, 'URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
|
217
|
-
options.declare(:sdk_folder, 'SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
|
213
|
+
options.declare(:ascp_path, 'Ascp: Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
|
214
|
+
options.declare(:use_product, 'Ascp: Use ascp from specified product', handler: {o: self, m: :option_use_product})
|
215
|
+
options.declare(:sdk_url, 'Ascp: URL to get Aspera Transfer Executables', default: SpecialValues::DEF)
|
216
|
+
options.declare(:locations_url, 'Ascp: URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
|
217
|
+
options.declare(:sdk_folder, 'Ascp: SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
|
218
218
|
options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
|
219
219
|
# email options
|
220
|
-
options.declare(:smtp, 'SMTP configuration', types: Hash)
|
221
|
-
options.declare(:notify_to, 'Email
|
222
|
-
options.declare(:notify_template, 'Email ERB template for notification of transfers')
|
220
|
+
options.declare(:smtp, 'Email: SMTP configuration', types: Hash)
|
221
|
+
options.declare(:notify_to, 'Email: Recipient for notification of transfers')
|
222
|
+
options.declare(:notify_template, 'Email: ERB template for notification of transfers')
|
223
223
|
# HTTP options
|
224
|
-
options.declare(:insecure, 'Do not validate any
|
225
|
-
options.declare(:ignore_certificate, 'Do not validate
|
226
|
-
options.declare(:silent_insecure, 'Issue a warning if certificate is ignored', values: :bool, handler: {o: self, m: :option_warn_insecure_cert}, default: :yes)
|
227
|
-
options.declare(:cert_stores, 'List of folder with trusted certificates', types: [Array, String], handler: {o: self, m: :trusted_cert_locations})
|
228
|
-
options.declare(:http_options, 'Options for HTTP/S socket', types: Hash, handler: {o: self, m: :option_http_options}, default: {})
|
229
|
-
options.declare(:http_proxy, 'URL for
|
224
|
+
options.declare(:insecure, 'HTTP/S: Do not validate any certificate', values: :bool, handler: {o: self, m: :option_insecure}, default: :no)
|
225
|
+
options.declare(:ignore_certificate, 'HTTP/S: Do not validate certificate for these URLs', types: Array, handler: {o: self, m: :option_ignore_cert_host_port})
|
226
|
+
options.declare(:silent_insecure, 'HTTP/S: Issue a warning if certificate is ignored', values: :bool, handler: {o: self, m: :option_warn_insecure_cert}, default: :yes)
|
227
|
+
options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates', types: [Array, String], handler: {o: self, m: :trusted_cert_locations})
|
228
|
+
options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket', types: Hash, handler: {o: self, m: :option_http_options}, default: {})
|
229
|
+
options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials', types: String, handler: {o: self, m: :option_http_proxy})
|
230
230
|
options.declare(:cache_tokens, 'Save and reuse OAuth tokens', values: :bool, handler: {o: self, m: :option_cache_tokens})
|
231
231
|
options.declare(:fpac, 'Proxy auto configuration script')
|
232
232
|
options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password', types: Array)
|
@@ -691,7 +691,7 @@ module Aspera
|
|
691
691
|
# collect info from ascp executable
|
692
692
|
data = Ascp::Installation.instance.ascp_info
|
693
693
|
# add command line transfer spec
|
694
|
-
data['ts'] = transfer.
|
694
|
+
data['ts'] = transfer.option_transfer_spec
|
695
695
|
# add keys
|
696
696
|
DataRepository::ELEMENTS.each_with_object(data){ |i, h| h[i.to_s] = DataRepository.instance.item(i)}
|
697
697
|
# declare those as secrets
|
@@ -1298,6 +1298,7 @@ module Aspera
|
|
1298
1298
|
)
|
1299
1299
|
end
|
1300
1300
|
|
1301
|
+
# Artifically raise an exception for tests
|
1301
1302
|
def execute_test
|
1302
1303
|
case options.get_next_command(%i[throw web])
|
1303
1304
|
when :throw
|
@@ -1317,6 +1318,8 @@ module Aspera
|
|
1317
1318
|
url.sub(%r{/+$}, '').sub(%r{^(https://[^/]+):443$}, '\1')
|
1318
1319
|
end
|
1319
1320
|
|
1321
|
+
# Look for a preset that has the corresponding URL and username
|
1322
|
+
# @return the first one matching
|
1320
1323
|
def lookup_preset(url:, username:)
|
1321
1324
|
# remove extra info to maximize match
|
1322
1325
|
url = canonical_url(url)
|
@@ -1329,6 +1332,8 @@ module Aspera
|
|
1329
1332
|
nil
|
1330
1333
|
end
|
1331
1334
|
|
1335
|
+
# Lookup the corresponding secret for the given URL and usernames
|
1336
|
+
# @raise Exception if mandatory and not found
|
1332
1337
|
def lookup_secret(url:, username:, mandatory: false)
|
1333
1338
|
secret = options.get_option(:secret)
|
1334
1339
|
if secret.nil?
|