aspera-cli 4.24.2 → 4.25.0.pre

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 (65) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +1064 -758
  4. data/CONTRIBUTING.md +43 -100
  5. data/README.md +671 -419
  6. data/lib/aspera/api/aoc.rb +71 -43
  7. data/lib/aspera/api/cos_node.rb +3 -2
  8. data/lib/aspera/api/faspex.rb +6 -5
  9. data/lib/aspera/api/node.rb +10 -12
  10. data/lib/aspera/ascmd.rb +1 -2
  11. data/lib/aspera/ascp/installation.rb +53 -39
  12. data/lib/aspera/assert.rb +25 -3
  13. data/lib/aspera/cli/error.rb +4 -2
  14. data/lib/aspera/cli/extended_value.rb +84 -60
  15. data/lib/aspera/cli/formatter.rb +55 -22
  16. data/lib/aspera/cli/main.rb +21 -14
  17. data/lib/aspera/cli/manager.rb +348 -247
  18. data/lib/aspera/cli/plugins/alee.rb +3 -3
  19. data/lib/aspera/cli/plugins/aoc.rb +70 -14
  20. data/lib/aspera/cli/plugins/base.rb +57 -49
  21. data/lib/aspera/cli/plugins/config.rb +69 -84
  22. data/lib/aspera/cli/plugins/console.rb +13 -8
  23. data/lib/aspera/cli/plugins/cos.rb +1 -1
  24. data/lib/aspera/cli/plugins/faspex.rb +32 -26
  25. data/lib/aspera/cli/plugins/faspex5.rb +45 -43
  26. data/lib/aspera/cli/plugins/faspio.rb +5 -5
  27. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  28. data/lib/aspera/cli/plugins/node.rb +131 -120
  29. data/lib/aspera/cli/plugins/oauth.rb +1 -1
  30. data/lib/aspera/cli/plugins/orchestrator.rb +114 -32
  31. data/lib/aspera/cli/plugins/preview.rb +26 -46
  32. data/lib/aspera/cli/plugins/server.rb +6 -8
  33. data/lib/aspera/cli/plugins/shares.rb +27 -32
  34. data/lib/aspera/cli/sync_actions.rb +49 -38
  35. data/lib/aspera/cli/transfer_agent.rb +16 -34
  36. data/lib/aspera/cli/version.rb +1 -1
  37. data/lib/aspera/cli/wizard.rb +8 -5
  38. data/lib/aspera/command_line_builder.rb +20 -17
  39. data/lib/aspera/coverage.rb +1 -1
  40. data/lib/aspera/environment.rb +41 -34
  41. data/lib/aspera/faspex_gw.rb +1 -1
  42. data/lib/aspera/keychain/factory.rb +1 -2
  43. data/lib/aspera/markdown.rb +31 -0
  44. data/lib/aspera/nagios.rb +6 -5
  45. data/lib/aspera/oauth/base.rb +17 -27
  46. data/lib/aspera/oauth/factory.rb +1 -1
  47. data/lib/aspera/oauth/url_json.rb +2 -1
  48. data/lib/aspera/preview/file_types.rb +23 -37
  49. data/lib/aspera/products/connect.rb +3 -3
  50. data/lib/aspera/rest.rb +51 -39
  51. data/lib/aspera/rest_error_analyzer.rb +4 -4
  52. data/lib/aspera/ssh.rb +5 -2
  53. data/lib/aspera/ssl.rb +41 -0
  54. data/lib/aspera/sync/conf.schema.yaml +182 -34
  55. data/lib/aspera/sync/database.rb +2 -1
  56. data/lib/aspera/sync/operations.rb +125 -69
  57. data/lib/aspera/transfer/parameters.rb +3 -4
  58. data/lib/aspera/transfer/spec.rb +2 -3
  59. data/lib/aspera/transfer/spec.schema.yaml +48 -18
  60. data/lib/aspera/transfer/spec_doc.rb +14 -14
  61. data/lib/aspera/uri_reader.rb +1 -1
  62. data/lib/transferd_pb.rb +2 -2
  63. data.tar.gz.sig +0 -0
  64. metadata +19 -6
  65. metadata.gz.sig +3 -2
@@ -10,6 +10,7 @@ require 'aspera/cli/formatter'
10
10
  require 'aspera/cli/info'
