aspera-cli 4.17.0 → 4.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -4
  3. data/CHANGELOG.md +23 -0
  4. data/CONTRIBUTING.md +15 -1
  5. data/README.md +620 -378
  6. data/bin/ascli +5 -0
  7. data/bin/asession +2 -2
  8. data/lib/aspera/agent/alpha.rb +6 -4
  9. data/lib/aspera/agent/base.rb +9 -6
  10. data/lib/aspera/agent/connect.rb +4 -4
  11. data/lib/aspera/agent/direct.rb +56 -37
  12. data/lib/aspera/agent/httpgw.rb +23 -324
  13. data/lib/aspera/agent/node.rb +19 -20
  14. data/lib/aspera/agent/trsdk.rb +19 -20
  15. data/lib/aspera/api/aoc.rb +17 -14
  16. data/lib/aspera/api/cos_node.rb +4 -4
  17. data/lib/aspera/api/httpgw.rb +339 -0
  18. data/lib/aspera/api/node.rb +34 -21
  19. data/lib/aspera/ascmd.rb +4 -3
  20. data/lib/aspera/ascp/installation.rb +15 -7
  21. data/lib/aspera/ascp/management.rb +2 -2
  22. data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
  23. data/lib/aspera/cli/extended_value.rb +12 -6
  24. data/lib/aspera/cli/formatter.rb +155 -65
  25. data/lib/aspera/cli/hints.rb +18 -0
  26. data/lib/aspera/cli/main.rb +22 -29
  27. data/lib/aspera/cli/manager.rb +53 -36
  28. data/lib/aspera/cli/plugin.rb +26 -17
  29. data/lib/aspera/cli/plugin_factory.rb +31 -20
  30. data/lib/aspera/cli/plugins/alee.rb +14 -2
  31. data/lib/aspera/cli/plugins/aoc.rb +141 -131
  32. data/lib/aspera/cli/plugins/ats.rb +1 -1
  33. data/lib/aspera/cli/plugins/config.rb +52 -46
  34. data/lib/aspera/cli/plugins/console.rb +8 -5
  35. data/lib/aspera/cli/plugins/faspex.rb +27 -19
  36. data/lib/aspera/cli/plugins/faspex5.rb +222 -149
  37. data/lib/aspera/cli/plugins/faspio.rb +85 -0
  38. data/lib/aspera/cli/plugins/httpgw.rb +55 -0
  39. data/lib/aspera/cli/plugins/node.rb +86 -29
  40. data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
  41. data/lib/aspera/cli/plugins/preview.rb +6 -2
  42. data/lib/aspera/cli/plugins/server.rb +5 -5
  43. data/lib/aspera/cli/plugins/shares.rb +16 -14
  44. data/lib/aspera/cli/sync_actions.rb +6 -6
  45. data/lib/aspera/cli/transfer_agent.rb +5 -4
  46. data/lib/aspera/cli/version.rb +1 -1
  47. data/lib/aspera/environment.rb +7 -6
  48. data/lib/aspera/faspex_gw.rb +5 -4
  49. data/lib/aspera/faspex_postproc.rb +2 -2
  50. data/lib/aspera/log.rb +6 -3
  51. data/lib/aspera/node_simulator.rb +2 -2
  52. data/lib/aspera/oauth/base.rb +31 -19
  53. data/lib/aspera/oauth/factory.rb +12 -13
  54. data/lib/aspera/oauth/generic.rb +1 -0
  55. data/lib/aspera/oauth/jwt.rb +18 -15
  56. data/lib/aspera/oauth/url_json.rb +8 -6
  57. data/lib/aspera/open_application.rb +5 -7
  58. data/lib/aspera/persistency_folder.rb +2 -2
  59. data/lib/aspera/preview/generator.rb +3 -3
  60. data/lib/aspera/preview/options.rb +3 -3
  61. data/lib/aspera/preview/terminal.rb +4 -4
  62. data/lib/aspera/preview/utils.rb +3 -3
  63. data/lib/aspera/proxy_auto_config.rb +5 -1
  64. data/lib/aspera/rest.rb +60 -74
  65. data/lib/aspera/rest_call_error.rb +1 -1
  66. data/lib/aspera/rest_error_analyzer.rb +2 -2
  67. data/lib/aspera/rest_errors_aspera.rb +1 -1
  68. data/lib/aspera/resumer.rb +1 -1
  69. data/lib/aspera/secret_hider.rb +2 -4
  70. data/lib/aspera/ssh.rb +1 -1
  71. data/lib/aspera/transfer/parameters.rb +39 -36
  72. data/lib/aspera/transfer/spec.rb +2 -0
  73. data/lib/aspera/transfer/sync.rb +2 -1
  74. data/lib/aspera/transfer/uri.rb +1 -1
  75. data/lib/aspera/uri_reader.rb +5 -4
  76. data/lib/aspera/web_auth.rb +1 -1
  77. data/lib/aspera/web_server_simple.rb +4 -3
  78. data.tar.gz.sig +0 -0
  79. metadata +5 -3
  80. metadata.gz.sig +0 -0
  81. 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: result[:http].uri.to_s[0..url_length]
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
- query = { path: get_next_arg_add_prefix(prefix_path, 'path')}
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: 'services/soap/Transfer-201210',
362
- headers: {'Content-Type' => 'text/xml;charset=UTF-8', 'SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'},
363
- text_body_params: CENTRAL_SOAP_API_TEST)[:http].body
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].oauth_token
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", old_query_read_delete)
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.result_picture_in_terminal(options, result[:http].body)
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 # command_repo
630
+ end
578
631
  Aspera.error_unreachable_line
