aspera-cli 4.22.0 → 4.24.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 (114) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +405 -364
  4. data/CONTRIBUTING.md +86 -29
  5. data/README.md +1856 -961
  6. data/bin/ascli +2 -1
  7. data/bin/asession +4 -4
  8. data/lib/aspera/agent/base.rb +4 -0
  9. data/lib/aspera/agent/connect.rb +20 -18
  10. data/lib/aspera/agent/desktop.rb +14 -11
  11. data/lib/aspera/agent/direct.rb +39 -31
  12. data/lib/aspera/agent/httpgw.rb +2 -2
  13. data/lib/aspera/agent/node.rb +9 -11
  14. data/lib/aspera/agent/transferd.rb +18 -11
  15. data/lib/aspera/api/aoc.rb +53 -43
  16. data/lib/aspera/api/cos_node.rb +7 -5
  17. data/lib/aspera/api/httpgw.rb +23 -22
  18. data/lib/aspera/api/node.rb +104 -22
  19. data/lib/aspera/ascmd.rb +35 -21
  20. data/lib/aspera/ascp/installation.rb +43 -43
  21. data/lib/aspera/ascp/management.rb +5 -4
  22. data/lib/aspera/assert.rb +55 -24
  23. data/lib/aspera/cli/basic_auth_plugin.rb +8 -7
  24. data/lib/aspera/cli/error.rb +1 -1
  25. data/lib/aspera/cli/extended_value.rb +28 -29
  26. data/lib/aspera/cli/formatter.rb +191 -168
  27. data/lib/aspera/cli/hints.rb +38 -4
  28. data/lib/aspera/cli/main.rb +139 -108
  29. data/lib/aspera/cli/manager.rb +51 -31
  30. data/lib/aspera/cli/plugin.rb +149 -78
  31. data/lib/aspera/cli/plugin_factory.rb +2 -2
  32. data/lib/aspera/cli/plugins/aoc.rb +217 -88
  33. data/lib/aspera/cli/plugins/ats.rb +15 -13
  34. data/lib/aspera/cli/plugins/config.rb +105 -227
  35. data/lib/aspera/cli/plugins/console.rb +49 -18
  36. data/lib/aspera/cli/plugins/cos.rb +4 -4
  37. data/lib/aspera/cli/plugins/faspex.rb +45 -51
  38. data/lib/aspera/cli/plugins/faspex5.rb +162 -163
  39. data/lib/aspera/cli/plugins/faspio.rb +6 -5
  40. data/lib/aspera/cli/plugins/httpgw.rb +2 -2
  41. data/lib/aspera/cli/plugins/node.rb +233 -247
  42. data/lib/aspera/cli/plugins/orchestrator.rb +10 -14
  43. data/lib/aspera/cli/plugins/preview.rb +26 -29
  44. data/lib/aspera/cli/plugins/server.rb +29 -28
  45. data/lib/aspera/cli/plugins/shares.rb +40 -28
  46. data/lib/aspera/cli/sync_actions.rb +101 -80
  47. data/lib/aspera/cli/transfer_agent.rb +55 -58
  48. data/lib/aspera/cli/transfer_progress.rb +29 -20
  49. data/lib/aspera/cli/version.rb +1 -1
  50. data/lib/aspera/cli/wizard.rb +160 -0
  51. data/lib/aspera/colors.rb +13 -8
  52. data/lib/aspera/command_line_builder.rb +28 -22
  53. data/lib/aspera/command_line_converter.rb +31 -0
  54. data/lib/aspera/data_repository.rb +1 -0
  55. data/lib/aspera/environment.rb +144 -100
  56. data/lib/aspera/faspex_gw.rb +1 -1
  57. data/lib/aspera/faspex_postproc.rb +3 -2
  58. data/lib/aspera/hash_ext.rb +1 -1
  59. data/lib/aspera/id_generator.rb +10 -10
  60. data/lib/aspera/keychain/base.rb +18 -0
  61. data/lib/aspera/keychain/encrypted_hash.rb +6 -12
  62. data/lib/aspera/keychain/factory.rb +9 -3
  63. data/lib/aspera/keychain/hashicorp_vault.rb +9 -6
  64. data/lib/aspera/keychain/macos_security.rb +13 -13
  65. data/lib/aspera/log.rb +70 -20
  66. data/lib/aspera/nagios.rb +5 -6
  67. data/lib/aspera/node_simulator.rb +12 -7
  68. data/lib/aspera/oauth/base.rb +6 -2
  69. data/lib/aspera/oauth/factory.rb +25 -18
  70. data/lib/aspera/oauth/jwt.rb +13 -1
  71. data/lib/aspera/oauth/url_json.rb +3 -3
  72. data/lib/aspera/oauth/web.rb +5 -3
  73. data/lib/aspera/persistency_folder.rb +2 -2
  74. data/lib/aspera/preview/file_types.rb +43 -35
  75. data/lib/aspera/preview/generator.rb +26 -13
  76. data/lib/aspera/preview/terminal.rb +10 -7
  77. data/lib/aspera/preview/utils.rb +11 -9
  78. data/lib/aspera/products/connect.rb +2 -1
  79. data/lib/aspera/products/desktop.rb +1 -1
  80. data/lib/aspera/products/other.rb +2 -2
  81. data/lib/aspera/products/transferd.rb +8 -6
  82. data/lib/aspera/proxy_auto_config.rb +1 -1
  83. data/lib/aspera/rest.rb +46 -28
  84. data/lib/aspera/rest_call_error.rb +1 -1
  85. data/lib/aspera/rest_error_analyzer.rb +1 -0
  86. data/lib/aspera/resumer.rb +1 -1
  87. data/lib/aspera/secret_hider.rb +46 -40
  88. data/lib/aspera/ssh.rb +14 -4
  89. data/lib/aspera/sync/args.schema.yaml +102 -0
  90. data/lib/aspera/sync/conf.schema.yaml +701 -0
  91. data/lib/aspera/sync/database.rb +83 -0
  92. data/lib/aspera/{transfer/sync.rb → sync/operations.rb} +145 -68
  93. data/lib/aspera/temp_file_manager.rb +4 -2
  94. data/lib/aspera/timer_limiter.rb +7 -5
  95. data/lib/aspera/transfer/error.rb +1 -1
  96. data/lib/aspera/transfer/error_info.rb +1 -2
  97. data/lib/aspera/transfer/faux_file.rb +11 -10
  98. data/lib/aspera/transfer/parameters.rb +6 -5
  99. data/lib/aspera/transfer/spec.rb +15 -1
  100. data/lib/aspera/transfer/spec.schema.yaml +316 -293
  101. data/lib/aspera/transfer/spec_doc.rb +34 -16
  102. data/lib/aspera/transfer/uri.rb +5 -5
  103. data/lib/aspera/uri_reader.rb +14 -10
  104. data/lib/aspera/web_auth.rb +2 -2
  105. data/lib/aspera/web_server_simple.rb +2 -2
  106. data.tar.gz.sig +0 -0
  107. metadata +15 -15
  108. metadata.gz.sig +0 -0
  109. data/examples/dascli +0 -30
  110. data/examples/get_proto_file.rb +0 -8
  111. data/examples/proxy.pac +0 -60
  112. data/lib/aspera/transfer/convert.rb +0 -29
  113. data/lib/aspera/transfer/sync_instance.schema.yaml +0 -13
  114. data/lib/aspera/transfer/sync_session.schema.yaml +0 -79