11
11
  require 'aspera/cli/transfer_progress'
12
12
  require 'aspera/cli/wizard'
13
+ require 'aspera/cli/sync_actions'
13
14
  require 'aspera/ascp/installation'
14
15
  require 'aspera/sync/operations'
15
16
  require 'aspera/products/transferd'
@@ -29,6 +30,7 @@ require 'aspera/oauth/jwt'
29
30
  require 'aspera/log'
30
31
  require 'aspera/assert'
31
32
  require 'aspera/oauth'
33
+ require 'aspera/ssl'
32
34
  require 'openssl'
33
35
  require 'open3'
34
36
  require 'date'
@@ -39,6 +41,8 @@ module Aspera
39
41
  module Plugins
40
42
  # Manage the CLI config file
41
43
  class Config < Base
44
+ include SyncActions
45
+
42
46
  class << self
43
47
  # Folder containing plugins in the gem's main folder
44
48
  def gem_plugins_folder
@@ -89,7 +93,7 @@ module Aspera
89
93
  @option_cache_tokens = true
90
94
  @main_folder = nil
91
95
  @option_config_file = nil
92
- # Store is used for ruby https
96
+ # Store is used for ruby https (OpenSSL::X509::Store)
93
97
  @certificate_store = nil
94
98
  # Paths are used for ascp
95
99
  @certificate_paths = nil
@@ -98,7 +102,6 @@ module Aspera
98
102
  options.declare(
99
103
  :home, 'Home folder for tool',
100
104
  handler: {o: self, m: :main_folder},
101
- types: String,
102
105
  default: self.class.default_app_main_folder(app_name: Info::CMD_NAME)
103
106
  )
104
107
  options.parse_options!
@@ -118,65 +121,49 @@ module Aspera
118
121
  # Read config file (set @config_presets)
119
122
  read_config_file
120
123
  # Add preset handler (needed for smtp)
121
- ExtendedValue.instance.set_handler(EXTEND_PRESET, lambda{ |v| preset_by_name(v)})
122
- ExtendedValue.instance.set_handler(EXTEND_VAULT, lambda{ |v| vault_value(v)})
124
+ ExtendedValue.instance.on(EXTEND_PRESET){ |v| preset_by_name(v)}
125
+ ExtendedValue.instance.on(EXTEND_VAULT){ |v| vault_value(v)}
126
+ ExtendedValue.instance.on(EXTEND_ARGS){ |v| options.args_as_extended(v)}
123
127
  # Load defaults before it can be overridden
124
128
  add_plugin_default_preset(CONF_GLOBAL_SYM)
125
129
  # Vault options
126
130
  options.declare(:secret, 'Secret for access keys')
127
- options.declare(:vault, 'Vault for secrets', types: Hash, default: {})
131
+ options.declare(:vault, 'Vault for secrets', allowed: Hash)
128
132
  options.declare(:vault_password, 'Vault password')
129
133
  options.parse_options!
130
134
  # Declare generic plugin options only after handlers are declared
131
135
  Base.declare_options(options)
132
136
  # Configuration options
133
- options.declare(:no_default, 'Do not load default configuration for plugin', values: :none, short: 'N'){@use_plugin_defaults = false}
137
+ options.declare(:no_default, 'Do not load default configuration for plugin', allowed: Allowed::TYPES_NONE, short: 'N'){@use_plugin_defaults = false}
134
138
  options.declare(:preset, 'Load the named option preset from current config file', short: 'P', handler: {o: self, m: :option_preset})
135
- options.declare(:version_check_days, 'Period in days to check new version (zero to disable)', coerce: Integer, default: DEFAULT_CHECK_NEW_VERSION_DAYS)
139
+ options.declare(:version_check_days, 'Period in days to check new version (zero to disable)', allowed: Allowed::TYPES_INTEGER, default: DEFAULT_CHECK_NEW_VERSION_DAYS)
136
140
  options.declare(:plugin_folder, 'Folder where to find additional plugins', handler: {o: self, m: :option_plugin_folder})
137
141
  # Declare wizard options
138
142
  @wizard = Wizard.new(self, @main_folder)
139
143
  # Transfer SDK options