579
- end # execute_command_gen4
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.create("asyncs/#{asyncs_id}/#{sync_command}", parameters)
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', old_query_read_delete)
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, old_query_read_delete)
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 # case command
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
- def call_ao(endpoint, opt={})
64
- opt[:prefix] = 'api' unless opt.key?(:prefix)
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] = "#{opt[:prefix]}/#{call_args[:subpath]}" unless opt[:prefix].nil?
75
+ call_args[:subpath] = "#{prefix}/#{call_args[:subpath]}" unless prefix.nil?
69
76
  # specify id if necessary
70
- call_args[:subpath] = "#{call_args[:subpath]}/#{opt[:id]}" if opt.key?(:id)
71
- call_type = options.get_option(:ret_style, mandatory: true)
72
- call_type = opt[:ret_style] if opt.key?(:ret_style)
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 call_type
81
+ case ret_style
78
82
  when :header
79
83
  call_args[:headers] = {'Accept' => "application/#{format}" }
80
84
  when :arg
81
- call_args[:url_params] ||= {}
82
- call_args[:url_params][:format] = format
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(call_type)
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, opt[:xml_opt] || {'ForceArray' => true}) if format.eql?('xml')
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', xml_opt: {'ForceArray' => false})[:data]
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', xml_opt: {'ForceArray' => false})[:data]
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
- call_opts = {}
150
- call_opts[:id] = wf_id unless wf_id.eql?(ExtendedValue::ALL)
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, accept: override_accept)[:data]
198
+ result[:data] = call_ao('initiate', id: wf_id, args: call_params)[:data]
198
199
  return result
199
- end # wf command
200
+ end
200
201
  else Aspera.error_unexpected_value(command)
201
- end # case command
202
- end # execute_action
203
- end # Orchestrator
204
- end # Plugins
205
- end # Cli
206
- end # Aspera
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(operation: 'GET', subpath: "files/#{file_id}/files", headers: headers, url_params: request_args)[:data]
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 # generate_preview
345
+ end
342
346
 
343
347
  # scan all files in provided folder entry
344
348
  # @param top_path subpath to start folder scan inside
@@ -251,8 +251,8 @@ module Aspera
251
251
  end
252
252
  else Aspera.error_unreachable_line
253
253
  end
254
- end # execute_action
255
- end # Server
256
- end # Plugins
257
- end # Cli
258
- end # Aspera
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
@@ -7,7 +7,7 @@ module Aspera
7
7
  module Plugins
8
8
  # Plugin for Aspera Shares v1
9
9
  class Shares < Cli::BasicAuthPlugin
10
- API_BASE = 'node_api'
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("#{API_BASE}/app")
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)}/#{API_BASE}")
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
- return_error: true)
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('node api', e.to_s)
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(API_BASE)
80
+ api_shares_node = basic_auth_api(NODE_API_PREFIX)
81
81
  repo_command = options.get_next_command(Node::COMMANDS_SHARES)
82
- return Node.new(**init_params, api: api_shares_node).execute_action(repo_command)
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 # execute action
154
- end # Shares
155
- end # Plugins
156
- end # Cli
157
- end # Aspera
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 # command2
64
- end # command
65
- end # execute_action
66
- end # SyncActions
67
- end # Cli
68
- end # Aspera
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
- new_agent = Kernel.const_get("Aspera::Agent::#{agent_type.capitalize}").new(agent_options)
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
@@ -4,6 +4,6 @@ module Aspera
4
4
  module Cli
5
5
  # for beta add extension : .beta1
6
6
  # for dev version add extension : .pre
7
- VERSION = '4.17.0'
7
+ VERSION = '4.18.0'
8
8
  end
9
9
  end
@@ -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 use_unicode?
125
- @use_unicode = terminal? && ENV.values_at('LC_ALL', 'LC_CTYPE', 'LANG').compact.first.include?('UTF-8') if @use_unicode.nil?
126
- return @use_unicode
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 # self
129
- end # Environment
130
- end # Aspera
129
+ end
130
+ end
131
+ end