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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +29 -3
- data/CHANGELOG.md +300 -185
- data/CONTRIBUTING.md +74 -23
- data/README.md +2346 -1619
- data/bin/ascli +16 -25
- data/bin/asession +15 -15
- data/examples/dascli +2 -2
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +216 -150
- data/lib/aspera/ascmd.rb +25 -18
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +51 -16
- data/lib/aspera/cli/formatter.rb +276 -174
- data/lib/aspera/cli/hints.rb +81 -0
- data/lib/aspera/cli/main.rb +114 -147
- data/lib/aspera/cli/manager.rb +181 -136
- data/lib/aspera/cli/plugin.rb +82 -64
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +327 -331
- data/lib/aspera/cli/plugins/ats.rb +12 -8
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +575 -439
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +111 -92
- data/lib/aspera/cli/plugins/faspex5.rb +245 -182
- data/lib/aspera/cli/plugins/node.rb +239 -160
- data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
- data/lib/aspera/cli/plugins/preview.rb +54 -38
- data/lib/aspera/cli/plugins/server.rb +63 -20
- data/lib/aspera/cli/plugins/shares.rb +64 -38
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -67
- data/lib/aspera/cli/transfer_progress.rb +73 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +27 -22
- data/lib/aspera/cos_node.rb +6 -4
- data/lib/aspera/coverage.rb +22 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +21 -8
- data/lib/aspera/fasp/agent_alpha.rb +116 -0
- data/lib/aspera/fasp/agent_base.rb +40 -76
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +169 -179
- data/lib/aspera/fasp/agent_httpgw.rb +200 -195
- data/lib/aspera/fasp/agent_node.rb +43 -35
- data/lib/aspera/fasp/agent_trsdk.rb +124 -41
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +89 -191
- data/lib/aspera/fasp/management.rb +249 -0
- data/lib/aspera/fasp/parameters.rb +86 -47
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +7 -5
- data/lib/aspera/fasp/sync.rb +273 -0
- data/lib/aspera/fasp/transfer_spec.rb +10 -8
- data/lib/aspera/fasp/uri.rb +6 -6
- data/lib/aspera/faspex_gw.rb +11 -8
- data/lib/aspera/faspex_postproc.rb +8 -7
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/id_generator.rb +3 -1
- data/lib/aspera/json_rpc.rb +51 -0
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +15 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +61 -19
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node.rb +105 -21
- data/lib/aspera/node_simulator.rb +214 -0
- data/lib/aspera/oauth.rb +57 -36
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +5 -4
- data/lib/aspera/preview/file_types.rb +56 -268
- data/lib/aspera/preview/generator.rb +28 -39
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +36 -16
- data/lib/aspera/preview/utils.rb +23 -29
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +127 -80
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +16 -14
- data/lib/aspera/rest_errors_aspera.rb +39 -34
- data/lib/aspera/secret_hider.rb +18 -17
- data/lib/aspera/ssh.rb +10 -5
- data/lib/aspera/temp_file_manager.rb +11 -4
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +11 -5
- data.tar.gz.sig +0 -0
- metadata +108 -39
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
- data/lib/aspera/sync.rb +0 -213
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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)
|
|
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)
|
|
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
|
|
95
|
-
def
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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')
|
|
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, :
|
|
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
|
-
|
|
165
|
-
cert
|
|
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
|
-
|
|
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
|
|
204
|
-
return
|
|
150
|
+
def ssh_cert_uuid
|
|
151
|
+
return DataRepository.instance.item(:uuid)
|
|
205
152
|
end
|
|
206
153
|
|
|
207
|
-
def
|
|
208
|
-
return %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
|
-
|
|
271
|
-
|
|
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(
|
|
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,
|
|
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
|