@@ -35,10 +35,10 @@ module Aspera
35
35
  Log.log.debug{"detect error: #{e}"}
36
36
  end
37
37
  raise error if error
38
- return nil
38
+ return
39
39
  end
40
40
 
41
- def wizard(object:, private_key_path: nil, pub_key_pem: nil)
41
+ def wizard(object:)
42
42
  options = object.options
43
43
  return {
44
44
  preset_value: {
@@ -51,8 +51,9 @@ module Aspera
51
51
  end
52
52
  end
53
53
 
54
- def initialize(**env)
54
+ def initialize(**_)
55
55
  super
56
+ @api_orch = nil
56
57
  options.declare(:result, "Specify result value as: 'work_step:parameter'")
57
58
  options.declare(:synchronous, 'Wait for completion', values: :bool, default: :no)
58
59
  options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
@@ -89,7 +90,7 @@ module Aspera
89
90
  result = @api_orch.call(**call_args)
90
91
  return result[:http] if http
91
92
  result = format.eql?('xml') ? XmlSimple.xml_in(result[:http].body, {'ForceArray' => xml_arrays}) : result[:data]
92
- Log.log.debug{Log.dump(:data, result)}
93
+ Log.dump(:data, result)
93
94
  return result
94
95
  end
95
96
 
@@ -101,7 +102,8 @@ module Aspera
101
102
  type: :url,
102
103
  url_query: {
103
104
  'login' => options.get_option(:username, mandatory: true),
104
- 'password' => options.get_option(:password, mandatory: true)}
105
+ 'password' => options.get_option(:password, mandatory: true)
106
+ }
105
107
  }
