aspera-cli 4.15.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +375 -280
  5. data/CONTRIBUTING.md +71 -18
  6. data/README.md +1978 -1656
  7. data/bin/ascli +13 -31
  8. data/bin/asession +32 -22
  9. data/examples/dascli +2 -2
  10. data/lib/aspera/agent/alpha.rb +117 -0
  11. data/lib/aspera/agent/base.rb +61 -0
  12. data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
  13. data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +116 -116
  14. data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +21 -19
  15. data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +21 -33
  16. data/lib/aspera/agent/trsdk.rb +188 -0
  17. data/lib/aspera/api/aoc.rb +586 -0
  18. data/lib/aspera/api/ats.rb +46 -0
  19. data/lib/aspera/api/cos_node.rb +95 -0
  20. data/lib/aspera/api/node.rb +344 -0
  21. data/lib/aspera/ascmd.rb +47 -14
  22. data/lib/aspera/{fasp → ascp}/installation.rb +54 -15
  23. data/lib/aspera/{fasp → ascp}/management.rb +14 -14
  24. data/lib/aspera/{fasp → ascp}/products.rb +1 -1
  25. data/lib/aspera/assert.rb +45 -0
  26. data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
  27. data/lib/aspera/cli/extended_value.rb +5 -5
  28. data/lib/aspera/cli/formatter.rb +27 -14
  29. data/lib/aspera/cli/hints.rb +7 -6
  30. data/lib/aspera/cli/main.rb +49 -29
  31. data/lib/aspera/cli/manager.rb +46 -36
  32. data/lib/aspera/cli/plugin.rb +34 -20
  33. data/lib/aspera/cli/plugin_factory.rb +61 -0
  34. data/lib/aspera/cli/plugins/alee.rb +7 -7
  35. data/lib/aspera/cli/plugins/aoc.rb +168 -132
  36. data/lib/aspera/cli/plugins/ats.rb +33 -33
  37. data/lib/aspera/cli/plugins/bss.rb +3 -4
  38. data/lib/aspera/cli/plugins/config.rb +250 -272
  39. data/lib/aspera/cli/plugins/console.rb +8 -6
  40. data/lib/aspera/cli/plugins/cos.rb +20 -19
  41. data/lib/aspera/cli/plugins/faspex.rb +71 -60
  42. data/lib/aspera/cli/plugins/faspex5.rb +212 -133
  43. data/lib/aspera/cli/plugins/node.rb +83 -75
  44. data/lib/aspera/cli/plugins/orchestrator.rb +36 -44
  45. data/lib/aspera/cli/plugins/preview.rb +33 -31
  46. data/lib/aspera/cli/plugins/server.rb +33 -32
  47. data/lib/aspera/cli/plugins/shares.rb +39 -33
  48. data/lib/aspera/cli/sync_actions.rb +9 -9
  49. data/lib/aspera/cli/transfer_agent.rb +45 -25
  50. data/lib/aspera/cli/transfer_progress.rb +2 -3
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/colors.rb +5 -0
  53. data/lib/aspera/command_line_builder.rb +16 -14
  54. data/lib/aspera/coverage.rb +21 -0
  55. data/lib/aspera/data_repository.rb +33 -2
  56. data/lib/aspera/environment.rb +5 -4
  57. data/lib/aspera/faspex_gw.rb +13 -11
  58. data/lib/aspera/faspex_postproc.rb +6 -5
  59. data/lib/aspera/id_generator.rb +4 -2
  60. data/lib/aspera/json_rpc.rb +10 -8
  61. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  62. data/lib/aspera/keychain/macos_security.rb +29 -22
  63. data/lib/aspera/log.rb +5 -4
  64. data/lib/aspera/nagios.rb +7 -2
  65. data/lib/aspera/node_simulator.rb +213 -0
  66. data/lib/aspera/oauth/base.rb +143 -0
  67. data/lib/aspera/oauth/factory.rb +124 -0
  68. data/lib/aspera/oauth/generic.rb +34 -0
  69. data/lib/aspera/oauth/jwt.rb +51 -0
  70. data/lib/aspera/oauth/url_json.rb +31 -0
  71. data/lib/aspera/oauth/web.rb +50 -0
  72. data/lib/aspera/oauth.rb +5 -328
  73. data/lib/aspera/open_application.rb +7 -7
  74. data/lib/aspera/persistency_action_once.rb +13 -14
  75. data/lib/aspera/persistency_folder.rb +3 -2
  76. data/lib/aspera/preview/file_types.rb +53 -267
  77. data/lib/aspera/preview/generator.rb +7 -5
  78. data/lib/aspera/preview/terminal.rb +17 -7
  79. data/lib/aspera/preview/utils.rb +8 -7
  80. data/lib/aspera/proxy_auto_config.rb +6 -3
  81. data/lib/aspera/rest.rb +187 -140
  82. data/lib/aspera/rest_error_analyzer.rb +1 -0
  83. data/lib/aspera/rest_errors_aspera.rb +5 -3
  84. data/lib/aspera/resumer.rb +77 -0
  85. data/lib/aspera/secret_hider.rb +5 -2
  86. data/lib/aspera/ssh.rb +15 -8
  87. data/lib/aspera/temp_file_manager.rb +1 -1
  88. data/lib/aspera/{fasp → transfer}/error.rb +3 -3
  89. data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
  90. data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
  91. data/lib/aspera/{fasp → transfer}/parameters.rb +95 -120
  92. data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +23 -19
  93. data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
  94. data/lib/aspera/transfer/sync.rb +273 -0
  95. data/lib/aspera/{fasp → transfer}/uri.rb +10 -9
  96. data/lib/aspera/web_server_simple.rb +12 -3
  97. data.tar.gz.sig +0 -0
  98. metadata +92 -68
  99. metadata.gz.sig +0 -0
  100. data/lib/aspera/aoc.rb +0 -606
  101. data/lib/aspera/ats_api.rb +0 -47
  102. data/lib/aspera/cos_node.rb +0 -93
  103. data/lib/aspera/fasp/agent_aspera.rb +0 -126
  104. data/lib/aspera/fasp/agent_base.rb +0 -48
  105. data/lib/aspera/fasp/agent_trsdk.rb +0 -146
  106. data/lib/aspera/fasp/resume_policy.rb +0 -77
  107. data/lib/aspera/node.rb +0 -338
  108. data/lib/aspera/sync.rb +0 -219