140
- options.declare(:ascp_path, 'Ascp: Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
141
- options.declare(:use_product, 'Ascp: Use ascp from specified product', handler: {o: self, m: :option_use_product})
142
144
  options.declare(:sdk_url, 'Ascp: URL to get Aspera Transfer Executables', default: SpecialValues::DEF)
143
- options.declare(:locations_url, 'Ascp: URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
144
- options.declare(:sdk_folder, 'Ascp: SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
145
- options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
145
+ options.parse_options!
146
+ set_sdk_dir
147
+ options.declare(:ascp_path, 'Ascp: Path to ascp (or product with "product:")', handler: {o: Ascp::Installation.instance, m: :ascp_path}, default: "#{Ascp::Installation::USE_PRODUCT_PREFIX}#{Ascp::Installation::FIRST_FOUND}")
148
+ options.declare(:locations_url, 'Ascp: URL to get download locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
149
+ options.declare(:sdk_folder, 'Ascp: SDK installation folder path', handler: {o: Products::Transferd, m: :sdk_directory})
150
+ options.declare(:progress_bar, 'Display progress bar', allowed: Allowed::TYPES_BOOLEAN, default: Environment.terminal?)
146
151
  # Email options
147
- options.declare(:smtp, 'Email: SMTP configuration', types: Hash)
152
+ options.declare(:smtp, 'Email: SMTP configuration', allowed: Hash)
148
153
  options.declare(:notify_to, 'Email: Recipient for notification of transfers')
149
154
  options.declare(:notify_template, 'Email: ERB template for notification of transfers')
150
155
  # HTTP options
151
- options.declare(:insecure, 'HTTP/S: Do not validate any certificate', values: :bool, handler: {o: self, m: :option_insecure}, default: :no)
152
- options.declare(:ignore_certificate, 'HTTP/S: Do not validate certificate for these URLs', types: Array, handler: {o: self, m: :option_ignore_cert_host_port})
153
- options.declare(:warn_insecure, 'HTTP/S: Issue a warning if certificate is ignored', values: :bool, handler: {o: self, m: :option_warn_insecure_cert}, default: :yes)
154
- options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates', types: [Array, String], handler: {o: self, m: :trusted_cert_locations})
155
- options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket', types: Hash, handler: {o: self, m: :option_http_options}, default: {})
156
- options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials', types: String, handler: {o: self, m: :option_http_proxy})
157
- options.declare(:cache_tokens, 'Save and reuse OAuth tokens', values: :bool, handler: {o: self, m: :option_cache_tokens})
156
+ options.declare(:insecure, 'HTTP/S: Do not validate any certificate', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_insecure}, default: false)
157
+ options.declare(:ignore_certificate, 'HTTP/S: Do not validate certificate for these URLs', allowed: [Array, NilClass], handler: {o: self, m: :option_ignore_cert_host_port})
158
+ options.declare(:warn_insecure, 'HTTP/S: Issue a warning if certificate is ignored', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_warn_insecure_cert}, default: true)
159
+ options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates', allowed: Allowed::TYPES_STRING_ARRAY, handler: {o: self, m: :trusted_cert_locations})
160
+ options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket', allowed: Hash, handler: {o: self, m: :option_http_options}, default: {})
161
+ options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials', handler: {o: self, m: :option_http_proxy})
162
+ options.declare(:cache_tokens, 'Save and reuse OAuth tokens', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_cache_tokens})
158
163
  options.declare(:fpac, 'Proxy auto configuration script')
159
- options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password', types: Array)
164
+ options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password', allowed: [Array, NilClass])
160
165
  options.parse_options!
161
166
  @progress_bar = TransferProgress.new if options.get_option(:progress_bar)
162
- # Check SDK folder is set or not, for compatibility, we check in two places
163
- sdk_dir = Products::Transferd.sdk_directory rescue nil
164
- if sdk_dir.nil?
165
- @sdk_default_location = true
166
- Log.log.debug('SDK folder is not set, checking default')
167
- # New location
168
- sdk_dir = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME)
169
- Log.log.debug{"Checking: #{sdk_dir}"}
170
- if !Dir.exist?(sdk_dir)
171
- Log.log.debug{"No such folder: #{sdk_dir}"}
172
- # Former location
173
- former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), TRANSFERD_APP_NAME)
174
- Log.log.debug{"Checking: #{former_sdk_folder}"}
175
- sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
176
- end
177
- Log.log.debug{"Using: #{sdk_dir}"}
178
- Products::Transferd.sdk_directory = sdk_dir
179
- end
180
167
  pac_script = options.get_option(:fpac)