106
108
  when :head_basic
107
109
  {
@@ -110,7 +112,7 @@ module Aspera
110
112
  password: options.get_option(:password, mandatory: true)
111
113
  }
112
114
  when :apikey
113
- raise 'Not implemented'
115
+ Aspera.error_not_implemented
114
116
  end
115
117
 
116
118
  @api_orch = Rest.new(
@@ -150,11 +152,7 @@ module Aspera
150
152
  return Main.result_object_list(result['workflows']['workflow'])
151
153
  when :list
152
154
  result = call_ao('workflows_list/0')
153
- return {
154
- type: :object_list,
155
- data: result['workflows']['workflow'],
156
- fields: %w[id portable_id name published_status published_revision_id latest_revision_id last_modification]
157
- }
155
+ return Main.result_object_list(result['workflows']['workflow'], fields: %w[id portable_id name published_status published_revision_id latest_revision_id last_modification])
158
156
  when :details
159
157
  result = call_ao("workflow_details/#{instance_identifier}")
160
158
  return Main.result_object_list(result['workflows']['workflow']['statuses'])
@@ -188,9 +186,7 @@ module Aspera
188
186
  # implicitly, call is synchronous
189
187
  call_params['synchronous'] = true
190
188
  end
191
- if call_params['synchronous']
192
- result[:type] = :text
193
- end
189
+ result[:type] = :text if call_params['synchronous']
194
190
  result[:data] = call_ao("initiate/#{wf_id}", args: call_params)
195
191
  return result
196
192
  end
@@ -49,7 +49,7 @@ module Aspera
49
49
  attr_accessor :option_previews_folder
50
50
  attr_accessor :option_folder_reset_cache, :option_skip_folders, :option_overwrite, :option_file_access
51
51
 
52
- def initialize(**env)
52
+ def initialize(**_)
53
53
  super
54
54
  @skip_types = []
55
55
  @default_transfer_spec = nil
@@ -64,12 +64,14 @@ module Aspera
64
64
  # link CLI options to gen_info attributes
65
65
  options.declare(
66
66
  :skip_format, 'Skip this preview format (multiple possible)', values: Aspera::Preview::Generator::PREVIEW_FORMATS,
67
- handler: {o: self, m: :option_skip_format}, default: [])
67
+ handler: {o: self, m: :option_skip_format}, default: []
68
+ )
68
69
  options.declare(
69
70
  :folder_reset_cache, 'Force detection of generated preview by refresh cache',
70
71
  values: %i[no header read],
71
72
  handler: {o: self, m: :option_folder_reset_cache},
72
- default: :no)
73
+ default: :no
74
+ )
73
75
  options.declare(:skip_types, 'Skip types in comma separated list', handler: {o: self, m: :option_skip_types})
74
76
  options.declare(:previews_folder, 'Preview folder in storage root', handler: {o: self, m: :option_previews_folder}, default: DEFAULT_PREVIEWS_FOLDER)
75
77
  options.declare(:temp_folder, 'Path to temp folder', default: Dir.tmpdir)
@@ -83,7 +85,8 @@ module Aspera
83
85
  :file_access, 'How to read and write files in repository',
84
86
  values: %i[local remote],
85
87
  handler: {o: self, m: :option_file_access},
86
- default: :local)
88
+ default: :local
89
+ )
87
90
 
88
91
  # add other options for generator (and set default values)
89
92
  Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
@@ -125,14 +128,15 @@ module Aspera
125
128
 