@@ -3,24 +3,24 @@
3
3
  # cspell:ignore snid fnid bidi ssync asyncs rund asnodeadmin mkfile mklink asperabrowser asperabrowserurl watchfolders watchfolderd entsrv
4
4
  require 'aspera/cli/basic_auth_plugin'
5
5
  require 'aspera/cli/sync_actions'
6
- require 'aspera/fasp/transfer_spec'
6
+ require 'aspera/transfer/spec'
7
7
  require 'aspera/nagios'
8
8
  require 'aspera/hash_ext'
9
9
  require 'aspera/id_generator'
10
- require 'aspera/node'
11
- require 'aspera/aoc'
12
- require 'aspera/sync'
10
+ require 'aspera/api/node'
11
+ require 'aspera/api/aoc'
13
12
  require 'aspera/oauth'
13
+ require 'aspera/node_simulator'
14
+ require 'aspera/assert'
14
15
  require 'base64'
15
16
  require 'zlib'
16
17
 
17
18
  module Aspera
18
19
  module Cli
19
20
  module Plugins
20
- class Node < Aspera::Cli::BasicAuthPlugin
21
+ class Node < Cli::BasicAuthPlugin
21
22
  include SyncActions
22
23
  class << self
23
- @@node_options_declared = false # rubocop:disable Style/ClassVars
24
24
  def application_name
25
25
  'HSTS Node API'
26
26
  end
@@ -35,7 +35,7 @@ module Aspera
35
35
  "http://#{address_or_url}:9091"
36
36
  ]
37
37
  end
38
-
38
+ error = nil
39
39
  urls.each do |base_url|
40
40
  next unless base_url.match?('https?://')
41
41
  api = Rest.new(base_url: base_url)
@@ -47,8 +47,10 @@ module Aspera
47
47
  url: result[:http].uri.to_s[0..url_length]
48
48
  }
49
49
  rescue StandardError => e
50
+ error = e
50
51
  Log.log.debug{"detect error: #{e}"}
