aspera-cli 4.25.2 → 4.25.3
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 +412 -406
- data/CONTRIBUTING.md +17 -8
- data/README.md +6 -3
- data/lib/aspera/api/aoc.rb +19 -12
- data/lib/aspera/api/faspex.rb +25 -6
- data/lib/aspera/api/node.rb +4 -2
- data/lib/aspera/assert.rb +1 -1
- data/lib/aspera/cli/hints.rb +7 -0
- data/lib/aspera/cli/manager.rb +38 -26
- data/lib/aspera/cli/plugins/aoc.rb +149 -122
- data/lib/aspera/cli/plugins/base.rb +14 -17
- data/lib/aspera/cli/plugins/config.rb +4 -43
- data/lib/aspera/cli/plugins/faspex.rb +4 -4
- data/lib/aspera/cli/plugins/faspex5.rb +70 -73
- data/lib/aspera/cli/plugins/node.rb +3 -5
- data/lib/aspera/cli/plugins/oauth.rb +26 -25
- data/lib/aspera/cli/plugins/preview.rb +3 -3
- data/lib/aspera/cli/plugins/shares.rb +15 -7
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +7 -0
- data/lib/aspera/faspex_gw.rb +5 -5
- data/lib/aspera/faspex_postproc.rb +4 -4
- data/lib/aspera/log.rb +12 -11
- data/lib/aspera/markdown.rb +5 -0
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/base.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -2
- data/lib/aspera/rest.rb +44 -37
- data/lib/aspera/rest_error_analyzer.rb +38 -36
- data/lib/aspera/rest_errors_aspera.rb +19 -18
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
|
@@ -94,7 +94,7 @@ module Aspera
|
|
|
94
94
|
|
|
95
95
|
def initialize(**_)
|
|
96
96
|
super
|
|
97
|
-
options.declare(:box, "Package inbox, either shared inbox name or one of: #{Api::Faspex::API_LIST_MAILBOX_TYPES.join(', ')} or #{SpecialValues::ALL}", default: '
|
|
97
|
+
options.declare(:box, "Package inbox, either shared inbox name or one of: #{Api::Faspex::API_LIST_MAILBOX_TYPES.join(', ')} or #{SpecialValues::ALL}", default: 'inbox_all')
|
|
98
98
|
options.declare(:shared_folder, 'Send package with files from shared folder')
|
|
99
99
|
options.declare(:group_type, 'Type of shared box', allowed: %i[shared_inboxes workgroups], default: :shared_inboxes)
|
|
100
100
|
options.parse_options!
|
|
@@ -102,7 +102,7 @@ module Aspera
|
|
|
102
102
|
|
|
103
103
|
def set_api
|
|
104
104
|
# create an API object with the same options, but with a different subpath
|
|
105
|
-
@api_v5 =
|
|
105
|
+
@api_v5 = Api::Faspex.new(**Oauth.args_from_options(options))
|
|
106
106
|
# in case user wants to use HTTPGW tell transfer agent how to get address
|
|
107
107
|
transfer.httpgw_url_cb = lambda{@api_v5.read('account')['gateway_url']}
|
|
108
108
|
end
|
|
@@ -118,7 +118,7 @@ module Aspera
|
|
|
118
118
|
recipient_types = [recipient_types] unless recipient_types.is_a?(Array)
|
|
119
119
|
end
|
|
120
120
|
parameters['recipients'].map! do |recipient_data|
|
|
121
|
-
#
|
|
121
|
+
# If just a string, make a general lookup and build expected name/type hash
|
|
122
122
|
if recipient_data.is_a?(String)
|
|
123
123
|
matched = @api_v5.lookup_by_name('contacts', recipient_data, query: Rest.php_style({context: 'packages', type: recipient_types}))
|
|
124
124
|
recipient_data = {
|
|
@@ -174,8 +174,8 @@ module Aspera
|
|
|
174
174
|
# list all packages with optional filter
|
|
175
175
|
def list_packages_with_filter(query: {})
|
|
176
176
|
filter = options.get_next_argument('filter', mandatory: false, validation: Proc, default: ->(_x){true})
|
|
177
|
-
# translate box name to API prefix (with ending slash)
|
|
178
177
|
box = options.get_option(:box)
|
|
178
|
+
# Translate box name to API prefix (with ending slash)
|
|
179
179
|
entity =
|
|
180
180
|
case box
|
|
181
181
|
when SpecialValues::ALL then 'packages' # only admin can list all packages globally
|
|
@@ -236,17 +236,12 @@ module Aspera
|
|
|
236
236
|
rescue Cli::BadArgument
|
|
237
237
|
# paths is optional
|
|
238
238
|
end
|
|
239
|
+
box = options.get_option(:box)
|
|
239
240
|
download_params = {
|
|
240
|
-
type:
|
|
241
|
+
type: Api::Faspex.box_type(box),
|
|
241
242
|
transfer_type: Api::Faspex::TRANSFER_CONNECT
|
|
242
243
|
}
|
|
243
|
-
|
|
244
|
-
case box
|
|
245
|
-
when /outbox/ then download_params[:type] = 'sent'
|
|
246
|
-
when *Api::Faspex::API_LIST_MAILBOX_TYPES then nil # nothing to do
|
|
247
|
-
else # shared inbox / workgroup
|
|
248
|
-
download_params[:recipient_workgroup_id] = lookup_entity_by_field(api: @api_v5, entity: options.get_option(:group_type), value: box)['id']
|
|
249
|
-
end
|
|
244
|
+
download_params[:recipient_workgroup_id] = lookup_entity_by_field(api: @api_v5, entity: options.get_option(:group_type), value: box)['id'] if !Api::Faspex::API_LIST_MAILBOX_TYPES.include?(box) && box != SpecialValues::ALL
|
|
250
245
|
packages.each do |package|
|
|
251
246
|
pkg_id = package['id']
|
|
252
247
|
formatter.display_status("Receiving package #{pkg_id}")
|
|
@@ -255,9 +250,9 @@ module Aspera
|
|
|
255
250
|
operation: 'POST',
|
|
256
251
|
subpath: "packages/#{pkg_id}/transfer_spec/download",
|
|
257
252
|
query: download_params,
|
|
258
|
-
content_type:
|
|
253
|
+
content_type: Mime::JSON,
|
|
259
254
|
body: param_file_list,
|
|
260
|
-
headers: {'Accept' =>
|
|
255
|
+
headers: {'Accept' => Mime::JSON}
|
|
261
256
|
)
|
|
262
257
|
# delete flag for Connect Client
|
|
263
258
|
transfer_spec.delete('authentication')
|
|
@@ -272,6 +267,56 @@ module Aspera
|
|
|
272
267
|
return Main.result_transfer_multiple(result_transfer)
|
|
273
268
|
end
|
|
274
269
|
|
|
270
|
+
def package_send
|
|
271
|
+
parameters = value_create_modify(command: :send)
|
|
272
|
+
# autofill recipient for public url
|
|
273
|
+
if @api_v5.pub_link_context&.key?('recipient_type') && !parameters.key?('recipients')
|
|
274
|
+
parameters['recipients'] = [{
|
|
275
|
+
name: @api_v5.pub_link_context['name'],
|
|
276
|
+
recipient_type: @api_v5.pub_link_context['recipient_type']
|
|
277
|
+
}]
|
|
278
|
+
end
|
|
279
|
+
normalize_recipients(parameters)
|
|
280
|
+
# User specified content prot in tspec, but faspex requires in package creation
|
|
281
|
+
# `transfer_spec/upload` will set `content_protection`
|
|
282
|
+
if transfer.user_transfer_spec['content_protection'] && !parameters.key?('ear_enabled')
|
|
283
|
+
transfer.user_transfer_spec.delete('content_protection')
|
|
284
|
+
parameters['ear_enabled'] = true
|
|
285
|
+
end
|
|
286
|
+
package = @api_v5.create('packages', parameters)
|
|
287
|
+
shared_folder = options.get_option(:shared_folder)
|
|
288
|
+
if shared_folder.nil?
|
|
289
|
+
# send from local files
|
|
290
|
+
transfer_spec = @api_v5.create(
|
|
291
|
+
"packages/#{package['id']}/transfer_spec/upload",
|
|
292
|
+
{paths: transfer.source_list},
|
|
293
|
+
query: {transfer_type: Api::Faspex::TRANSFER_CONNECT}
|
|
294
|
+
)
|
|
295
|
+
# well, we asked a TS for connect, but we actually want a generic one
|
|
296
|
+
transfer_spec.delete('authentication')
|
|
297
|
+
return Main.result_transfer(transfer.start(transfer_spec))
|
|
298
|
+
else
|
|
299
|
+
# send from remote shared folder
|
|
300
|
+
if (m = Base.percent_selector(shared_folder))
|
|
301
|
+
shared_folder = lookup_entity_by_field(
|
|
302
|
+
api: @api_v5,
|
|
303
|
+
entity: 'shared_folders',
|
|
304
|
+
field: m[:field],
|
|
305
|
+
value: m[:value]
|
|
306
|
+
)['id']
|
|
307
|
+
end
|
|
308
|
+
transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
|
|
309
|
+
# start remote transfer and get first status
|
|
310
|
+
result = @api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)
|
|
311
|
+
result['id'] = package['id']
|
|
312
|
+
unless result['status'].eql?('completed')
|
|
313
|
+
formatter.display_status("Package #{package['id']}")
|
|
314
|
+
result = wait_package_status(package['id'])
|
|
315
|
+
end
|
|
316
|
+
return Main.result_single_object(result)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
275
320
|
# Browse a folder
|
|
276
321
|
# @param browse_endpoint [String] the endpoint to browse
|
|
277
322
|
def browse_folder(browse_endpoint)
|
|
@@ -300,9 +345,9 @@ module Aspera
|
|
|
300
345
|
operation: 'POST',
|
|
301
346
|
subpath: browse_endpoint,
|
|
302
347
|
query: query,
|
|
303
|
-
content_type:
|
|
348
|
+
content_type: Mime::JSON,
|
|
304
349
|
body: {'path' => path, 'filters' => filters},
|
|
305
|
-
headers: {'Accept' =>
|
|
350
|
+
headers: {'Accept' => Mime::JSON},
|
|
306
351
|
ret: :both
|
|
307
352
|
)
|
|
308
353
|
all_items.concat(data['items'])
|
|
@@ -339,12 +384,7 @@ module Aspera
|
|
|
339
384
|
when :show
|
|
340
385
|
return Main.result_single_object(@api_v5.read("packages/#{package_id}"))
|
|
341
386
|
when :browse
|
|
342
|
-
|
|
343
|
-
when 'inbox' then 'received'
|
|
344
|
-
when 'outbox' then 'sent'
|
|
345
|
-
else raise BadArgument, 'Browse only available for inbox and outbox'
|
|
346
|
-
end
|
|
347
|
-
return browse_folder("packages/#{package_id}/files/#{location}")
|
|
387
|
+
return browse_folder("packages/#{package_id}/files/#{Api::Faspex.box_type(options.get_option(:box))}")
|
|
348
388
|
when :status
|
|
349
389
|
status_list = options.get_next_argument('list of states, or nothing', mandatory: false, validation: Array)
|
|
350
390
|
status = wait_package_status(package_id, status_list: status_list)
|
|
@@ -357,64 +397,21 @@ module Aspera
|
|
|
357
397
|
@api_v5.call(
|
|
358
398
|
operation: 'DELETE',
|
|
359
399
|
subpath: 'packages',
|
|
360
|
-
content_type:
|
|
400
|
+
content_type: Mime::JSON,
|
|
361
401
|
body: {ids: ids},
|
|
362
|
-
headers: {'Accept' =>
|
|
402
|
+
headers: {'Accept' => Mime::JSON}
|
|
363
403
|
)
|
|
364
404
|
return Main.result_status('Package(s) deleted')
|
|
365
405
|
when :receive
|
|
366
406
|
return package_receive(package_id)
|
|
367
407
|
when :send
|
|
368
|
-
|
|
369
|
-
# autofill recipient for public url
|
|
370
|
-
if @api_v5.pub_link_context&.key?('recipient_type') && !parameters.key?('recipients')
|
|
371
|
-
parameters['recipients'] = [{
|
|
372
|
-
name: @api_v5.pub_link_context['name'],
|
|
373
|
-
recipient_type: @api_v5.pub_link_context['recipient_type']
|
|
374
|
-
}]
|
|
375
|
-
end
|
|
376
|
-
normalize_recipients(parameters)
|
|
377
|
-
# User specified content prot in tspec, but faspex requires in package creation
|
|
378
|
-
# `transfer_spec/upload` will set `content_protection`
|
|
379
|
-
if transfer.user_transfer_spec['content_protection'] && !parameters.key?('ear_enabled')
|
|
380
|
-
transfer.user_transfer_spec.delete('content_protection')
|
|
381
|
-
parameters['ear_enabled'] = true
|
|
382
|
-
end
|
|
383
|
-
package = @api_v5.create('packages', parameters)
|
|
384
|
-
shared_folder = options.get_option(:shared_folder)
|
|
385
|
-
if shared_folder.nil?
|
|
386
|
-
# send from local files
|
|
387
|
-
transfer_spec = @api_v5.create(
|
|
388
|
-
"packages/#{package['id']}/transfer_spec/upload",
|
|
389
|
-
{paths: transfer.source_list},
|
|
390
|
-
query: {transfer_type: Api::Faspex::TRANSFER_CONNECT}
|
|
391
|
-
)
|
|
392
|
-
# well, we asked a TS for connect, but we actually want a generic one
|
|
393
|
-
transfer_spec.delete('authentication')
|
|
394
|
-
return Main.result_transfer(transfer.start(transfer_spec))
|
|
395
|
-
else
|
|
396
|
-
# send from remote shared folder
|
|
397
|
-
if (m = Base.percent_selector(shared_folder))
|
|
398
|
-
shared_folder = lookup_entity_by_field(
|
|
399
|
-
api: @api_v5,
|
|
400
|
-
entity: 'shared_folders',
|
|
401
|
-
field: m[:field],
|
|
402
|
-
value: m[:value]
|
|
403
|
-
)['id']
|
|
404
|
-
end
|
|
405
|
-
transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
|
|
406
|
-
# start remote transfer and get first status
|
|
407
|
-
result = @api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)
|
|
408
|
-
result['id'] = package['id']
|
|
409
|
-
unless result['status'].eql?('completed')
|
|
410
|
-
formatter.display_status("Package #{package['id']}")
|
|
411
|
-
result = wait_package_status(package['id'])
|
|
412
|
-
end
|
|
413
|
-
return Main.result_single_object(result)
|
|
414
|
-
end
|
|
408
|
+
return package_send
|
|
415
409
|
when :list
|
|
416
410
|
list, total = list_packages_with_filter
|
|
417
|
-
|
|
411
|
+
fields = %w[id title status sender.name recipients.0.name release_date total_bytes total_files]
|
|
412
|
+
fields.delete('recipients.0.name') if %w[inbox inbox_history].include?(options.get_option(:box))
|
|
413
|
+
fields.delete('sender.name') if %w[outbox outbox_history].include?(options.get_option(:box))
|
|
414
|
+
return Main.result_object_list(list, total: total, fields: fields)
|
|
418
415
|
end
|
|
419
416
|
end
|
|
420
417
|
|
|
@@ -687,7 +684,7 @@ module Aspera
|
|
|
687
684
|
@api_v5.create(invitation_endpoint, params)
|
|
688
685
|
end
|
|
689
686
|
when :resend
|
|
690
|
-
@api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend")
|
|
687
|
+
@api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend", nil)
|
|
691
688
|
return Main.result_status('Invitation resent')
|
|
692
689
|
else
|
|
693
690
|
return entity_execute(
|
|
@@ -450,7 +450,7 @@ module Aspera
|
|
|
450
450
|
@api_node.call(
|
|
451
451
|
operation: 'POST',
|
|
452
452
|
subpath: 'services/soap/Transfer-201210',
|
|
453
|
-
content_type:
|
|
453
|
+
content_type: Mime::TEXT,
|
|
454
454
|
body: CENTRAL_SOAP_API_TEST,
|
|
455
455
|
headers: {'Content-Type' => 'text/xml;charset=UTF-8', 'SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'},
|
|
456
456
|
ret: :resp
|
|
@@ -471,9 +471,7 @@ module Aspera
|
|
|
471
471
|
return Main.result_single_object(nd_info)
|
|
472
472
|
when :license
|
|
473
473
|
# requires: asnodeadmin -mu <node user> --acl-add=internal --internal
|
|
474
|
-
|
|
475
|
-
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal') if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
|
476
|
-
return Main.result_single_object(node_license)
|
|
474
|
+
return Main.result_single_object(@api_node.read('license'))
|
|
477
475
|
when :api_details
|
|
478
476
|
return Main.result_single_object({base_url: @api_node.base_url}.merge(@api_node.params))
|
|
479
477
|
end
|
|
@@ -837,7 +835,7 @@ module Aspera
|
|
|
837
835
|
@api_node.call(
|
|
838
836
|
operation: 'POST',
|
|
839
837
|
subpath: "asyncs/#{asyncs_id}/#{sync_command}",
|
|
840
|
-
content_type:
|
|
838
|
+
content_type: Mime::TEXT,
|
|
841
839
|
body: '',
|
|
842
840
|
ret: :resp
|
|
843
841
|
).body
|
|
@@ -7,9 +7,33 @@ module Aspera
|
|
|
7
7
|
module Plugins
|
|
8
8
|
# base class for applications supporting OAuth 2.0 authentication
|
|
9
9
|
class Oauth < BasicAuth
|
|
10
|
-
|
|
10
|
+
class << self
|
|
11
|
+
# Get command line options specified by `AUTH_OPTIONS` and `defaults.keys` (value is default).
|
|
12
|
+
# Adds those not nil to the `kwargs`.
|
|
13
|
+
# Instantiate the provided `klass` with those `kwargs`.
|
|
14
|
+
# `defaults` can specify a default value (not `nil`)
|
|
15
|
+
# @param options [Cli::Manager] Object to get command line options.
|
|
16
|
+
# @param kwargs [Hash] Object creation arguments
|
|
17
|
+
# @param defaults [Hash] Additional options, key=symbol, value=default value or nil
|
|
18
|
+
# @return [Object] instance of `klass`
|
|
19
|
+
# @raise [Cli::Error] if a required option is missing
|
|
20
|
+
def args_from_options(options, defaults: nil, **kwargs)
|
|
21
|
+
defaults ||= {}
|
|
22
|
+
(AUTH_OPTIONS + defaults.keys).each_with_object(kwargs) do |i, m|
|
|
23
|
+
v = options.get_option(i)
|
|
24
|
+
m[i] = v unless v.nil?
|
|
25
|
+
m[i] = defaults[i] if m[i].nil? && !defaults[i].nil?
|
|
26
|
+
end
|
|
27
|
+
rescue ::ArgumentError => e
|
|
28
|
+
if (m = e.message.match(/missing keyword: :(.*)$/))
|
|
29
|
+
raise Cli::Error, "Missing option: #{m[1]}"
|
|
30
|
+
end
|
|
31
|
+
raise
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
# OAuth methods supported (web, jwt)
|
|
11
35
|
AUTH_TYPES = %i[web jwt boot].freeze
|
|
12
|
-
# Options used for authentication
|
|
36
|
+
# Options used for authentication (url, auth, client_id, etc...)
|
|
13
37
|
AUTH_OPTIONS = %i[url auth client_id client_secret redirect_uri private_key passphrase username password].freeze
|
|
14
38
|
def initialize(**_)
|
|
15
39
|
super
|
|
@@ -20,29 +44,6 @@ module Aspera
|
|
|
20
44
|
options.declare(:private_key, 'OAuth (JWT) RSA private key PEM value (prefix file path with @file:)')
|
|
21
45
|
options.declare(:passphrase, 'OAuth (JWT) RSA private key passphrase')
|
|
22
46
|
end
|
|
23
|
-
|
|
24
|
-
# Get command line options specified by `AUTH_OPTIONS` and `option.keys` (value is default).
|
|
25
|
-
# Adds those not nil to the `kwargs`.
|
|
26
|
-
# Instantiate the provided `klass` with those kwargs.
|
|
27
|
-
# `option` can specify a default value (not `nil`)
|
|
28
|
-
# @param klass [Class] API object to create
|
|
29
|
-
# @param kwargs [Hash] The fixed keyword arguments for creation
|
|
30
|
-
# @param option [Hash] Additional options, key=symbol, value:default value or nil
|
|
31
|
-
# @return [Object] instance of `klass`
|
|
32
|
-
# @raise [Cli::Error] if a required option is missing
|
|
33
|
-
def new_with_options(klass, kwargs: {}, option: {})
|
|
34
|
-
klass.new(**
|
|
35
|
-
(AUTH_OPTIONS + option.keys).each_with_object(kwargs) do |i, m|
|
|
36
|
-
v = options.get_option(i)
|
|
37
|
-
m[i] = v unless v.nil?
|
|
38
|
-
m[i] = option[i] unless !m[i].nil? || option[i].nil?
|
|
39
|
-
end)
|
|
40
|
-
rescue ::ArgumentError => e
|
|
41
|
-
if (m = e.message.match(/missing keyword: :(.*)$/))
|
|
42
|
-
raise Cli::Error, "Missing option: #{m[1]}"
|
|
43
|
-
end
|
|
44
|
-
raise
|
|
45
|
-
end
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
end
|
|
@@ -90,8 +90,8 @@ module Aspera
|
|
|
90
90
|
Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
|
|
91
91
|
values = if opt.key?(:values)
|
|
92
92
|
opt[:values]
|
|
93
|
-
elsif
|
|
94
|
-
|
|
93
|
+
elsif BoolValue.symbol?(opt[:default])
|
|
94
|
+
BoolValue::TYPES
|
|
95
95
|
end
|
|
96
96
|
options.declare(opt[:name], opt[:description].capitalize, allowed: values, handler: {o: @gen_options, m: opt[:name]}, default: opt[:default])
|
|
97
97
|
end
|
|
@@ -109,7 +109,7 @@ module Aspera
|
|
|
109
109
|
# /files/id/files is normally cached in Redis, but we can discard the cache
|
|
110
110
|
# but /files/id is not cached
|
|
111
111
|
def get_folder_entries(file_id, request_args = nil)
|
|
112
|
-
headers = {'Accept' =>
|
|
112
|
+
headers = {'Accept' => Mime::JSON}
|
|
113
113
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
|
114
114
|
return @api_node.read("files/#{file_id}/files", request_args, headers: headers)
|
|
115
115
|
end
|
|
@@ -17,20 +17,21 @@ module Aspera
|
|
|
17
17
|
# @return [Hash] with version, ping, api
|
|
18
18
|
def health_check(url)
|
|
19
19
|
result = {}
|
|
20
|
+
# Get version from main page
|
|
20
21
|
result[:version] =
|
|
21
22
|
begin
|
|
22
23
|
version = nil
|
|
23
24
|
login_page = Rest
|
|
24
25
|
.new(base_url: url, redirect_max: 2)
|
|
25
26
|
.read('', headers: {'Accept'=>'text/html'})
|
|
27
|
+
raise 'not Shares' unless login_page.include?('aspera-Shares')
|
|
26
28
|
if (m = login_page.match(/\(v([0-9a-f\.]+)\)/))
|
|
27
29
|
version = m[1]
|
|
28
30
|
if (m = login_page.match(/Patch level ([0-9]+)/))
|
|
29
|
-
version = "#{
|
|
31
|
+
version = "#{version} #{m[0]}"
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
|
-
|
|
33
|
-
version
|
|
34
|
+
version.nil? ? 'no version' : version
|
|
34
35
|
rescue => e
|
|
35
36
|
e
|
|
36
37
|
end
|
|
@@ -45,10 +46,15 @@ module Aspera
|
|
|
45
46
|
end
|
|
46
47
|
result[:api] =
|
|
47
48
|
begin
|
|
48
|
-
resp = Rest
|
|
49
|
+
data, resp = Rest
|
|
50
|
+
.new(base_url: "#{url}/#{NODE_API_PATH}", redirect_max: 1)
|
|
51
|
+
.read('info', exception: false, ret: :both)
|
|
49
52
|
# shall fail: shares requires auth, but we check error message
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
if resp.code.to_s.eql?('401') && data&.dig('error', 'user_message')&.include?('authentication failed')
|
|
54
|
+
'available'
|
|
55
|
+
else
|
|
56
|
+
raise "not found (#{resp.code})"
|
|
57
|
+
end
|
|
52
58
|
rescue => e
|
|
53
59
|
e
|
|
54
60
|
end
|
|
@@ -88,7 +94,7 @@ module Aspera
|
|
|
88
94
|
SAML_IMPORT_MANDATORY = %w[id name_id].freeze
|
|
89
95
|
SAML_IMPORT_ALLOWED = %w[email given_name surname].concat(SAML_IMPORT_MANDATORY).freeze
|
|
90
96
|
|
|
91
|
-
ACTIONS = %i[health files admin].freeze
|
|
97
|
+
ACTIONS = %i[health info files admin].freeze
|
|
92
98
|
# common to users and groups
|
|
93
99
|
USR_GRP_SETTINGS = %i[transfer_settings app_authorizations share_permissions].freeze
|
|
94
100
|
|
|
@@ -111,6 +117,8 @@ module Aspera
|
|
|
111
117
|
nagios.add_critical('API', health[:api].to_s)
|
|
112
118
|
end
|
|
113
119
|
Main.result_object_list(nagios.status_list)
|
|
120
|
+
when :info
|
|
121
|
+
return Main.result_single_object(basic_auth_api(NODE_API_PATH).read('info', headers: {'Content-Type'=>'application/json'}))
|
|
114
122
|
when :files
|
|
115
123
|
api_shares_node = basic_auth_api(NODE_API_PATH)
|
|
116
124
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/colors.rb
CHANGED
|
@@ -58,6 +58,13 @@ class String
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# Applies the provided list of string decoration (colors).
|
|
62
|
+
# @param colors [Array<Symbol>] List of decorations.
|
|
63
|
+
# @return [String] Enhanced String.
|
|
64
|
+
def apply(*colors)
|
|
65
|
+
colors.reduce(self){ |s, c| s.public_send(c)}
|
|
66
|
+
end
|
|
67
|
+
|
|
61
68
|
# Transform capitalized to snake case
|
|
62
69
|
def capital_to_snake
|
|
63
70
|
return gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
data/lib/aspera/faspex_gw.rb
CHANGED
|
@@ -52,9 +52,9 @@ module Aspera
|
|
|
52
52
|
operation: 'POST',
|
|
53
53
|
subpath: "packages/#{package['id']}/transfer_spec/upload",
|
|
54
54
|
query: {transfer_type: Api::Faspex::TRANSFER_CONNECT},
|
|
55
|
-
content_type:
|
|
55
|
+
content_type: Mime::JSON,
|
|
56
56
|
body: {paths: [{'destination'=>'/'}]},
|
|
57
|
-
headers: {'Accept' =>
|
|
57
|
+
headers: {'Accept' => Mime::JSON}
|
|
58
58
|
)
|
|
59
59
|
transfer_spec.delete('authentication')
|
|
60
60
|
# but we place it in a Faspex package creation response
|
|
@@ -82,18 +82,18 @@ module Aspera
|
|
|
82
82
|
end
|
|
83
83
|
Log.log.debug{"faspex_package_create_result=#{faspex_package_create_result}"}
|
|
84
84
|
response.status = 200
|
|
85
|
-
response.content_type =
|
|
85
|
+
response.content_type = Mime::JSON
|
|
86
86
|
response.body = JSON.generate(faspex_package_create_result)
|
|
87
87
|
rescue => e
|
|
88
88
|
response.status = 500
|
|
89
|
-
response['Content-Type'] =
|
|
89
|
+
response['Content-Type'] = Mime::JSON
|
|
90
90
|
response.body = {error: e.message, stacktrace: e.backtrace}.to_json
|
|
91
91
|
Log.log.error(e.message)
|
|
92
92
|
Log.log.debug{e.backtrace.join("\n")}
|
|
93
93
|
end
|
|
94
94
|
else
|
|
95
95
|
response.status = 400
|
|
96
|
-
response['Content-Type'] =
|
|
96
|
+
response['Content-Type'] = Mime::JSON
|
|
97
97
|
response.body = {error: 'Unsupported endpoint'}.to_json
|
|
98
98
|
end
|
|
99
99
|
end
|
|
@@ -32,13 +32,13 @@ module Aspera
|
|
|
32
32
|
# Only accept requests on the root
|
|
33
33
|
if !request.path.start_with?(@parameters[:root])
|
|
34
34
|
response.status = 400
|
|
35
|
-
response['Content-Type'] =
|
|
35
|
+
response['Content-Type'] = Mime::JSON
|
|
36
36
|
response.body = {status: 'error', message: 'Request outside domain'}.to_json
|
|
37
37
|
return
|
|
38
38
|
end
|
|
39
39
|
if request.body.nil?
|
|
40
40
|
response.status = 400
|
|
41
|
-
response['Content-Type'] =
|
|
41
|
+
response['Content-Type'] = Mime::JSON
|
|
42
42
|
response.body = {status: 'error', message: 'Empty request'}.to_json
|
|
43
43
|
return
|
|
44
44
|
end
|
|
@@ -65,7 +65,7 @@ module Aspera
|
|
|
65
65
|
raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
|
|
66
66
|
end
|
|
67
67
|
response.status = 200
|
|
68
|
-
response.content_type =
|
|
68
|
+
response.content_type = Mime::JSON
|
|
69
69
|
response.body = JSON.generate({status: 'success', script: script_path, exit_code: process_status.exitstatus})
|
|
70
70
|
Log.log.debug{'Script executed successfully'}
|
|
71
71
|
rescue => e
|
|
@@ -76,7 +76,7 @@ module Aspera
|
|
|
76
76
|
Log.log.error("Killed process: #{post_proc_pid}")
|
|
77
77
|
end
|
|
78
78
|
response.status = 500
|
|
79
|
-
response['Content-Type'] =
|
|
79
|
+
response['Content-Type'] = Mime::JSON
|
|
80
80
|
response.body = {status: 'error', script: script_path, message: e.message}.to_json
|
|
81
81
|
end
|
|
82
82
|
end
|
data/lib/aspera/log.rb
CHANGED
|
@@ -65,11 +65,8 @@ module Aspera
|
|
|
65
65
|
|
|
66
66
|
# Class methods
|
|
67
67
|
class << self
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# @param colors [Array(Symbol)] List of decorations
|
|
71
|
-
def apply_colors(value, colors)
|
|
72
|
-
colors.inject(value){ |s, c| s.send(c)}
|
|
68
|
+
def short_levl(level)
|
|
69
|
+
"#{level[0, 3]}#{level[-1]}"
|
|
73
70
|
end
|
|
74
71
|
|
|
75
72
|
# Get the logger object of singleton
|
|
@@ -154,8 +151,8 @@ module Aspera
|
|
|
154
151
|
|
|
155
152
|
def formatter=(formatter)
|
|
156
153
|
if formatter.is_a?(String)
|
|
157
|
-
raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.
|
|
158
|
-
formatter =
|
|
154
|
+
raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.join(', ')}" unless FORMATTER_LAMBDAS.key?(formatter.to_sym)
|
|
155
|
+
formatter = FORMATTER_LAMBDAS[formatter.to_sym]
|
|
159
156
|
elsif !formatter.respond_to?(:call) && !formatter.is_a?(Logger::Formatter)
|
|
160
157
|
raise Error, 'Formatter must be a String, a Logger::Formatter or a Proc'
|
|
161
158
|
end
|
|
@@ -226,18 +223,22 @@ module Aspera
|
|
|
226
223
|
UNKNOWN: %i{blink}
|
|
227
224
|
}.freeze
|
|
228
225
|
|
|
229
|
-
# Short levels with color
|
|
230
|
-
LVL_COLOR = LVL_DECO.
|
|
226
|
+
# Short (4-letters) levels with color
|
|
227
|
+
LVL_COLOR = LVL_DECO.to_h do |k, v|
|
|
228
|
+
[k, short_levl(k).apply(*v)]
|
|
229
|
+
end.freeze
|
|
231
230
|
|
|
232
231
|
DEFAULT_FORMATTER = ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{m}\n"}
|
|
233
232
|
|
|
234
233
|
# pre-defined formatters
|
|
235
|
-
|
|
234
|
+
FORMATTER_LAMBDAS = {
|
|
236
235
|
standard: Logger::Formatter.new,
|
|
237
236
|
default: DEFAULT_FORMATTER,
|
|
238
237
|
caller: ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{Log.caller_method}\n#{m}\n"}
|
|
239
238
|
}.freeze
|
|
240
239
|
|
|
241
|
-
|
|
240
|
+
FORMATTERS = FORMATTER_LAMBDAS.keys
|
|
241
|
+
|
|
242
|
+
private_constant :LVL_DECO, :DEFAULT_FORMATTER, :FORMATTER_LAMBDAS
|
|
242
243
|
end
|
|
243
244
|
end
|
data/lib/aspera/markdown.rb
CHANGED
|
@@ -328,7 +328,7 @@ module Aspera
|
|
|
328
328
|
|
|
329
329
|
def set_json_response(request, response, json, code: 200)
|
|
330
330
|
response.status = code
|
|
331
|
-
response['Content-Type'] =
|
|
331
|
+
response['Content-Type'] = Mime::JSON
|
|
332
332
|
response.body = json.to_json
|
|
333
333
|
Log.log.trace1{Log.obj_dump("response for #{request.request_method} #{request.path}", json)}
|
|
334
334
|
end
|
data/lib/aspera/oauth/base.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Aspera
|
|
|
53
53
|
def create_token_call(creation_params)
|
|
54
54
|
Log.log.debug{'Generating a new token'.bg_green}
|
|
55
55
|
return @api.create(@path_token, nil, query: creation_params, ret: :resp) if @use_query
|
|
56
|
-
return @api.create(@path_token, creation_params, content_type:
|
|
56
|
+
return @api.create(@path_token, creation_params, content_type: Mime::WWW, ret: :resp)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
# Create base parameters for token creation calls
|
|
@@ -24,9 +24,9 @@ module Aspera
|
|
|
24
24
|
operation: 'POST',
|
|
25
25
|
subpath: path_token,
|
|
26
26
|
query: @query.merge(scope: params[:scope]), # scope is here because it may change over time (node)
|
|
27
|
-
content_type:
|
|
27
|
+
content_type: Mime::JSON,
|
|
28
28
|
body: @body,
|
|
29
|
-
headers: {'Accept' =>
|
|
29
|
+
headers: {'Accept' => Mime::JSON},
|
|
30
30
|
ret: :resp
|
|
31
31
|
)
|
|
32
32
|
end
|