181
168
  # Create PAC executor
182
169
  if !pac_script.nil?
@@ -200,27 +187,7 @@ module Aspera
200
187
  RestParameters.instance.send(method, v)
201
188
  elsif k.eql?('ssl_options')
202
189
  keys_to_delete.push(k)
203
- # NOTE: here is a hack that allows setting SSLContext options
204
- Aspera.assert_type(v, Array){'ssl_options'}
205
- # Start with default options
206
- ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
207
- v.each do |opt|
208
- case opt
209
- when Integer
210
- ssl_options = opt
211
- when String
212
- name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
213
- raise Cli::BadArgument, "Unknown ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
214
- if opt.start_with?('-')
215
- ssl_options &= ~OpenSSL::SSL.const_get(name)
216
- else
217
- ssl_options |= OpenSSL::SSL.const_get(name)
218
- end
219
- else
220
- Aspera.error_unexpected_value(opt.class.name){'Expected String or Integer in ssl_options'}
221
- end
222
- end
223
- OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = ssl_options
190
+ Aspera::SSL.option_list = v
224
191
  elsif OAuth::Factory.instance.parameters.key?(k.to_sym)
225
192
  keys_to_delete.push(k)
226
193
  OAuth::Factory.instance.parameters[k.to_sym] = v
@@ -238,11 +205,31 @@ module Aspera
238
205
  attr_accessor :main_folder, :option_cache_tokens, :option_insecure, :option_warn_insecure_cert, :option_http_options
239
206
  attr_reader :option_ignore_cert_host_port, :progress_bar
240
207
 
208
+ def set_sdk_dir
209
+ # Check SDK folder is set or not, for compatibility, we check in two places
210
+ sdk_dir = Products::Transferd.sdk_directory rescue nil
211
+ if sdk_dir.nil?
212
+ @sdk_default_location = true
213
+ Log.log.debug('SDK folder is not set, checking default')
214
+ # New location
215
+ sdk_dir = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME)
216
+ Log.log.debug{"Checking: #{sdk_dir}"}
217
+ if !Dir.exist?(sdk_dir)
218
+ Log.log.debug{"No such folder: #{sdk_dir}"}
219
+ # Former location
220
+ former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), TRANSFERD_APP_NAME)
221
+ Log.log.debug{"Checking: #{former_sdk_folder}"}
222
+ sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
223
+ end
224
+ Log.log.debug{"Using: #{sdk_dir}"}
225
+ Products::Transferd.sdk_directory = sdk_dir
226
+ end
227
+ end
228
+
241
229
  # Add files, folders or default locations to the certificate store
242
- # @param path_list [Array<String>] list of paths to add
230
+ # @param path_list [Array<String>] List of paths to add
243
231
  # @return the list of paths
244
232
  def trusted_cert_locations=(path_list)
245
- path_list = [path_list] unless path_list.is_a?(Array)
246
233
  Aspera.assert_type(path_list, Array){'cert locations'}
247
234
  if @certificate_store.nil?
248
235
  Log.log.debug('Creating SSL Cert store')
@@ -273,6 +260,7 @@ module Aspera
273
260
  pp = Dir.entries(p)
274
261
  .map{ |e| File.realpath(File.join(p, e))}
275
262
  .select{ |entry| File.file?(entry)}
263
+ .select{ |entry| CERT_EXT.any?{ |ext| entry.end_with?(ext)}}
276
264
  end
277
265
  @certificate_paths.concat(pp)
278
266
  end
@@ -285,7 +273,7 @@ module Aspera
285
273
  locations = @certificate_paths
286
274
  if locations.nil?
287
275
  # Compute default locations
288
- self.trusted_cert_locations = SpecialValues::DEF
276
+ self.trusted_cert_locations = [SpecialValues::DEF]
289
277
  locations = @certificate_paths
290
278
  # Restore defaults
291
279
  @certificate_paths = @certificate_store = nil