51
52
  end
53
+ raise error if error
52
54
  return nil
53
55
  end
54
56
 
@@ -64,15 +66,13 @@ module Aspera
64
66
  }
65
67
  end
66
68
 
67
- def declare_options(options, force: false)
68
- return if @@node_options_declared && !force
69
- @@node_options_declared = true # rubocop:disable Style/ClassVars
69
+ def declare_options(options)
70
70
  options.declare(:validator, 'Identifier of validator (optional for central)')
71
71
  options.declare(:asperabrowserurl, 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net')
72
72
  options.declare(:sync_name, 'Sync name')
73
73
  options.declare(
74
74
  :default_ports, 'Use standard FASP ports or get from node api (gen4)', values: :bool, default: :yes,
75
- handler: {o: Aspera::Node, m: :use_standard_ports})
75
+ handler: {o: Api::Node, m: :use_standard_ports})
76
76
  options.declare(:root_id, 'File id of top folder if using bearer tokens')
77
77
  SyncActions.declare_options(options)
78
78
  options.parse_options!
@@ -116,28 +116,29 @@ module Aspera
116
116
  COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
117
117
  COMMANDS_FASPEX = COMMON_ACTIONS
118
118
 
119
- def initialize(env, api: nil)
120
- super(env)
121
- Node.declare_options(options, force: env[:all_manuals])
119
+ def initialize(api: nil, **env)
120
+ super(**env, basic_options: api.nil?)
121
+ Node.declare_options(options) if api.nil?
122
+ return if only_manual
122
123
  @api_node =
123
- if !api.nil? || env[:all_manuals]
124
- # this can be Aspera::Node or Aspera::Rest (shares)
124
+ if !api.nil?
125
+ # this can be Api::Node or Rest (shares)
125
126
  api
126
- elsif Oauth.bearer?(options.get_option(:password, mandatory: true))
127
+ elsif OAuth::Factory.bearer?(options.get_option(:password, mandatory: true))
127
128
  # info is provided like node_info of aoc
128
- Aspera::Node.new(params: {
129
+ Api::Node.new(
129
130
  base_url: options.get_option(:url, mandatory: true),
130
- headers: Aspera::Node.bearer_headers(options.get_option(:password, mandatory: true))
131
- })
131
+ headers: Api::Node.bearer_headers(options.get_option(:password, mandatory: true))
132
+ )
132
133
  else
133
134
  # this is normal case
134
- Aspera::Node.new(params: {
135
+ Api::Node.new(
135
136
  base_url: options.get_option(:url, mandatory: true),
136
137
  auth: {
137
138
  type: :basic,
138
139
  username: options.get_option(:username, mandatory: true),
139
140
  password: options.get_option(:password, mandatory: true)
140
- }})
141
+ })
141
142
  end
142
143
  end
143
144
 
@@ -165,7 +166,7 @@ module Aspera
165
166
  result = success_msg
166
167
  if p.key?('error')
167
168
  Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
168
- result = 'ERROR: ' + p['error']['user_message']
169
+ result = "ERROR: #{p['error']['user_message']}"
169
170
  errors.push([p['path'], p['error']['user_message']])
170
171
  end
171
172
  final_result[:data].push({type => p['path'], 'result' => result})
@@ -191,7 +192,7 @@ module Aspera
191
192
  case command
192
193
  when :delete
193
194
  paths_to_delete = get_next_arg_add_prefix(prefix_path, 'file list', :multiple)
194
- resp = @api_node.create('files/delete', { paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i : '/' + i} }})
195
+ resp = @api_node.create('files/delete', { paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i : "/#{i}"} }})
195
196
  return c_result_translate_rem_prefix(resp, 'file', 'deleted', prefix_path)
196
197
  when :search
197
198
  search_root = get_next_arg_add_prefix(prefix_path, 'search root')
@@ -283,7 +284,7 @@ module Aspera
283
284
  request_transfer_spec[:paths] = if command.eql?(:download)
284
285
  transfer.ts_source_paths
285
286
  else
286
- [{ destination: transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND) }]
287
+ [{ destination: transfer.destination_folder(Transfer::Spec::DIRECTION_SEND) }]
287
288
  end
