aspera-cli 4.24.2 → 4.25.0.pre2
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/CHANGELOG.md +1067 -758
- data/CONTRIBUTING.md +93 -120
- data/README.md +817 -510
- data/lib/aspera/agent/direct.rb +14 -12
- data/lib/aspera/agent/transferd.rb +4 -4
- data/lib/aspera/api/aoc.rb +71 -43
- data/lib/aspera/api/cos_node.rb +3 -2
- data/lib/aspera/api/faspex.rb +6 -5
- data/lib/aspera/api/node.rb +10 -12
- data/lib/aspera/ascmd.rb +1 -2
- data/lib/aspera/ascp/installation.rb +55 -41
- data/lib/aspera/ascp/management.rb +9 -5
- data/lib/aspera/assert.rb +28 -6
- data/lib/aspera/cli/error.rb +4 -2
- data/lib/aspera/cli/extended_value.rb +94 -62
- data/lib/aspera/cli/formatter.rb +55 -22
- data/lib/aspera/cli/main.rb +21 -14
- data/lib/aspera/cli/manager.rb +349 -248
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +94 -51
- data/lib/aspera/cli/plugins/base.rb +62 -49
- data/lib/aspera/cli/plugins/config.rb +85 -96
- data/lib/aspera/cli/plugins/console.rb +15 -9
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +34 -27
- data/lib/aspera/cli/plugins/faspex5.rb +47 -44
- data/lib/aspera/cli/plugins/faspio.rb +7 -6
- data/lib/aspera/cli/plugins/httpgw.rb +3 -2
- data/lib/aspera/cli/plugins/node.rb +132 -120
- data/lib/aspera/cli/plugins/oauth.rb +1 -1
- data/lib/aspera/cli/plugins/orchestrator.rb +116 -33
- data/lib/aspera/cli/plugins/preview.rb +26 -46
- data/lib/aspera/cli/plugins/server.rb +9 -10
- data/lib/aspera/cli/plugins/shares.rb +77 -43
- data/lib/aspera/cli/sync_actions.rb +49 -38
- data/lib/aspera/cli/transfer_agent.rb +16 -34
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +8 -5
- data/lib/aspera/command_line_builder.rb +20 -17
- data/lib/aspera/coverage.rb +6 -2
- data/lib/aspera/environment.rb +71 -84
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/keychain/factory.rb +1 -2
- data/lib/aspera/keychain/macos_security.rb +2 -2
- data/lib/aspera/log.rb +2 -1
- data/lib/aspera/markdown.rb +31 -0
- data/lib/aspera/nagios.rb +6 -5
- data/lib/aspera/oauth/base.rb +17 -27
- data/lib/aspera/oauth/factory.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -1
- data/lib/aspera/preview/file_types.rb +23 -37
- data/lib/aspera/preview/terminal.rb +95 -29
- data/lib/aspera/preview/utils.rb +6 -5
- data/lib/aspera/products/connect.rb +3 -3
- data/lib/aspera/rest.rb +51 -39
- data/lib/aspera/rest_error_analyzer.rb +4 -4
- data/lib/aspera/ssh.rb +5 -2
- data/lib/aspera/ssl.rb +41 -0
- data/lib/aspera/sync/conf.schema.yaml +182 -34
- data/lib/aspera/sync/database.rb +2 -1
- data/lib/aspera/sync/operations.rb +128 -72
- data/lib/aspera/transfer/parameters.rb +3 -4
- data/lib/aspera/transfer/spec.rb +2 -3
- data/lib/aspera/transfer/spec.schema.yaml +49 -19
- data/lib/aspera/transfer/spec_doc.rb +14 -14
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/transferd_pb.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +33 -6
- metadata.gz.sig +0 -0
|
@@ -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,7 +30,9 @@ 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'
|
|
35
|
+
require 'digest'
|
|
33
36
|
require 'open3'
|
|
34
37
|
require 'date'
|
|
35
38
|
require 'erb'
|
|
@@ -39,6 +42,8 @@ module Aspera
|
|
|
39
42
|
module Plugins
|
|
40
43
|
# Manage the CLI config file
|
|
41
44
|
class Config < Base
|
|
45
|
+
include SyncActions
|
|
46
|
+
|
|
42
47
|
class << self
|
|
43
48
|
# Folder containing plugins in the gem's main folder
|
|
44
49
|
def gem_plugins_folder
|
|
@@ -76,7 +81,7 @@ module Aspera
|
|
|
76
81
|
# We need to defer parsing of options until we have the config file, so we can use @extend with @preset
|
|
77
82
|
super
|
|
78
83
|
@use_plugin_defaults = true
|
|
79
|
-
@config_presets =
|
|
84
|
+
@config_presets = {}
|
|
80
85
|
@config_checksum_on_disk = nil
|
|
81
86
|
@vault_instance = nil
|
|
82
87
|
@pac_exec = nil
|
|
@@ -89,7 +94,7 @@ module Aspera
|
|
|
89
94
|
@option_cache_tokens = true
|
|
90
95
|
@main_folder = nil
|
|
91
96
|
@option_config_file = nil
|
|
92
|
-
# Store is used for ruby https
|
|
97
|
+
# Store is used for ruby https (OpenSSL::X509::Store)
|
|
93
98
|
@certificate_store = nil
|
|
94
99
|
# Paths are used for ascp
|
|
95
100
|
@certificate_paths = nil
|
|
@@ -98,7 +103,6 @@ module Aspera
|
|
|
98
103
|
options.declare(
|
|
99
104
|
:home, 'Home folder for tool',
|
|
100
105
|
handler: {o: self, m: :main_folder},
|
|
101
|
-
types: String,
|
|
102
106
|
default: self.class.default_app_main_folder(app_name: Info::CMD_NAME)
|
|
103
107
|
)
|
|
104
108
|
options.parse_options!
|
|
@@ -118,65 +122,49 @@ module Aspera
|
|
|
118
122
|
# Read config file (set @config_presets)
|
|
119
123
|
read_config_file
|
|
120
124
|
# Add preset handler (needed for smtp)
|
|
121
|
-
ExtendedValue.instance.
|
|
122
|
-
ExtendedValue.instance.
|
|
125
|
+
ExtendedValue.instance.on(EXTEND_PRESET){ |v| preset_by_name(v)}
|
|
126
|
+
ExtendedValue.instance.on(EXTEND_VAULT){ |v| vault_value(v)}
|
|
127
|
+
ExtendedValue.instance.on(EXTEND_ARGS){ |v| options.args_as_extended(v)}
|
|
123
128
|
# Load defaults before it can be overridden
|
|
124
129
|
add_plugin_default_preset(CONF_GLOBAL_SYM)
|
|
125
130
|
# Vault options
|
|
126
131
|
options.declare(:secret, 'Secret for access keys')
|
|
127
|
-
options.declare(:vault, 'Vault for secrets',
|
|
132
|
+
options.declare(:vault, 'Vault for secrets', allowed: Hash)
|
|
128
133
|
options.declare(:vault_password, 'Vault password')
|
|
129
134
|
options.parse_options!
|
|
130
135
|
# Declare generic plugin options only after handlers are declared
|
|
131
136
|
Base.declare_options(options)
|
|
132
137
|
# Configuration options
|
|
133
|
-
options.declare(:no_default, 'Do not load default configuration for plugin',
|
|
138
|
+
options.declare(:no_default, 'Do not load default configuration for plugin', allowed: Allowed::TYPES_NONE, short: 'N'){@use_plugin_defaults = false}
|
|
134
139
|
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)',
|
|
140
|
+
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
141
|
options.declare(:plugin_folder, 'Folder where to find additional plugins', handler: {o: self, m: :option_plugin_folder})
|
|
137
142
|
# Declare wizard options
|
|
138
143
|
@wizard = Wizard.new(self, @main_folder)
|
|
139
144
|
# 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
145
|
options.declare(:sdk_url, 'Ascp: URL to get Aspera Transfer Executables', default: SpecialValues::DEF)
|
|
143
|
-
options.
|
|
144
|
-
|
|
145
|
-
options.declare(:
|
|
146
|
+
options.parse_options!
|
|
147
|
+
set_sdk_dir
|
|
148
|
+
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}")
|
|
149
|
+
options.declare(:locations_url, 'Ascp: URL to get download locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
|
|
150
|
+
options.declare(:sdk_folder, 'Ascp: SDK installation folder path', handler: {o: Products::Transferd, m: :sdk_directory})
|
|
151
|
+
options.declare(:progress_bar, 'Display progress bar', allowed: Allowed::TYPES_BOOLEAN, default: Environment.terminal?)
|
|
146
152
|
# Email options
|
|
147
|
-
options.declare(:smtp, 'Email: SMTP configuration',
|
|
153
|
+
options.declare(:smtp, 'Email: SMTP configuration', allowed: Hash)
|
|
148
154
|
options.declare(:notify_to, 'Email: Recipient for notification of transfers')
|
|
149
155
|
options.declare(:notify_template, 'Email: ERB template for notification of transfers')
|
|
150
156
|
# HTTP options
|
|
151
|
-
options.declare(:insecure, 'HTTP/S: Do not validate any certificate',
|
|
152
|
-
options.declare(:ignore_certificate, 'HTTP/S: Do not validate certificate for these URLs',
|
|
153
|
-
options.declare(:warn_insecure, 'HTTP/S: Issue a warning if certificate is ignored',
|
|
154
|
-
options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates',
|
|
155
|
-
options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket',
|
|
156
|
-
options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials',
|
|
157
|
-
options.declare(:cache_tokens, 'Save and reuse OAuth tokens',
|
|
157
|
+
options.declare(:insecure, 'HTTP/S: Do not validate any certificate', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_insecure}, default: false)
|
|
158
|
+
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})
|
|
159
|
+
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)
|
|
160
|
+
options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates', allowed: Allowed::TYPES_STRING_ARRAY, handler: {o: self, m: :trusted_cert_locations})
|
|
161
|
+
options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket', allowed: Hash, handler: {o: self, m: :option_http_options}, default: {})
|
|
162
|
+
options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials', handler: {o: self, m: :option_http_proxy})
|
|
163
|
+
options.declare(:cache_tokens, 'Save and reuse OAuth tokens', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_cache_tokens})
|
|
158
164
|
options.declare(:fpac, 'Proxy auto configuration script')
|
|
159
|
-
options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password',
|
|
165
|
+
options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password', allowed: [Array, NilClass])
|
|
160
166
|
options.parse_options!
|
|
161
167
|
@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
168
|
pac_script = options.get_option(:fpac)
|
|
181
169
|
# Create PAC executor
|
|
182
170
|
if !pac_script.nil?
|
|
@@ -200,27 +188,7 @@ module Aspera
|
|
|
200
188
|
RestParameters.instance.send(method, v)
|
|
201
189
|
elsif k.eql?('ssl_options')
|
|
202
190
|
keys_to_delete.push(k)
|
|
203
|
-
|
|
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
|
|
191
|
+
Aspera::SSL.option_list = v
|
|
224
192
|
elsif OAuth::Factory.instance.parameters.key?(k.to_sym)
|
|
225
193
|
keys_to_delete.push(k)
|
|
226
194
|
OAuth::Factory.instance.parameters[k.to_sym] = v
|
|
@@ -238,11 +206,31 @@ module Aspera
|
|
|
238
206
|
attr_accessor :main_folder, :option_cache_tokens, :option_insecure, :option_warn_insecure_cert, :option_http_options
|
|
239
207
|
attr_reader :option_ignore_cert_host_port, :progress_bar
|
|
240
208
|
|
|
209
|
+
def set_sdk_dir
|
|
210
|
+
# Check SDK folder is set or not, for compatibility, we check in two places
|
|
211
|
+
sdk_dir = Products::Transferd.sdk_directory rescue nil
|
|
212
|
+
if sdk_dir.nil?
|
|
213
|
+
@sdk_default_location = true
|
|
214
|
+
Log.log.debug('SDK folder is not set, checking default')
|
|
215
|
+
# New location
|
|
216
|
+
sdk_dir = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME)
|
|
217
|
+
Log.log.debug{"Checking: #{sdk_dir}"}
|
|
218
|
+
if !Dir.exist?(sdk_dir)
|
|
219
|
+
Log.log.debug{"No such folder: #{sdk_dir}"}
|
|
220
|
+
# Former location
|
|
221
|
+
former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), TRANSFERD_APP_NAME)
|
|
222
|
+
Log.log.debug{"Checking: #{former_sdk_folder}"}
|
|
223
|
+
sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
|
|
224
|
+
end
|
|
225
|
+
Log.log.debug{"Using: #{sdk_dir}"}
|
|
226
|
+
Products::Transferd.sdk_directory = sdk_dir
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
241
230
|
# Add files, folders or default locations to the certificate store
|
|
242
|
-
# @param path_list [Array<String>]
|
|
231
|
+
# @param path_list [Array<String>] List of paths to add
|
|
243
232
|
# @return the list of paths
|
|
244
233
|
def trusted_cert_locations=(path_list)
|
|
245
|
-
path_list = [path_list] unless path_list.is_a?(Array)
|
|
246
234
|
Aspera.assert_type(path_list, Array){'cert locations'}
|
|
247
235
|
if @certificate_store.nil?
|
|
248
236
|
Log.log.debug('Creating SSL Cert store')
|
|
@@ -273,6 +261,7 @@ module Aspera
|
|
|
273
261
|
pp = Dir.entries(p)
|
|
274
262
|
.map{ |e| File.realpath(File.join(p, e))}
|
|
275
263
|
.select{ |entry| File.file?(entry)}
|
|
264
|
+
.select{ |entry| CERT_EXT.any?{ |ext| entry.end_with?(ext)}}
|
|
276
265
|
end
|
|
277
266
|
@certificate_paths.concat(pp)
|
|
278
267
|
end
|
|
@@ -285,7 +274,7 @@ module Aspera
|
|
|
285
274
|
locations = @certificate_paths
|
|
286
275
|
if locations.nil?
|
|
287
276
|
# Compute default locations
|
|
288
|
-
self.trusted_cert_locations = SpecialValues::DEF
|
|
277
|
+
self.trusted_cert_locations = [SpecialValues::DEF]
|
|
289
278
|
locations = @certificate_paths
|
|
290
279
|
# Restore defaults
|
|
291
280
|
@certificate_paths = @certificate_store = nil
|
|
@@ -447,7 +436,7 @@ module Aspera
|
|
|
447
436
|
Log.log.warn{"keeping same value for #{preset}: #{param_name}: #{param_value}"}
|
|
448
437
|
return
|
|
449
438
|
end
|
|
450
|
-
Log.log.warn{"overwriting value: #{selected_preset[param_name]}"}
|
|
439
|
+
Log.log.warn{"overwriting value for #{param_name}: #{selected_preset[param_name]}"}
|
|
451
440
|
end
|
|
452
441
|
selected_preset[param_name] = param_value
|
|
453
442
|
formatter.display_status("Updated: #{preset}: #{param_name} <- #{param_value}")
|
|
@@ -479,21 +468,12 @@ module Aspera
|
|
|
479
468
|
raise Cli::Error, "Unknown config preset: #{include_path}" if current.nil?
|
|
480
469
|
end
|
|
481
470
|
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'
|
|
471
|
+
return ExtendedValue.instance.evaluate(current, context: 'preset')
|
|
491
472
|
end
|
|
492
473
|
|
|
493
474
|
def option_plugin_folder=(value)
|
|
494
|
-
|
|
495
|
-
value
|
|
496
|
-
Aspera.assert(value.all?(String)){'plugin folder'}
|
|
475
|
+
value = [value] unless value.is_a?(Array)
|
|
476
|
+
Aspera.assert_array_all(value, String){'plugin folder(s)'}
|
|
497
477
|
value.each{ |f| Plugins::Factory.instance.add_lookup_folder(f)}
|
|
498
478
|
end
|
|
499
479
|
|
|
@@ -514,8 +494,9 @@ module Aspera
|
|
|
514
494
|
end
|
|
515
495
|
end
|
|
516
496
|
|
|
497
|
+
# @return [Integer]
|
|
517
498
|
def config_checksum
|
|
518
|
-
JSON.generate(@config_presets)
|
|
499
|
+
Digest::SHA1.hexdigest(JSON.generate(@config_presets))
|
|
519
500
|
end
|
|
520
501
|
|
|
521
502
|
# Read config file and validate format
|
|
@@ -556,6 +537,7 @@ module Aspera
|
|
|
556
537
|
Log.log.warn{"#{file} -> #{@main_folder}"}
|
|
557
538
|
end
|
|
558
539
|
end
|
|
540
|
+
return
|
|
559
541
|
rescue Psych::SyntaxError => e
|
|
560
542
|
Log.log.error('YAML error in config file')
|
|
561
543
|
raise e
|
|
@@ -605,6 +587,15 @@ module Aspera
|
|
|
605
587
|
return Main.result_status("Opened: #{one_link['href']}")
|
|
606
588
|
end
|
|
607
589
|
end
|
|
590
|
+
Aspera.error_unreachable_line
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def install_transfer_sdk
|
|
594
|
+
# Reset to default location, if older default was used
|
|
595
|
+
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
596
|
+
asked_version = options.get_next_argument('transferd version', mandatory: false)
|
|
597
|
+
name, version, folder = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: asked_version)
|
|
598
|
+
return Main.result_status("Installed #{name} version #{version} in #{folder}")
|
|
608
599
|
end
|
|
609
600
|
|
|
610
601
|
def execute_action_ascp
|
|
@@ -624,7 +615,7 @@ module Aspera
|
|
|
624
615
|
# Collect info from ascp executable
|
|
625
616
|
data = Ascp::Installation.instance.ascp_info
|
|
626
617
|
# Add command line transfer spec
|
|
627
|
-
data['ts'] = transfer.
|
|
618
|
+
data['ts'] = transfer.user_transfer_spec
|
|
628
619
|
# Add keys
|
|
629
620
|
DataRepository::ELEMENTS.each_with_object(data){ |i, h| h[i.to_s] = DataRepository.instance.item(i)}
|
|
630
621
|
# Declare those as secrets
|
|
@@ -638,15 +629,11 @@ module Aspera
|
|
|
638
629
|
when :use
|
|
639
630
|
default_product = options.get_next_argument('product name')
|
|
640
631
|
Ascp::Installation.instance.use_ascp_from_product(default_product)
|
|
641
|
-
set_global_default(:ascp_path, Ascp::Installation
|
|
632
|
+
set_global_default(:ascp_path, "#{Ascp::Installation::USE_PRODUCT_PREFIX}#{default_product}")
|
|
642
633
|
return Main.result_nothing
|
|
643
634
|
end
|
|
644
635
|
when :install
|
|
645
|
-
|
|
646
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
647
|
-
version = options.get_next_argument('transferd version', mandatory: false)
|
|
648
|
-
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
649
|
-
return Main.result_status("Installed #{n} version #{v}")
|
|
636
|
+
return install_transfer_sdk
|
|
650
637
|
when :spec
|
|
651
638
|
fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true)
|
|
652
639
|
return Main.result_object_list(data, fields: fields.map(&:to_s))
|
|
@@ -671,11 +658,7 @@ module Aspera
|
|
|
671
658
|
command = options.get_next_command(%i[list install])
|
|
672
659
|
case command
|
|
673
660
|
when :install
|
|
674
|
-
|
|
675
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
676
|
-
version = options.get_next_argument('transferd version', mandatory: false)
|
|
677
|
-
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
678
|
-
return Main.result_status("Installed #{n} version #{v}")
|
|
661
|
+
return install_transfer_sdk
|
|
679
662
|
when :list
|
|
680
663
|
sdk_list = Ascp::Installation.instance.sdk_locations
|
|
681
664
|
return Main.result_object_list(
|
|
@@ -725,7 +708,7 @@ module Aspera
|
|
|
725
708
|
value = @config_presets[name][param_name]
|
|
726
709
|
raise "no such option in preset #{name} : #{param_name}" if value.nil?
|
|
727
710
|
case value
|
|
728
|
-
when Numeric, String then return Main.result_text(ExtendedValue.instance.evaluate(value.to_s))
|
|
711
|
+
when Numeric, String then return Main.result_text(ExtendedValue.instance.evaluate(value.to_s, context: 'preset'))
|
|
729
712
|
end
|
|
730
713
|
return Main.result_single_object(value)
|
|
731
714
|
when :unset
|
|
@@ -754,7 +737,7 @@ module Aspera
|
|
|
754
737
|
options.ask_missing_mandatory = true
|
|
755
738
|
@config_presets[name] ||= {}
|
|
756
739
|
options.get_next_argument('option names', multiple: true).each do |option_name|
|
|
757
|
-
option_value = options.get_interactive(option_name,
|
|
740
|
+
option_value = options.get_interactive(option_name, check_option: true)
|
|
758
741
|
@config_presets[name][option_name] = option_value
|
|
759
742
|
end
|
|
760
743
|
return Main.result_status("Updated: #{name}")
|
|
@@ -889,7 +872,7 @@ module Aspera
|
|
|
889
872
|
result.push({
|
|
890
873
|
plugin: name,
|
|
891
874
|
detect: Formatter.tick(plugin_class.respond_to?(:detect)),
|
|
892
|
-
wizard: Formatter.tick(plugin_class.
|
|
875
|
+
wizard: Formatter.tick(plugin_class.method_defined?(:wizard)),
|
|
893
876
|
path: Plugins::Factory.instance.plugin_source(name)
|
|
894
877
|
})
|
|
895
878
|
end
|
|
@@ -930,10 +913,14 @@ module Aspera
|
|
|
930
913
|
when :ascp
|
|
931
914
|
execute_action_ascp
|
|
932
915
|
when :sync
|
|
933
|
-
case options.get_next_command(%i[spec])
|
|
916
|
+
case options.get_next_command(%i[spec admin translate])
|
|
934
917
|
when :spec
|
|
935
918
|
fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true, agent_columns: false, schema: Sync::Operations::CONF_SCHEMA)
|
|
936
919
|
return Main.result_object_list(data, fields: fields.map(&:to_s))
|
|
920
|
+
when :admin
|
|
921
|
+
return execute_sync_admin
|
|
922
|
+
when :translate
|
|
923
|
+
return Main.result_single_object(Sync::Operations.args_to_conf(options.get_next_argument('async arguments', multiple: true)))
|
|
937
924
|
else Aspera.error_unreachable_line
|
|
938
925
|
end
|
|
939
926
|
when :transferd
|
|
@@ -1227,6 +1214,7 @@ module Aspera
|
|
|
1227
1214
|
# Special extended values
|
|
1228
1215
|
EXTEND_PRESET = :preset
|
|
1229
1216
|
EXTEND_VAULT = :vault
|
|
1217
|
+
EXTEND_ARGS = :''
|
|
1230
1218
|
PRESET_DIG_SEPARATOR = '.'
|
|
1231
1219
|
DEFAULT_CHECK_NEW_VERSION_DAYS = 7
|
|
1232
1220
|
COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
|
|
@@ -1235,7 +1223,7 @@ module Aspera
|
|
|
1235
1223
|
SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
|
|
1236
1224
|
CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
|
|
1237
1225
|
SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
|
|
1238
|
-
|
|
1226
|
+
CERT_EXT = %w[crt cer pem der].freeze
|
|
1239
1227
|
private_constant :ASPERA_HOME_FOLDER_NAME,
|
|
1240
1228
|
:DEFAULT_CONFIG_FILENAME,
|
|
1241
1229
|
:CONF_PRESET_CONFIG,
|
|
@@ -1260,7 +1248,8 @@ module Aspera
|
|
|
1260
1248
|
:TRANSFERD_APP_NAME,
|
|
1261
1249
|
:GLOBAL_DEFAULT_KEYWORD,
|
|
1262
1250
|
:CONF_GLOBAL_SYM,
|
|
1263
|
-
:GEM_CHECK_DATE_FMT
|
|
1251
|
+
:GEM_CHECK_DATE_FMT,
|
|
1252
|
+
:CERT_EXT
|
|
1264
1253
|
end
|
|
1265
1254
|
end
|
|
1266
1255
|
end
|
|
@@ -13,6 +13,7 @@ module Aspera
|
|
|
13
13
|
private_constant :STANDARD_PATH, :DEFAULT_FILTER_AGE_SECONDS, :EXPR_RE
|
|
14
14
|
|
|
15
15
|
class << self
|
|
16
|
+
# @return [Hash,NilClass]
|
|
16
17
|
def detect(address_or_url)
|
|
17
18
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
18
19
|
urls = [address_or_url]
|
|
@@ -22,17 +23,18 @@ module Aspera
|
|
|
22
23
|
next unless base_url.start_with?('https://')
|
|
23
24
|
api = Rest.new(base_url: base_url, redirect_max: 2)
|
|
24
25
|
test_endpoint = 'login'
|
|
25
|
-
|
|
26
|
+
http = api.call(
|
|
26
27
|
operation: 'GET',
|
|
27
28
|
subpath: test_endpoint,
|
|
28
|
-
query: {local: true}
|
|
29
|
+
query: {local: true},
|
|
30
|
+
ret: :resp
|
|
29
31
|
)
|
|
30
|
-
next unless
|
|
32
|
+
next unless http.body.include?('Aspera Console')
|
|
31
33
|
version = 'unknown'
|
|
32
|
-
if (m =
|
|
34
|
+
if (m = http.body.match(/\(v([1-9]\..*)\)/))
|
|
33
35
|
version = m[1]
|
|
34
36
|
end
|
|
35
|
-
url =
|
|
37
|
+
url = http.uri.to_s
|
|
36
38
|
return {
|
|
37
39
|
version: version,
|
|
38
40
|
url: url[0..url.index(test_endpoint) - 2]
|
|
@@ -44,10 +46,14 @@ module Aspera
|
|
|
44
46
|
raise error if error
|
|
45
47
|
return
|
|
46
48
|
end
|
|
49
|
+
|
|
50
|
+
def time_to_string(time)
|
|
51
|
+
return time.strftime('%Y-%m-%d %H:%M:%S')
|
|
52
|
+
end
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
# @param wizard [Wizard] The wizard object
|
|
50
|
-
# @param app_url [
|
|
56
|
+
# @param app_url [String] Tested URL
|
|
51
57
|
# @return [Hash] :preset_value, :test_args
|
|
52
58
|
def wizard(wizard, app_url)
|
|
53
59
|
return {
|
|
@@ -91,7 +97,7 @@ module Aspera
|
|
|
91
97
|
rescue StandardError => e
|
|
92
98
|
nagios.add_critical('console api', e.to_s)
|
|
93
99
|
end
|
|
94
|
-
|
|
100
|
+
Main.result_object_list(nagios.status_list)
|
|
95
101
|
when :transfer
|
|
96
102
|
command = options.get_next_command(%i[current smart])
|
|
97
103
|
case command
|
|
@@ -113,8 +119,8 @@ module Aspera
|
|
|
113
119
|
query = query_read_delete(default: {})
|
|
114
120
|
if query['from'].nil? && query['to'].nil?
|
|
115
121
|
time_now = Time.now
|
|
116
|
-
query['from'] =
|
|
117
|
-
query['to'] =
|
|
122
|
+
query['from'] = self.class.time_to_string(time_now - DEFAULT_FILTER_AGE_SECONDS)
|
|
123
|
+
query['to'] = self.class.time_to_string(time_now)
|
|
118
124
|
end
|
|
119
125
|
if (filter = query.delete('filter'))
|
|
120
126
|
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',
|
|
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!
|
|
@@ -39,6 +39,7 @@ module Aspera
|
|
|
39
39
|
private_constant :KEY_NODE, :KEY_PATH, :PACKAGE_MATCH_FIELD, :ATOM_MAILBOXES, :ATOM_PARAMS, :ATOM_EXT_PARAMS, :PUB_LINK_EXTERNAL_MATCH, :HEADER_FASPEX_VERSION
|
|
40
40
|
|
|
41
41
|
class << self
|
|
42
|
+
# @return [Hash,NilClass]
|
|
42
43
|
def detect(address_or_url)
|
|
43
44
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
44
45
|
urls = [address_or_url]
|
|
@@ -47,22 +48,23 @@ module Aspera
|
|
|
47
48
|
urls.each do |base_url|
|
|
48
49
|
next unless base_url.start_with?('https://')
|
|
49
50
|
api = Rest.new(base_url: base_url, redirect_max: 1)
|
|
50
|
-
|
|
51
|
+
http = api.call(
|
|
51
52
|
operation: 'POST',
|
|
52
53
|
headers: {
|
|
53
54
|
'Content-type' => Rest::MIME_TEXT,
|
|
54
55
|
'Accept' => 'application/xrds+xml'
|
|
55
|
-
}
|
|
56
|
+
},
|
|
57
|
+
ret: :resp
|
|
56
58
|
)
|
|
57
59
|
# 4.x
|
|
58
|
-
next unless
|
|
59
|
-
res_s = XmlSimple.xml_in(
|
|
60
|
-
Log.log.debug{"version: #{
|
|
60
|
+
next unless http.body.start_with?('<?xml')
|
|
61
|
+
res_s = XmlSimple.xml_in(http.body, {'ForceArray' => false})
|
|
62
|
+
Log.log.debug{"version: #{http[HEADER_FASPEX_VERSION]}"}
|
|
61
63
|
version = res_s['XRD']['application']['version']
|
|
62
64
|
# take redirect if any
|
|
63
65
|
return {
|
|
64
66
|
version: version,
|
|
65
|
-
url:
|
|
67
|
+
url: http.uri.to_s
|
|
66
68
|
}
|
|
67
69
|
rescue StandardError => e
|
|
68
70
|
error = e
|
|
@@ -107,7 +109,7 @@ module Aspera
|
|
|
107
109
|
end
|
|
108
110
|
|
|
109
111
|
# @param wizard [Wizard] The wizard object
|
|
110
|
-
# @param app_url [
|
|
112
|
+
# @param app_url [String] Tested URL
|
|
111
113
|
# @return [Hash] :preset_value, :test_args
|
|
112
114
|
def wizard(wizard, app_url)
|
|
113
115
|
return {
|
|
@@ -125,11 +127,11 @@ module Aspera
|
|
|
125
127
|
@api_v3 = nil
|
|
126
128
|
@api_v4 = nil
|
|
127
129
|
options.declare(:link, 'Public link for specific operation')
|
|
128
|
-
options.declare(:delivery_info, 'Package delivery information',
|
|
130
|
+
options.declare(:delivery_info, 'Package delivery information', allowed: Hash)
|
|
129
131
|
options.declare(:remote_source, 'Remote source for package send (id or %name:)')
|
|
130
132
|
options.declare(:storage, 'Faspex local storage definition (for browsing source)')
|
|
131
133
|
options.declare(:recipient, 'Use if recipient is a dropbox (with *)')
|
|
132
|
-
options.declare(:box, 'Package box',
|
|
134
|
+
options.declare(:box, 'Package box', allowed: ATOM_MAILBOXES, default: :inbox)
|
|
133
135
|
options.parse_options!
|
|
134
136
|
end
|
|
135
137
|
|
|
@@ -184,8 +186,9 @@ module Aspera
|
|
|
184
186
|
operation: 'GET',
|
|
185
187
|
subpath: "#{mailbox}.atom",
|
|
186
188
|
headers: {'Accept' => 'application/xml'},
|
|
187
|
-
query: mailbox_query
|
|
188
|
-
|
|
189
|
+
query: mailbox_query,
|
|
190
|
+
ret: :resp
|
|
191
|
+
).body
|
|
189
192
|
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
|
|
190
193
|
Log.dump(:box_data, box_data)
|
|
191
194
|
items = box_data.key?('entry') ? box_data['entry'] : []
|
|
@@ -251,8 +254,9 @@ module Aspera
|
|
|
251
254
|
subpath: create_path,
|
|
252
255
|
content_type: Rest::MIME_JSON,
|
|
253
256
|
body: package_create_params,
|
|
254
|
-
headers: {'Accept' => 'text/javascript'}
|
|
255
|
-
|
|
257
|
+
headers: {'Accept' => 'text/javascript'},
|
|
258
|
+
ret: :resp
|
|
259
|
+
).body
|
|
256
260
|
# get arguments of function call
|
|
257
261
|
package_creation_data.delete!("\n") # one line
|
|
258
262
|
package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
|
|
@@ -280,7 +284,7 @@ module Aspera
|
|
|
280
284
|
rescue StandardError => e
|
|
281
285
|
nagios.add_critical('faspex api', e.to_s)
|
|
282
286
|
end
|
|
283
|
-
|
|
287
|
+
Main.result_object_list(nagios.status_list)
|
|
284
288
|
when :package
|
|
285
289
|
command_pkg = options.get_next_command(%i[send receive list show], aliases: {recv: :receive})
|
|
286
290
|
case command_pkg
|
|
@@ -300,10 +304,11 @@ module Aspera
|
|
|
300
304
|
delivery_info['sources'] ||= [{'paths' => []}]
|
|
301
305
|
first_source = delivery_info['sources'].first
|
|
302
306
|
first_source['paths'].concat(transfer.source_list)
|
|
303
|
-
source_id =
|
|
304
|
-
|
|
307
|
+
source_id = options.get_option(:remote_source)
|
|
308
|
+
if source_id && (m = Base.percent_selector(source_id))
|
|
309
|
+
Aspera.assert(m[:field].eql?('name'), type: Cli::BadArgument){'only name as selector, or give id'}
|
|
305
310
|
source_list = api_v3.read('source_shares')['items']
|
|
306
|
-
self.class.get_source_id_by_name(value, source_list)
|
|
311
|
+
source_id = self.class.get_source_id_by_name(m[:value], source_list)
|
|
307
312
|
end
|
|
308
313
|
first_source['id'] = source_id.to_i unless source_id.nil?
|
|
309
314
|
pkg_created = api_v3.create('send', package_create_params)
|
|
@@ -362,7 +367,7 @@ module Aspera
|
|
|
362
367
|
when :inbox, :archive then'received'
|
|
363
368
|
when :sent then 'sent'
|
|
364
369
|
end
|
|
365
|
-
entry_xml = api_v3.call(operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'})
|
|
370
|
+
entry_xml = api_v3.call(operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'}, ret: :resp).body
|
|
366
371
|
package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
|
367
372
|
pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
|
368
373
|
end
|
|
@@ -373,17 +378,18 @@ module Aspera
|
|
|
373
378
|
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
379
|
# NOTE: unauthenticated API (authorization is in url params)
|
|
375
380
|
api_public_link = Rest.new(base_url: link_data[:base_url])
|
|
376
|
-
|
|
381
|
+
pkg_xml = api_public_link.call(
|
|
377
382
|
operation: 'GET',
|
|
378
383
|
subpath: link_data[:subpath],
|
|
379
384
|
headers: {'Accept' => 'application/xml'},
|
|
380
|
-
query: {passcode: link_data[:query]['passcode']}
|
|
381
|
-
|
|
382
|
-
|
|
385
|
+
query: {passcode: link_data[:query]['passcode']},
|
|
386
|
+
ret: :resp
|
|
387
|
+
).body
|
|
388
|
+
if !pkg_xml.start_with?('<?xml ')
|
|
383
389
|
Environment.instance.open_uri(link_url)
|
|
384
390
|
raise Cli::Error, 'Unexpected response: package not found ?'
|
|
385
391
|
end
|
|
386
|
-
package_entry = XmlSimple.xml_in(
|
|
392
|
+
package_entry = XmlSimple.xml_in(pkg_xml, {'ForceArray' => false})
|
|
387
393
|
Log.dump(:package_entry, package_entry)
|
|
388
394
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
|
389
395
|
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
|
@@ -412,8 +418,9 @@ module Aspera
|
|
|
412
418
|
query: {'direction' => 'down'},
|
|
413
419
|
content_type: Rest::MIME_TEXT,
|
|
414
420
|
body: xml_payload,
|
|
415
|
-
headers: {'Accept' => Rest::MIME_TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'}
|
|
416
|
-
|
|
421
|
+
headers: {'Accept' => Rest::MIME_TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
|
|
422
|
+
ret: :resp
|
|
423
|
+
).body
|
|
417
424
|
end
|
|
418
425
|
transfer_spec['direction'] = Transfer::Spec::DIRECTION_RECEIVE
|
|
419
426
|
statuses = transfer.start(transfer_spec)
|
|
@@ -455,7 +462,7 @@ module Aspera
|
|
|
455
462
|
when :info
|
|
456
463
|
return Main.result_single_object(source_info)
|
|
457
464
|
when :node
|
|
458
|
-
node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
|
|
465
|
+
node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE], context: 'faspex node')
|
|
459
466
|
Log.log.debug{"node=#{node_config}"}
|
|
460
467
|
Aspera.assert_type(node_config, Hash, type: Cli::Error){source_info[KEY_NODE]}
|
|
461
468
|
api_node = Rest.new(
|
|
@@ -519,7 +526,7 @@ module Aspera
|
|
|
519
526
|
end
|
|
520
527
|
return Main.result_object_list(users)
|
|
521
528
|
when :login_methods
|
|
522
|
-
login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'})
|
|
529
|
+
login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'}, ret: :resp).body
|
|
523
530
|
login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
|
|
524
531
|
return Main.result_object_list(login_methods['XRD']['Service'])
|
|
525
532
|
end
|