aspera-cli 4.16.0 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +50 -19
- data/CONTRIBUTING.md +3 -1
- data/README.md +965 -793
- data/bin/asession +29 -21
- data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
- data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
- data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
- data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
- data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
- data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
- data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
- data/lib/aspera/api/aoc.rb +586 -0
- data/lib/aspera/api/ats.rb +46 -0
- data/lib/aspera/api/cos_node.rb +95 -0
- data/lib/aspera/api/node.rb +344 -0
- data/lib/aspera/ascmd.rb +46 -10
- data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
- data/lib/aspera/{fasp → ascp}/management.rb +3 -8
- data/lib/aspera/{fasp → ascp}/products.rb +1 -1
- data/lib/aspera/assert.rb +30 -30
- data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
- data/lib/aspera/cli/extended_value.rb +1 -1
- data/lib/aspera/cli/formatter.rb +13 -13
- data/lib/aspera/cli/hints.rb +5 -5
- data/lib/aspera/cli/main.rb +35 -28
- data/lib/aspera/cli/manager.rb +25 -24
- data/lib/aspera/cli/plugin.rb +22 -15
- data/lib/aspera/cli/plugin_factory.rb +61 -0
- data/lib/aspera/cli/plugins/alee.rb +7 -7
- data/lib/aspera/cli/plugins/aoc.rb +83 -77
- data/lib/aspera/cli/plugins/ats.rb +32 -33
- data/lib/aspera/cli/plugins/bss.rb +3 -4
- data/lib/aspera/cli/plugins/config.rb +169 -186
- data/lib/aspera/cli/plugins/console.rb +8 -6
- data/lib/aspera/cli/plugins/cos.rb +19 -18
- data/lib/aspera/cli/plugins/faspex.rb +61 -54
- data/lib/aspera/cli/plugins/faspex5.rb +150 -103
- data/lib/aspera/cli/plugins/node.rb +68 -73
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
- data/lib/aspera/cli/plugins/preview.rb +31 -31
- data/lib/aspera/cli/plugins/server.rb +31 -33
- data/lib/aspera/cli/plugins/shares.rb +13 -11
- data/lib/aspera/cli/sync_actions.rb +8 -8
- data/lib/aspera/cli/transfer_agent.rb +32 -19
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +5 -0
- data/lib/aspera/command_line_builder.rb +14 -14
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +2 -3
- data/lib/aspera/faspex_gw.rb +5 -6
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +2 -2
- data/lib/aspera/json_rpc.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +6 -6
- data/lib/aspera/keychain/macos_security.rb +27 -22
- data/lib/aspera/log.rb +2 -2
- data/lib/aspera/nagios.rb +3 -3
- data/lib/aspera/node_simulator.rb +5 -6
- data/lib/aspera/oauth/base.rb +143 -0
- data/lib/aspera/oauth/factory.rb +124 -0
- data/lib/aspera/oauth/generic.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +51 -0
- data/lib/aspera/oauth/url_json.rb +31 -0
- data/lib/aspera/oauth/web.rb +50 -0
- data/lib/aspera/oauth.rb +5 -331
- data/lib/aspera/open_application.rb +7 -7
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +5 -5
- data/lib/aspera/preview/terminal.rb +3 -2
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +4 -4
- data/lib/aspera/rest.rb +175 -144
- data/lib/aspera/rest_errors_aspera.rb +3 -3
- data/lib/aspera/resumer.rb +77 -0
- data/lib/aspera/ssh.rb +6 -1
- data/lib/aspera/{fasp → transfer}/error.rb +3 -3
- data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
- data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
- data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
- data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
- data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
- data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
- data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
- data/lib/aspera/web_server_simple.rb +11 -3
- data.tar.gz.sig +0 -0
- metadata +36 -63
- metadata.gz.sig +0 -0
- data/lib/aspera/aoc.rb +0 -601
- data/lib/aspera/ats_api.rb +0 -47
- data/lib/aspera/cos_node.rb +0 -94
- data/lib/aspera/fasp/resume_policy.rb +0 -79
- data/lib/aspera/node.rb +0 -339
|
@@ -15,10 +15,9 @@ require 'tty-spinner'
|
|
|
15
15
|
module Aspera
|
|
16
16
|
module Cli
|
|
17
17
|
module Plugins
|
|
18
|
-
class Faspex5 <
|
|
18
|
+
class Faspex5 < Cli::BasicAuthPlugin
|
|
19
19
|
RECIPIENT_TYPES = %w[user workgroup external_user distribution_list shared_inbox].freeze
|
|
20
20
|
PACKAGE_TERMINATED = %w[completed failed].freeze
|
|
21
|
-
API_DETECT = 'api/v5/configuration/ping'
|
|
22
21
|
# list of supported mailbox types (to list packages)
|
|
23
22
|
API_LIST_MAILBOX_TYPES = %w[inbox inbox_history inbox_all inbox_all_history outbox outbox_history pending pending_history all].freeze
|
|
24
23
|
PACKAGE_SEND_FROM_REMOTE_SOURCE = 'remote_source'
|
|
@@ -28,34 +27,49 @@ module Aspera
|
|
|
28
27
|
accounts contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs
|
|
29
28
|
metadata_profiles email_notifications alternate_addresses
|
|
30
29
|
].freeze
|
|
30
|
+
# states for jobs not in final state
|
|
31
31
|
JOB_RUNNING = %w[queued working].freeze
|
|
32
|
-
|
|
32
|
+
PATH_STANDARD_ROOT = '/aspera/faspex'
|
|
33
|
+
PATH_API_V5 = 'api/v5'
|
|
34
|
+
# endpoint for authentication API
|
|
35
|
+
PATH_AUTH = 'auth'
|
|
36
|
+
PATH_HEALTH = 'configuration/ping'
|
|
33
37
|
PER_PAGE_DEFAULT = 100
|
|
34
|
-
|
|
38
|
+
# OAuth methods supported
|
|
39
|
+
STD_AUTH_TYPES = %i[web jwt boot].freeze
|
|
40
|
+
HEADER_ITERATION_TOKEN = 'X-Aspera-Next-Iteration-Token'
|
|
41
|
+
private_constant(*%i[JOB_RUNNING RECIPIENT_TYPES PACKAGE_TERMINATED PATH_HEALTH API_LIST_MAILBOX_TYPES PACKAGE_SEND_FROM_REMOTE_SOURCE PER_PAGE_DEFAULT
|
|
42
|
+
STD_AUTH_TYPES])
|
|
35
43
|
class << self
|
|
36
44
|
def application_name
|
|
37
45
|
'Faspex'
|
|
38
46
|
end
|
|
39
47
|
|
|
40
48
|
def detect(address_or_url)
|
|
49
|
+
# add scheme if missing
|
|
41
50
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
42
51
|
urls = [address_or_url]
|
|
43
|
-
urls.push("#{address_or_url}#{
|
|
44
|
-
|
|
52
|
+
urls.push("#{address_or_url}#{PATH_STANDARD_ROOT}") unless address_or_url.end_with?(PATH_STANDARD_ROOT)
|
|
53
|
+
error = nil
|
|
45
54
|
urls.each do |base_url|
|
|
55
|
+
# Faspex is always HTTPS
|
|
46
56
|
next unless base_url.start_with?('https://')
|
|
47
57
|
api = Rest.new(base_url: base_url, redirect_max: 1)
|
|
48
|
-
|
|
58
|
+
path_api_detect = "#{PATH_API_V5}/#{PATH_HEALTH}"
|
|
59
|
+
result = api.read(path_api_detect)
|
|
49
60
|
next unless result[:http].code.start_with?('2') && result[:http].body.strip.empty?
|
|
50
|
-
|
|
61
|
+
# end is at -1, and substract 1 for "/"
|
|
62
|
+
url_length = -2 - path_api_detect.length
|
|
51
63
|
# take redirect if any
|
|
52
64
|
return {
|
|
53
65
|
version: result[:http]['x-ibm-aspera'] || '5',
|
|
54
66
|
url: result[:http].uri.to_s[0..url_length]
|
|
55
67
|
}
|
|
56
68
|
rescue StandardError => e
|
|
69
|
+
error = e
|
|
57
70
|
Log.log.debug{"detect error: #{e}"}
|
|
58
71
|
end
|
|
72
|
+
raise error if error
|
|
59
73
|
return nil
|
|
60
74
|
end
|
|
61
75
|
|
|
@@ -91,31 +105,25 @@ module Aspera
|
|
|
91
105
|
}
|
|
92
106
|
end
|
|
93
107
|
|
|
108
|
+
# @return true if the URL is a public link
|
|
94
109
|
def public_link?(url)
|
|
95
|
-
url.include?('
|
|
110
|
+
url.include?('?context=')
|
|
96
111
|
end
|
|
97
112
|
end
|
|
98
113
|
|
|
99
|
-
def initialize(env)
|
|
100
|
-
super
|
|
114
|
+
def initialize(**env)
|
|
115
|
+
super
|
|
101
116
|
options.declare(:client_id, 'OAuth client identifier')
|
|
102
117
|
options.declare(:client_secret, 'OAuth client secret')
|
|
103
118
|
options.declare(:redirect_uri, 'OAuth redirect URI for web authentication')
|
|
104
|
-
options.declare(:auth, 'OAuth type of authentication', values:
|
|
119
|
+
options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
|
|
105
120
|
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
|
106
121
|
options.declare(:passphrase, 'OAuth JWT RSA private key passphrase')
|
|
107
122
|
options.declare(:box, "Package inbox, either shared inbox name or one of: #{API_LIST_MAILBOX_TYPES.join(', ')} or #{ExtendedValue::ALL}", default: 'inbox')
|
|
108
123
|
options.declare(:shared_folder, 'Send package with files from shared folder')
|
|
109
124
|
options.declare(:group_type, 'Type of shared box', values: %i[shared_inboxes workgroups], default: :shared_inboxes)
|
|
110
125
|
options.parse_options!
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def api_url
|
|
114
|
-
return "#{@faspex5_api_base_url}/api/v5"
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def auth_api_url
|
|
118
|
-
return "#{@faspex5_api_base_url}/auth"
|
|
126
|
+
@pub_link_context = nil
|
|
119
127
|
end
|
|
120
128
|
|
|
121
129
|
def set_api
|
|
@@ -124,60 +132,63 @@ module Aspera
|
|
|
124
132
|
auth_type = self.class.public_link?(@faspex5_api_base_url) ? :public_link : options.get_option(:auth, mandatory: true)
|
|
125
133
|
case auth_type
|
|
126
134
|
when :public_link
|
|
135
|
+
# resolve any redirect
|
|
136
|
+
@faspex5_api_base_url = Rest.new(base_url: @faspex5_api_base_url, redirect_max: 3).read('')[:http].uri.to_s
|
|
127
137
|
encoded_context = Rest.decode_query(URI.parse(@faspex5_api_base_url).query)['context']
|
|
128
138
|
raise 'Bad faspex5 public link, missing context in query' if encoded_context.nil?
|
|
139
|
+
# public link information (allowed usage)
|
|
129
140
|
@pub_link_context = JSON.parse(Base64.decode64(encoded_context))
|
|
130
141
|
Log.log.trace1{Log.dump(:@pub_link_context, @pub_link_context)}
|
|
131
142
|
# ok, we have the additional parameters, get the base url
|
|
132
143
|
@faspex5_api_base_url = @faspex5_api_base_url.gsub(%r{/public/.*}, '').gsub(/\?.*/, '')
|
|
133
|
-
@api_v5 = Rest.new(
|
|
134
|
-
base_url:
|
|
144
|
+
@api_v5 = Rest.new(
|
|
145
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
|
135
146
|
headers: {'Passcode' => @pub_link_context['passcode']}
|
|
136
|
-
|
|
147
|
+
)
|
|
137
148
|
when :boot
|
|
138
149
|
# the password here is the token copied directly from browser in developer mode
|
|
139
|
-
@api_v5 = Rest.new(
|
|
140
|
-
base_url:
|
|
150
|
+
@api_v5 = Rest.new(
|
|
151
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
|
141
152
|
headers: {'Authorization' => options.get_option(:password, mandatory: true)}
|
|
142
|
-
|
|
153
|
+
)
|
|
143
154
|
when :web
|
|
144
155
|
# opens a browser and ask user to auth using web
|
|
145
|
-
@api_v5 = Rest.new(
|
|
146
|
-
base_url:
|
|
156
|
+
@api_v5 = Rest.new(
|
|
157
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
|
147
158
|
auth: {
|
|
148
159
|
type: :oauth2,
|
|
149
|
-
base_url:
|
|
160
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}",
|
|
150
161
|
grant_method: :web,
|
|
151
162
|
client_id: options.get_option(:client_id, mandatory: true),
|
|
152
|
-
|
|
153
|
-
}
|
|
163
|
+
redirect_uri: options.get_option(:redirect_uri, mandatory: true)
|
|
164
|
+
})
|
|
154
165
|
when :jwt
|
|
155
166
|
app_client_id = options.get_option(:client_id, mandatory: true)
|
|
156
|
-
@api_v5 = Rest.new(
|
|
157
|
-
base_url:
|
|
167
|
+
@api_v5 = Rest.new(
|
|
168
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
|
158
169
|
auth: {
|
|
159
|
-
type:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
client_id:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}})
|
|
173
|
-
else error_unexpected_value(auth_type)
|
|
170
|
+
type: :oauth2,
|
|
171
|
+
grant_method: :jwt,
|
|
172
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}",
|
|
173
|
+
client_id: app_client_id,
|
|
174
|
+
payload: {
|
|
175
|
+
iss: app_client_id, # issuer
|
|
176
|
+
aud: app_client_id, # audience (this field is not clear...)
|
|
177
|
+
sub: "user:#{options.get_option(:username, mandatory: true)}" # subject is a user
|
|
178
|
+
},
|
|
179
|
+
private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, mandatory: true), options.get_option(:passphrase)),
|
|
180
|
+
headers: {typ: 'JWT'}
|
|
181
|
+
})
|
|
182
|
+
else Aspera.error_unexpected_value(auth_type)
|
|
174
183
|
end
|
|
184
|
+
# in case user wants to use HTTPGW tell transfer agent how to get address
|
|
185
|
+
transfer.httpgw_url_cb = lambda { @api_v5.read('account')[:data]['gateway_url'] }
|
|
175
186
|
end
|
|
176
187
|
|
|
177
188
|
# if recipient is just an email, then convert to expected API hash : name and type
|
|
178
189
|
def normalize_recipients(parameters)
|
|
179
190
|
return unless parameters.key?('recipients')
|
|
180
|
-
assert_type(parameters['recipients'], Array){'recipients'}
|
|
191
|
+
Aspera.assert_type(parameters['recipients'], Array){'recipients'}
|
|
181
192
|
recipient_types = RECIPIENT_TYPES
|
|
182
193
|
if parameters.key?('recipient_types')
|
|
183
194
|
recipient_types = parameters['recipient_types']
|
|
@@ -185,7 +196,7 @@ module Aspera
|
|
|
185
196
|
recipient_types = [recipient_types] unless recipient_types.is_a?(Array)
|
|
186
197
|
end
|
|
187
198
|
parameters['recipients'].map! do |recipient_data|
|
|
188
|
-
# if just a string,
|
|
199
|
+
# if just a string, make a general lookup and build expected name/type hash
|
|
189
200
|
if recipient_data.is_a?(String)
|
|
190
201
|
matched = @api_v5.lookup_by_name('contacts', recipient_data, {context: 'packages', type: Rest.array_params(recipient_types)})
|
|
191
202
|
recipient_data = {
|
|
@@ -238,7 +249,7 @@ module Aspera
|
|
|
238
249
|
spinner.spin
|
|
239
250
|
sleep(0.5)
|
|
240
251
|
end
|
|
241
|
-
error_unreachable_line
|
|
252
|
+
Aspera.error_unreachable_line
|
|
242
253
|
end
|
|
243
254
|
|
|
244
255
|
# Get a (full or partial) list of all entities of a given type
|
|
@@ -248,7 +259,7 @@ module Aspera
|
|
|
248
259
|
# @param item_list_key [String] key in the result to get the list of items
|
|
249
260
|
def list_entities(type:, real_path: nil, query: {}, item_list_key: nil)
|
|
250
261
|
type = type.to_s if type.is_a?(Symbol)
|
|
251
|
-
assert_type(type, String)
|
|
262
|
+
Aspera.assert_type(type, String)
|
|
252
263
|
item_list_key = type if item_list_key.nil?
|
|
253
264
|
full_path = real_path.nil? ? type : real_path
|
|
254
265
|
result = []
|
|
@@ -277,7 +288,7 @@ module Aspera
|
|
|
277
288
|
# lookup an entity id from its name
|
|
278
289
|
def lookup_entity_by_field(type:, value:, field: 'name', query: :default, real_path: nil, item_list_key: nil)
|
|
279
290
|
if query.eql?(:default)
|
|
280
|
-
assert(field.eql?('name')){'Default query is on name only'}
|
|
291
|
+
Aspera.assert(field.eql?('name')){'Default query is on name only'}
|
|
281
292
|
query = {'q'=> value}
|
|
282
293
|
end
|
|
283
294
|
found = list_entities(type: type, real_path: real_path, query: query, item_list_key: item_list_key).select{|i|i[field].eql?(value)}
|
|
@@ -313,7 +324,7 @@ module Aspera
|
|
|
313
324
|
if options.get_option(:once_only, mandatory: true)
|
|
314
325
|
# read ids from persistency
|
|
315
326
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
316
|
-
manager:
|
|
327
|
+
manager: persistency,
|
|
317
328
|
data: [],
|
|
318
329
|
id: IdGenerator.from_list([
|
|
319
330
|
'faspex_recv',
|
|
@@ -325,7 +336,7 @@ module Aspera
|
|
|
325
336
|
packages = []
|
|
326
337
|
case package_ids
|
|
327
338
|
when ExtendedValue::INIT
|
|
328
|
-
assert(skip_ids_persistency){'Only with option once_only'}
|
|
339
|
+
Aspera.assert(skip_ids_persistency){'Only with option once_only'}
|
|
329
340
|
skip_ids_persistency.data.clear.concat(list_packages_with_filter.map{|p|p['id']})
|
|
330
341
|
skip_ids_persistency.save
|
|
331
342
|
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
|
@@ -339,8 +350,8 @@ module Aspera
|
|
|
339
350
|
else
|
|
340
351
|
# a single id was provided, or a list of ids
|
|
341
352
|
package_ids = [package_ids] unless package_ids.is_a?(Array)
|
|
342
|
-
assert_type(package_ids, Array){'Expecting a single package id or a list of ids'}
|
|
343
|
-
assert(package_ids.all?(String)){'Package id shall be String'}
|
|
353
|
+
Aspera.assert_type(package_ids, Array){'Expecting a single package id or a list of ids'}
|
|
354
|
+
Aspera.assert(package_ids.all?(String)){'Package id shall be String'}
|
|
344
355
|
# packages = package_ids.map{|pkg_id|@api_v5.read("packages/#{pkg_id}")[:data]}
|
|
345
356
|
packages = package_ids.map{|pkg_id|{'id'=>pkg_id}}
|
|
346
357
|
end
|
|
@@ -386,6 +397,45 @@ module Aspera
|
|
|
386
397
|
return Main.result_transfer_multiple(result_transfer)
|
|
387
398
|
end
|
|
388
399
|
|
|
400
|
+
# browse a folder
|
|
401
|
+
# @param browse_endpoint [String] the endpoint to browse
|
|
402
|
+
def browse_folder(browse_endpoint)
|
|
403
|
+
path = options.get_next_argument('folder path', mandatory: false, default: '/')
|
|
404
|
+
query = query_read_delete(default: {})
|
|
405
|
+
query['filters'] = {} unless query.key?('filters')
|
|
406
|
+
filters = query.delete('filters')
|
|
407
|
+
filters['basenames'] = [] unless filters.key?('basenames')
|
|
408
|
+
Aspera.assert_type(filters, Hash){'filters'}
|
|
409
|
+
max_items = query.delete('max')
|
|
410
|
+
recursive = query.delete('recursive')
|
|
411
|
+
all_items = []
|
|
412
|
+
folders_to_process = [path]
|
|
413
|
+
until folders_to_process.empty?
|
|
414
|
+
path = folders_to_process.shift
|
|
415
|
+
query.delete('iteration_token')
|
|
416
|
+
loop do
|
|
417
|
+
response = @api_v5.call(
|
|
418
|
+
operation: 'POST',
|
|
419
|
+
subpath: browse_endpoint,
|
|
420
|
+
headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
|
|
421
|
+
url_params: query,
|
|
422
|
+
json_params: {'path' => path, 'filters' => filters})
|
|
423
|
+
all_items.concat(response[:data]['items'])
|
|
424
|
+
if recursive
|
|
425
|
+
folders_to_process.concat(response[:data]['items'].select{|i|i['type'].eql?('directory')}.map{|i|i['path']})
|
|
426
|
+
end
|
|
427
|
+
if !max_items.nil? && (all_items.count >= max_items)
|
|
428
|
+
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
|
429
|
+
break
|
|
430
|
+
end
|
|
431
|
+
iteration_token = response[:http][HEADER_ITERATION_TOKEN]
|
|
432
|
+
break if iteration_token.nil? || iteration_token.empty?
|
|
433
|
+
query['iteration_token'] = iteration_token
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
return {type: :object_list, data: all_items}
|
|
437
|
+
end
|
|
438
|
+
|
|
389
439
|
def package_action
|
|
390
440
|
command = options.get_next_command(%i[show browse status delete receive send list])
|
|
391
441
|
package_id =
|
|
@@ -396,36 +446,34 @@ module Aspera
|
|
|
396
446
|
when :show
|
|
397
447
|
return {type: :single_object, data: @api_v5.read("packages/#{package_id}")[:data]}
|
|
398
448
|
when :browse
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
result = @api_v5.call({
|
|
407
|
-
operation: 'POST',
|
|
408
|
-
subpath: "packages/#{package_id}/files/received",
|
|
409
|
-
headers: {'Accept' => 'application/json'},
|
|
410
|
-
url_params: params,
|
|
411
|
-
json_params: {'path' => path, 'filters' => {'basenames'=>[]}}})[:data]
|
|
412
|
-
formatter.display_item_count(result['item_count'], result['total_count'])
|
|
413
|
-
return {type: :object_list, data: result['items']}
|
|
449
|
+
location = case options.get_option(:box)
|
|
450
|
+
when 'inbox' then 'received'
|
|
451
|
+
when 'outbox' then 'sent'
|
|
452
|
+
else raise 'Browse only available for inbox and outbox'
|
|
453
|
+
end
|
|
454
|
+
return browse_folder("packages/#{package_id}/files/#{location}")
|
|
414
455
|
when :status
|
|
415
456
|
status = wait_package_status(package_id, status_list: nil)
|
|
416
457
|
return {type: :single_object, data: status}
|
|
417
458
|
when :delete
|
|
418
459
|
ids = package_id
|
|
419
460
|
ids = [ids] unless ids.is_a?(Array)
|
|
420
|
-
assert_type(ids, Array){'Package identifier'}
|
|
421
|
-
assert(ids.all?(String)){'Package id shall be String'}
|
|
461
|
+
Aspera.assert_type(ids, Array){'Package identifier'}
|
|
462
|
+
Aspera.assert(ids.all?(String)){'Package id shall be String'}
|
|
422
463
|
# API returns 204, empty on success
|
|
423
|
-
@api_v5.call(
|
|
464
|
+
@api_v5.call(operation: 'DELETE', subpath: 'packages', headers: {'Accept' => 'application/json'}, json_params: {ids: ids})
|
|
424
465
|
return Main.result_status('Package(s) deleted')
|
|
425
466
|
when :receive
|
|
426
467
|
return package_receive(package_id)
|
|
427
468
|
when :send
|
|
428
469
|
parameters = value_create_modify(command: command)
|
|
470
|
+
# autofill recipient for public url
|
|
471
|
+
if @pub_link_context&.key?('recipient_type') && !parameters.key?('recipients')
|
|
472
|
+
parameters['recipients'] = [{
|
|
473
|
+
name: @pub_link_context['name'],
|
|
474
|
+
recipient_type: @pub_link_context['recipient_type']
|
|
475
|
+
}]
|
|
476
|
+
end
|
|
429
477
|
normalize_recipients(parameters)
|
|
430
478
|
package = @api_v5.create('packages', parameters)[:data]
|
|
431
479
|
shared_folder = options.get_option(:shared_folder)
|
|
@@ -465,7 +513,7 @@ module Aspera
|
|
|
465
513
|
end # case package
|
|
466
514
|
end
|
|
467
515
|
|
|
468
|
-
ACTIONS = %i[health version user bearer_token packages shared_folders admin gateway postprocessing].freeze
|
|
516
|
+
ACTIONS = %i[health version user bearer_token packages shared_folders admin gateway postprocessing invitations].freeze
|
|
469
517
|
|
|
470
518
|
def execute_action
|
|
471
519
|
command = options.get_next_command(ACTIONS)
|
|
@@ -485,7 +533,9 @@ module Aspera
|
|
|
485
533
|
end
|
|
486
534
|
return nagios.result
|
|
487
535
|
when :user
|
|
488
|
-
case options.get_next_command(%i[profile])
|
|
536
|
+
case options.get_next_command(%i[account profile])
|
|
537
|
+
when :account
|
|
538
|
+
return { type: :single_object, data: @api_v5.read('account')[:data] }
|
|
489
539
|
when :profile
|
|
490
540
|
case options.get_next_command(%i[show modify])
|
|
491
541
|
when :show
|
|
@@ -511,21 +561,9 @@ module Aspera
|
|
|
511
561
|
raise "multiple matches for #{field} = #{value}" if matches.length > 1
|
|
512
562
|
matches.first['id']
|
|
513
563
|
end
|
|
514
|
-
path = options.get_next_argument('folder path', mandatory: false) || '/'
|
|
515
564
|
node = all_shared_folders.find{|i|i['id'].eql?(shared_folder_id)}
|
|
516
565
|
raise "No such shared folder id #{shared_folder_id}" if node.nil?
|
|
517
|
-
|
|
518
|
-
operation: 'POST',
|
|
519
|
-
subpath: "nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse",
|
|
520
|
-
headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
|
|
521
|
-
json_params: {'path': path, 'filters': {'basenames': []}},
|
|
522
|
-
url_params: {offset: 0, limit: 100}
|
|
523
|
-
})[:data]
|
|
524
|
-
if result.key?('items')
|
|
525
|
-
return {type: :object_list, data: result['items']}
|
|
526
|
-
else
|
|
527
|
-
return {type: :single_object, data: result['self']}
|
|
528
|
-
end
|
|
566
|
+
return browse_folder("nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse")
|
|
529
567
|
end
|
|
530
568
|
when :admin
|
|
531
569
|
case options.get_next_command(%i[resource smtp].freeze)
|
|
@@ -550,12 +588,12 @@ module Aspera
|
|
|
550
588
|
display_fields = Formatter.all_but('user_profile_data_attributes')
|
|
551
589
|
when :oauth_clients
|
|
552
590
|
display_fields = Formatter.all_but('public_key')
|
|
553
|
-
adm_api = Rest.new(
|
|
591
|
+
adm_api = Rest.new(**@api_v5.params.merge(base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}"))
|
|
554
592
|
when :shared_inboxes, :workgroups
|
|
555
593
|
available_commands.push(:members, :saml_groups, :invite_external_collaborator)
|
|
556
594
|
special_query = {'all': true}
|
|
557
595
|
when :nodes
|
|
558
|
-
available_commands.push(:shared_folders)
|
|
596
|
+
available_commands.push(:shared_folders, :browse)
|
|
559
597
|
end
|
|
560
598
|
res_command = options.get_next_command(available_commands)
|
|
561
599
|
case res_command
|
|
@@ -573,6 +611,8 @@ module Aspera
|
|
|
573
611
|
lookup_entity_by_field(
|
|
574
612
|
type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
|
|
575
613
|
end
|
|
614
|
+
when :browse
|
|
615
|
+
return browse_folder("#{res_path}/#{instance_identifier}/browse")
|
|
576
616
|
when :invite_external_collaborator
|
|
577
617
|
shared_inbox_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value)['id']}
|
|
578
618
|
creation_payload = value_create_modify(command: res_command, type: [Hash, String])
|
|
@@ -637,34 +677,41 @@ module Aspera
|
|
|
637
677
|
return { type: :single_object, data: result }
|
|
638
678
|
end
|
|
639
679
|
end
|
|
680
|
+
when :invitations
|
|
681
|
+
invitation_endpoint = 'invitations'
|
|
682
|
+
invitation_command = options.get_next_command(%i[resend].concat(Plugin::ALL_OPS))
|
|
683
|
+
case invitation_command
|
|
684
|
+
when :create
|
|
685
|
+
return do_bulk_operation(command: invitation_command, descr: 'data') do |params|
|
|
686
|
+
invitation_endpoint = params.key?('recipient_name') ? 'public_invitations' : 'invitations'
|
|
687
|
+
@api_v5.create(invitation_endpoint, params)[:data]
|
|
688
|
+
end
|
|
689
|
+
when :resend
|
|
690
|
+
@api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend")
|
|
691
|
+
return Main.result_status('Invitation resent')
|
|
692
|
+
else
|
|
693
|
+
return entity_command(
|
|
694
|
+
invitation_command, @api_v5, invitation_endpoint, item_list_key: invitation_endpoint,
|
|
695
|
+
display_fields: %w[id public recipient_type recipient_name email_address])
|
|
696
|
+
end
|
|
640
697
|
when :gateway
|
|
641
698
|
require 'aspera/faspex_gw'
|
|
642
699
|
url = value_create_modify(command: command, description: 'listening url (e.g. https://localhost:12345)', type: String)
|
|
643
700
|
uri = URI.parse(url)
|
|
644
701
|
server = WebServerSimple.new(uri)
|
|
645
702
|
server.mount(uri.path, Faspex4GWServlet, @api_v5, nil)
|
|
646
|
-
# on ctrl-c, tell server main loop to exit
|
|
647
|
-
trap('INT') { server.shutdown }
|
|
648
|
-
formatter.display_status("Gateway for Faspex 4-style API listening on #{url}")
|
|
649
|
-
Log.log.info("Listening on #{url}")
|
|
650
|
-
# this is blocking until server exits
|
|
651
703
|
server.start
|
|
652
704
|
return Main.result_status('Gateway terminated')
|
|
653
705
|
when :postprocessing
|
|
654
706
|
require 'aspera/faspex_postproc' # cspell:disable-line
|
|
655
707
|
parameters = value_create_modify(command: command)
|
|
656
708
|
parameters = parameters.symbolize_keys
|
|
657
|
-
assert(parameters.key?(:url)){'Missing key: url'}
|
|
709
|
+
Aspera.assert(parameters.key?(:url)){'Missing key: url'}
|
|
658
710
|
uri = URI.parse(parameters[:url])
|
|
659
711
|
parameters[:processing] ||= {}
|
|
660
712
|
parameters[:processing][:root] = uri.path
|
|
661
713
|
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
|
662
714
|
server.mount(uri.path, Faspex4PostProcServlet, parameters[:processing])
|
|
663
|
-
# on ctrl-c, tell server main loop to exit
|
|
664
|
-
trap('INT') { server.shutdown }
|
|
665
|
-
formatter.display_status("Web-hook for Faspex 4-style post processing listening on #{uri.port}")
|
|
666
|
-
Log.log.info("Listening on #{uri.port}")
|
|
667
|
-
# this is blocking until server exits
|
|
668
715
|
server.start
|
|
669
716
|
return Main.result_status('Gateway terminated')
|
|
670
717
|
end # case command
|