288
289
  # add fixed parameters if any (for COS)
289
290
  @api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
@@ -300,10 +301,10 @@ module Aspera
300
301
  @api_node.call(
301
302
  operation: 'GET',
302
303
  subpath: "files/#{URI.encode_www_form_component(remote_path)}/contents",
303
- save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE), file_name))
304
+ save_to_file: File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_name))
304
305
  return Main.result_status("downloaded: #{file_name}")
305
306
  end
306
- raise 'INTERNAL ERROR'
307
+ Aspera.error_unreachable_line
307
308
  end
308
309
 
309
310
  # common API to node and Shares
@@ -327,8 +328,8 @@ module Aspera
327
328
  ak_info = @api_node.read("access_keys/#{access_key_id}")[:data]
328
329
  # change API credentials if different access key
329
330
  if !access_key_id.eql?('self')
330
- @api_node.params[:auth][:username] = ak_info['id']
331
- @api_node.params[:auth][:password] = config.lookup_secret(url: @api_node.params[:base_url], username: ak_info['id'], mandatory: true)
331
+ @api_node.auth_params[:username] = ak_info['id']
332
+ @api_node.auth_params[:password] = config.lookup_secret(url: @api_node.base_url, username: ak_info['id'], mandatory: true)
332
333
  end
333
334
  root_file_id = ak_info['root_file_id']
334
335
  end
@@ -380,9 +381,9 @@ module Aspera
380
381
  if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
381
382
  Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
382
383
  end
383
- return { type: :single_object, data: node_license}
384
+ return {type: :single_object, data: node_license}
384
385
  when :api_details
385
- return { type: :single_object, data: @api_node.params }
386
+ return {type: :single_object, data: {base_url: @api_node.base_url}.merge(@api_node.params)}
386
387
  end
387
388
  end
388
389
 
@@ -405,26 +406,26 @@ module Aspera
405
406
  command_legacy = options.get_next_command(V3_IN_V4_ACTIONS)
406
407
  # TODO: shall we support all methods here ? what if there is a link ?
407
408
  apifid = @api_node.resolve_api_fid(top_file_id, '')
408
- return Node.new(@agents, api: apifid[:api]).execute_action(command_legacy)
409
+ return Node.new(**init_params, api: apifid[:api]).execute_action(command_legacy)
409
410
  when :node_info, :bearer_token_node
410
411
  apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
411
412
  result = {
412
- url: apifid[:api].params[:base_url],
413
+ url: apifid[:api].base_url,
413
414
  root_id: apifid[:file_id]
414
415
  }
415
- raise 'No auth for node' if apifid[:api].params[:auth].nil?
416
- case apifid[:api].params[:auth][:type]
416
+ Aspera.assert_values(apifid[:api].auth_params[:type], %i[basic oauth2])
417
+ case apifid[:api].auth_params[:type]
417
418
  when :basic
418
- result[:username] = apifid[:api].params[:auth][:username]
419
- result[:password] = apifid[:api].params[:auth][:password]
419
+ result[:username] = apifid[:api].auth_params[:username]
420
+ result[:password] = apifid[:api].auth_params[:password]
420
421
  when :oauth2
421
- result[:username] = apifid[:api].params[:headers][Aspera::Node::HEADER_X_ASPERA_ACCESS_KEY]
422
+ result[:username] = apifid[:api].params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
422
423
  result[:password] = apifid[:api].oauth_token
423
- else raise 'internal error: unknown auth type'
424
+ else Aspera.error_unreachable_line
424
425
  end
425
426
  return {type: :single_object, data: result} if command_repo.eql?(:node_info)
426
427
  # check format of bearer token
427
- Oauth.bearer_extract(result[:password])
428
+ OAuth::Factory.bearer_extract(result[:password])
428
429
  return Main.result_status(result[:password])
429
430
  when :browse
430
431
  apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
@@ -439,12 +440,12 @@ module Aspera
439
440
  return {type: :object_list, data: items, fields: %w[name type recursive_size size modified_time access_level]}
440
441
  when :find
441
442
  apifid = @api_node.resolve_api_fid(top_file_id, options.get_next_argument('path'))