126
129
  # /files/id/files is normally cached in redis, but we can discard the cache
127
130
  # but /files/id is not cached
128
- def get_folder_entries(file_id, request_args=nil)
131
+ def get_folder_entries(file_id, request_args = nil)
129
132
  headers = {'Accept' => Rest::MIME_JSON}
130
133
  headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
131
134
  return @api_node.call(
132
135
  operation: 'GET',
133
136
  subpath: "files/#{file_id}/files",
134
137
  headers: headers,
135
- query: request_args)[:data]
138
+ query: request_args
139
+ )[:data]
136
140
  end
137
141
 
138
142
  # old version based on folders
@@ -196,12 +200,8 @@ module Aspera
196
200
  if !file_entry.nil? &&
197
201
  @option_skip_folders.none?{ |d| file_entry['path'].start_with?(d)}
198
202
  file_entry['parent_file_id'] = event['data']['parent_file_id']
199
- if event['types'].include?('file.deleted')
200
- Log.log.error('TODO'.red)
201
- end
202
- if event['types'].include?('file.deleted')
203
- generate_preview(file_entry)
204
- end
203
+ Log.log.error('TODO'.red) if event['types'].include?('file.deleted')
204
+ generate_preview(file_entry) if event['types'].include?('file.deleted')
205
205
  end
206
206
  end
207
207
  # log/persist periodically or last one
@@ -215,7 +215,7 @@ module Aspera
215
215
  end
216
216
  end
217
217
 
218
- def do_transfer(direction, folder_id, source_filename, destination='/')
218
+ def do_transfer(direction, folder_id, source_filename, destination = '/')
219
219
  Aspera.assert(!(destination.nil? && direction.eql?(Transfer::Spec::DIRECTION_RECEIVE)))