@@ -447,7 +435,7 @@ module Aspera
447
435
  Log.log.warn{"keeping same value for #{preset}: #{param_name}: #{param_value}"}
448
436
  return
449
437
  end
450
- Log.log.warn{"overwriting value: #{selected_preset[param_name]}"}
438
+ Log.log.warn{"overwriting value for #{param_name}: #{selected_preset[param_name]}"}
451
439
  end
452
440
  selected_preset[param_name] = param_value
453
441
  formatter.display_status("Updated: #{preset}: #{param_name} <- #{param_value}")
@@ -479,21 +467,12 @@ module Aspera
479
467
  raise Cli::Error, "Unknown config preset: #{include_path}" if current.nil?
480
468
  end
481
469
  current = self.class.deep_clone(current) unless current.is_a?(String)
482
- return ExtendedValue.instance.evaluate(current)
483
- end
484
-
485
- def option_use_product=(value)
486
- Ascp::Installation.instance.use_ascp_from_product(value)
487
- end
488
-
489
- def option_use_product
490
- 'write-only option, see value of ascp_path'
470
+ return ExtendedValue.instance.evaluate(current, context: 'preset')
491
471
  end
492
472
 
493
473
  def option_plugin_folder=(value)
494
- Aspera.assert_values(value.class, [String, Array]){'plugin folder'}
495
- value = [value] if value.is_a?(String)
496
- Aspera.assert(value.all?(String)){'plugin folder'}
474
+ value = [value] unless value.is_a?(Array)
475
+ Aspera.assert_array_all(value, String){'plugin folder(s)'}
497
476
  value.each{ |f| Plugins::Factory.instance.add_lookup_folder(f)}
498
477
  end
499
478
 
@@ -624,7 +603,7 @@ module Aspera
624
603
  # Collect info from ascp executable
625
604
  data = Ascp::Installation.instance.ascp_info
626
605
  # Add command line transfer spec
627
- data['ts'] = transfer.option_transfer_spec
606
+ data['ts'] = transfer.user_transfer_spec
628
607
  # Add keys
629
608
  DataRepository::ELEMENTS.each_with_object(data){ |i, h| h[i.to_s] = DataRepository.instance.item(i)}
630
609
  # Declare those as secrets
@@ -638,7 +617,7 @@ module Aspera
638
617
  when :use
639
618
  default_product = options.get_next_argument('product name')
640
619
  Ascp::Installation.instance.use_ascp_from_product(default_product)
641
- set_global_default(:ascp_path, Ascp::Installation.instance.path(:ascp))
620
+ set_global_default(:ascp_path, "#{Ascp::Installation::USE_PRODUCT_PREFIX}#{default_product}")
642
621
  return Main.result_nothing
643
622
  end
644
623
  when :install
@@ -725,7 +704,7 @@ module Aspera
725
704
  value = @config_presets[name][param_name]
726
705
  raise "no such option in preset #{name} : #{param_name}" if value.nil?
727
706
  case value
728
- when Numeric, String then return Main.result_text(ExtendedValue.instance.evaluate(value.to_s))
707
+ when Numeric, String then return Main.result_text(ExtendedValue.instance.evaluate(value.to_s, context: 'preset'))
729
708
  end
730
709
  return Main.result_single_object(value)
731
710
  when :unset
@@ -754,7 +733,7 @@ module Aspera
754
733
  options.ask_missing_mandatory = true
755
734
  @config_presets[name] ||= {}
756
735
  options.get_next_argument('option names', multiple: true).each do |option_name|
757
- option_value = options.get_interactive(option_name, option: true)
736
+ option_value = options.get_interactive(option_name, check_option: true)
758
737
  @config_presets[name][option_name] = option_value
759
738
  end
760
739
  return Main.result_status("Updated: #{name}")
@@ -889,7 +868,7 @@ module Aspera
889
868
  result.push({
890
869
  plugin: name,
891
870
  detect: Formatter.tick(plugin_class.respond_to?(:detect)),
892
- wizard: Formatter.tick(plugin_class.instance_methods.include?(:wizard)),
871
+ wizard: Formatter.tick(plugin_class.method_defined?(:wizard)),
893
872
  path: Plugins::Factory.instance.plugin_source(name)
894
873
  })
895
874
  end
@@ -930,10 +909,14 @@ module Aspera
930
909
  when :ascp
