aspera-cli 4.14.0 → 4.16.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 (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +300 -185
  5. data/CONTRIBUTING.md +74 -23
  6. data/README.md +2346 -1619
  7. data/bin/ascli +16 -25
  8. data/bin/asession +15 -15
  9. data/examples/dascli +2 -2
  10. data/examples/proxy.pac +1 -1
  11. data/lib/aspera/aoc.rb +216 -150
  12. data/lib/aspera/ascmd.rb +25 -18
  13. data/lib/aspera/assert.rb +45 -0
  14. data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
  15. data/lib/aspera/cli/error.rb +17 -0
  16. data/lib/aspera/cli/extended_value.rb +51 -16
  17. data/lib/aspera/cli/formatter.rb +276 -174
  18. data/lib/aspera/cli/hints.rb +81 -0
  19. data/lib/aspera/cli/main.rb +114 -147
  20. data/lib/aspera/cli/manager.rb +181 -136
  21. data/lib/aspera/cli/plugin.rb +82 -64
  22. data/lib/aspera/cli/plugins/alee.rb +0 -1
  23. data/lib/aspera/cli/plugins/aoc.rb +327 -331
  24. data/lib/aspera/cli/plugins/ats.rb +12 -8
  25. data/lib/aspera/cli/plugins/bss.rb +2 -2
  26. data/lib/aspera/cli/plugins/config.rb +575 -439
  27. data/lib/aspera/cli/plugins/console.rb +40 -0
  28. data/lib/aspera/cli/plugins/cos.rb +4 -5
  29. data/lib/aspera/cli/plugins/faspex.rb +111 -92
  30. data/lib/aspera/cli/plugins/faspex5.rb +245 -182
  31. data/lib/aspera/cli/plugins/node.rb +239 -160
  32. data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
  33. data/lib/aspera/cli/plugins/preview.rb +54 -38
  34. data/lib/aspera/cli/plugins/server.rb +63 -20
  35. data/lib/aspera/cli/plugins/shares.rb +64 -38
  36. data/lib/aspera/cli/sync_actions.rb +68 -0
  37. data/lib/aspera/cli/transfer_agent.rb +64 -67
  38. data/lib/aspera/cli/transfer_progress.rb +73 -0
  39. data/lib/aspera/cli/version.rb +1 -1
  40. data/lib/aspera/colors.rb +3 -1
  41. data/lib/aspera/command_line_builder.rb +27 -22
  42. data/lib/aspera/cos_node.rb +6 -4
  43. data/lib/aspera/coverage.rb +22 -0
  44. data/lib/aspera/data_repository.rb +33 -2
  45. data/lib/aspera/environment.rb +21 -8
  46. data/lib/aspera/fasp/agent_alpha.rb +116 -0
  47. data/lib/aspera/fasp/agent_base.rb +40 -76
  48. data/lib/aspera/fasp/agent_connect.rb +21 -22
  49. data/lib/aspera/fasp/agent_direct.rb +169 -179
  50. data/lib/aspera/fasp/agent_httpgw.rb +200 -195
  51. data/lib/aspera/fasp/agent_node.rb +43 -35
  52. data/lib/aspera/fasp/agent_trsdk.rb +124 -41
  53. data/lib/aspera/fasp/error_info.rb +2 -2
  54. data/lib/aspera/fasp/faux_file.rb +52 -0
  55. data/lib/aspera/fasp/installation.rb +89 -191
  56. data/lib/aspera/fasp/management.rb +249 -0
  57. data/lib/aspera/fasp/parameters.rb +86 -47
  58. data/lib/aspera/fasp/parameters.yaml +75 -8
  59. data/lib/aspera/fasp/products.rb +162 -0
  60. data/lib/aspera/fasp/resume_policy.rb +7 -5
  61. data/lib/aspera/fasp/sync.rb +273 -0
  62. data/lib/aspera/fasp/transfer_spec.rb +10 -8
  63. data/lib/aspera/fasp/uri.rb +6 -6
  64. data/lib/aspera/faspex_gw.rb +11 -8
  65. data/lib/aspera/faspex_postproc.rb +8 -7
  66. data/lib/aspera/hash_ext.rb +2 -2
  67. data/lib/aspera/id_generator.rb +3 -1
  68. data/lib/aspera/json_rpc.rb +51 -0
  69. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  70. data/lib/aspera/keychain/macos_security.rb +15 -13
  71. data/lib/aspera/line_logger.rb +23 -0
  72. data/lib/aspera/log.rb +61 -19
  73. data/lib/aspera/nagios.rb +7 -2
  74. data/lib/aspera/node.rb +105 -21
  75. data/lib/aspera/node_simulator.rb +214 -0
  76. data/lib/aspera/oauth.rb +57 -36
  77. data/lib/aspera/open_application.rb +4 -4
  78. data/lib/aspera/persistency_action_once.rb +13 -14
  79. data/lib/aspera/persistency_folder.rb +5 -4
  80. data/lib/aspera/preview/file_types.rb +56 -268
  81. data/lib/aspera/preview/generator.rb +28 -39
  82. data/lib/aspera/preview/options.rb +2 -0
  83. data/lib/aspera/preview/terminal.rb +36 -16
  84. data/lib/aspera/preview/utils.rb +23 -29
  85. data/lib/aspera/proxy_auto_config.rb +6 -3
  86. data/lib/aspera/rest.rb +127 -80
  87. data/lib/aspera/rest_call_error.rb +1 -1
  88. data/lib/aspera/rest_error_analyzer.rb +16 -14
  89. data/lib/aspera/rest_errors_aspera.rb +39 -34
  90. data/lib/aspera/secret_hider.rb +18 -17
  91. data/lib/aspera/ssh.rb +10 -5
  92. data/lib/aspera/temp_file_manager.rb +11 -4
  93. data/lib/aspera/web_auth.rb +10 -7
  94. data/lib/aspera/web_server_simple.rb +11 -5
  95. data.tar.gz.sig +0 -0
  96. metadata +108 -39
  97. metadata.gz.sig +0 -0
  98. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  99. data/lib/aspera/cli/listener/logger.rb +0 -22
  100. data/lib/aspera/cli/listener/progress.rb +0 -50
  101. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  102. data/lib/aspera/cli/plugins/sync.rb +0 -44
  103. data/lib/aspera/fasp/listener.rb +0 -13
  104. data/lib/aspera/sync.rb +0 -213
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'English'
4
- require 'singleton'
5
- require 'aspera/log'
3
+ # cspell:ignore protobuf ckpt
6
4
  require 'aspera/environment'
7
5
  require 'aspera/data_repository'
6
+ require 'aspera/fasp/products'
7
+ require 'aspera/log'
8
+ require 'aspera/assert'
9
+ require 'aspera/web_server_simple'
10
+ require 'English'
11
+ require 'singleton'
8
12
  require 'xmlsimple'
9
13
  require 'zlib'
10
14
  require 'base64'
@@ -13,24 +17,18 @@ require 'openssl'
13
17
 
14
18
  module Aspera
15
19
  module Fasp
16
- # Singleton that tells where to find ascp and other local resources (keys..) , using the "path(symb)" method.
20
+ # Singleton that tells where to find ascp and other local resources (keys..) , using the "path(:name)" method.
17
21
  # It is used by object : AgentDirect to find necessary resources
18
- # By default it takes the first Aspera product found specified in product_locations
22
+ # By default it takes the first Aspera product found
19
23
  # but the user can specify ascp location by calling:
20
24
  # Installation.instance.use_ascp_from_product(product_name)
21
25
  # or
22
26
  # Installation.instance.ascp_path=""
23
27
  class Installation
24
28
  include Singleton
25
- # known product names
26
- PRODUCT_CONNECT = 'Aspera Connect'
27
- PRODUCT_CLI_V1 = 'Aspera CLI'
28
- PRODUCT_DRIVE = 'Aspera Drive'
29
- PRODUCT_ENTSRV = 'Enterprise Server'
30
29
  # protobuf generated files from sdk
31
30
  EXT_RUBY_PROTOBUF = '_pb.rb'
32
31
  RB_SDK_FOLDER = 'lib'
33
- ONE_YEAR_SECONDS = 365 * 24 * 60 * 60
34
32
  DEFAULT_ASPERA_CONF = <<~END_OF_CONFIG_FILE
35
33
  <?xml version='1.0' encoding='UTF-8'?>
36
34
  <CONF version="2">
@@ -42,9 +40,9 @@ module Aspera
42
40
  </default>
43
41
  </CONF>
44
42
  END_OF_CONFIG_FILE
45
- DUMMY_CERT_INFO = '/C=US/ST=California/L=Emeryville/O=Aspera Inc./OU=Corporate/CN=Aspera Inc./emailAddress=info@asperasoft.com'
46
- private_constant :PRODUCT_CONNECT, :PRODUCT_CLI_V1, :PRODUCT_DRIVE, :PRODUCT_ENTSRV, :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER,
47
- :ONE_YEAR_SECONDS, :DEFAULT_ASPERA_CONF, :DUMMY_CERT_INFO
43
+ # all ascp files (in SDK)
44
+ FILES = %i[ascp ascp4 transferd ssh_private_dsa ssh_private_rsa aspera_license aspera_conf fallback_certificate fallback_private_key].freeze
45
+ private_constant :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER, :DEFAULT_ASPERA_CONF, :FILES
48
46
  # set ascp executable path
49
47
  def ascp_path=(v)
50
48
  @path_to_ascp = v
@@ -56,7 +54,7 @@ module Aspera
56
54
 
57
55
  def sdk_ruby_folder
58
56
  ruby_pb_folder = File.join(sdk_folder, RB_SDK_FOLDER)
59
- FileUtils.mkdir_p(ruby_pb_folder) unless Dir.exist?(ruby_pb_folder)
57
+ FileUtils.mkdir_p(ruby_pb_folder)
60
58
  return ruby_pb_folder
61
59
  end
62
60
 
@@ -73,61 +71,36 @@ module Aspera
73
71
  # @return the path to folder where SDK is installed
74
72
  def sdk_folder
75
73
  raise 'SDK path was ot initialized' if @sdk_dir.nil?
76
- FileUtils.mkdir_p(@sdk_dir) unless Dir.exist?(@sdk_dir)
74
+ FileUtils.mkdir_p(@sdk_dir)
77
75
  @sdk_dir
78
76
  end
79
77
 
80
78
  # find ascp in named product (use value : FIRST_FOUND='FIRST' to just use first one)
81
- # or select one from installed_products()
79
+ # or select one from Products.installed_products()
82
80
  def use_ascp_from_product(product_name)
83
81
  if product_name.eql?(FIRST_FOUND)
84
- pl = installed_products.first
82
+ pl = Products.installed_products.first
85
83
  raise "no FASP installation found\nPlease check manual on how to install FASP." if pl.nil?
86
84
  else
87
- pl = installed_products.find{|i|i[:name].eql?(product_name)}
85
+ pl = Products.installed_products.find{|i|i[:name].eql?(product_name)}
88
86
  raise "no such product installed: #{product_name}" if pl.nil?
89
87
  end
90
88
  self.ascp_path = pl[:ascp_path]
91
89
  Log.log.debug{"ascp_path=#{@path_to_ascp}"}
92
90
  end
93
91
 
94
- # @return the list of installed products in format of product_locations
95
- def installed_products
96
- if @found_products.nil?
97
- scan_locations = product_locations.clone
98
- # add SDK as first search path
99
- scan_locations.unshift({
100
- expected: 'SDK',
101
- app_root: sdk_folder,
102
- sub_bin: ''
103
- })
104
- # search installed products: with ascp
105
- @found_products = scan_locations.select! do |item|
106
- # skip if not main folder
107
- next false unless Dir.exist?(item[:app_root])
108
- Log.log.debug{"Found #{item[:app_root]}"}
109
- sub_bin = item[:sub_bin] || BIN_SUBFOLDER
110
- item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
111
- # skip if no ascp
112
- next false unless File.exist?(item[:ascp_path])
113
- # read info from product info file if present
114
- product_info_file = "#{item[:app_root]}/#{PRODUCT_INFO}"
115
- if File.exist?(product_info_file)
116
- res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
117
- item[:name] = res_s['name']
118
- item[:version] = res_s['version']
119
- else
120
- item[:name] = item[:expected]
92
+ # @return [Hash] with key = file name (String), and value = path to file
93
+ def file_paths
94
+ return FILES.each_with_object({}) do |v, m|
95
+ m[v.to_s] =
96
+ begin
97
+ path(v)
98
+ rescue => e
99
+ e.message
121
100
  end
122
- true # select this version
123
- end
124
101
  end
125
- return @found_products
126
102
  end
127
103
 
128
- # all ascp files (in SDK)
129
- FILES = %i[ascp ascp4 ssh_bypass_dsa_privkey ssh_bypass_rsa_privkey aspera_license aspera_conf fallback_certificate fallback_cert_privkey].freeze
130
-
131
104
  def check_or_create_sdk_file(filename, force: false, &block)
132
105
  return Environment.write_file_restricted(File.join(sdk_folder, filename), force: force, mode: 0o644, &block)
133
106
  end
@@ -135,6 +108,7 @@ module Aspera
135
108
  # get path of one resource file of currently activated product
136
109
  # keys and certs are generated locally... (they are well known values, arch. independent)
137
110
  def path(k)
111
+ file_is_optional = false
138
112
  case k
139
113
  when :ascp, :ascp4
140
114
  use_ascp_from_product(FIRST_FOUND) if @path_to_ascp.nil?
@@ -143,69 +117,42 @@ module Aspera
143
117
  file = file.gsub('ascp', 'ascp4') if k.eql?(:ascp4)
144
118
  when :transferd
145
119
  file = transferd_filepath
146
- when :ssh_bypass_dsa_privkey
147
- file = check_or_create_sdk_file('aspera_bypass_dsa.pem') {get_key('dsa', 1)}
148
- when :ssh_bypass_rsa_privkey
149
- file = check_or_create_sdk_file('aspera_bypass_rsa.pem') {get_key('rsa', 2)}
120
+ file_is_optional = true
121
+ when :ssh_private_dsa, :ssh_private_rsa
122
+ # assume last 3 letters are type
123
+ type = k.to_s[-3..-1].to_sym
124
+ file = check_or_create_sdk_file("aspera_bypass_#{type}.pem") {DataRepository.instance.item(type)}
150
125
  when :aspera_license
151
- file = check_or_create_sdk_file('aspera-license') do
152
- Zlib::Inflate.inflate(DataRepository.instance.data(6))
153
- end
126
+ file = check_or_create_sdk_file('aspera-license') {DataRepository.instance.item(:license)}
154
127
  when :aspera_conf
155
128
  file = check_or_create_sdk_file('aspera.conf') {DEFAULT_ASPERA_CONF}
156
- when :fallback_certificate, :fallback_cert_privkey
129
+ when :fallback_certificate, :fallback_private_key
157
130
  file_key = File.join(sdk_folder, 'aspera_fallback_cert_private_key.pem')
158
131
  file_cert = File.join(sdk_folder, 'aspera_fallback_cert.pem')
159
132
  if !File.exist?(file_key) || !File.exist?(file_cert)
160
133
  require 'openssl'
161
134
  # create new self signed certificate for http fallback
162
- private_key = OpenSSL::PKey::RSA.new(1024)
163
135
  cert = OpenSSL::X509::Certificate.new
164
- cert.subject = cert.issuer = OpenSSL::X509::Name.parse(DUMMY_CERT_INFO)
165
- cert.not_before = Time.now
166
- cert.not_after = Time.now + ONE_YEAR_SECONDS
167
- cert.public_key = private_key.public_key
168
- cert.serial = 0x0
169
- cert.version = 2
170
- cert.sign(private_key, OpenSSL::Digest.new('SHA1'))
136
+ private_key = OpenSSL::PKey::RSA.new(4096)
137
+ WebServerSimple.fill_self_signed_cert(cert, private_key)
171
138
  check_or_create_sdk_file('aspera_fallback_cert_private_key.pem', force: true) {private_key.to_pem}
172
139
  check_or_create_sdk_file('aspera_fallback_cert.pem', force: true) {cert.to_pem}
173
140
  end
174
141
  file = k.eql?(:fallback_certificate) ? file_cert : file_key
175
- else
176
- raise "INTERNAL ERROR: #{k}"
142
+ else error_unexpected_value(k)
177
143
  end
178
- raise "no such file: #{file}" unless File.exist?(file)
144
+ return nil if file_is_optional && !File.exist?(file)
145
+ assert(File.exist?(file)){"no such file: #{file}"}
179
146
  return file
180
147
  end
181
148
 
182
- # @return the file path of local connect where API's URI can be read
183
- def connect_uri
184
- connect = get_product_folders(PRODUCT_CONNECT)
185
- folder = File.join(connect[:run_root], VAR_RUN_SUBFOLDER)
186
- ['', 's'].each do |ext|
187
- uri_file = File.join(folder, "http#{ext}.uri")
188
- Log.log.debug{"checking connect port file: #{uri_file}"}
189
- if File.exist?(uri_file)
190
- return File.open(uri_file, &:gets).strip
191
- end
192
- end
193
- raise "no connect uri file found in #{folder}"
194
- end
195
-
196
- # @ return path to configuration file of aspera CLI
197
- def cli_conf_file
198
- connect = get_product_folders(PRODUCT_CLI_V1)
199
- return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
200
- end
201
-
202
149
  # default bypass key phrase
203
- def bypass_pass
204
- return format('%08x-%04x-%04x-%04x-%04x%08x', *DataRepository.instance.data(3).unpack('NnnnnN'))
150
+ def ssh_cert_uuid
151
+ return DataRepository.instance.item(:uuid)
205
152
  end
206
153
 
207
- def bypass_keys
208
- return %i[ssh_bypass_dsa_privkey ssh_bypass_rsa_privkey].map{|i|Installation.instance.path(i)}
154
+ def aspera_token_ssh_key_paths
155
+ return %i[ssh_private_dsa ssh_private_rsa].map{|i|Installation.instance.path(i)}
209
156
  end
210
157
 
211
158
  # use in plugin `config`
@@ -226,6 +173,47 @@ module Aspera
226
173
  return exe_version
227
174
  end
228
175
 
176
+ def ascp_info
177
+ data = file_paths
178
+ # read PATHs from ascp directly, and pvcl modules as well
179
+ Open3.popen3(data['ascp'], '-DDL-') do |_stdin, _stdout, stderr, thread|
180
+ last_line = ''
181
+ while (line = stderr.gets)
182
+ line.chomp!
183
+ last_line = line
184
+ case line
185
+ when /^DBG Path ([^ ]+) (dir|file) +: (.*)$/
186
+ data[Regexp.last_match(1)] = Regexp.last_match(3)
187
+ when /^DBG Added module group:"(?<module>[^"]+)" name:"(?<scheme>[^"]+)", version:"(?<version>[^"]+)" interface:"(?<interface>[^"]+)"$/
188
+ c = Regexp.last_match.named_captures.symbolize_keys
189
+ data[c[:interface]] ||= {}
190
+ data[c[:interface]][c[:module]] ||= []
191
+ data[c[:interface]][c[:module]].push("#{c[:scheme]} v#{c[:version]}")
192
+ when %r{^DBG License result \(/license/(\S+)\): (.+)$}
193
+ data[Regexp.last_match(1)] = Regexp.last_match(2)
194
+ when /^LOG (.+) version ([0-9.]+)$/
195
+ data['product_name'] = Regexp.last_match(1)
196
+ data['product_version'] = Regexp.last_match(2)
197
+ when /^LOG Initializing FASP version ([^,]+),/
198
+ data['ascp_version'] = Regexp.last_match(1)
199
+ end
200
+ end
201
+ if !thread.value.exitstatus.eql?(1) && !data.key?('root')
202
+ raise last_line
203
+ end
204
+ end
205
+ # ascp's openssl directory
206
+ ascp_file = data['ascp']
207
+ File.binread(ascp_file).scan(/[\x20-\x7E]{4,}/) do |match|
208
+ if (m = match.match(/OPENSSLDIR.*"(.*)"/))
209
+ data['openssldir'] = m[1]
210
+ end
211
+ end if File.file?(ascp_file)
212
+ # log is "-" no need to display
213
+ data.delete('log')
214
+ return data
215
+ end
216
+
229
217
  # download aspera SDK or use local file
230
218
  # extracts ascp binary for current system architecture
231
219
  # @return ascp version (from execution)
@@ -267,123 +255,33 @@ module Aspera
267
255
  # ensure license file are generated so that ascp invocation for version works
268
256
  path(:aspera_license)
269
257
  path(:aspera_conf)
270
- ascp_path = File.join(sdk_folder, ascp_filename)
271
- raise "No #{ascp_filename} found in SDK archive" unless File.exist?(ascp_path)
258
+ ascp_file = Products.ascp_filename
259
+ ascp_path = File.join(sdk_folder, ascp_file)
260
+ raise "No #{ascp_file} found in SDK archive" unless File.exist?(ascp_path)
272
261
  Environment.restrict_file_access(ascp_path, mode: 0o755)
273
262
  Environment.restrict_file_access(ascp_path.gsub('ascp', 'ascp4'), mode: 0o755)
274
- ascp_version = get_ascp_version(File.join(sdk_folder, ascp_filename))
263
+ ascp_version = get_ascp_version(ascp_path)
275
264
  trd_path = transferd_filepath
276
265
  Log.log.warn{"No #{trd_path} in SDK archive"} unless File.exist?(trd_path)
277
266
  Environment.restrict_file_access(trd_path, mode: 0o755) if File.exist?(trd_path)
278
267
  transferd_version = get_exe_version(trd_path, 'version')
279
268
  sdk_version = transferd_version || ascp_version
280
- File.write(File.join(sdk_folder, PRODUCT_INFO), "<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
269
+ File.write(File.join(sdk_folder, Products::INFO_META_FILE), "<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
281
270
  return sdk_version
282
271
  end
283
272
 
284
273
  private
285
274
 
286
- BIN_SUBFOLDER = 'bin'
287
- ETC_SUBFOLDER = 'etc'
288
- VAR_RUN_SUBFOLDER = File.join('var', 'run')
289
- # product information manifest: XML (part of aspera product)
290
- PRODUCT_INFO = 'product-info.mf'
291
275
  # policy for product selection
292
276
  FIRST_FOUND = 'FIRST'
293
277
 
294
- private_constant :BIN_SUBFOLDER, :ETC_SUBFOLDER, :VAR_RUN_SUBFOLDER, :PRODUCT_INFO
295
-
296
278
  def initialize
297
279
  @path_to_ascp = nil
298
280
  @sdk_dir = nil
299
- @found_products = nil
300
- end
301
-
302
- # @return folder paths for specified applications
303
- # @param name Connect or CLI
304
- def get_product_folders(name)
305
- found = installed_products.select{|i|i[:expected].eql?(name) || i[:name].eql?(name)}
306
- raise "Product: #{name} not found, please install." if found.empty?
307
- return found.first
308
- end
309
-
310
- # filename for ascp with optional extension (Windows)
311
- def ascp_filename
312
- return 'ascp' + Environment.exe_extension
313
281
  end
314
282
 
315
283
  def transferd_filepath
316
- return File.join(sdk_folder, 'asperatransferd' + Environment.exe_extension)
317
- end
318
-
319
- # @return product folders depending on OS fields
320
- # :expected M app name is taken from the manifest if present, else defaults to this value
321
- # :app_root M main folder for the application
322
- # :log_root O location of log files (Linux uses syslog)
323
- # :run_root O only for Connect Client, location of http port file
324
- # :sub_bin O subfolder with executables, default : bin
325
- def product_locations
326
- case Aspera::Environment.os
327
- when Aspera::Environment::OS_WINDOWS; return [{
328
- expected: PRODUCT_CONNECT,
329
- app_root: File.join(ENV['LOCALAPPDATA'], 'Programs', 'Aspera', 'Aspera Connect'),
330
- log_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect', 'var', 'log'),
331
- run_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect')
332
- }, {
333
- expected: PRODUCT_CLI_V1,
334
- app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
335
- log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
336
- }, {
337
- expected: PRODUCT_ENTSRV,
338
- app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
339
- log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
340
- }]
341
- when Aspera::Environment::OS_X; return [{
342
- expected: PRODUCT_CONNECT,
343
- app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
344
- log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
345
- run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
346
- sub_bin: File.join('Contents', 'Resources')
347
- }, {
348
- expected: PRODUCT_CONNECT,
349
- app_root: File.join('', 'Applications', 'Aspera Connect.app'),
350
- log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
351
- run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
352
- sub_bin: File.join('Contents', 'Resources')
353
- }, {
354
- expected: PRODUCT_CLI_V1,
355
- app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
356
- log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
357
- }, {
358
- expected: PRODUCT_ENTSRV,
359
- app_root: File.join('', 'Library', 'Aspera'),
360
- log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
361
- }, {
362
- expected: PRODUCT_DRIVE,
363
- app_root: File.join('', 'Applications', 'Aspera Drive.app'),
364
- log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
365
- sub_bin: File.join('Contents', 'Resources')
366
- }]
367
- else; return [{ # other: Linux and Unix family
368
- expected: PRODUCT_CONNECT,
369
- app_root: File.join(Dir.home, '.aspera', 'connect'),
370
- run_root: File.join(Dir.home, '.aspera', 'connect')
371
- }, {
372
- expected: PRODUCT_CLI_V1,
373
- app_root: File.join(Dir.home, '.aspera', 'cli')
374
- }, {
375
- expected: PRODUCT_ENTSRV,
376
- app_root: File.join('', 'opt', 'aspera')
377
- }]
378
- end
379
- end
380
-
381
- # @return a standard bypass key
382
- # @param type rsa or dsa
383
- # @param id in repository 1 for dsa, 2 for rsa
384
- def get_key(type, id)
385
- # generate PEM from DER
386
- OpenSSL::PKey.const_get(type.upcase).new(DataRepository.instance.data(id)).to_pem
284
+ return File.join(sdk_folder, 'asperatransferd' + Environment.exe_extension) # cspell:disable-line
387
285
  end
388
286
  end # Installation
389
287
  end
@@ -0,0 +1,249 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aspera
4
+ module Fasp
5
+ # executes a local "ascp", connects mgt port, equivalent of "Fasp Manager"
6
+ class Management
7
+ # cspell: disable
8
+ OPERATIONS = %w[
9
+ NOP
10
+ START
11
+ QUERY
12
+ QUERYRSP
13
+ STATS
14
+ STOP
15
+ ERROR
16
+ CANCEL
17
+ DONE
18
+ RATE
19
+ FILEERROR
20
+ SESSION
21
+ NOTIFICATION
22
+ INIT
23
+ VLINK
24
+ NOTIFICATION
25
+ PUT
26
+ WRITE
27
+ CLOSE
28
+ SKIP
29
+ ARGSTOP
30
+ ]
31
+
32
+ PARAMETERS = %w[
33
+ Type
34
+ File
35
+ Size
36
+ Written
37
+ Bytescont
38
+ Rate
39
+ Loss
40
+ Query
41
+ Code
42
+ Password
43
+ Progress
44
+ Remaining
45
+ Elapsed
46
+ RexInfo
47
+ BlockInfo
48
+ DiskInfo
49
+ RateInfo
50
+ MinRate
51
+ Description
52
+ Elapsedusec
53
+ ServiceLevel
54
+ SessionId
55
+ User
56
+ Host
57
+ Encryption
58
+ Adaptive
59
+ Direction
60
+ Remote
61
+ Port
62
+ UserStr
63
+ CommandId
64
+ StartByte
65
+ EndByte
66
+ Token
67
+ Cookie
68
+ QueryResponse
69
+ Source
70
+ Destination
71
+ BWMeasurement
72
+ BWInfo
73
+ PMTU
74
+ TransferBytes
75
+ FileBytes
76
+ Operation
77
+ Delay
78
+ PreTransferFiles
79
+ PreTransferDirs
80
+ PreTransferSpecial
81
+ PreTransferFailed
82
+ PartialPreTransferBytes
83
+ PreTransferBytes
84
+ Priority
85
+ Transport
86
+ VlinkID
87
+ VlinkOn
88
+ VlinkCapIn
89
+ VlinkCapOut
90
+ ManifestFile
91
+ ArgScansAttempted
92
+ ArgScansCompleted
93
+ PathScansAttempted
94
+ PathScansFailed
95
+ PathScansIrregular
96
+ PathScansExcluded
97
+ DirScansCompleted
98
+ FileScansCompleted
99
+ DirCreatesAttempted
100
+ DirCreatesFailed
101
+ DirCreatesPassed
102
+ TransfersAttempted
103
+ TransfersFailed
104
+ TransfersPassed
105
+ TransfersSkipped
106
+ FallbackProtocol
107
+ RetryTimeout
108
+ PreTransferExcluded
109
+ XferId
110
+ XferRetry
111
+ Tags
112
+ FaspFileArgIndex
113
+ ArgTransfersStatus
114
+ ArgTransfersAttempted
115
+ ArgTransfersFailed
116
+ ArgTransfersPassed
117
+ ArgTransfersSkipped
118
+ FaspFileID
119
+ RateCap
120
+ MinRateCap
121
+ PolicyCap
122
+ PriorityCap
123
+ RateLock
124
+ MinRateLock
125
+ PolicyLock
126
+ FileChecksum
127
+ ServerHostname
128
+ ServerNodeId
129
+ ClientNodeId
130
+ ServerClusterId
131
+ ClientClusterId
132
+ FileChecksumType
133
+ ServerDocroot
134
+ ClientDocroot
135
+ NodeUser
136
+ ClientUser
137
+ SourcePrefix
138
+ RemoteAddress
139
+ TCPPort
140
+ Cipher
141
+ ResumePolicy
142
+ CreatePolicy
143
+ ManifestPolicy
144
+ Precalc
145
+ OverwritePolicy
146
+ RTTAutocorrect
147
+ TimePolicy
148
+ ManifestPath
149
+ ManifestInprogress
150
+ PartialFiles
151
+ FilesEncrypt
152
+ FilesDecrypt
153
+ DatagramSize
154
+ PrepostCommand
155
+ XoptFlags
156
+ VLinkVersion
157
+ PeerVLinkVersion
158
+ VLinkLocalEnabled
159
+ VLinkLocalId
160
+ VLinkLocalCL
161
+ VLinkRemoteEnabled
162
+ VLinkRemoteId
163
+ VLRemoteCL
164
+ DSPipelineDepth
165
+ PeerDSPipelineDepth
166
+ LocalIP
167
+ SourceBase
168
+ ReadBlockSize
169
+ WriteBlockSize
170
+ ClusterNumNodes
171
+ ClusterNodeId
172
+ MoveRange
173
+ MoveRangeLow
174
+ MoveRangeHigh
175
+ Keepalive
176
+ TestLogin
177
+ UseProxy
178
+ ProxyIP
179
+ RateControlAlgorithm
180
+ ClientMacAddress
181
+ Offset
182
+ ChunkSize
183
+ PostTransferValidation
184
+ OverwritePolicyCap
185
+ ExtraCreatePolicy]
186
+ # Management port start message
187
+ MGT_HEADER = 'FASPMGR 2'
188
+ # empty line is separator to end event information
189
+ MGT_FRAME_SEPARATOR = ''
190
+ # fields description for JSON generation
191
+ # spellchecker: disable
192
+ INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
193
+ DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
194
+ ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
195
+ ArgScansCompleted PathScansAttempted FileScansCompleted TransfersAttempted TransfersPassed Delay].freeze
196
+ BOOLEAN_FIELDS = %w[Encryption Remote RateLock MinRateLock PolicyLock FilesEncrypt FilesDecrypt VLinkLocalEnabled VLinkRemoteEnabled
197
+ MoveRange Keepalive TestLogin UseProxy Precalc RTTAutocorrect].freeze
198
+ BOOLEAN_TRUE = 'Yes'
199
+ # cspell: enable
200
+
201
+ class << self
202
+ # translates mgt port event into (enhanced) typed event
203
+ def enhanced_event_format(event)
204
+ return event.keys.each_with_object({}) do |e, h|
205
+ # capital_to_snake_case
206
+ new_name = e
207
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
208
+ .gsub(/([a-z\d])(usec)$/, '\1_\2')
209
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
210
+ .downcase
211
+ value = event[e]
212
+ value = value.to_i if INTEGER_FIELDS.include?(e)
213
+ value = value.eql?(BOOLEAN_TRUE) if BOOLEAN_FIELDS.include?(e)
214
+ h[new_name] = value
215
+ end
216
+ end
217
+ end # class << self
218
+
219
+ def initialize
220
+ # current event being parsed line by line
221
+ @event_build = nil
222
+ # last fully built event
223
+ @last_event = nil
224
+ end
225
+ attr_reader :last_event
226
+
227
+ def process_line(line)
228
+ # Log.log.debug{"line=[#{line}]"}
229
+ case line
230
+ when MGT_HEADER
231
+ # begin event
232
+ @event_build = {}
233
+ when /^([^:]+): (.*)$/
234
+ raise 'mgt port: unexpected line: data without header' if @event_build.nil?
235
+ # event field
236
+ @event_build[Regexp.last_match(1)] = Regexp.last_match(2)
237
+ when MGT_FRAME_SEPARATOR
238
+ raise 'mgt port: unexpected line: end frame without header' if @event_build.nil?
239
+ @last_event = @event_build
240
+ @event_build = nil
241
+ return @last_event
242
+ else
243
+ raise "mgt port: unexpected line: [#{line}]"
244
+ end # case
245
+ return nil
246
+ end
247
+ end
248
+ end
249
+ end