220
220
  t_spec = @api_node.transfer_spec_gen4(folder_id, direction, {
221
221
  'paths' => [{'source' => source_filename}],
@@ -268,7 +268,7 @@ module Aspera
268
268
  end
269
269
 
270
270
  # Generate a file name based on basename and format (extension)
271
- def preview_filename(preview_format, base_name=nil)
271
+ def preview_filename(preview_format, base_name = nil)
272
272
  base_name ||= PREVIEW_BASENAME
273
273
  return "#{base_name}.#{preview_format}"
274
274
  end
@@ -319,7 +319,7 @@ module Aspera
319
319
  # create folder if needed
320
320
  FileUtils.mkdir_p(local_entry_preview_dir)
321
321
  if @access_remote
322
- raise 'missing parent_file_id in entry' if entry['parent_file_id'].nil?
322
+ Aspera.assert(!entry['parent_file_id'].nil?){'missing parent_file_id in entry'}
323
323
  # download original file to temp folder
324
324
  do_transfer(Transfer::Spec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
325
325
  end
@@ -335,9 +335,7 @@ module Aspera
335
335
  File.delete(File.join(@tmp_folder, entry['name']))
336
336
  end
337
337
  # force read file updated previews
338
- if @option_folder_reset_cache.eql?(:read)
339
- @api_node.read("files/#{entry['id']}")
340
- end
338
+ @api_node.read("files/#{entry['id']}") if @option_folder_reset_cache.eql?(:read)
341
339
  rescue StandardError => e
342
340
  Log.log.error{"Ignore: #{e.message}"}
343
341
  Log.log.debug(e.backtrace.join("\n").red)
@@ -345,10 +343,10 @@ module Aspera
345
343
 
346
344
  # scan all files in provided folder entry
347
345
  # @param top_path subpath to start folder scan inside
348
- def scan_folder_files(top_entry, top_path=nil)
346
+ def scan_folder_files(top_entry, top_path = nil)
349
347
  unless top_path.nil?
350
348
  # canonical path: start with / and ends with /
351
- top_path = '/' + top_path.split('/').reject(&:empty?).join('/') + '/'
349
+ top_path = "/#{top_path.split('/').reject(&:empty?).join('/')}/"
352
350
  end
353
351
  Log.log.debug{"scan: #{top_entry} : #{top_path}".green}
354
352
  # don't use recursive call, use list instead
@@ -384,9 +382,7 @@ module Aspera
384
382
  # process all items in current folder
385
383
  folder_entries.each do |folder_entry|
386
384
  # add path for older versions of ES
387
- if !folder_entry.key?('path')
388
- folder_entry['path'] = entry_path_with_slash + folder_entry['name']
389
- end
385
+ folder_entry['path'] = entry_path_with_slash + folder_entry['name'] if !folder_entry.key?('path')
390
386
  folder_entry['parent_file_id'] = entry['id']
391
387
  entries_to_process.push(folder_entry)
392
388
  end
@@ -418,7 +414,7 @@ module Aspera
418
414
  Log.log.debug{"remote: #{@access_remote}"}
419
415
  Log.log.debug{"access key info: #{@access_key_self}"}
420
416
  # TODO: can the previews folder parameter be read from node api ?
421
- @option_skip_folders.push('/' + @option_previews_folder)
417
+ @option_skip_folders.push("/#{@option_previews_folder}")
422
418
  if @access_remote
423
419
  # NOTE: the filter "name", it's why we take the first one
424
420
  @previews_folder_entry = get_folder_entries(@access_key_self['root_file_id'], {name: @option_previews_folder}).first
@@ -431,7 +427,7 @@ module Aspera
431
427
  @local_storage_root = @local_storage_root[PVCL_LOCAL_STORAGE.length..-1] if @local_storage_root.start_with?(PVCL_LOCAL_STORAGE)
432
428
  # TODO: windows could have "C:" ?
433
429
  Aspera.assert(@local_storage_root.start_with?('/')){"not local storage: #{@local_storage_root}"}
434
- Aspera.assert(File.directory?(@local_storage_root), exception_class: Cli::Error){"Local storage root folder #{@local_storage_root} does not exist."}
430
+ Aspera.assert(File.directory?(@local_storage_root), type: Cli::Error){"Local storage root folder #{@local_storage_root} does not exist."}
435
431
  @local_preview_folder = File.join(@local_storage_root, @option_previews_folder)
436
432
  raise Cli::Error, "Folder #{@local_preview_folder} does not exist locally. " \
437
433
  'Please create it, or specify an alternate name.' unless File.directory?(@local_preview_folder)
@@ -460,7 +456,8 @@ module Aspera
460
456
  'id' => @access_key_self['root_file_id'],
461
457
  'name' => '/',
462
458
  'type' => 'folder',
463
- 'path' => '/'}
459
+ 'path' => '/'
460
+ }
464
461
  else
465
462
  @api_node.read("files/#{scan_id}")
466
463
  end
@@ -479,7 +476,8 @@ module Aspera
479
476
  command.to_s,
480
477
  options.get_option(:url, mandatory: true),
481
478
  options.get_option(:username, mandatory: true)
482
- ]))
479
+ ])
480
+ )
483
481
  end
484
482
  # call processing method specified by command line command
485
483
  send(:"process_#{command}", iteration_persistency)
@@ -498,8 +496,7 @@ module Aspera
498
496
  formatter.display_status(Aspera::Preview::Terminal.build(File.read(generated_file_path), **terminal_options))
499
497
  end
500
498
  return Main.result_status("generated: #{generated_file_path}")
501
- else
502
- raise 'error'
499
+ else Aspera.error_unexpected_value(command)
503
500
  end
504
501
  ensure
505
502
  Log.log.debug{"cleaning up temp folder #{@tmp_folder}"}
@@ -10,15 +10,13 @@ require 'aspera/nagios'
10
10
  require 'aspera/log'
11
11
  require 'aspera/assert'
12
12
  require 'aspera/environment'
13
- require 'tempfile'
14
- require 'open3'
15
-
16
13
  module Aspera
17
14
  module Cli
18
15
  module Plugins
19
- # implement basic remote access with FASP/SSH
16
+ # Operations on HSTS with SSH/FASP (ascmd/ascp)
20
17
  class Server < Cli::BasicAuthPlugin
21
18
  include SyncActions
19
+
22
20
  SSH_SCHEME = 'ssh'
23
21
  LOCAL_SCHEME = 'local'
24
22
  HTTPS_SCHEME = 'https'