931
910
  execute_action_ascp
932
911
  when :sync
933
- case options.get_next_command(%i[spec])
912
+ case options.get_next_command(%i[spec admin translate])
934
913
  when :spec
935
914
  fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true, agent_columns: false, schema: Sync::Operations::CONF_SCHEMA)
936
915
  return Main.result_object_list(data, fields: fields.map(&:to_s))
916
+ when :admin
917
+ return execute_sync_admin
918
+ when :translate
919
+ return Main.result_single_object(Sync::Operations.args_to_conf(options.get_next_argument('async arguments', multiple: true)))
937
920
  else Aspera.error_unreachable_line
938
921
  end
939
922
  when :transferd
@@ -1227,6 +1210,7 @@ module Aspera
1227
1210
  # Special extended values
1228
1211
  EXTEND_PRESET = :preset
1229
1212
  EXTEND_VAULT = :vault
1213
+ EXTEND_ARGS = :''
1230
1214
  PRESET_DIG_SEPARATOR = '.'
1231
1215
  DEFAULT_CHECK_NEW_VERSION_DAYS = 7
1232
1216
  COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
@@ -1235,7 +1219,7 @@ module Aspera
1235
1219
  SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
1236
1220
  CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
1237
1221
  SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
1238
-
1222
+ CERT_EXT = %w[crt cer pem der].freeze
1239
1223
  private_constant :ASPERA_HOME_FOLDER_NAME,
1240
1224
  :DEFAULT_CONFIG_FILENAME,
1241
1225
  :CONF_PRESET_CONFIG,
@@ -1260,7 +1244,8 @@ module Aspera
1260
1244
  :TRANSFERD_APP_NAME,
1261
1245
  :GLOBAL_DEFAULT_KEYWORD,
1262
1246
  :CONF_GLOBAL_SYM,
1263
- :GEM_CHECK_DATE_FMT
1247
+ :GEM_CHECK_DATE_FMT,
1248
+ :CERT_EXT
1264
1249
  end
1265
1250
  end
1266
1251
  end
@@ -22,17 +22,18 @@ module Aspera
22
22
  next unless base_url.start_with?('https://')
23
23
  api = Rest.new(base_url: base_url, redirect_max: 2)
24
24
  test_endpoint = 'login'
