aspera-cli 4.17.0 → 4.18.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 +2 -4
- data/CHANGELOG.md +23 -0
- data/CONTRIBUTING.md +15 -1
- data/README.md +620 -378
- data/bin/ascli +5 -0
- data/bin/asession +2 -2
- data/lib/aspera/agent/alpha.rb +6 -4
- data/lib/aspera/agent/base.rb +9 -6
- data/lib/aspera/agent/connect.rb +4 -4
- data/lib/aspera/agent/direct.rb +56 -37
- data/lib/aspera/agent/httpgw.rb +23 -324
- data/lib/aspera/agent/node.rb +19 -20
- data/lib/aspera/agent/trsdk.rb +19 -20
- data/lib/aspera/api/aoc.rb +17 -14
- data/lib/aspera/api/cos_node.rb +4 -4
- data/lib/aspera/api/httpgw.rb +339 -0
- data/lib/aspera/api/node.rb +34 -21
- data/lib/aspera/ascmd.rb +4 -3
- data/lib/aspera/ascp/installation.rb +15 -7
- data/lib/aspera/ascp/management.rb +2 -2
- data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
- data/lib/aspera/cli/extended_value.rb +12 -6
- data/lib/aspera/cli/formatter.rb +155 -65
- data/lib/aspera/cli/hints.rb +18 -0
- data/lib/aspera/cli/main.rb +22 -29
- data/lib/aspera/cli/manager.rb +53 -36
- data/lib/aspera/cli/plugin.rb +26 -17
- data/lib/aspera/cli/plugin_factory.rb +31 -20
- data/lib/aspera/cli/plugins/alee.rb +14 -2
- data/lib/aspera/cli/plugins/aoc.rb +141 -131
- data/lib/aspera/cli/plugins/ats.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +52 -46
- data/lib/aspera/cli/plugins/console.rb +8 -5
- data/lib/aspera/cli/plugins/faspex.rb +27 -19
- data/lib/aspera/cli/plugins/faspex5.rb +222 -149
- data/lib/aspera/cli/plugins/faspio.rb +85 -0
- data/lib/aspera/cli/plugins/httpgw.rb +55 -0
- data/lib/aspera/cli/plugins/node.rb +86 -29
- data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
- data/lib/aspera/cli/plugins/preview.rb +6 -2
- data/lib/aspera/cli/plugins/server.rb +5 -5
- data/lib/aspera/cli/plugins/shares.rb +16 -14
- data/lib/aspera/cli/sync_actions.rb +6 -6
- data/lib/aspera/cli/transfer_agent.rb +5 -4
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +7 -6
- data/lib/aspera/faspex_gw.rb +5 -4
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/log.rb +6 -3
- data/lib/aspera/node_simulator.rb +2 -2
- data/lib/aspera/oauth/base.rb +31 -19
- data/lib/aspera/oauth/factory.rb +12 -13
- data/lib/aspera/oauth/generic.rb +1 -0
- data/lib/aspera/oauth/jwt.rb +18 -15
- data/lib/aspera/oauth/url_json.rb +8 -6
- data/lib/aspera/open_application.rb +5 -7
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/preview/options.rb +3 -3
- data/lib/aspera/preview/terminal.rb +4 -4
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +5 -1
- data/lib/aspera/rest.rb +60 -74
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +2 -2
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +2 -4
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/parameters.rb +39 -36
- data/lib/aspera/transfer/spec.rb +2 -0
- data/lib/aspera/transfer/sync.rb +2 -1
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +5 -4
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +4 -3
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/plugins/bss.rb +0 -71
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aspera/rest'
|
4
|
+
require 'aspera/nagios'
|
5
|
+
require 'aspera/cli/basic_auth_plugin'
|
6
|
+
|
7
|
+
module Aspera
|
8
|
+
module Cli
|
9
|
+
module Plugins
|
10
|
+
class Faspio < BasicAuthPlugin
|
11
|
+
class << self
|
12
|
+
def application_name
|
13
|
+
'faspio Gateway'
|
14
|
+
end
|
15
|
+
|
16
|
+
def detect(base_url)
|
17
|
+
api = Rest.new(base_url: base_url)
|
18
|
+
ping_result = api.read('ping')
|
19
|
+
server_type = ping_result[:http]['Server']
|
20
|
+
return nil unless ping_result[:data].is_a?(Hash) && ping_result[:data].empty?
|
21
|
+
return nil unless server_type.is_a?(String) && server_type.include?('faspio')
|
22
|
+
return {
|
23
|
+
version: server_type.gsub(%r{^.*/}, ''),
|
24
|
+
url: base_url
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
ACTIONS = %i[health bridges].freeze
|
29
|
+
|
30
|
+
def initialize(**env)
|
31
|
+
super
|
32
|
+
options.declare(:auth, 'OAuth type of authentication', values: %i[jwt basic])
|
33
|
+
options.declare(:client_id, 'OAuth client identifier')
|
34
|
+
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
35
|
+
options.declare(:passphrase, 'OAuth JWT RSA private key passphrase')
|
36
|
+
options.parse_options!
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute_action
|
40
|
+
base_url = options.get_option(:url, mandatory: true)
|
41
|
+
api =
|
42
|
+
case options.get_option(:auth, mandatory: true)
|
43
|
+
when :basic
|
44
|
+
basic_auth_api
|
45
|
+
when :jwt
|
46
|
+
app_client_id = options.get_option(:client_id, mandatory: true)
|
47
|
+
Rest.new(
|
48
|
+
base_url: base_url,
|
49
|
+
auth: {
|
50
|
+
type: :oauth2,
|
51
|
+
grant_method: :jwt,
|
52
|
+
base_url: "#{base_url}/auth",
|
53
|
+
client_id: app_client_id,
|
54
|
+
use_query: true,
|
55
|
+
payload: {
|
56
|
+
iss: app_client_id, # issuer
|
57
|
+
sub: app_client_id # subject
|
58
|
+
},
|
59
|
+
private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, mandatory: true), options.get_option(:passphrase)),
|
60
|
+
headers: {typ: 'JWT'}
|
61
|
+
})
|
62
|
+
end
|
63
|
+
command = options.get_next_command(ACTIONS)
|
64
|
+
case command
|
65
|
+
when :health
|
66
|
+
nagios = Nagios.new
|
67
|
+
begin
|
68
|
+
result = api.read('ping')[:data]
|
69
|
+
if result.is_a?(Hash) && result.empty?
|
70
|
+
nagios.add_ok('api', 'answered ok')
|
71
|
+
else
|
72
|
+
nagios.add_critical('api', 'not expected answer')
|
73
|
+
end
|
74
|
+
rescue StandardError => e
|
75
|
+
nagios.add_critical('api', e.to_s)
|
76
|
+
end
|
77
|
+
return nagios.result
|
78
|
+
when :bridges
|
79
|
+
return entity_action(api, 'bridges')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aspera/rest'
|
4
|
+
require 'aspera/api/httpgw'
|
5
|
+
require 'aspera/nagios'
|
6
|
+
|
7
|
+
module Aspera
|
8
|
+
module Cli
|
9
|
+
module Plugins
|
10
|
+
class Httpgw < Plugin
|
11
|
+
class << self
|
12
|
+
def application_name
|
13
|
+
'HTTP Gateway'
|
14
|
+
end
|
15
|
+
|
16
|
+
def detect(base_url)
|
17
|
+
api = Api::Httpgw.new(url: base_url)
|
18
|
+
api_info = api.info
|
19
|
+
return {
|
20
|
+
url: base_url,
|
21
|
+
version: api_info['version']
|
22
|
+
} if api_info.is_a?(Hash) && api_info.key?('download_endpoint')
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
ACTIONS = %i[health info].freeze
|
27
|
+
|
28
|
+
def initialize(**env)
|
29
|
+
super
|
30
|
+
options.declare(:url, 'URL of application, e.g. https://app.example.com/aspera/app')
|
31
|
+
options.parse_options!
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute_action
|
35
|
+
base_url = options.get_option(:url, mandatory: true)
|
36
|
+
command = options.get_next_command(ACTIONS)
|
37
|
+
case command
|
38
|
+
when :health
|
39
|
+
nagios = Nagios.new
|
40
|
+
begin
|
41
|
+
Api::Httpgw.new(url: base_url)
|
42
|
+
nagios.add_ok('api', 'answered ok')
|
43
|
+
rescue StandardError => e
|
44
|
+
nagios.add_critical('api', e.to_s)
|
45
|
+
end
|
46
|
+
return nagios.result
|
47
|
+
when :info
|
48
|
+
api_v1 = Api::Httpgw.new(url: base_url)
|
49
|
+
return {type: :single_object, data: api_v1.info}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -44,7 +44,8 @@ module Aspera
|
|
44
44
|
next unless result[:http].body.eql?('')
|
45
45
|
url_length = -2 - test_endpoint.length
|
46
46
|
return {
|
47
|
-
url:
|
47
|
+
url: result[:http].uri.to_s[0..url_length],
|
48
|
+
version: 'requires authentication'
|
48
49
|
}
|
49
50
|
rescue StandardError => e
|
50
51
|
error = e
|
@@ -92,7 +93,7 @@ module Aspera
|
|
92
93
|
SEARCH_REMOVE_FIELDS = %w[basename permissions].freeze
|
93
94
|
|
94
95
|
# actions in execute_command_gen3
|
95
|
-
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete browse upload download http_node_download sync]
|
96
|
+
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete browse upload download http_node_download sync transport]
|
96
97
|
|
97
98
|
BASE_ACTIONS = %i[api_details].concat(COMMANDS_GEN3).freeze
|
98
99
|
|
@@ -187,6 +188,68 @@ module Aspera
|
|
187
188
|
raise StandardError, 'expect: nil, String or Array'
|
188
189
|
end
|
189
190
|
|
191
|
+
# directory: node, container: shares
|
192
|
+
FOLDER_TYPE = %w[directory container].freeze
|
193
|
+
|
194
|
+
def browse_gen3(prefix_path)
|
195
|
+
folders_to_process = [get_next_arg_add_prefix(prefix_path, 'path')]
|
196
|
+
query = options.get_option(:query, default: {})
|
197
|
+
# special parameter: max number of entries in result
|
198
|
+
max_items = query.delete('max')
|
199
|
+
# special parameter: recursive browsing
|
200
|
+
recursive = query.delete('recursive')
|
201
|
+
# special parameter: only return one entry for the path, even if folder
|
202
|
+
only_path = query.delete('self')
|
203
|
+
# allow user to specify a single call, and not recursive
|
204
|
+
single_call = query.key?('skip')
|
205
|
+
# API default is 100, so use 1000 for default
|
206
|
+
query['count'] ||= 1000
|
207
|
+
raise Cli::BadArgument, 'options recursive and skip cannot be used together' if recursive && single_call
|
208
|
+
all_items = []
|
209
|
+
until folders_to_process.empty?
|
210
|
+
path = folders_to_process.shift
|
211
|
+
query['path'] = path
|
212
|
+
offset = 0
|
213
|
+
total_count = nil
|
214
|
+
result = nil
|
215
|
+
loop do
|
216
|
+
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
217
|
+
response = @api_node.call(
|
218
|
+
operation: 'POST',
|
219
|
+
subpath: 'files/browse',
|
220
|
+
headers: {'Accept' => 'application/json'},
|
221
|
+
body: query,
|
222
|
+
body_type: :json)
|
223
|
+
# 'file','symbolic_link'
|
224
|
+
if only_path || !FOLDER_TYPE.include?(response[:data]['self']['type'])
|
225
|
+
result = { type: :single_object, data: response[:data]['self']}
|
226
|
+
break
|
227
|
+
end
|
228
|
+
items = response[:data]['items']
|
229
|
+
total_count ||= response[:data]['total_count']
|
230
|
+
all_items.concat(items)
|
231
|
+
if single_call
|
232
|
+
formatter.display_item_count(response[:data]['item_count'], total_count)
|
233
|
+
break
|
234
|
+
end
|
235
|
+
if recursive
|
236
|
+
folders_to_process.concat(items.select{|i|FOLDER_TYPE.include?(i['type'])}.map{|i|i['path']})
|
237
|
+
end
|
238
|
+
if !max_items.nil? && (all_items.count >= max_items)
|
239
|
+
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
240
|
+
break
|
241
|
+
end
|
242
|
+
break if all_items.count >= total_count
|
243
|
+
offset += items.count
|
244
|
+
query['skip'] = offset
|
245
|
+
formatter.long_operation_running(all_items.count)
|
246
|
+
end
|
247
|
+
query.delete('skip')
|
248
|
+
end
|
249
|
+
result ||= {type: :object_list, data: all_items}
|
250
|
+
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
251
|
+
end
|
252
|
+
|
190
253
|
# file and folder related commands
|
191
254
|
def execute_command_gen3(command, prefix_path)
|
192
255
|
case command
|
@@ -235,20 +298,7 @@ module Aspera
|
|
235
298
|
resp = @api_node.create('files/rename', { 'paths' => [{ 'path' => path_base, 'source' => path_src, 'destination' => path_dst }] })
|
236
299
|
return c_result_translate_rem_prefix(resp, 'entry', 'moved', prefix_path)
|
237
300
|
when :browse
|
238
|
-
|
239
|
-
additional_query = options.get_option(:query)
|
240
|
-
query.merge!(additional_query) unless additional_query.nil?
|
241
|
-
send_result = @api_node.create('files/browse', query)[:data]
|
242
|
-
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
243
|
-
# if there is no items
|
244
|
-
case send_result['self']['type']
|
245
|
-
when 'directory', 'container' # directory: node, container: shares
|
246
|
-
result = { data: send_result['items'], type: :object_list }
|
247
|
-
formatter.display_item_count(send_result['item_count'], send_result['total_count'])
|
248
|
-
else # 'file','symbolic_link'
|
249
|
-
result = { data: send_result['self'], type: :single_object}
|
250
|
-
end
|
251
|
-
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
301
|
+
return browse_gen3(prefix_path)
|
252
302
|
when :sync
|
253
303
|
return execute_sync_action do |sync_direction, local_path, remote_path|
|
254
304
|
# Gen3 API
|
@@ -303,6 +353,8 @@ module Aspera
|
|
303
353
|
subpath: "files/#{URI.encode_www_form_component(remote_path)}/contents",
|
304
354
|
save_to_file: File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_name))
|
305
355
|
return Main.result_status("downloaded: #{file_name}")
|
356
|
+
when :transport
|
357
|
+
return {type: :single_object, data: @api_node.transport_params}
|
306
358
|
end
|
307
359
|
Aspera.error_unreachable_line
|
308
360
|
end
|
@@ -358,9 +410,10 @@ module Aspera
|
|
358
410
|
begin
|
359
411
|
@api_node.call(
|
360
412
|
operation: 'POST',
|
361
|
-
subpath:
|
362
|
-
headers:
|
363
|
-
|
413
|
+
subpath: 'services/soap/Transfer-201210',
|
414
|
+
headers: {'Content-Type' => 'text/xml;charset=UTF-8', 'SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'},
|
415
|
+
body: CENTRAL_SOAP_API_TEST,
|
416
|
+
body_type: :text)[:http].body
|
364
417
|
nagios.add_ok('central', 'accessible by node')
|
365
418
|
rescue StandardError => e
|
366
419
|
nagios.add_critical('central', e.to_s)
|
@@ -420,7 +473,7 @@ module Aspera
|
|
420
473
|
result[:password] = apifid[:api].auth_params[:password]
|
421
474
|
when :oauth2
|
422
475
|
result[:username] = apifid[:api].params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
|
423
|
-
result[:password] = apifid[:api].
|
476
|
+
result[:password] = apifid[:api].oauth.token
|
424
477
|
else Aspera.error_unreachable_line
|
425
478
|
end
|
426
479
|
return {type: :single_object, data: result} if command_repo.eql?(:node_info)
|
@@ -431,7 +484,7 @@ module Aspera
|
|
431
484
|
apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
|
432
485
|
file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
433
486
|
if file_info['type'].eql?('folder')
|
434
|
-
result = apifid[:api].read("files/#{apifid[:file_id]}/files",
|
487
|
+
result = apifid[:api].read("files/#{apifid[:file_id]}/files", query_read_delete)
|
435
488
|
items = result[:data]
|
436
489
|
formatter.display_item_count(result[:data].length, result[:http]['X-Total-Count'])
|
437
490
|
else
|
@@ -538,7 +591,7 @@ module Aspera
|
|
538
591
|
subpath: "files/#{apifid[:file_id]}/preview",
|
539
592
|
headers: {'Accept' => 'image/png'}
|
540
593
|
)
|
541
|
-
return Main.
|
594
|
+
return Main.result_image(result[:http].body, formatter: formatter)
|
542
595
|
when :permission
|
543
596
|
apifid = apifid_from_next_arg(top_file_id)
|
544
597
|
command_perm = options.get_next_command(%i[list create delete])
|
@@ -574,9 +627,9 @@ module Aspera
|
|
574
627
|
else Aspera.error_unreachable_line
|
575
628
|
end
|
576
629
|
else Aspera.error_unreachable_line
|
577
|
-
end
|
630
|
+
end
|
578
631
|
Aspera.error_unreachable_line
|
579
|
-
end
|
632
|
+
end
|
580
633
|
|
581
634
|
# This is older API
|
582
635
|
def execute_async
|
@@ -695,11 +748,15 @@ module Aspera
|
|
695
748
|
when *Plugin::ALL_OPS then return entity_command(sync_command, @api_node, 'asyncs', item_list_key: 'ids'){|field, value|ssync_lookup(field, value)}
|
696
749
|
else
|
697
750
|
asyncs_id = instance_identifier {|field, value|ssync_lookup(field, value)}
|
698
|
-
parameters = nil
|
699
751
|
if %i[start stop].include?(sync_command)
|
700
|
-
@api_node.
|
752
|
+
@api_node.call(
|
753
|
+
operation: 'POST',
|
754
|
+
subpath: "asyncs/#{asyncs_id}/#{sync_command}",
|
755
|
+
body: '',
|
756
|
+
body_type: :text)[:http].body
|
701
757
|
return Main.result_status('Done')
|
702
758
|
end
|
759
|
+
parameters = nil
|
703
760
|
parameters = query_option(default: {}) if %i[bandwidth counters files].include?(sync_command)
|
704
761
|
return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters)[:data] }
|
705
762
|
end
|
@@ -707,7 +764,7 @@ module Aspera
|
|
707
764
|
command = options.get_next_command(%i[list create show modify cancel])
|
708
765
|
case command
|
709
766
|
when :list
|
710
|
-
resp = @api_node.read('ops/transfers',
|
767
|
+
resp = @api_node.read('ops/transfers', query_read_delete)
|
711
768
|
return { type: :object_list, data: resp[:data], fields: %w[id status] } # TODO: useful?
|
712
769
|
when :create
|
713
770
|
resp = @api_node.create('streams', value_create_modify(command: command))
|
@@ -841,7 +898,7 @@ module Aspera
|
|
841
898
|
resp = @api_node.create(res_class_path, value_create_modify(command: command))
|
842
899
|
return Main.result_status("#{resp[:data]['id']} created")
|
843
900
|
when :list
|
844
|
-
resp = @api_node.read(res_class_path,
|
901
|
+
resp = @api_node.read(res_class_path, query_read_delete)
|
845
902
|
return { type: :value_list, data: resp[:data]['ids'], name: 'id' }
|
846
903
|
when :show
|
847
904
|
return { type: :single_object, data: @api_node.read(one_res_path)[:data]}
|
@@ -914,7 +971,7 @@ module Aspera
|
|
914
971
|
server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], transfer)
|
915
972
|
server.start
|
916
973
|
return Main.result_status('Simulator terminated')
|
917
|
-
end
|
974
|
+
end
|
918
975
|
raise 'ERROR: shall not reach this line'
|
919
976
|
end
|
920
977
|
end
|
@@ -60,33 +60,37 @@ module Aspera
|
|
60
60
|
|
61
61
|
ACTIONS = %i[health info workflow plugins processes].freeze
|
62
62
|
|
63
|
-
|
64
|
-
|
63
|
+
# call orchestrator api
|
64
|
+
# @param endpoint [String] the endpoint to call
|
65
|
+
# @param prefix [String] the prefix to add to the endpoint
|
66
|
+
# @param id [String] the id to add to the endpoint
|
67
|
+
# @param ret_style [Symbol] the return style, :header, :arg, :ext(extension)
|
68
|
+
# @param format [String] the format to request, 'json', 'xml', nil
|
69
|
+
# @param args [Hash] the arguments to pass
|
70
|
+
# @param xml_arrays [Boolean] if true, force arrays in xml parsing
|
71
|
+
def call_ao(endpoint, prefix: 'api', id: nil, ret_style: nil, format: 'json', args: nil, xml_arrays: true)
|
65
72
|
# calls are GET
|
66
73
|
call_args = {operation: 'GET', subpath: endpoint}
|
67
74
|
# specify prefix if necessary
|
68
|
-
call_args[:subpath] = "#{
|
75
|
+
call_args[:subpath] = "#{prefix}/#{call_args[:subpath]}" unless prefix.nil?
|
69
76
|
# specify id if necessary
|
70
|
-
call_args[:subpath] = "#{call_args[:subpath]}/#{
|
71
|
-
|
72
|
-
|
73
|
-
format = 'json'
|
74
|
-
format = opt[:format] if opt.key?(:format)
|
75
|
-
call_args[:url_params] = opt[:args] unless opt[:args].nil?
|
77
|
+
call_args[:subpath] = "#{call_args[:subpath]}/#{id}" unless id.nil?
|
78
|
+
ret_style = options.get_option(:ret_style, mandatory: true) if ret_style.nil?
|
79
|
+
call_args[:query] = args unless args.nil?
|
76
80
|
unless format.nil?
|
77
|
-
case
|
81
|
+
case ret_style
|
78
82
|
when :header
|
79
83
|
call_args[:headers] = {'Accept' => "application/#{format}" }
|
80
84
|
when :arg
|
81
|
-
call_args[:
|
82
|
-
call_args[:
|
85
|
+
call_args[:query] ||= {}
|
86
|
+
call_args[:query][:format] = format
|
83
87
|
when :ext
|
84
88
|
call_args[:subpath] = "#{call_args[:subpath]}.#{format}"
|
85
|
-
else Aspera.error_unexpected_value(
|
89
|
+
else Aspera.error_unexpected_value(ret_style)
|
86
90
|
end
|
87
91
|
end
|
88
92
|
result = @api_orch.call(**call_args)
|
89
|
-
result[:data] = XmlSimple.xml_in(result[:http].body,
|
93
|
+
result[:data] = XmlSimple.xml_in(result[:http].body, {'ForceArray' => xml_arrays}) if format.eql?('xml')
|
90
94
|
Log.log.debug{Log.dump(:data, result[:data])}
|
91
95
|
return result
|
92
96
|
end
|
@@ -121,7 +125,7 @@ module Aspera
|
|
121
125
|
when :health
|
122
126
|
nagios = Nagios.new
|
123
127
|
begin
|
124
|
-
info = call_ao('remote_node_ping', format: 'xml',
|
128
|
+
info = call_ao('remote_node_ping', format: 'xml', xml_arrays: false)[:data]
|
125
129
|
nagios.add_ok('api', 'accessible')
|
126
130
|
nagios.check_product_version('api', 'orchestrator', info['orchestrator-version'])
|
127
131
|
rescue StandardError => e
|
@@ -129,7 +133,7 @@ module Aspera
|
|
129
133
|
end
|
130
134
|
return nagios.result
|
131
135
|
when :info
|
132
|
-
result = call_ao('remote_node_ping', format: 'xml',
|
136
|
+
result = call_ao('remote_node_ping', format: 'xml', xml_arrays: false)[:data]
|
133
137
|
return {type: :single_object, data: result}
|
134
138
|
when :processes
|
135
139
|
# TODO: Bug ? API has only XML format
|
@@ -146,9 +150,8 @@ module Aspera
|
|
146
150
|
end
|
147
151
|
case command
|
148
152
|
when :status
|
149
|
-
|
150
|
-
|
151
|
-
result = call_ao('workflows_status', call_opts)[:data]
|
153
|
+
wf_id = nil if wf_id.eql?(ExtendedValue::ALL)
|
154
|
+
result = call_ao('workflows_status', id: wf_id)[:data]
|
152
155
|
return {type: :object_list, data: result['workflows']['workflow']}
|
153
156
|
when :list
|
154
157
|
result = call_ao('workflows_list', id: 0)[:data]
|
@@ -172,7 +175,6 @@ module Aspera
|
|
172
175
|
data: nil
|
173
176
|
}
|
174
177
|
call_params = {format: :json}
|
175
|
-
override_accept = nil
|
176
178
|
# get external parameters if any
|
177
179
|
options.get_next_argument('external_parameters', mandatory: false, type: Hash, default: {}).each do |name, value|
|
178
180
|
call_params["external_parameters[#{name}]"] = value
|
@@ -192,15 +194,15 @@ module Aspera
|
|
192
194
|
end
|
193
195
|
if call_params['synchronous']
|
194
196
|
result[:type] = :text
|
195
|
-
override_accept = 'text/plain'
|
196
197
|
end
|
197
|
-
result[:data] = call_ao('initiate', id: wf_id, args: call_params
|
198
|
+
result[:data] = call_ao('initiate', id: wf_id, args: call_params)[:data]
|
198
199
|
return result
|
199
|
-
end
|
200
|
+
end
|
200
201
|
else Aspera.error_unexpected_value(command)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
private :call_ao
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -128,7 +128,11 @@ module Aspera
|
|
128
128
|
def get_folder_entries(file_id, request_args=nil)
|
129
129
|
headers = {'Accept' => 'application/json'}
|
130
130
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
131
|
-
return @api_node.call(
|
131
|
+
return @api_node.call(
|
132
|
+
operation: 'GET',
|
133
|
+
subpath: "files/#{file_id}/files",
|
134
|
+
headers: headers,
|
135
|
+
query: request_args)[:data]
|
132
136
|
# return @api_node.read("files/#{file_id}/files",request_args)[:data]
|
133
137
|
end
|
134
138
|
|
@@ -338,7 +342,7 @@ module Aspera
|
|
338
342
|
rescue StandardError => e
|
339
343
|
Log.log.error{"Ignore: #{e.message}"}
|
340
344
|
Log.log.debug(e.backtrace.join("\n").red)
|
341
|
-
end
|
345
|
+
end
|
342
346
|
|
343
347
|
# scan all files in provided folder entry
|
344
348
|
# @param top_path subpath to start folder scan inside
|
@@ -7,7 +7,7 @@ module Aspera
|
|
7
7
|
module Plugins
|
8
8
|
# Plugin for Aspera Shares v1
|
9
9
|
class Shares < Cli::BasicAuthPlugin
|
10
|
-
|
10
|
+
NODE_API_PREFIX = 'node_api'
|
11
11
|
class << self
|
12
12
|
def detect(address_or_url)
|
13
13
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
@@ -16,7 +16,7 @@ module Aspera
|
|
16
16
|
begin
|
17
17
|
# shall fail: shares requires auth, but we check error message
|
18
18
|
# TODO: use ping instead ?
|
19
|
-
api.read("#{
|
19
|
+
api.read("#{NODE_API_PREFIX}/app")
|
20
20
|
rescue RestCallError => e
|
21
21
|
if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
22
22
|
found = true
|
@@ -64,22 +64,24 @@ module Aspera
|
|
64
64
|
when :health
|
65
65
|
nagios = Nagios.new
|
66
66
|
begin
|
67
|
-
Rest
|
68
|
-
.new(base_url: "#{options.get_option(:url, mandatory: true)}/#{
|
67
|
+
res = Rest
|
68
|
+
.new(base_url: "#{options.get_option(:url, mandatory: true)}/#{NODE_API_PREFIX}")
|
69
69
|
.call(
|
70
70
|
operation: 'GET',
|
71
71
|
subpath: 'ping',
|
72
|
-
headers: {'content-type': 'application/json'}
|
73
|
-
|
72
|
+
headers: {'content-type': 'application/json'})
|
73
|
+
raise 'Shares not detected' unless res[:http].body.eql?(' ')
|
74
74
|
nagios.add_ok('shares api', 'accessible')
|
75
75
|
rescue StandardError => e
|
76
|
-
nagios.add_critical('
|
76
|
+
nagios.add_critical('API', e.to_s)
|
77
77
|
end
|
78
78
|
return nagios.result
|
79
79
|
when :repository, :files
|
80
|
-
api_shares_node = basic_auth_api(
|
80
|
+
api_shares_node = basic_auth_api(NODE_API_PREFIX)
|
81
81
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
82
|
-
return Node
|
82
|
+
return Node
|
83
|
+
.new(**init_params, api: api_shares_node)
|
84
|
+
.execute_action(repo_command)
|
83
85
|
when :admin
|
84
86
|
api_shares_admin = basic_auth_api('api/v1')
|
85
87
|
admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
|
@@ -150,8 +152,8 @@ module Aspera
|
|
150
152
|
end
|
151
153
|
end
|
152
154
|
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -60,9 +60,9 @@ module Aspera
|
|
60
60
|
sync_session_name = options.get_next_argument('name of sync session', mandatory: false, type: String)
|
61
61
|
async_params = options.get_option(:sync_info, mandatory: true)
|
62
62
|
return {type: :single_object, data: Transfer::Sync.admin_status(async_params, sync_session_name)}
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -26,6 +26,7 @@ module Aspera
|
|
26
26
|
|
27
27
|
<%=ts.to_yaml%>
|
28
28
|
END_OF_TEMPLATE
|
29
|
+
CP4I_REMOTE_HOST_LB = 'N/A'
|
29
30
|
# % (formatting bug in eclipse)
|
30
31
|
private_constant :FILE_LIST_FROM_ARGS,
|
31
32
|
:FILE_LIST_FROM_TRANSFER_SPEC,
|
@@ -101,8 +102,6 @@ module Aspera
|
|
101
102
|
def agent_instance
|
102
103
|
return @agent unless @agent.nil?
|
103
104
|
agent_type = @opt_mgr.get_option(:transfer, mandatory: true)
|
104
|
-
# agent plugin is loaded on demand to avoid loading unnecessary dependencies
|
105
|
-
require "aspera/agent/#{agent_type}"
|
106
105
|
# set keys as symbols
|
107
106
|
agent_options = @opt_mgr.get_option(:transfer_info).symbolize_keys
|
108
107
|
# special cases
|
@@ -126,8 +125,7 @@ module Aspera
|
|
126
125
|
end
|
127
126
|
agent_options[:progress] = @config.progress_bar
|
128
127
|
# get agent instance
|
129
|
-
|
130
|
-
self.agent_instance = new_agent
|
128
|
+
self.agent_instance = Agent::Base.factory_create(agent_type, agent_options)
|
131
129
|
Log.log.debug{"transfer agent is a #{@agent.class}"}
|
132
130
|
return @agent
|
133
131
|
end
|
@@ -218,6 +216,9 @@ module Aspera
|
|
218
216
|
def start(transfer_spec, rest_token: nil)
|
219
217
|
# check parameters
|
220
218
|
Aspera.assert_type(transfer_spec, Hash){'transfer_spec'}
|
219
|
+
if transfer_spec['remote_host'].eql?(CP4I_REMOTE_HOST_LB)
|
220
|
+
raise "Wrong remote host: #{CP4I_REMOTE_HOST_LB}"
|
221
|
+
end
|
221
222
|
# process :src option
|
222
223
|
case transfer_spec['direction']
|
223
224
|
when Transfer::Spec::DIRECTION_RECEIVE
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/environment.rb
CHANGED
@@ -27,6 +27,7 @@ module Aspera
|
|
27
27
|
BYTES_PER_MEBIBIT = MEBI / BITS_PER_BYTE
|
28
28
|
|
29
29
|
class << self
|
30
|
+
@terminal_supports_unicode = nil
|
30
31
|
def ruby_version
|
31
32
|
return RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
|
32
33
|
end
|
@@ -121,10 +122,10 @@ module Aspera
|
|
121
122
|
end
|
122
123
|
|
123
124
|
# @return true if we can display Unicode characters
|
124
|
-
def
|
125
|
-
@
|
126
|
-
return @
|
125
|
+
def terminal_supports_unicode?
|
126
|
+
@terminal_supports_unicode = terminal? && ENV.values_at('LC_ALL', 'LC_CTYPE', 'LANG').compact.first.include?('UTF-8') if @terminal_supports_unicode.nil?
|
127
|
+
return @terminal_supports_unicode
|
127
128
|
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|