aspera-cli 4.14.0 → 4.16.0

Sign up to get free protection for your applications and to get access to all the features.
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