@@ -33,8 +31,8 @@ module Aspera
33
31
  private_constant :SSH_SCHEME, :URI_SCHEMES, :ASCMD_ALIASES, :TRANSFER_COMMANDS
34
32
 
35
33
  class LocalExecutor
36
- def execute(ascmd_path, line)
37
- return Environment.secure_capture(exec: ascmd_path, stdin_data: line, binmode: true)
34
+ def execute(ascmd_path, input:)
35
+ return Environment.secure_capture(exec: ascmd_path, stdin_data: input, binmode: true, exception: false)
38
36
  end
39
37
  end
40
38
 
@@ -61,18 +59,16 @@ module Aspera
61
59
  socket = TCPSocket.new(server_uri.hostname, server_uri.port)
62
60
  socket.puts('SSH-2.0-Ascli_0.0')
63
61
  version = socket.gets.chomp
64
- if version.match?(/^SSH-2.0-/)
65
- return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url}
66
- end
62
+ return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url} if version.match?(/^SSH-2.0-/)
67
63
  rescue StandardError => e
68
64
  error = e
69
65
  Log.log.debug{"detect error: #{e}"}
70
66
  end
71
67
  raise error if error
72
- return nil
68
+ return
73
69
  end
74
70
 
75
- def wizard(object:, private_key_path: nil, pub_key_pem: nil)
71
+ def wizard(object:)
76
72
  options = object.options