25
- test_page = api.call(
25
+ http = api.call(
26
26
  operation: 'GET',
27
27
  subpath: test_endpoint,
28
- query: {local: true}
28
+ query: {local: true},
29
+ ret: :resp
29
30
  )
30
- next unless test_page[:http].body.include?('Aspera Console')
31
+ next unless http.body.include?('Aspera Console')
31
32
  version = 'unknown'
32
- if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
33
+ if (m = http.body.match(/\(v([1-9]\..*)\)/))
33
34
  version = m[1]
34
35
  end
35
- url = test_page[:http].uri.to_s
36
+ url = http.uri.to_s
36
37
  return {
37
38
  version: version,
38
39
  url: url[0..url.index(test_endpoint) - 2]
@@ -44,6 +45,10 @@ module Aspera
44
45
  raise error if error
45
46
  return
46
47
  end
48
+
49
+ def time_to_string(time)
50
+ return time.strftime('%Y-%m-%d %H:%M:%S')
51
+ end
47
52
  end
48
53
 
49
54
  # @param wizard [Wizard] The wizard object
@@ -91,7 +96,7 @@ module Aspera
91
96
  rescue StandardError => e
92
97
  nagios.add_critical('console api', e.to_s)
93
98
  end
94
- return nagios.result
99
+ Main.result_object_list(nagios.status_list)
95
100
  when :transfer
96
101
  command = options.get_next_command(%i[current smart])
97
102
  case command
@@ -113,8 +118,8 @@ module Aspera
113
118
  query = query_read_delete(default: {})
114
119
  if query['from'].nil? && query['to'].nil?
115
120
  time_now = Time.now
116
- query['from'] = Manager.time_to_string(time_now - DEFAULT_FILTER_AGE_SECONDS)
117
- query['to'] = Manager.time_to_string(time_now)
121
+ query['from'] = self.class.time_to_string(time_now - DEFAULT_FILTER_AGE_SECONDS)
122
+ query['to'] = self.class.time_to_string(time_now)
118
123
  end
119
124
  if (filter = query.delete('filter'))
120
125
  parse_extended_filter(filter, query)
@@ -15,7 +15,7 @@ module Aspera
15
15
  options.declare(:endpoint, 'Storage endpoint (URL)')
16
16
  options.declare(:apikey, 'Storage API key')
17
17
  options.declare(:crn, 'Resource instance id (CRN)')
18
- options.declare(:service_credentials, 'IBM Cloud service credentials', types: Hash)
18
+ options.declare(:service_credentials, 'IBM Cloud service credentials', allowed: [Hash, NilClass])
19
19
  options.declare(:region, 'Storage region')
20
20
  options.declare(:identity, "Authentication URL (#{Api::CosNode::IBM_CLOUD_TOKEN_URL})", default: Api::CosNode::IBM_CLOUD_TOKEN_URL)
21
21
  options.parse_options!
@@ -47,22 +47,23 @@ module Aspera
47
47
  urls.each do |base_url|
48
48
  next unless base_url.start_with?('https://')
49
49
  api = Rest.new(base_url: base_url, redirect_max: 1)
50
- result = api.call(
50
+ http = api.call(
51
51
  operation: 'POST',
52
52
  headers: {
53
53
  'Content-type' => Rest::MIME_TEXT,
54
54
  'Accept' => 'application/xrds+xml'
55
- }
55
+ },
56
+ ret: :resp
56
57
  )
57
58
  # 4.x
58
- next unless result[:http].body.start_with?('<?xml')
59
- res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
60
- Log.log.debug{"version: #{result[:http][HEADER_FASPEX_VERSION]}"}
59
+ next unless http.body.start_with?('<?xml')
60
+ res_s = XmlSimple.xml_in(http.body, {'ForceArray' => false})
61
+ Log.log.debug{"version: #{http[HEADER_FASPEX_VERSION]}"}
61
62
  version = res_s['XRD']['application']['version']
62
63
  # take redirect if any
63
64
  return {
64
65
  version: version,
65
- url: result[:http].uri.to_s
66
+ url: http.uri.to_s
66
67
  }
67
68
  rescue StandardError => e
68
69
  error = e
@@ -125,11 +126,11 @@ module Aspera
125
126
  @api_v3 = nil
126
127
  @api_v4 = nil
127
128
  options.declare(:link, 'Public link for specific operation')
128
- options.declare(:delivery_info, 'Package delivery information', types: Hash)
129
+ options.declare(:delivery_info, 'Package delivery information', allowed: Hash)
129
130
  options.declare(:remote_source, 'Remote source for package send (id or %name:)')
130
131
  options.declare(:storage, 'Faspex local storage definition (for browsing source)')
131
132
  options.declare(:recipient, 'Use if recipient is a dropbox (with *)')
132
- options.declare(:box, 'Package box', values: ATOM_MAILBOXES, default: :inbox)
133
+ options.declare(:box, 'Package box', allowed: ATOM_MAILBOXES, default: :inbox)
133
134
  options.parse_options!
134
135
  end
135
136
 
@@ -184,8 +185,9 @@ module Aspera
184
185
  operation: 'GET',
185
186
  subpath: "#{mailbox}.atom",
186
187
  headers: {'Accept' => 'application/xml'},
187
- query: mailbox_query
188
- )[:http].body
188
+ query: mailbox_query,
189
+ ret: :resp
190
+ ).body
189
191
  box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
190
192
  Log.dump(:box_data, box_data)
191
193
  items = box_data.key?('entry') ? box_data['entry'] : []
@@ -251,8 +253,9 @@ module Aspera
251
253
  subpath: create_path,
252
254
  content_type: Rest::MIME_JSON,
253
255
  body: package_create_params,
254
- headers: {'Accept' => 'text/javascript'}
255
- )[:http].body
256
+ headers: {'Accept' => 'text/javascript'},
257
+ ret: :resp
258
+ ).body
256
259
  # get arguments of function call
257
260
  package_creation_data.delete!("\n") # one line
258
261
  package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
@@ -280,7 +283,7 @@ module Aspera
280
283
  rescue StandardError => e
281
284
  nagios.add_critical('faspex api', e.to_s)
282
285
  end