442
- test_block = Aspera::Node.file_matcher_from_argument(options)
443
+ test_block = Api::Node.file_matcher_from_argument(options)
443
444
  return {type: :object_list, data: @api_node.find_files(apifid[:file_id], test_block), fields: ['path']}
444
445
  when :mkdir
445
- containing_folder_path = options.get_next_argument('path').split(Aspera::Node::PATH_SEPARATOR)
446
+ containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
446
447
  new_folder = containing_folder_path.pop
447
- apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Aspera::Node::PATH_SEPARATOR))
448
+ apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Api::Node::PATH_SEPARATOR))
448
449
  result = apifid[:api].create("files/#{apifid[:file_id]}/files", {name: new_folder, type: :folder})[:data]
449
450
  return Main.result_status("created: #{result['name']} (id=#{result['id']})")
450
451
  when :rename
@@ -463,10 +464,11 @@ module Aspera
463
464
  return execute_sync_action do |sync_direction, _local_path, remote_path|
464
465
  # Gen4 API
465
466
  # direction is push pull, bidi
467
+ Aspera.assert_values(sync_direction, %i[push pull bidi])
466
468
  ts_direction = case sync_direction
467
- when :push, :bidi then Fasp::TransferSpec::DIRECTION_SEND
468
- when :pull then Fasp::TransferSpec::DIRECTION_RECEIVE
469
- else raise "internal error: bad direction: #{sync_direction} (#{sync_direction.class})"
469
+ when :push, :bidi then Transfer::Spec::DIRECTION_SEND
470
+ when :pull then Transfer::Spec::DIRECTION_RECEIVE
471
+ else Aspera.error_unreachable_line
470
472
  end
471
473
  # remote is specified by option to_folder
472
474
  apifid = @api_node.resolve_api_fid(top_file_id, remote_path)
@@ -475,8 +477,8 @@ module Aspera
475
477
  transfer_spec
476
478
  end
477
479
  when :upload
478
- apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND))
479
- return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Fasp::TransferSpec::DIRECTION_SEND)))
480
+ apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND))
481
+ return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_SEND)))
480
482
  when :download
481
483
  source_paths = transfer.ts_source_paths
482
484
  # special case for AoC : all files must be in same folder
@@ -488,11 +490,11 @@ module Aspera
488
490
  case file_info['type']
489
491
  when 'file'
490
492
  # if the single source is a file, we need to split into folder path and filename
491
- src_dir_elements = source_folder.split(Aspera::Node::PATH_SEPARATOR)
493
+ src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
492
494
  # filename is the last one
493
495
  source_paths = [{'source' => src_dir_elements.pop}]
494
496
  # source folder is what remains
495
- source_folder = src_dir_elements.join(Aspera::Node::PATH_SEPARATOR)
497
+ source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
496
498
  # TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
497
499
  apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
498
500
  when 'link', 'folder'
@@ -503,14 +505,14 @@ module Aspera
503
505
  raise "Unknown source type: #{file_info['type']}"
504
506
  end
505
507
  end
506
- return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Fasp::TransferSpec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
508
+ return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
507
509
  when :http_node_download
508
510
  source_paths = transfer.ts_source_paths
509
511
  source_folder = source_paths.shift['source']
510
512
  if source_paths.empty?
511
- source_folder = source_folder.split(Aspera::Node::PATH_SEPARATOR)
513
+ source_folder = source_folder.split(Api::Node::PATH_SEPARATOR)
512
514
  source_paths = [{'source' => source_folder.pop}]
513
- source_folder = source_folder.join(Aspera::Node::PATH_SEPARATOR)
515
+ source_folder = source_folder.join(Api::Node::PATH_SEPARATOR)
514
516
  end
515
517
  raise Cli::BadArgument, 'one file at a time only in HTTP mode' if source_paths.length > 1
516
518
  file_name = source_paths.first['source']
@@ -518,7 +520,7 @@ module Aspera
518
520
  apifid[:api].call(
519
521
  operation: 'GET',
520
522
  subpath: "files/#{apifid[:file_id]}/content",
521
- save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE), file_name))
523
+ save_to_file: File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_name))
522
524
  return Main.result_status("downloaded: #{file_name}")
523
525
  when :show
524
526
  apifid = apifid_from_next_arg(top_file_id)