77
73
  return {
78
74
  preset_value: {
@@ -85,14 +81,23 @@ module Aspera
85
81
  end
86
82
  end
87
83
 
88
- def initialize(**env)
84
+ def initialize(**_)
89
85
  super
86
+ @ssh_opts = {}
87
+ @connection_type = :ssh
90
88
  options.declare(:ssh_keys, 'SSH key path list (Array or single)')
91
89
  options.declare(:passphrase, 'SSH private key passphrase')
92
- options.declare(:ssh_options, 'SSH options', types: Hash, default: {})
90
+ options.declare(:ssh_options, 'SSH options', types: Hash, handler: {o: self, m: :option_ssh_opts})
93
91
  SyncActions.declare_options(options)
94
92
  options.parse_options!
95
- @ssh_opts = options.get_option(:ssh_options).symbolize_keys
93
+ end
94
+
95
+ def option_ssh_opts; @ssh_opts; end
96
+
97
+ # multiple option are merged
98
+ def option_ssh_opts=(value)
99
+ Aspera.assert_type(value, Hash)
100
+ @ssh_opts.deep_merge!(value.compact.symbolize_keys)
96
101
  end
97
102
 
98
103
  # Read command line options
@@ -110,12 +115,14 @@ module Aspera
110
115
  if server_uri.scheme.eql?(LOCAL_SCHEME)
111
116
  # Using local execution (mostly for testing)
112
117
  server_transfer_spec['remote_host'] = 'localhost'
113
- # simulate SSH environment, else ascp will fail
118
+ # simulate SSH environment, else ascmd will fail
114
119
  ENV['SSH_CLIENT'] = 'local 0 0'
120
+ @connection_type = :local
115
121
  return server_transfer_spec
116
122
  elsif transfer.option_transfer_spec['token'].is_a?(String) && server_uri.scheme.eql?(HTTPS_SCHEME)
117
123
  server_transfer_spec['wss_enabled'] = true
118
124
  server_transfer_spec['wss_port'] = server_uri.port
125
+ @connection_type = :wss
119
126
  # Using WSS
120
127
  return server_transfer_spec
121
128
  end
@@ -165,7 +172,7 @@ module Aspera
165
172
  end
166
173
  # if user provided transfer spec has a token, we will use bypass keys
167
174
  cred_set = true if transfer.option_transfer_spec['token'].is_a?(String)
168
- raise 'Either password, key , or transfer spec token must be provided' if !cred_set
175
+ Aspera.assert(cred_set, type: BadArgument){'Either password, key , or transfer spec token must be provided'}
169
176
  return server_transfer_spec
170
177
  end
171
178
 
@@ -187,12 +194,11 @@ module Aspera
187
194
 
188
195
  def execute_action
189
196
  server_transfer_spec = options_to_base_transfer_spec
190
- ascmd_executor = if !@ssh_opts.empty?
191
- Ssh.new(server_transfer_spec['remote_host'], server_transfer_spec['remote_user'], @ssh_opts)
192
- elsif server_transfer_spec.key?('wss_enabled')
193
- nil
194
- else
195
- LocalExecutor.new
197
+ ascmd_executor = case @connection_type
198
+ when :local then LocalExecutor.new
199
+ when :wss then nil
200
+ when :ssh then Ssh.new(server_transfer_spec['remote_host'], server_transfer_spec['remote_user'], @ssh_opts)
201
+ else Aspera.error_unexpected_value(@connection_type){'connection type'}
196
202
  end
197
203
  # the set of available commands depends on SSH executor availability (i.e. no WSS)
198
204
  available_commands = ascmd_executor.nil? ? BASE_ACTIONS : ACTIONS
@@ -205,18 +211,13 @@ module Aspera
205
211
  command_nagios = options.get_next_command(%i[transfer])
206
212
  case command_nagios
207
213
  when :transfer
208
- file = Tempfile.new('transfer_test')
209
- filepath = file.path
210
- file.write('This is a test file for transfer test')
211
- file.close
212
214
  probe_ts = server_transfer_spec.merge({
213
215
  'direction' => 'send',
214
216
  'cookie' => 'aspera.sync', # hide in console
215
217
  'resume_policy' => 'none',
216
- 'paths' => [{'source' => filepath, 'destination' => '.fasping'}]
218
+ 'paths' => [{'source' => 'faux:///pingfile?1k', 'destination' => '.fasping'}]
217
219
  })
218
220
  statuses = transfer.start(probe_ts)
219
- file.unlink
220
221
  if TransferAgent.session_status(statuses).eql?(:success)
221
222
  nagios.add_ok('transfer', 'ok')
222
223
  else
@@ -21,11 +21,9 @@ module Aspera
21
21
  # TODO: use ping instead ?
22
22
  api.read("#{NODE_API_PATH}/app")
23
23
  rescue RestCallError => e
24
- if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
25
- found = true
26
- end
24
+ found = true if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
27
25
  end
28
- return nil unless found
26
+ return unless found
29
27
  version = 'unknown'
30
28
  test_page = api.call(operation: 'GET', subpath: 'login')
31
29
  if (m = test_page[:http].body.match(/\(v(1\..*)\)/))
@@ -37,7 +35,7 @@ module Aspera
37
35
  }
38
36
  end
39
37
 
40
- def wizard(object:, private_key_path: nil, pub_key_pem: nil)
38
+ def wizard(object:)
41
39
  options = object.options
42
40
  return {
43
41
  preset_value: {
@@ -72,8 +70,9 @@ module Aspera
72
70
  .call(
73
71
  operation: 'GET',
74
72
  subpath: 'ping',
75
- headers: {'content-type': Rest::MIME_JSON})
76
- raise 'Shares not detected' unless res[:http].body.eql?(' ')
73
+ headers: {'content-type': Rest::MIME_JSON}
74
+ )
75
+ raise Error, 'Shares not detected' unless res[:http].body.eql?(' ')
77
76
  nagios.add_ok('shares api', 'accessible')
78
77
  rescue StandardError => e
79
78
  nagios.add_critical('API', e.to_s)
@@ -83,59 +82,72 @@ module Aspera
83
82
  api_shares_node = basic_auth_api(NODE_API_PATH)
84
83
  repo_command = options.get_next_command(Node::COMMANDS_SHARES)
85
84
  return Node
86
- .new(**init_params, api: api_shares_node)
85
+ .new(context: context, api: api_shares_node)
87
86
  .execute_action(repo_command)
88
87
  when :admin
89
88
  api_shares_admin = basic_auth_api(ADMIN_API_PATH)
90
89
  admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
91
90
  case admin_command
92
91
  when :node
93
- return entity_action(api_shares_admin, 'data/nodes')
92
+ return entity_execute(api: api_shares_admin, entity: 'data/nodes')
94
93
  when :share
95
94
  share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
96
95
  case share_command
97
96
  when *Plugin::ALL_OPS
98
- return entity_command(
99
- share_command, api_shares_admin, 'data/shares',
100
- display_fields: %w[id name node_id directory percent_free])
97
+ return entity_execute(
98
+ api: api_shares_admin,
99
+ entity: 'data/shares',
100
+ command: share_command,
101
+ display_fields: %w[id name node_id directory percent_free]
102
+ )
101
103
  when :user_permissions, :group_permissions
102
104
  share_id = instance_identifier
103
- return entity_action(api_shares_admin, "data/shares/#{share_id}/#{share_command}")
105
+ return entity_execute(api: api_shares_admin, entity: "data/shares/#{share_id}/#{share_command}")
104
106
  end
105
107
  when :transfer_settings
106
108
  xfer_settings_command = options.get_next_command(%i[show modify])
107
- return entity_command(xfer_settings_command, api_shares_admin, 'data/transfer_settings', is_singleton: true)
109
+ return entity_execute(
110
+ api: api_shares_admin,
111
+ entity: 'data/transfer_settings',
112
+ command: xfer_settings_command,
113
+ is_singleton: true
114
+ )
108
115
  when :user, :group
109
116
  entity_type = admin_command
110
117
  entities_location = options.get_next_command(%i[all local ldap saml])
111
118
  entities_prefix = entities_location.eql?(:all) ? '' : "#{entities_location}_"
112
119
  entities_path = "data/#{entities_prefix}#{entity_type}s"
113
- entity_action = nil
120
+ entity_commands = nil
114
121
  case entities_location
115
122
  when :all
116
- entity_action = %i[list show delete]
117
- entity_action.concat(USR_GRP_SETTINGS)
118
- entity_action.push(:users) if entity_type.eql?(:group)
119
- entity_action.freeze
123
+ entity_commands = %i[list show delete]
124
+ entity_commands.concat(USR_GRP_SETTINGS)
125
+ entity_commands.push(:users) if entity_type.eql?(:group)
126
+ entity_commands.freeze
120
127
  when :local
121
- entity_action = %i[list show delete create modify]
122
- entity_action.push(:users) if entity_type.eql?(:group)
123
- entity_action.freeze
128
+ entity_commands = %i[list show delete create modify]
129
+ entity_commands.push(:users) if entity_type.eql?(:group)
130
+ entity_commands.freeze
124
131
  when :ldap
125
- entity_action = %i[add].freeze
132
+ entity_commands = %i[add].freeze
126
133
  when :saml
127
- entity_action = %i[import].freeze
134
+ entity_commands = %i[import].freeze
128
135
  end
129
- entity_verb = options.get_next_command(entity_action)
136
+ entity_verb = options.get_next_command(entity_commands)
130
137
  case entity_verb
131
138
  when *Plugin::ALL_OPS # list, show, delete, create, modify
132
139
  display_fields = entity_type.eql?(:user) ? %w[id username first_name last_name email] : nil
133
140
  display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:all)
134
- return entity_command(entity_verb, api_shares_admin, entities_path, display_fields: display_fields)
141
+ return entity_execute(
142
+ api: api_shares_admin,
143
+ entity: entities_path,
144
+ command: entity_verb,
145
+ display_fields: display_fields
146
+ )
135
147
  when *USR_GRP_SETTINGS # transfer_settings, app_authorizations, share_permissions
136
148
  group_id = instance_identifier
137
149
  entities_path = "#{entities_path}/#{group_id}/#{entity_verb}"
138
- return entity_action(api_shares_admin, entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
150
+ return entity_execute(api: api_shares_admin, entity: entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
139
151
  when :import # saml
140
152
  return do_bulk_operation(command: entity_verb, descr: 'user information') do |entity_parameters|
141
153
  entity_parameters = entity_parameters.transform_keys{ |k| k.gsub(/\s+/, '_').downcase}
@@ -151,7 +163,7 @@ module Aspera
151
163
  api_shares_admin.create(entities_path, {entity_type=>entity_name})
152
164
  end
153
165
  when :users # group
154
- return entity_action(api_shares_admin, "#{entities_path}/#{instance_identifier}/#{entities_prefix}users")
166
+ return entity_execute(api: api_shares_admin, entity: "#{entities_path}/#{instance_identifier}/#{entities_prefix}users")
155
167
  else Aspera.error_unexpected_value(entity_verb)
156
168
  end
157
169
  end