283
- return nagios.result
286
+ Main.result_object_list(nagios.status_list)
284
287
  when :package
285
288
  command_pkg = options.get_next_command(%i[send receive list show], aliases: {recv: :receive})
286
289
  case command_pkg
@@ -300,10 +303,11 @@ module Aspera
300
303
  delivery_info['sources'] ||= [{'paths' => []}]
301
304
  first_source = delivery_info['sources'].first
302
305
  first_source['paths'].concat(transfer.source_list)
303
- source_id = instance_identifier(as_option: :remote_source) do |field, value|
304
- Aspera.assert(field.eql?('name'), type: Cli::BadArgument){'only name as selector, or give id'}
306
+ source_id = options.get_option(:remote_source)
307
+ if source_id && (m = Base.percent_selector(source_id))
308
+ Aspera.assert(m[:field].eql?('name'), type: Cli::BadArgument){'only name as selector, or give id'}
305
309
  source_list = api_v3.read('source_shares')['items']
306
- self.class.get_source_id_by_name(value, source_list)
310
+ source_id = self.class.get_source_id_by_name(m[:value], source_list)
307
311
  end
308
312
  first_source['id'] = source_id.to_i unless source_id.nil?
309
313
  pkg_created = api_v3.create('send', package_create_params)
@@ -362,7 +366,7 @@ module Aspera
362
366
  when :inbox, :archive then'received'
363
367
  when :sent then 'sent'
364
368
  end
365
- entry_xml = api_v3.call(operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'})[:http].body
369
+ entry_xml = api_v3.call(operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'}, ret: :resp).body
366
370
  package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
367
371
  pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
368
372
  end
@@ -373,17 +377,18 @@ module Aspera
373
377
  raise Cli::BadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}" if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
374
378
  # NOTE: unauthenticated API (authorization is in url params)
375
379
  api_public_link = Rest.new(base_url: link_data[:base_url])
376
- package_creation_data = api_public_link.call(
380
+ pkg_xml = api_public_link.call(
377
381
  operation: 'GET',
378
382
  subpath: link_data[:subpath],
379
383
  headers: {'Accept' => 'application/xml'},
380
- query: {passcode: link_data[:query]['passcode']}
381
- )
382
- if !package_creation_data[:http].body.start_with?('<?xml ')
384
+ query: {passcode: link_data[:query]['passcode']},
385
+ ret: :resp
386
+ ).body
387
+ if !pkg_xml.start_with?('<?xml ')
383
388
  Environment.instance.open_uri(link_url)
384
389
  raise Cli::Error, 'Unexpected response: package not found ?'
385
390
  end
386
- package_entry = XmlSimple.xml_in(package_creation_data[:http].body, {'ForceArray' => false})
391
+ package_entry = XmlSimple.xml_in(pkg_xml, {'ForceArray' => false})
387
392
  Log.dump(:package_entry, package_entry)
388
393
  transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
389
394
  pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
@@ -412,8 +417,9 @@ module Aspera
412
417
  query: {'direction' => 'down'},
413
418
  content_type: Rest::MIME_TEXT,
414
419
  body: xml_payload,
415
- headers: {'Accept' => Rest::MIME_TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'}
416
- )[:http].body
420
+ headers: {'Accept' => Rest::MIME_TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
421
+ ret: :resp
422
+ ).body
417
423
  end
418
424
  transfer_spec['direction'] = Transfer::Spec::DIRECTION_RECEIVE
419
425
  statuses = transfer.start(transfer_spec)
@@ -455,7 +461,7 @@ module Aspera
455
461
  when :info
456
462
  return Main.result_single_object(source_info)
457
463
  when :node
458
- node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
464
+ node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE], context: 'faspex node')
459
465
  Log.log.debug{"node=#{node_config}"}
460
466
  Aspera.assert_type(node_config, Hash, type: Cli::Error){source_info[KEY_NODE]}
461
467
  api_node = Rest.new(
@@ -519,7 +525,7 @@ module Aspera
519
525
  end
520
526
  return Main.result_object_list(users)
521
527
  when :login_methods
522
- login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'})[:http].body
528
+ login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'}, ret: :resp).body
523
529
  login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
524
530
  return Main.result_object_list(login_methods['XRD']['Service'])
525
531
  end