@@ -536,12 +538,7 @@ module Aspera
536
538
  subpath: "files/#{apifid[:file_id]}/preview",
537
539
  headers: {'Accept' => 'image/png'}
538
540
  )
539
- require 'aspera/preview/terminal'
540
- terminal_options = options.get_option(:query, default: {}).symbolize_keys
541
- allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
542
- unknown_options = terminal_options.keys - allowed_options
543
- raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
544
- return Main.result_status(Preview::Terminal.build(result[:http].body, **terminal_options))
541
+ return Main.result_picture_in_terminal(options, result[:http].body)
545
542
  when :permission
546
543
  apifid = apifid_from_next_arg(top_file_id)
547
544
  command_perm = options.get_next_command(%i[list create delete])
@@ -565,7 +562,7 @@ module Aspera
565
562
  create_param = options.get_next_argument('creation data', type: Hash)
566
563
  raise 'no file_id' if create_param.key?('file_id')
567
564
  create_param['file_id'] = apifid[:file_id]
568
- create_param['access_levels'] = Aspera::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
565
+ create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
569
566
  # add application specific tags (AoC)
570
567
  the_app = apifid[:api].app_info
571
568
  the_app[:api].permissions_set_create_params(create_param: create_param, app_info: the_app) unless the_app.nil?
@@ -574,11 +571,11 @@ module Aspera
574
571
  # notify application of creation
575
572
  the_app[:api].permissions_send_event(created_data: created_data, app_info: the_app) unless the_app.nil?
576
573
  return { type: :single_object, data: created_data}
577
- else raise "internal error:shall not reach here (#{command_perm})"
574
+ else Aspera.error_unreachable_line
578
575
  end
579
- else raise "INTERNAL ERROR: no case for #{command_repo}"
576
+ else Aspera.error_unreachable_line
580
577
  end # command_repo
581
- # raise 'INTERNAL ERROR: missing return'
578
+ Aspera.error_unreachable_line
582
579
  end # execute_command_gen4
583
580
 
584
581
  # This is older API
@@ -637,7 +634,7 @@ module Aspera
637
634
  skip_ids_persistency = nil
638
635
  if options.get_option(:once_only, mandatory: true)
639
636
  skip_ids_persistency = PersistencyActionOnce.new(
640
- manager: @agents[:persistency],
637
+ manager: persistency,
641
638
  data: iteration_data,
642
639
  id: IdGenerator.from_list([
643
640
  'sync_files',
@@ -683,7 +680,8 @@ module Aspera
683
680
  central
684
681
  asperabrowser
685
682
  basic_token
686
- bearer_token].concat(COMMON_ACTIONS).freeze
683
+ bearer_token
684
+ simulator].concat(COMMON_ACTIONS).freeze
687
685
 
688
686
  def execute_action(command=nil, prefix_path=nil)
689
687
  command ||= options.get_next_command(ACTIONS)
@@ -783,7 +781,7 @@ module Aspera
783
781
  # do not process last one
784
782
  break if end_date.nil?
785
783
  # init data for this period
786
- period_bandwidth = Fasp::TransferSpec::DIRECTION_ENUM_VALUES.map(&:to_sym).each_with_object({}) do |direction, h|
784
+ period_bandwidth = Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).each_with_object({}) do |direction, h|
787
785
  h[direction] = dir_info.each_with_object({}) do |k2, h2|
788
786
  h2[k2] = 0
789
787
  end
@@ -801,7 +799,7 @@ module Aspera
801
799
  info[:sessions] += 1
802
800
  # end
803
801
  end
804
- next if Fasp::TransferSpec::DIRECTION_ENUM_VALUES.map(&:to_sym).all? do |dir|
802
+ next if Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).all? do |dir|
805
803
  period_bandwidth[dir][:sessions].zero?
806
804
  end
807
805
  result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
@@ -897,7 +895,7 @@ module Aspera
897
895
  }
898
896
  # encode parameters so that it looks good in url
899
897
  encoded_params = Base64.strict_encode64(Zlib::Deflate.deflate(JSON.generate(browse_params))).gsub(/=+$/, '').tr('+/', '-_').reverse
