aspera-cli 4.25.0.pre → 4.25.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/CHANGELOG.md +23 -17
- data/CONTRIBUTING.md +119 -47
- data/README.md +325 -239
- data/lib/aspera/agent/direct.rb +14 -12
- data/lib/aspera/agent/factory.rb +9 -6
- data/lib/aspera/agent/transferd.rb +8 -8
- data/lib/aspera/api/aoc.rb +33 -24
- data/lib/aspera/api/ats.rb +1 -0
- data/lib/aspera/api/faspex.rb +11 -5
- data/lib/aspera/ascmd.rb +1 -1
- data/lib/aspera/ascp/installation.rb +7 -7
- data/lib/aspera/ascp/management.rb +9 -5
- data/lib/aspera/assert.rb +3 -3
- data/lib/aspera/cli/extended_value.rb +10 -2
- data/lib/aspera/cli/formatter.rb +15 -62
- data/lib/aspera/cli/manager.rb +9 -43
- data/lib/aspera/cli/plugins/aoc.rb +71 -66
- data/lib/aspera/cli/plugins/ats.rb +30 -36
- data/lib/aspera/cli/plugins/base.rb +11 -6
- data/lib/aspera/cli/plugins/config.rb +21 -16
- data/lib/aspera/cli/plugins/console.rb +2 -1
- data/lib/aspera/cli/plugins/faspex.rb +7 -4
- data/lib/aspera/cli/plugins/faspex5.rb +12 -9
- data/lib/aspera/cli/plugins/faspio.rb +5 -2
- data/lib/aspera/cli/plugins/httpgw.rb +2 -1
- data/lib/aspera/cli/plugins/node.rb +10 -6
- data/lib/aspera/cli/plugins/oauth.rb +12 -11
- data/lib/aspera/cli/plugins/orchestrator.rb +2 -1
- data/lib/aspera/cli/plugins/preview.rb +2 -2
- data/lib/aspera/cli/plugins/server.rb +3 -2
- data/lib/aspera/cli/plugins/shares.rb +59 -20
- data/lib/aspera/cli/transfer_agent.rb +1 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +5 -5
- data/lib/aspera/coverage.rb +5 -1
- data/lib/aspera/dot_container.rb +108 -0
- data/lib/aspera/environment.rb +69 -89
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +7 -10
- data/lib/aspera/keychain/macos_security.rb +2 -2
- data/lib/aspera/log.rb +2 -1
- data/lib/aspera/oauth/base.rb +25 -38
- data/lib/aspera/oauth/factory.rb +5 -6
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +4 -3
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/preview/file_types.rb +1 -1
- data/lib/aspera/preview/terminal.rb +95 -29
- data/lib/aspera/preview/utils.rb +6 -5
- data/lib/aspera/rest.rb +5 -2
- data/lib/aspera/ssh.rb +6 -5
- data/lib/aspera/sync/conf.schema.yaml +2 -2
- data/lib/aspera/sync/operations.rb +3 -3
- data/lib/aspera/transfer/parameters.rb +6 -6
- data/lib/aspera/transfer/spec.schema.yaml +4 -4
- data/lib/aspera/transfer/spec_doc.rb +11 -21
- data/lib/aspera/uri_reader.rb +17 -3
- data.tar.gz.sig +0 -0
- metadata +17 -2
- metadata.gz.sig +0 -0
|
@@ -32,6 +32,7 @@ require 'aspera/assert'
|
|
|
32
32
|
require 'aspera/oauth'
|
|
33
33
|
require 'aspera/ssl'
|
|
34
34
|
require 'openssl'
|
|
35
|
+
require 'digest'
|
|
35
36
|
require 'open3'
|
|
36
37
|
require 'date'
|
|
37
38
|
require 'erb'
|
|
@@ -80,7 +81,7 @@ module Aspera
|
|
|
80
81
|
# We need to defer parsing of options until we have the config file, so we can use @extend with @preset
|
|
81
82
|
super
|
|
82
83
|
@use_plugin_defaults = true
|
|
83
|
-
@config_presets =
|
|
84
|
+
@config_presets = {}
|
|
84
85
|
@config_checksum_on_disk = nil
|
|
85
86
|
@vault_instance = nil
|
|
86
87
|
@pac_exec = nil
|
|
@@ -493,8 +494,9 @@ module Aspera
|
|
|
493
494
|
end
|
|
494
495
|
end
|
|
495
496
|
|
|
497
|
+
# @return [Integer]
|
|
496
498
|
def config_checksum
|
|
497
|
-
JSON.generate(@config_presets)
|
|
499
|
+
Digest::SHA1.hexdigest(JSON.generate(@config_presets))
|
|
498
500
|
end
|
|
499
501
|
|
|
500
502
|
# Read config file and validate format
|
|
@@ -535,6 +537,7 @@ module Aspera
|
|
|
535
537
|
Log.log.warn{"#{file} -> #{@main_folder}"}
|
|
536
538
|
end
|
|
537
539
|
end
|
|
540
|
+
return
|
|
538
541
|
rescue Psych::SyntaxError => e
|
|
539
542
|
Log.log.error('YAML error in config file')
|
|
540
543
|
raise e
|
|
@@ -584,6 +587,15 @@ module Aspera
|
|
|
584
587
|
return Main.result_status("Opened: #{one_link['href']}")
|
|
585
588
|
end
|
|
586
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}")
|
|
587
599
|
end
|
|
588
600
|
|
|
589
601
|
def execute_action_ascp
|
|
@@ -621,11 +633,7 @@ module Aspera
|
|
|
621
633
|
return Main.result_nothing
|
|
622
634
|
end
|
|
623
635
|
when :install
|
|
624
|
-
|
|
625
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
626
|
-
version = options.get_next_argument('transferd version', mandatory: false)
|
|
627
|
-
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
628
|
-
return Main.result_status("Installed #{n} version #{v}")
|
|
636
|
+
return install_transfer_sdk
|
|
629
637
|
when :spec
|
|
630
638
|
fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true)
|
|
631
639
|
return Main.result_object_list(data, fields: fields.map(&:to_s))
|
|
@@ -650,11 +658,7 @@ module Aspera
|
|
|
650
658
|
command = options.get_next_command(%i[list install])
|
|
651
659
|
case command
|
|
652
660
|
when :install
|
|
653
|
-
|
|
654
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
655
|
-
version = options.get_next_argument('transferd version', mandatory: false)
|
|
656
|
-
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
657
|
-
return Main.result_status("Installed #{n} version #{v}")
|
|
661
|
+
return install_transfer_sdk
|
|
658
662
|
when :list
|
|
659
663
|
sdk_list = Ascp::Installation.instance.sdk_locations
|
|
660
664
|
return Main.result_object_list(
|
|
@@ -1166,16 +1170,17 @@ module Aspera
|
|
|
1166
1170
|
end
|
|
1167
1171
|
|
|
1168
1172
|
# Lookup the corresponding secret for the given URL and usernames
|
|
1169
|
-
# @
|
|
1170
|
-
|
|
1173
|
+
# @param url [String] Server URL
|
|
1174
|
+
# @param username [String] Username
|
|
1175
|
+
# @return [String, nil] Secret if found
|
|
1176
|
+
def lookup_secret(url:, username:)
|
|
1171
1177
|
secret = options.get_option(:secret)
|
|
1172
|
-
if secret.
|
|
1178
|
+
if secret.eql?('PRESET')
|
|
1173
1179
|
conf = lookup_preset(url: url, username: username)
|
|
1174
1180
|
if conf.is_a?(Hash)
|
|
1175
1181
|
Log.log.debug{"Found preset #{conf} with URL and username"}
|
|
1176
1182
|
secret = conf['password']
|
|
1177
1183
|
end
|
|
1178
|
-
raise "Please provide secret for #{username} using option: secret or by setting a preset for #{username}@#{url}." if secret.nil? && mandatory
|
|
1179
1184
|
end
|
|
1180
1185
|
return secret
|
|
1181
1186
|
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]
|
|
@@ -52,7 +53,7 @@ module Aspera
|
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
# @param wizard [Wizard] The wizard object
|
|
55
|
-
# @param app_url [
|
|
56
|
+
# @param app_url [String] Tested URL
|
|
56
57
|
# @return [Hash] :preset_value, :test_args
|
|
57
58
|
def wizard(wizard, app_url)
|
|
58
59
|
return {
|
|
@@ -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]
|
|
@@ -108,7 +109,7 @@ module Aspera
|
|
|
108
109
|
end
|
|
109
110
|
|
|
110
111
|
# @param wizard [Wizard] The wizard object
|
|
111
|
-
# @param app_url [
|
|
112
|
+
# @param app_url [String] Tested URL
|
|
112
113
|
# @return [Hash] :preset_value, :test_args
|
|
113
114
|
def wizard(wizard, app_url)
|
|
114
115
|
return {
|
|
@@ -149,7 +150,9 @@ module Aspera
|
|
|
149
150
|
grant_method: :generic,
|
|
150
151
|
base_url: "#{faspex_api_base}/auth/oauth2",
|
|
151
152
|
auth: {type: :basic, username: options.get_option(:username, mandatory: true), password: options.get_option(:password, mandatory: true)},
|
|
152
|
-
|
|
153
|
+
params: {
|
|
154
|
+
scope: 'admin'
|
|
155
|
+
},
|
|
153
156
|
grant_type: 'password'
|
|
154
157
|
}
|
|
155
158
|
)
|
|
@@ -336,12 +339,12 @@ module Aspera
|
|
|
336
339
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
337
340
|
manager: persistency,
|
|
338
341
|
data: skip_ids_data,
|
|
339
|
-
id: IdGenerator.from_list(
|
|
342
|
+
id: IdGenerator.from_list(
|
|
340
343
|
'faspex_recv',
|
|
341
344
|
options.get_option(:url, mandatory: true),
|
|
342
345
|
options.get_option(:username, mandatory: true),
|
|
343
346
|
options.get_option(:box, mandatory: true).to_s
|
|
344
|
-
|
|
347
|
+
)
|
|
345
348
|
)
|
|
346
349
|
end
|
|
347
350
|
# get command line parameters
|
|
@@ -23,6 +23,7 @@ module Aspera
|
|
|
23
23
|
'Faspex'
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# @return [Hash,NilClass]
|
|
26
27
|
def detect(address_or_url)
|
|
27
28
|
# add scheme if missing
|
|
28
29
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
@@ -52,7 +53,7 @@ module Aspera
|
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
# @param wizard [Wizard] The wizard object
|
|
55
|
-
# @param app_url [
|
|
56
|
+
# @param app_url [String] Tested URL
|
|
56
57
|
# @return [Hash] :preset_value, :test_args
|
|
57
58
|
def wizard(wizard, app_url)
|
|
58
59
|
client_id = options.get_option(:client_id)
|
|
@@ -78,12 +79,14 @@ module Aspera
|
|
|
78
79
|
)
|
|
79
80
|
return {
|
|
80
81
|
preset_value: {
|
|
81
|
-
url:
|
|
82
|
-
username:
|
|
83
|
-
auth:
|
|
84
|
-
private_key:
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
url: app_url,
|
|
83
|
+
username: wiz_username,
|
|
84
|
+
auth: :jwt.to_s,
|
|
85
|
+
private_key: "@file:#{private_key_path}",
|
|
86
|
+
params: {
|
|
87
|
+
client_id: client_id,
|
|
88
|
+
client_secret: client_secret
|
|
89
|
+
}
|
|
87
90
|
},
|
|
88
91
|
test_args: 'user profile show'
|
|
89
92
|
}
|
|
@@ -197,12 +200,12 @@ module Aspera
|
|
|
197
200
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
198
201
|
manager: persistency,
|
|
199
202
|
data: [],
|
|
200
|
-
id: IdGenerator.from_list(
|
|
203
|
+
id: IdGenerator.from_list(
|
|
201
204
|
'faspex_recv',
|
|
202
205
|
options.get_option(:url, mandatory: true),
|
|
203
206
|
options.get_option(:username, mandatory: true),
|
|
204
207
|
options.get_option(:box, mandatory: true)
|
|
205
|
-
|
|
208
|
+
)
|
|
206
209
|
)
|
|
207
210
|
end
|
|
208
211
|
packages = []
|
|
@@ -13,6 +13,7 @@ module Aspera
|
|
|
13
13
|
'faspio Gateway'
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# @return [Hash,NilClass]
|
|
16
17
|
def detect(base_url)
|
|
17
18
|
api = Rest.new(base_url: base_url)
|
|
18
19
|
data, http = api.read('ping', ret: :both)
|
|
@@ -27,7 +28,7 @@ module Aspera
|
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
# @param wizard [Wizard] The wizard object
|
|
30
|
-
# @param app_url [
|
|
31
|
+
# @param app_url [String] Tested URL
|
|
31
32
|
# @return [Hash] :preset_value, :test_args
|
|
32
33
|
def wizard(wizard, app_url)
|
|
33
34
|
return {
|
|
@@ -63,7 +64,9 @@ module Aspera
|
|
|
63
64
|
type: :oauth2,
|
|
64
65
|
grant_method: :jwt,
|
|
65
66
|
base_url: "#{base_url}/auth",
|
|
66
|
-
|
|
67
|
+
params: {
|
|
68
|
+
client_id: app_client_id
|
|
69
|
+
},
|
|
67
70
|
use_query: true,
|
|
68
71
|
payload: {
|
|
69
72
|
iss: app_client_id, # issuer
|
|
@@ -14,6 +14,7 @@ module Aspera
|
|
|
14
14
|
'HTTP Gateway'
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
# @return [Hash,NilClass]
|
|
17
18
|
def detect(base_url)
|
|
18
19
|
api = Api::Httpgw.new(url: base_url)
|
|
19
20
|
api_info = api.info
|
|
@@ -26,7 +27,7 @@ module Aspera
|
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
# @param wizard [Wizard] The wizard object
|
|
29
|
-
# @param app_url [
|
|
30
|
+
# @param app_url [String] Tested URL
|
|
30
31
|
# @return [Hash] :preset_value, :test_args
|
|
31
32
|
def wizard(wizard, app_url)
|
|
32
33
|
return {
|
|
@@ -54,6 +54,7 @@ module Aspera
|
|
|
54
54
|
'HSTS Node API'
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# @return [Hash,NilClass]
|
|
57
58
|
def detect(address_or_url)
|
|
58
59
|
urls = if address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
59
60
|
[address_or_url]
|
|
@@ -414,10 +415,12 @@ module Aspera
|
|
|
414
415
|
root_file_id = options.get_option(:root_id)
|
|
415
416
|
if root_file_id.nil?
|
|
416
417
|
ak_info = @api_node.read("access_keys/#{access_key_id}")
|
|
418
|
+
ak_secret = config.lookup_secret(url: @api_node.base_url, username: ak_info['id'])
|
|
417
419
|
# change API credentials if different access key
|
|
418
420
|
if !access_key_id.eql?('self')
|
|
421
|
+
Aspera.assert(ak_secret, type: Cli::MissingArgument){"Please provide secret for #{ak_info['id']} using option: secret or by setting a preset for #{ak_info['id']}@#{@api_node.base_url}."}
|
|
419
422
|
@api_node.auth_params[:username] = ak_info['id']
|
|
420
|
-
@api_node.auth_params[:password] =
|
|
423
|
+
@api_node.auth_params[:password] = ak_secret
|
|
421
424
|
end
|
|
422
425
|
root_file_id = ak_info['root_file_id']
|
|
423
426
|
end
|
|
@@ -516,7 +519,8 @@ module Aspera
|
|
|
516
519
|
else Aspera.error_unreachable_line
|
|
517
520
|
end
|
|
518
521
|
return Main.result_single_object(result) if command_repo.eql?(:node_info)
|
|
519
|
-
|
|
522
|
+
Log.dump(:result, result)
|
|
523
|
+
raise BadArgument, "Cannot get bearer token if authenticating with secret (#{apifid[:api].auth_params[:type]})" unless apifid[:api].auth_params[:type].eql?(:oauth2)
|
|
520
524
|
Aspera.assert(OAuth::Factory.bearer_auth?(result[:password])){'Not using bearer token auth'}
|
|
521
525
|
return Main.result_text(result[:password])
|
|
522
526
|
when :browse
|
|
@@ -727,12 +731,12 @@ module Aspera
|
|
|
727
731
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
728
732
|
manager: persistency,
|
|
729
733
|
data: iteration_data,
|
|
730
|
-
id: IdGenerator.from_list(
|
|
734
|
+
id: IdGenerator.from_list(
|
|
731
735
|
'sync_files',
|
|
732
736
|
options.get_option(:url, mandatory: true),
|
|
733
737
|
options.get_option(:username, mandatory: true),
|
|
734
738
|
async_id
|
|
735
|
-
|
|
739
|
+
)
|
|
736
740
|
)
|
|
737
741
|
data.select!{ |l| l['fnid'].to_i > iteration_data.first} unless iteration_data.first.nil?
|
|
738
742
|
iteration_data[0] = data.last['fnid'].to_i unless data.empty?
|
|
@@ -872,11 +876,11 @@ module Aspera
|
|
|
872
876
|
iteration_persistency = PersistencyActionOnce.new(
|
|
873
877
|
manager: persistency,
|
|
874
878
|
data: [],
|
|
875
|
-
id: IdGenerator.from_list(
|
|
879
|
+
id: IdGenerator.from_list(
|
|
876
880
|
'node_transfers',
|
|
877
881
|
options.get_option(:url, mandatory: true),
|
|
878
882
|
options.get_option(:username, mandatory: true)
|
|
879
|
-
|
|
883
|
+
)
|
|
880
884
|
)
|
|
881
885
|
if transfer_filter.delete('reset')
|
|
882
886
|
iteration_persistency.data.clear
|
|
@@ -10,7 +10,7 @@ module Aspera
|
|
|
10
10
|
# OAuth methods supported
|
|
11
11
|
AUTH_TYPES = %i[web jwt boot].freeze
|
|
12
12
|
# Options used for authentication
|
|
13
|
-
AUTH_OPTIONS = %i[url auth client_id client_secret
|
|
13
|
+
AUTH_OPTIONS = %i[url auth client_id client_secret redirect_uri private_key passphrase username password].freeze
|
|
14
14
|
def initialize(**_)
|
|
15
15
|
super
|
|
16
16
|
options.declare(:auth, 'OAuth type of authentication', allowed: AUTH_TYPES, default: :jwt)
|
|
@@ -19,22 +19,23 @@ module Aspera
|
|
|
19
19
|
options.declare(:redirect_uri, 'OAuth (Web) redirect URI for web authentication')
|
|
20
20
|
options.declare(:private_key, 'OAuth (JWT) RSA private key PEM value (prefix file path with @file:)')
|
|
21
21
|
options.declare(:passphrase, 'OAuth (JWT) RSA private key passphrase')
|
|
22
|
-
options.declare(:scope, 'OAuth scope for API calls')
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
# Get
|
|
26
|
-
# Adds those not nil to the `
|
|
24
|
+
# Get command line options specified by `AUTH_OPTIONS` and `option.keys` (value is default).
|
|
25
|
+
# Adds those not nil to the `kwargs`.
|
|
27
26
|
# Instantiate the provided `klass` with those kwargs.
|
|
28
|
-
# `
|
|
29
|
-
# @param klass
|
|
30
|
-
# @param
|
|
31
|
-
# @param
|
|
32
|
-
|
|
27
|
+
# `option` can specify a default value (not `nil`)
|
|
28
|
+
# @param klass [Class] API object to create
|
|
29
|
+
# @param kwargs [Hash] The fixed keyword arguments for creation
|
|
30
|
+
# @param option [Hash] Additional options, key=symbol, value:default value or nil
|
|
31
|
+
# @return [Object] instance of `klass`
|
|
32
|
+
# @raise [Cli::Error] if a required option is missing
|
|
33
|
+
def new_with_options(klass, kwargs: {}, option: {})
|
|
33
34
|
klass.new(**
|
|
34
|
-
(AUTH_OPTIONS +
|
|
35
|
+
(AUTH_OPTIONS + option.keys).each_with_object(kwargs) do |i, m|
|
|
35
36
|
v = options.get_option(i)
|
|
36
37
|
m[i] = v unless v.nil?
|
|
37
|
-
m[i] =
|
|
38
|
+
m[i] = option[i] unless !m[i].nil? || option[i].nil?
|
|
38
39
|
end)
|
|
39
40
|
rescue ::ArgumentError => e
|
|
40
41
|
if (m = e.message.match(/missing keyword: :(.*)$/))
|
|
@@ -16,6 +16,7 @@ module Aspera
|
|
|
16
16
|
TEST_ENDPOINT = 'api/remote_node_ping'
|
|
17
17
|
private_constant :STANDARD_PATH, :TEST_ENDPOINT
|
|
18
18
|
class << self
|
|
19
|
+
# @return [Hash,NilClass]
|
|
19
20
|
def detect(address_or_url)
|
|
20
21
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
21
22
|
urls = [address_or_url]
|
|
@@ -41,7 +42,7 @@ module Aspera
|
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
# @param wizard [Wizard] The wizard object
|
|
44
|
-
# @param app_url [
|
|
45
|
+
# @param app_url [String] Tested URL
|
|
45
46
|
# @return [Hash] :preset_value, :test_args
|
|
46
47
|
def wizard(wizard, app_url)
|
|
47
48
|
return {
|
|
@@ -451,12 +451,12 @@ module Aspera
|
|
|
451
451
|
iteration_persistency = PersistencyActionOnce.new(
|
|
452
452
|
manager: persistency,
|
|
453
453
|
data: [],
|
|
454
|
-
id: IdGenerator.from_list(
|
|
454
|
+
id: IdGenerator.from_list(
|
|
455
455
|
'preview_iteration',
|
|
456
456
|
command.to_s,
|
|
457
457
|
options.get_option(:url, mandatory: true),
|
|
458
458
|
options.get_option(:username, mandatory: true)
|
|
459
|
-
|
|
459
|
+
)
|
|
460
460
|
)
|
|
461
461
|
end
|
|
462
462
|
# call processing method specified by command line command
|
|
@@ -32,7 +32,7 @@ module Aspera
|
|
|
32
32
|
|
|
33
33
|
class LocalExecutor
|
|
34
34
|
def execute(ascmd_path, input:)
|
|
35
|
-
return Environment.
|
|
35
|
+
return Environment.secure_execute(ascmd_path, mode: :capture, stdin_data: input, binmode: true, exception: false)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -41,6 +41,7 @@ module Aspera
|
|
|
41
41
|
'HSTS Fasp/SSH'
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# @return [Hash,NilClass]
|
|
44
45
|
def detect(address_or_url)
|
|
45
46
|
urls = if address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
46
47
|
[address_or_url]
|
|
@@ -70,7 +71,7 @@ module Aspera
|
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
# @param wizard [Wizard] The wizard object
|
|
73
|
-
# @param app_url [
|
|
74
|
+
# @param app_url [String] Tested URL
|
|
74
75
|
# @return [Hash] :preset_value, :test_args
|
|
75
76
|
def wizard(wizard, app_url)
|
|
76
77
|
return {
|
|
@@ -13,27 +13,62 @@ module Aspera
|
|
|
13
13
|
# path for node admin after base url
|
|
14
14
|
ADMIN_API_PATH = 'api/v1'
|
|
15
15
|
class << self
|
|
16
|
+
# Check various endpoints on Shares
|
|
17
|
+
# @return [Hash] with version, ping, api
|
|
18
|
+
def health_check(url)
|
|
19
|
+
result = {}
|
|
20
|
+
result[:version] =
|
|
21
|
+
begin
|
|
22
|
+
version = nil
|
|
23
|
+
login_page = Rest
|
|
24
|
+
.new(base_url: url, redirect_max: 2)
|
|
25
|
+
.read('', headers: {'Accept'=>'text/html'})
|
|
26
|
+
if (m = login_page.match(/\(v([0-9a-f\.]+)\)/))
|
|
27
|
+
version = m[1]
|
|
28
|
+
if (m = login_page.match(/Patch level ([0-9]+)/))
|
|
29
|
+
version = "#{result[:version]} #{m[0]}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
raise 'no version' if version.nil?
|
|
33
|
+
version
|
|
34
|
+
rescue => e
|
|
35
|
+
e
|
|
36
|
+
end
|
|
37
|
+
result[:ping] =
|
|
38
|
+
begin
|
|
39
|
+
Rest
|
|
40
|
+
.new(base_url: "#{url}/#{NODE_API_PATH}")
|
|
41
|
+
.read('ping', headers: {'Content-Type'=>'application/json'})
|
|
42
|
+
'ping ok'
|
|
43
|
+
rescue => e
|
|
44
|
+
e
|
|
45
|
+
end
|
|
46
|
+
result[:api] =
|
|
47
|
+
begin
|
|
48
|
+
resp = Rest.new(base_url: url, redirect_max: 1).read("#{NODE_API_PATH}/app", exception: false, ret: :resp)
|
|
49
|
+
# shall fail: shares requires auth, but we check error message
|
|
50
|
+
raise 'not found' unless resp.code.to_s.eql?('401') && resp.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
|
51
|
+
'available'
|
|
52
|
+
rescue => e
|
|
53
|
+
e
|
|
54
|
+
end
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Hash,NilClass]
|
|
16
59
|
def detect(address_or_url)
|
|
17
60
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
resp = api.read("#{NODE_API_PATH}/app", exception: false, ret: :resp)
|
|
21
|
-
# shall fail: shares requires auth, but we check error message
|
|
22
|
-
return unless resp.code.to_s.eql?('401') && resp.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
|
|
23
|
-
version = 'unknown'
|
|
24
|
-
http = api.read('login', headers: {'Accept'=>'*/*'}, ret: :resp)
|
|
25
|
-
if (m = http.body.match(/\(v(1\..*)\)/))
|
|
26
|
-
version = m[1]
|
|
27
|
-
end
|
|
61
|
+
health = health_check(address_or_url)
|
|
62
|
+
return unless health[:api].is_a?(String)
|
|
28
63
|
return {
|
|
29
|
-
version: version,
|
|
64
|
+
version: health[:version].is_a?(String) ? health[:version] : 'unknown',
|
|
30
65
|
url: address_or_url
|
|
31
66
|
}
|
|
32
67
|
end
|
|
33
68
|
end
|
|
34
69
|
|
|
35
70
|
# @param wizard [Wizard] The wizard object
|
|
36
|
-
# @param app_url [
|
|
71
|
+
# @param app_url [String] Tested URL
|
|
37
72
|
# @return [Hash] :preset_value, :test_args
|
|
38
73
|
def wizard(wizard, app_url)
|
|
39
74
|
return {
|
|
@@ -62,14 +97,18 @@ module Aspera
|
|
|
62
97
|
case command
|
|
63
98
|
when :health
|
|
64
99
|
nagios = Nagios.new
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
100
|
+
shares_url = options.get_option(:url, mandatory: true)
|
|
101
|
+
health = self.class.health_check(shares_url)
|
|
102
|
+
nagios.add_ok('version', health[:version]) if health[:version].is_a?(String)
|
|
103
|
+
if health[:ping].is_a?(String)
|
|
104
|
+
nagios.add_ok('ping', health[:ping])
|
|
105
|
+
else
|
|
106
|
+
nagios.add_critical('ping', health[:ping].to_s)
|
|
107
|
+
end
|
|
108
|
+
if health[:api].is_a?(String)
|
|
109
|
+
nagios.add_ok('API', health[:api])
|
|
110
|
+
else
|
|
111
|
+
nagios.add_critical('API', health[:api].to_s)
|
|
73
112
|
end
|
|
74
113
|
Main.result_object_list(nagios.status_list)
|
|
75
114
|
when :files
|
|
@@ -31,7 +31,6 @@ module Aspera
|
|
|
31
31
|
:FILE_LIST_FROM_TRANSFER_SPEC,
|
|
32
32
|
:FILE_LIST_OPTIONS,
|
|
33
33
|
:DEFAULT_TRANSFER_NOTIFY_TEMPLATE
|
|
34
|
-
TRANSFER_AGENTS = Agent::Factory.instance.list.freeze
|
|
35
34
|
|
|
36
35
|
class << self
|
|
37
36
|
# @return :success if all sessions statuses returned by "start" are success
|
|
@@ -65,7 +64,7 @@ module Aspera
|
|
|
65
64
|
@opt_mgr.declare(:to_folder, 'Destination folder for transferred files')
|
|
66
65
|
@opt_mgr.declare(:sources, "How list of transferred files is provided (#{FILE_LIST_OPTIONS.join(',')})", default: FILE_LIST_FROM_ARGS)
|
|
67
66
|
@opt_mgr.declare(:src_type, 'Type of file list', allowed: %i[list pair], default: :list)
|
|
68
|
-
@opt_mgr.declare(:transfer, 'Type of transfer agent', allowed:
|
|
67
|
+
@opt_mgr.declare(:transfer, 'Type of transfer agent', allowed: Agent::Factory::ALL.keys, default: :direct)
|
|
69
68
|
@opt_mgr.declare(:transfer_info, 'Parameters for transfer agent', allowed: Hash, handler: {o: self, m: :transfer_info})
|
|
70
69
|
@opt_mgr.parse_options!
|
|
71
70
|
@notification_cb = nil
|
data/lib/aspera/cli/version.rb
CHANGED
|
@@ -22,11 +22,11 @@ module Aspera
|
|
|
22
22
|
'x-cli-envvar', # [String] Name of env var
|
|
23
23
|
'x-cli-option', # [String] Command line option (starts with "-")
|
|
24
24
|
'x-cli-short', # [String] Command line option (starts with "-")
|
|
25
|
-
'x-cli-switch', # [
|
|
26
|
-
'x-cli-special', # [
|
|
25
|
+
'x-cli-switch', # [Boolean] `true` if option has no arg, else by default option has a value
|
|
26
|
+
'x-cli-special', # [Boolean] `true` if special handling (deferred)
|
|
27
27
|
'x-cli-convert', # [String,Hash] Method name for Convert object or Conversion for enum ts to arg
|
|
28
28
|
'x-agents', # [Array] Supported agents (for doc only), if not specified: all
|
|
29
|
-
'x-ts-name', # [
|
|
29
|
+
'x-ts-name', # [Boolean,String] (async) true if same name in transfer spec, else real name in transfer spec, else ignored
|
|
30
30
|
'x-ts-convert', # [String] (async) Name of methods to convert value from transfer spec to `conf` API.
|
|
31
31
|
'x-deprecation' # [String] Deprecation message for doc
|
|
32
32
|
].freeze
|
|
@@ -50,8 +50,8 @@ module Aspera
|
|
|
50
50
|
private
|
|
51
51
|
|
|
52
52
|
# Fill default values for some fields in the schema
|
|
53
|
-
# @param schema [Hash]
|
|
54
|
-
# @param ascp
|
|
53
|
+
# @param schema [Hash] The JSON schema
|
|
54
|
+
# @param ascp [Boolean] `true` if ascp
|
|
55
55
|
def validate_schema(schema, ascp: false)
|
|
56
56
|
direct_props = %w[x-cli-option x-cli-envvar x-cli-special].freeze
|
|
57
57
|
schema['properties'].each do |name, info|
|
data/lib/aspera/coverage.rb
CHANGED
|
@@ -6,14 +6,18 @@ if ENV.key?('ENABLE_COVERAGE')
|
|
|
6
6
|
require 'securerandom'
|
|
7
7
|
# compute development top folder based on this source location
|
|
8
8
|
development_root = File.dirname(File.realpath(__FILE__), 3)
|
|
9
|
+
coverage_dir = 'tmp/coverage'
|
|
10
|
+
coverage_root = File.join(development_root, coverage_dir)
|
|
11
|
+
FileUtils.mkdir_p(coverage_root)
|
|
9
12
|
SimpleCov.root(development_root)
|
|
13
|
+
SimpleCov.coverage_dir(coverage_dir)
|
|
10
14
|
SimpleCov.enable_for_subprocesses if SimpleCov.respond_to?(:enable_for_subprocesses)
|
|
11
15
|
# keep cache data for 1 day (must be longer than time to run the whole test suite)
|
|
12
16
|
SimpleCov.merge_timeout(86400)
|
|
13
17
|
SimpleCov.command_name(SecureRandom.uuid)
|
|
14
18
|
SimpleCov.at_exit do
|
|
15
19
|
original_file_descriptor = $stdout
|
|
16
|
-
$stdout.reopen(File.join(
|
|
20
|
+
$stdout.reopen(File.open(File.join(coverage_root, 'simplecov.log'), 'a'))
|
|
17
21
|
SimpleCov.result.format!
|
|
18
22
|
$stdout.reopen(original_file_descriptor)
|
|
19
23
|
end
|