900
- OpenApplication.instance.uri(options.get_option(:asperabrowserurl) + '?goto=' + encoded_params)
898
+ OpenApplication.instance.uri("#{options.get_option(:asperabrowserurl)}?goto=#{encoded_params}")
901
899
  return Main.result_status('done')
902
900
  when :basic_token
903
901
  return Main.result_status(Rest.basic_token(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
@@ -905,11 +903,21 @@ module Aspera
905
903
  private_key = OpenSSL::PKey::RSA.new(options.get_next_argument('private RSA key PEM value', type: String))
906
904
  token_info = options.get_next_argument('user and group identification', type: Hash)
907
905
  access_key = options.get_option(:username, mandatory: true)
908
- return Main.result_status(Aspera::Node.bearer_token(payload: token_info, access_key: access_key, private_key: private_key))
906
+ return Main.result_status(Api::Node.bearer_token(payload: token_info, access_key: access_key, private_key: private_key))
907
+ when :simulator
908
+ require 'aspera/node_simulator'
909
+ parameters = value_create_modify(command: command)
910
+ parameters = parameters.symbolize_keys
911
+ raise 'Missing key: url' unless parameters.key?(:url)
912
+ uri = URI.parse(parameters[:url])
913
+ server = WebServerSimple.new(uri, certificate: parameters[:certificate])
914
+ server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], transfer)
915
+ server.start
916
+ return Main.result_status('Simulator terminated')
909
917
  end # case command
910
918
  raise 'ERROR: shall not reach this line'
911
- end # execute_action
912
- end # Main
913
- end # Plugin
914
- end # Cli
915
- end # Aspera
919
+ end
920
+ end
921
+ end
922
+ end
923
+ end
@@ -2,18 +2,21 @@
2
2
 
3
3
  require 'aspera/cli/basic_auth_plugin'
4
4
  require 'aspera/nagios'
5
+ require 'aspera/log'
6
+ require 'aspera/assert'
5
7
  require 'xmlsimple'
6
8
 
7
9
  module Aspera
8
10
  module Cli
9
11
  module Plugins
10
- class Orchestrator < Aspera::Cli::BasicAuthPlugin
12
+ class Orchestrator < Cli::BasicAuthPlugin
11
13
  class << self
12
14
  STANDARD_PATH = '/aspera/orchestrator'
13
15
  def detect(address_or_url)
14
16
  address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
15
17
  urls = [address_or_url]
16
18
  urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
19
+ error = nil
17
20
  urls.each do |base_url|
18
21
  next unless base_url.match?('https?://')
19
22
  api = Rest.new(base_url: base_url)
@@ -26,8 +29,10 @@ module Aspera
26
29
  url: url[0..url.index(test_endpoint) - 2]
27
30
  }
28
31
  rescue StandardError => e
32
+ error = e
29
33
  Log.log.debug{"detect error: #{e}"}
30
34
  end
35
+ raise error if error
31
36
  return nil
32
37
  end
33
38
 
@@ -44,8 +49,8 @@ module Aspera
44
49
  end
45
50
  end
46
51
 
47
- def initialize(env)
48
- super(env)
52
+ def initialize(**env)
53
+ super
49
54
  options.declare(:result, "Specify result value as: 'work_step:parameter'")
50
55
  options.declare(:synchronous, 'Wait for completion', values: :bool, default: :no)
51
56
  options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
@@ -55,24 +60,6 @@ module Aspera
55
60
 
56
61
  ACTIONS = %i[health info workflow plugins processes].freeze
57
62
 
58
- # for JSON format: add extension ".json" or add url parameter: format=json or Accept: application/json
59
- # id can be: a parameter id=x, or at the end of url /id, for workflows: work_order[workflow_id]=wf_id
60
- # def call_API_orig(endpoint,id=nil,url_params={format: :json},accept=nil)
61
- # # calls are GET
62
- # call_args={operation: 'GET',subpath: endpoint}
63
- # # specify id if necessary
64
- # call_args[:subpath]=call_args[:subpath]+'/'+id unless id.nil?
65
- # unless url_params.nil?
66
- # if url_params.has_key?(:format)
67
- # call_args[:headers]={'Accept'=>'application/'+url_params[:format].to_s}
68
- # end
69
- # call_args[:headers]={'Accept'=>accept} unless accept.nil?
70
- # # add params if necessary
71
- # call_args[:url_params]=url_params
72
- # end
73
- # return @api_orch.call(call_args)
74
- # end
75
-
76
63
  def call_ao(endpoint, opt={})
77
64
  opt[:prefix] = 'api' unless opt.key?(:prefix)
78
65
  # calls are GET
@@ -89,40 +76,45 @@ module Aspera
89
76
  unless format.nil?
90
77
  case call_type
91
78
  when :header
92
- call_args[:headers] = {'Accept' => 'application/' + format}
79
+ call_args[:headers] = {'Accept' => "application/#{format}" }
93
80
  when :arg
94
81
  call_args[:url_params] ||= {}
95
82
  call_args[:url_params][:format] = format
96
83
  when :ext
97
84
  call_args[:subpath] = "#{call_args[:subpath]}.#{format}"
98
- else raise 'unexpected'
85
+ else Aspera.error_unexpected_value(call_type)
99
86
  end
100
87
  end
101
- result = @api_orch.call(call_args)
88
+ result = @api_orch.call(**call_args)
102
89
  result[:data] = XmlSimple.xml_in(result[:http].body, opt[:xml_opt] || {'ForceArray' => true}) if format.eql?('xml')
103
90
  Log.log.debug{Log.dump(:data, result[:data])}
104
91
  return result
105
92
  end
106
93
 
107
94
  def execute_action
108
- rest_params = {base_url: options.get_option(:url, mandatory: true)}
109
- case options.get_option(:auth_style, mandatory: true)
110
- when :arg_pass
111
- rest_params[:auth] = {
112
- type: :url,
113
- url_query: {
114
- 'login' => options.get_option(:username, mandatory: true),
115
- 'password' => options.get_option(:password, mandatory: true) }}
116
- when :head_basic
117
- rest_params[:auth] = {
118
- type: :basic,
119
- username: options.get_option(:username, mandatory: true),
120
- password: options.get_option(:password, mandatory: true) }
121
- when :apikey
122
- raise 'Not implemented'
123
- end
95
+ auth_params =
96
+ case options.get_option(:auth_style, mandatory: true)
97
+ when :arg_pass
98
+ {
99
+ type: :url,
100
+ url_query: {
101
+ 'login' => options.get_option(:username, mandatory: true),
102
+ 'password' => options.get_option(:password, mandatory: true) }
103
+ }
104
+ when :head_basic
105
+ {
106
+ type: :basic,
107
+ username: options.get_option(:username, mandatory: true),
108
+ password: options.get_option(:password, mandatory: true)
109
+ }
110
+ when :apikey
111
+ raise 'Not implemented'
112
+ end
124
113
 
125
- @api_orch = Rest.new(rest_params)
114
+ @api_orch = Rest.new(
115
+ base_url: options.get_option(:url, mandatory: true),
116
+ auth: auth_params
117
+ )
126
118
 
127
119
  command1 = options.get_next_command(ACTIONS)
128
120
  case command1
@@ -140,11 +132,11 @@ module Aspera
140
132
  result = call_ao('remote_node_ping', format: 'xml', xml_opt: {'ForceArray' => false})[:data]
141
133
  return {type: :single_object, data: result}
142
134
  when :processes
143
- # TODO: Jira ? API has only XML format
135
+ # TODO: Bug ? API has only XML format
144
136
  result = call_ao('processes_status', format: 'xml')[:data]
145
137
  return {type: :object_list, data: result['process']}
146
138
  when :plugins
147
- # TODO: Jira ? only json format on url
139
+ # TODO: Bug ? only json format on url
148
140
  result = call_ao('plugin_version')[:data]
149
141
  return {type: :object_list, data: result['Plugin']}
150
142
  when :workflow
@@ -205,7 +197,7 @@ module Aspera
205
197
  result[:data] = call_ao('initiate', id: wf_id, args: call_params, accept: override_accept)[:data]
206
198
  return result
207
199
  end # wf command
208
- else raise "ERROR, unknown command: [#{command}]"
200
+ else Aspera.error_unexpected_value(command)
209
201
  end # case command
210
202
  end # execute_action
211
203
  end # Orchestrator