aspera-cli 4.20.0 → 4.21.1
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 +29 -3
- data/CONTRIBUTING.md +2 -0
- data/README.md +571 -375
- data/bin/asession +2 -2
- data/examples/get_proto_file.rb +1 -1
- data/lib/aspera/agent/alpha.rb +10 -16
- data/lib/aspera/agent/connect.rb +20 -2
- data/lib/aspera/agent/direct.rb +21 -30
- data/lib/aspera/agent/node.rb +1 -11
- data/lib/aspera/agent/{trsdk.rb → transferd.rb} +13 -34
- data/lib/aspera/api/aoc.rb +13 -8
- data/lib/aspera/api/node.rb +45 -28
- data/lib/aspera/ascp/installation.rb +87 -48
- data/lib/aspera/ascp/management.rb +27 -6
- data/lib/aspera/cli/formatter.rb +148 -154
- data/lib/aspera/cli/info.rb +1 -1
- data/lib/aspera/cli/main.rb +12 -0
- data/lib/aspera/cli/manager.rb +2 -2
- data/lib/aspera/cli/plugin.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +28 -18
- data/lib/aspera/cli/plugins/config.rb +106 -54
- data/lib/aspera/cli/plugins/cos.rb +1 -0
- data/lib/aspera/cli/plugins/faspex.rb +4 -2
- data/lib/aspera/cli/plugins/faspex5.rb +21 -9
- data/lib/aspera/cli/plugins/node.rb +45 -38
- data/lib/aspera/cli/transfer_progress.rb +2 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +1 -1
- data/lib/aspera/environment.rb +48 -14
- data/lib/aspera/node_simulator.rb +230 -112
- data/lib/aspera/oauth/base.rb +34 -47
- data/lib/aspera/oauth/factory.rb +41 -2
- data/lib/aspera/oauth/jwt.rb +4 -1
- data/lib/aspera/persistency_action_once.rb +1 -1
- data/lib/aspera/persistency_folder.rb +20 -2
- data/lib/aspera/preview/generator.rb +1 -1
- data/lib/aspera/preview/utils.rb +8 -3
- data/lib/aspera/products/alpha.rb +30 -0
- data/lib/aspera/products/connect.rb +48 -0
- data/lib/aspera/products/other.rb +82 -0
- data/lib/aspera/products/transferd.rb +54 -0
- data/lib/aspera/rest.rb +18 -13
- data/lib/aspera/secret_hider.rb +2 -2
- data/lib/aspera/ssh.rb +31 -24
- data/lib/aspera/transfer/parameters.rb +2 -1
- data/lib/aspera/transfer/spec.yaml +22 -20
- data/lib/aspera/transfer/sync.rb +1 -5
- data/lib/aspera/transfer/uri.rb +2 -2
- data/lib/transferd_pb.rb +86 -0
- data/lib/transferd_services_pb.rb +84 -0
- data.tar.gz.sig +0 -0
- metadata +38 -21
- metadata.gz.sig +0 -0
- data/lib/aspera/ascp/products.rb +0 -168
- data/lib/transfer_pb.rb +0 -84
- data/lib/transfer_services_pb.rb +0 -82
@@ -9,11 +9,10 @@ require 'aspera/cli/formatter'
|
|
9
9
|
require 'aspera/cli/info'
|
10
10
|
require 'aspera/cli/transfer_progress'
|
11
11
|
require 'aspera/ascp/installation'
|
12
|
-
require 'aspera/
|
12
|
+
require 'aspera/products/transferd'
|
13
13
|
require 'aspera/transfer/error_info'
|
14
14
|
require 'aspera/transfer/parameters'
|
15
15
|
require 'aspera/transfer/spec'
|
16
|
-
require 'aspera/keychain/encrypted_hash'
|
17
16
|
require 'aspera/keychain/macos_security'
|
18
17
|
require 'aspera/proxy_auto_config'
|
19
18
|
require 'aspera/environment'
|
@@ -54,7 +53,7 @@ module Aspera
|
|
54
53
|
PERSISTENCY_FOLDER = 'persist_store'
|
55
54
|
ASPERA = 'aspera'
|
56
55
|
SERVER_COMMAND = 'server'
|
57
|
-
|
56
|
+
DIR_SDK = 'sdk'
|
58
57
|
CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
|
59
58
|
CONNECT_VERSIONS = 'connectversions.js' # cspell: disable-line
|
60
59
|
DEMO_SERVER = 'demo'
|
@@ -78,6 +77,7 @@ module Aspera
|
|
78
77
|
GEM_CHECK_DATE_FMT = '%Y/%m/%d'
|
79
78
|
# for testing only
|
80
79
|
SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
|
80
|
+
CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
|
81
81
|
private_constant :DEFAULT_CONFIG_FILENAME,
|
82
82
|
:CONF_PRESET_CONFIG,
|
83
83
|
:CONF_PRESET_VERSION,
|
@@ -98,7 +98,8 @@ module Aspera
|
|
98
98
|
:WIZARD_RESULT_KEYS,
|
99
99
|
:SELF_SIGNED_CERT,
|
100
100
|
:PERSISTENCY_FOLDER,
|
101
|
-
:DEFAULT_PRIV_KEY_LENGTH
|
101
|
+
:DEFAULT_PRIV_KEY_LENGTH,
|
102
|
+
:CONF_OVERVIEW_KEYS
|
102
103
|
|
103
104
|
class << self
|
104
105
|
def generate_rsa_private_key(path:, length: DEFAULT_PRIV_KEY_LENGTH)
|
@@ -145,7 +146,7 @@ module Aspera
|
|
145
146
|
|
146
147
|
def initialize(**env)
|
147
148
|
# we need to defer parsing of options until we have the config file, so we can use @extend with @preset
|
148
|
-
super
|
149
|
+
super
|
149
150
|
@use_plugin_defaults = true
|
150
151
|
@config_presets = nil
|
151
152
|
@config_checksum_on_disk = nil
|
@@ -213,7 +214,7 @@ module Aspera
|
|
213
214
|
options.declare(:ascp_path, 'Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
|
214
215
|
options.declare(:use_product, 'Use ascp from specified product', handler: {o: self, m: :option_use_product})
|
215
216
|
options.declare(:sdk_url, 'URL to get SDK', default: SpecialValues::DEF)
|
216
|
-
options.declare(:sdk_folder, 'SDK folder path', handler: {o:
|
217
|
+
options.declare(:sdk_folder, 'SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
|
217
218
|
options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
|
218
219
|
# email options
|
219
220
|
options.declare(:smtp, 'SMTP configuration', types: Hash)
|
@@ -232,22 +233,22 @@ module Aspera
|
|
232
233
|
options.parse_options!
|
233
234
|
@progress_bar = TransferProgress.new if options.get_option(:progress_bar)
|
234
235
|
# Check SDK folder is set or not, for compatibility, we check in two places
|
235
|
-
|
236
|
-
if
|
236
|
+
sdk_dir = Products::Transferd.sdk_directory rescue nil
|
237
|
+
if sdk_dir.nil?
|
237
238
|
@sdk_default_location = true
|
238
239
|
Log.log.debug('SDK folder is not set, checking default')
|
239
240
|
# new location
|
240
|
-
|
241
|
-
Log.log.debug{"checking: #{
|
242
|
-
if !Dir.exist?(
|
243
|
-
Log.log.debug{"not exists: #{
|
241
|
+
sdk_dir = self.class.default_app_main_folder(app_name: DIR_SDK)
|
242
|
+
Log.log.debug{"checking: #{sdk_dir}"}
|
243
|
+
if !Dir.exist?(sdk_dir)
|
244
|
+
Log.log.debug{"not exists: #{sdk_dir}"}
|
244
245
|
# former location
|
245
|
-
former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME),
|
246
|
+
former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), DIR_SDK)
|
246
247
|
Log.log.debug{"checking: #{former_sdk_folder}"}
|
247
|
-
|
248
|
+
sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
|
248
249
|
end
|
249
|
-
Log.log.debug{"using: #{
|
250
|
-
|
250
|
+
Log.log.debug{"using: #{sdk_dir}"}
|
251
|
+
Products::Transferd.sdk_directory = sdk_dir
|
251
252
|
end
|
252
253
|
pac_script = options.get_option(:fpac)
|
253
254
|
# create PAC executor
|
@@ -414,7 +415,7 @@ module Aspera
|
|
414
415
|
|
415
416
|
def periodic_check_newer_gem_version
|
416
417
|
# get verification period
|
417
|
-
delay_days = options.get_option(:version_check_days, mandatory: true)
|
418
|
+
delay_days = options.get_option(:version_check_days, mandatory: true).to_i
|
418
419
|
# check only if not zero day
|
419
420
|
return if delay_days.eql?(0)
|
420
421
|
# get last date from persistency
|
@@ -663,10 +664,10 @@ module Aspera
|
|
663
664
|
end
|
664
665
|
case command
|
665
666
|
when :list
|
666
|
-
return
|
667
|
+
return Main.result_object_list(connect_versions, fields: %w[id title version])
|
667
668
|
when :info
|
668
669
|
one_res.delete('links')
|
669
|
-
return
|
670
|
+
return Main.result_single_object(one_res)
|
670
671
|
when :version
|
671
672
|
all_links = one_res['links']
|
672
673
|
command = options.get_next_command(%i[list download open])
|
@@ -677,10 +678,9 @@ module Aspera
|
|
677
678
|
end
|
678
679
|
case command
|
679
680
|
when :list
|
680
|
-
return
|
681
|
+
return Main.result_object_list(all_links)
|
681
682
|
when :download
|
682
683
|
folder_dest = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
|
683
|
-
# folder_dest=self.options.get_next_argument('destination folder')
|
684
684
|
api_connect_cdn = Rest.new(base_url: CONNECT_WEB_URL)
|
685
685
|
file_url = one_link['href']
|
686
686
|
filename = file_url.gsub(%r{.*/}, '')
|
@@ -700,11 +700,12 @@ module Aspera
|
|
700
700
|
return execute_connect_action
|
701
701
|
when :use
|
702
702
|
ascp_path = options.get_next_argument('path to ascp')
|
703
|
+
Ascp::Installation.instance.ascp_path = ascp_path
|
703
704
|
formatter.display_status("ascp version: #{Ascp::Installation.instance.get_ascp_version(ascp_path)}")
|
704
705
|
set_global_default(:ascp_path, ascp_path)
|
705
706
|
return Main.result_nothing
|
706
707
|
when :show
|
707
|
-
return
|
708
|
+
return Main.result_status(Ascp::Installation.instance.path(:ascp))
|
708
709
|
when :info
|
709
710
|
# collect info from ascp executable
|
710
711
|
data = Ascp::Installation.instance.ascp_info
|
@@ -713,13 +714,13 @@ module Aspera
|
|
713
714
|
# add keys
|
714
715
|
DataRepository::ELEMENTS.each_with_object(data){|i, h|h[i.to_s] = DataRepository.instance.item(i)}
|
715
716
|
# declare those as secrets
|
716
|
-
SecretHider::ADDITIONAL_KEYS_TO_HIDE.
|
717
|
-
return
|
717
|
+
SecretHider::ADDITIONAL_KEYS_TO_HIDE.concat(DataRepository::ELEMENTS.map(&:to_s))
|
718
|
+
return Main.result_single_object(data)
|
718
719
|
when :products
|
719
720
|
command = options.get_next_command(%i[list use])
|
720
721
|
case command
|
721
722
|
when :list
|
722
|
-
return
|
723
|
+
return Main.result_object_list(Ascp::Installation.instance.installed_products, fields: %w[name app_root])
|
723
724
|
when :use
|
724
725
|
default_product = options.get_next_argument('product name')
|
725
726
|
Ascp::Installation.instance.use_ascp_from_product(default_product)
|
@@ -728,23 +729,44 @@ module Aspera
|
|
728
729
|
end
|
729
730
|
when :install
|
730
731
|
# reset to default location, if older default was used
|
731
|
-
|
732
|
-
|
732
|
+
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: DIR_SDK) if @sdk_default_location
|
733
|
+
version = options.get_next_argument('transferd version', mandatory: false)
|
734
|
+
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
733
735
|
return Main.result_status("Installed #{n} version #{v}")
|
734
736
|
when :spec
|
735
|
-
return
|
736
|
-
|
737
|
-
data: Transfer::Parameters.man_table(formatter),
|
737
|
+
return Main.result_object_list(
|
738
|
+
Transfer::Parameters.man_table(formatter),
|
738
739
|
fields: [%w[name type], Transfer::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s), %w[description]].flatten.freeze
|
739
|
-
|
740
|
+
)
|
740
741
|
when :errors
|
741
742
|
error_data = []
|
742
743
|
Transfer::ERROR_INFO.each_pair do |code, prop|
|
743
744
|
error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
|
744
745
|
end
|
745
|
-
return
|
746
|
+
return Main.result_object_list(error_data)
|
747
|
+
else Aspera.error_unexpected_value(command)
|
746
748
|
end
|
747
|
-
|
749
|
+
Aspera.error_unreachable_line
|
750
|
+
end
|
751
|
+
|
752
|
+
def execute_action_transferd
|
753
|
+
command = options.get_next_command(%i[list install])
|
754
|
+
case command
|
755
|
+
when :install
|
756
|
+
# reset to default location, if older default was used
|
757
|
+
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: DIR_SDK) if @sdk_default_location
|
758
|
+
version = options.get_next_argument('transferd version', mandatory: false)
|
759
|
+
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
760
|
+
return Main.result_status("Installed #{n} version #{v}")
|
761
|
+
when :list
|
762
|
+
sdk_list = Ascp::Installation.sdk_locations
|
763
|
+
return Main.result_object_list(
|
764
|
+
sdk_list,
|
765
|
+
fields: sdk_list.first.keys - ['url']
|
766
|
+
)
|
767
|
+
else Aspera.error_unexpected_value(command)
|
768
|
+
end
|
769
|
+
Aspera.error_unreachable_line
|
748
770
|
end
|
749
771
|
|
750
772
|
# legacy actions available globally
|
@@ -763,12 +785,20 @@ module Aspera
|
|
763
785
|
raise "no such preset: #{name}" if PRESET_EXIST_ACTIONS.include?(action) && !@config_presets.key?(name)
|
764
786
|
case action
|
765
787
|
when :list
|
766
|
-
return
|
788
|
+
return Main.result_value_list(@config_presets.keys, 'name')
|
767
789
|
when :overview
|
768
790
|
# display process modifies the value (hide secrets): we do not want to save removed secrets
|
769
|
-
|
791
|
+
data = self.class.deep_clone(@config_presets)
|
792
|
+
formatter.hide_secrets(data)
|
793
|
+
result = []
|
794
|
+
data.each do |config, preset|
|
795
|
+
preset.each do |parameter, value|
|
796
|
+
result.push(CONF_OVERVIEW_KEYS.zip([config, parameter, value]).to_h)
|
797
|
+
end
|
798
|
+
end
|
799
|
+
return Main.result_object_list(result, fields: CONF_OVERVIEW_KEYS)
|
770
800
|
when :show
|
771
|
-
return
|
801
|
+
return Main.result_single_object(self.class.deep_clone(@config_presets[name]))
|
772
802
|
when :delete
|
773
803
|
@config_presets.delete(name)
|
774
804
|
return Main.result_status("Deleted: #{name}")
|
@@ -779,7 +809,7 @@ module Aspera
|
|
779
809
|
case value
|
780
810
|
when Numeric, String then return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
|
781
811
|
end
|
782
|
-
return
|
812
|
+
return Main.result_single_object(value)
|
783
813
|
when :unset
|
784
814
|
param_name = options.get_next_argument('parameter name')
|
785
815
|
@config_presets[name].delete(param_name)
|
@@ -818,7 +848,7 @@ module Aspera
|
|
818
848
|
user = options.get_option(:username, mandatory: true)
|
819
849
|
result = lookup_preset(url: url, username: user)
|
820
850
|
raise 'no such config found' if result.nil?
|
821
|
-
return
|
851
|
+
return Main.result_single_object(result)
|
822
852
|
when :secure
|
823
853
|
identifier = options.get_next_argument('config name', mandatory: false)
|
824
854
|
preset_names = identifier.nil? ? @config_presets.keys : [identifier]
|
@@ -856,13 +886,15 @@ module Aspera
|
|
856
886
|
remote_certificate
|
857
887
|
gem
|
858
888
|
plugins
|
859
|
-
|
889
|
+
tokens
|
860
890
|
echo
|
891
|
+
download
|
861
892
|
wizard
|
862
893
|
detect
|
863
894
|
coffee
|
864
895
|
image
|
865
896
|
ascp
|
897
|
+
transferd
|
866
898
|
email_test
|
867
899
|
smtp_settings
|
868
900
|
proxy_check
|
@@ -912,9 +944,27 @@ module Aspera
|
|
912
944
|
end
|
913
945
|
when :echo # display the content of a value given on command line
|
914
946
|
return Formatter.auto_type(options.get_next_argument('value', validation: nil))
|
915
|
-
when :
|
916
|
-
|
917
|
-
|
947
|
+
when :download
|
948
|
+
file_url = options.get_next_argument('source URL').chomp
|
949
|
+
file_dest = options.get_next_argument('file path', mandatory: false)
|
950
|
+
if file_dest.nil?
|
951
|
+
file_dest = File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), file_url.gsub(%r{.*/}, ''))
|
952
|
+
end
|
953
|
+
formatter.display_status("Downloading: #{file_url}")
|
954
|
+
Rest.new(base_url: file_url).call(operation: 'GET', save_to_file: file_dest)
|
955
|
+
return Main.result_status("Saved to: #{file_dest}")
|
956
|
+
when :tokens
|
957
|
+
require 'aspera/api/node'
|
958
|
+
case options.get_next_command(%i{flush list show})
|
959
|
+
when :flush
|
960
|
+
return Main.result_value_list(OAuth::Factory.instance.flush_tokens, name: 'file')
|
961
|
+
when :list
|
962
|
+
return Main.result_object_list(OAuth::Factory.instance.persisted_tokens)
|
963
|
+
when :show
|
964
|
+
data = OAuth::Factory.instance.get_token_info(instance_identifier)
|
965
|
+
raise Cli::Error, 'No such identifier' if data.nil?
|
966
|
+
return Main.result_single_object(data)
|
967
|
+
end
|
918
968
|
when :plugins
|
919
969
|
case options.get_next_command(%i[list create])
|
920
970
|
when :list
|
@@ -928,7 +978,7 @@ module Aspera
|
|
928
978
|
path: PluginFactory.instance.plugin_source(name)
|
929
979
|
})
|
930
980
|
end
|
931
|
-
return
|
981
|
+
return Main.result_object_list(result, fields: %w[plugin detect wizard path])
|
932
982
|
when :create
|
933
983
|
plugin_name = options.get_next_argument('name').downcase
|
934
984
|
destination_folder = options.get_next_argument('folder', mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
|
@@ -954,10 +1004,7 @@ module Aspera
|
|
954
1004
|
options.ask_missing_mandatory = true
|
955
1005
|
# detect plugins by url and optional query
|
956
1006
|
apps = identify_plugins_for_url.freeze
|
957
|
-
return
|
958
|
-
type: :object_list,
|
959
|
-
data: apps
|
960
|
-
} if action.eql?(:detect)
|
1007
|
+
return Main.result_object_list(apps) if action.eql?(:detect)
|
961
1008
|
return wizard_find(apps)
|
962
1009
|
when :coffee
|
963
1010
|
return Main.result_image(COFFEE_IMAGE, formatter: formatter)
|
@@ -965,6 +1012,8 @@ module Aspera
|
|
965
1012
|
return Main.result_image(options.get_next_argument('image uri or blob'), formatter: formatter)
|
966
1013
|
when :ascp
|
967
1014
|
execute_action_ascp
|
1015
|
+
when :transferd
|
1016
|
+
execute_action_transferd
|
968
1017
|
when :gem
|
969
1018
|
case options.get_next_command(%i[path version name])
|
970
1019
|
when :path then return Main.result_status(self.class.gem_src_root)
|
@@ -979,14 +1028,14 @@ module Aspera
|
|
979
1028
|
send_email_template(email_template_default: EMAIL_TEST_TEMPLATE)
|
980
1029
|
return Main.result_nothing
|
981
1030
|
when :smtp_settings
|
982
|
-
return
|
1031
|
+
return Main.result_single_object(email_settings)
|
983
1032
|
when :proxy_check
|
984
1033
|
# ensure fpac was provided
|
985
1034
|
options.get_option(:fpac, mandatory: true)
|
986
1035
|
server_url = options.get_next_argument('server url')
|
987
1036
|
return Main.result_status(@pac_exec.find_proxy_for_url(server_url))
|
988
1037
|
when :check_update
|
989
|
-
return
|
1038
|
+
return Main.result_single_object(check_gem_version)
|
990
1039
|
when :initdemo
|
991
1040
|
if @config_presets.key?(DEMO_PRESET)
|
992
1041
|
Log.log.warn{"Demo server preset already present: #{DEMO_PRESET}"}
|
@@ -1085,7 +1134,7 @@ module Aspera
|
|
1085
1134
|
wiz_preset_name = elements.join('_').strip.downcase.gsub(/[^a-z0-9]/, '_').squeeze('_')
|
1086
1135
|
end
|
1087
1136
|
# test mode does not change conf file
|
1088
|
-
return
|
1137
|
+
return Main.result_single_object(wizard_result) if options.get_option(:test_mode)
|
1089
1138
|
# Write configuration file
|
1090
1139
|
formatter.display_status("Preparing preset: #{wiz_preset_name}")
|
1091
1140
|
# init defaults if necessary
|
@@ -1196,7 +1245,8 @@ module Aspera
|
|
1196
1245
|
Log.log.error do
|
1197
1246
|
"Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
|
1198
1247
|
'Please fix the issue: either create preset with one parameter: ' \
|
1199
|
-
"(#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}')
|
1248
|
+
"(#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}') " \
|
1249
|
+
"or remove default (#{Info::CMD_NAME} config id default remove #{plugin_name_sym})."
|
1200
1250
|
end
|
1201
1251
|
end
|
1202
1252
|
raise Cli::Error, "Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
|
@@ -1211,11 +1261,11 @@ module Aspera
|
|
1211
1261
|
command = options.get_next_command(%i[info list show create delete password])
|
1212
1262
|
case command
|
1213
1263
|
when :info
|
1214
|
-
return
|
1264
|
+
return Main.result_single_object(vault_info)
|
1215
1265
|
when :list
|
1216
|
-
return
|
1266
|
+
return Main.result_object_list(vault.list, fields: %w(label url username password description))
|
1217
1267
|
when :show
|
1218
|
-
return
|
1268
|
+
return Main.result_single_object(vault.get(label: options.get_next_argument('label')))
|
1219
1269
|
when :create
|
1220
1270
|
label = options.get_next_argument('label', validation: String)
|
1221
1271
|
info = options.get_next_argument('info', validation: Hash)
|
@@ -1264,6 +1314,8 @@ module Aspera
|
|
1264
1314
|
info = vault_info
|
1265
1315
|
case info[:type]
|
1266
1316
|
when 'file'
|
1317
|
+
# this module requires comilation, so it is optinal
|
1318
|
+
require 'aspera/keychain/encrypted_hash'
|
1267
1319
|
# absolute_path? introduced in ruby 2.7
|
1268
1320
|
@vault = Keychain::EncryptedHash.new(
|
1269
1321
|
info[:name].eql?(File.absolute_path(info[:name])) ? info[:name] : File.join(@main_folder, info[:name]),
|
@@ -19,6 +19,7 @@ module Aspera
|
|
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!
|
22
|
+
Node.declare_options(options)
|
22
23
|
end
|
23
24
|
|
24
25
|
ACTIONS = %i[node].freeze
|
@@ -305,7 +305,7 @@ module Aspera
|
|
305
305
|
# authenticated user
|
306
306
|
delivery_info['sources'] ||= [{'paths' => []}]
|
307
307
|
first_source = delivery_info['sources'].first
|
308
|
-
first_source['paths'].
|
308
|
+
first_source['paths'].concat(transfer.source_list)
|
309
309
|
source_id = instance_identifier(as_option: :remote_source) do |field, value|
|
310
310
|
Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
311
311
|
source_list = api_v3.read('source_shares')['items']
|
@@ -441,7 +441,9 @@ module Aspera
|
|
441
441
|
Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
442
442
|
self.class.get_source_id_by_name(value, source_list)
|
443
443
|
end.to_i
|
444
|
-
|
444
|
+
selected_source = source_list.find{|i|i['id'].eql?(source_id)}
|
445
|
+
raise 'No such source' if selected_source.nil?
|
446
|
+
source_name = selected_source['name']
|
445
447
|
source_hash = options.get_option(:storage, mandatory: true)
|
446
448
|
# check value of option
|
447
449
|
Aspera.assert_type(source_hash, Hash, exception_class: Cli::Error){'storage option'}
|
@@ -237,15 +237,18 @@ module Aspera
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
|
240
|
+
# @param [Srting] job identifier
|
241
|
+
# @return [Hash] result of API call for job status
|
240
242
|
def wait_for_job(job_id)
|
243
|
+
result = nil
|
241
244
|
loop do
|
242
|
-
|
243
|
-
|
244
|
-
formatter.long_operation_running(
|
245
|
+
result = @api_v5.read("jobs/#{job_id}", {type: :formatted})
|
246
|
+
break unless JOB_RUNNING.include?(result['status'])
|
247
|
+
formatter.long_operation_running(result['status'])
|
245
248
|
sleep(0.5)
|
246
249
|
end
|
247
250
|
formatter.long_operation_terminated
|
248
|
-
|
251
|
+
return result
|
249
252
|
end
|
250
253
|
|
251
254
|
# Get a (full or partial) list of all entities of a given type with query: offset/limit
|
@@ -253,9 +256,10 @@ module Aspera
|
|
253
256
|
# @param query [Hash,nil] additional query parameters
|
254
257
|
# @param real_path [String] real path if it's n ot just the type
|
255
258
|
# @param item_list_key [String] key in the result to get the list of items
|
256
|
-
def list_entities(type:, real_path: nil, item_list_key: nil, query:
|
259
|
+
def list_entities(type:, real_path: nil, item_list_key: nil, query: nil)
|
257
260
|
Log.log.trace1{"list_entities t=#{type} p=#{real_path} k=#{item_list_key} q=#{query}"}
|
258
261
|
type = type.to_s if type.is_a?(Symbol)
|
262
|
+
query = {} if query.nil?
|
259
263
|
Aspera.assert_type(type, String)
|
260
264
|
Aspera.assert_type(query, Hash)
|
261
265
|
item_list_key = type if item_list_key.nil?
|
@@ -555,9 +559,10 @@ module Aspera
|
|
555
559
|
id_as_arg = 'type'
|
556
560
|
when :accounts
|
557
561
|
display_fields = Formatter.all_but('user_profile_data_attributes')
|
562
|
+
available_commands.push(:reset_password)
|
558
563
|
when :oauth_clients
|
559
564
|
display_fields = Formatter.all_but('public_key')
|
560
|
-
adm_api = Rest.new(**@api_v5.params
|
565
|
+
adm_api = Rest.new(**@api_v5.params, base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}")
|
561
566
|
when :shared_inboxes, :workgroups
|
562
567
|
available_commands.push(:members, :saml_groups, :invite_external_collaborator)
|
563
568
|
res_id_query = {'all': true}
|
@@ -642,7 +647,12 @@ module Aspera
|
|
642
647
|
value: value,
|
643
648
|
query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
|
644
649
|
end
|
650
|
+
when :reset_password
|
651
|
+
contact_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
|
652
|
+
adm_api.create("#{res_type}/#{contact_id}/reset_password", {})
|
653
|
+
return Main.result_status('password reset, user shall check email')
|
645
654
|
end
|
655
|
+
Aspera.error_unreachable_line
|
646
656
|
end
|
647
657
|
|
648
658
|
def execute_admin
|
@@ -655,16 +665,18 @@ module Aspera
|
|
655
665
|
when *ADMIN_RESOURCES
|
656
666
|
return execute_resource(command)
|
657
667
|
when :clean_deleted
|
658
|
-
delete_data = value_create_modify(command: command, default: {
|
668
|
+
delete_data = value_create_modify(command: command, default: {})
|
669
|
+
delete_data = @api_v5.read('configuration').slice('days_before_deleting_package_records') if delete_data.empty?
|
659
670
|
res = @api_v5.create('internal/packages/clean_deleted', delete_data)
|
660
671
|
return {type: :single_object, data: res}
|
661
672
|
when :events
|
662
673
|
event_type = options.get_next_command(%i[application webhook])
|
663
674
|
case event_type
|
664
675
|
when :application
|
665
|
-
return {type: :object_list, data: list_entities(type: 'application_events'
|
676
|
+
return {type: :object_list, data: list_entities(type: 'application_events', query: query_read_delete),
|
677
|
+
fields: %w[event_type created_at application user.name]}
|
666
678
|
when :webhook
|
667
|
-
return {type: :object_list, data: list_entities(type: 'all_webhooks_events', item_list_key: 'events')}
|
679
|
+
return {type: :object_list, data: list_entities(type: 'all_webhooks_events', query: query_read_delete, item_list_key: 'events')}
|
668
680
|
end
|
669
681
|
when :configuration
|
670
682
|
conf_path = 'configuration'
|
@@ -127,10 +127,13 @@ module Aspera
|
|
127
127
|
# commands for execute_command_gen4
|
128
128
|
COMMANDS_GEN4 = %i[mkdir rename delete upload download sync http_node_download show modify permission thumbnail v3].concat(NODE4_READ_ACTIONS).freeze
|
129
129
|
|
130
|
+
# commands supported in ATS for COS
|
130
131
|
COMMANDS_COS = %i[upload download info access_keys api_details transfer].freeze
|
131
132
|
COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
|
132
133
|
COMMANDS_FASPEX = COMMON_ACTIONS
|
133
134
|
|
135
|
+
GEN4_LS_FIELDS = %w[name type recursive_size size modified_time access_level].freeze
|
136
|
+
|
134
137
|
def initialize(api: nil, **env)
|
135
138
|
super(**env, basic_options: api.nil?)
|
136
139
|
Node.declare_options(options) if api.nil?
|
@@ -484,22 +487,15 @@ module Aspera
|
|
484
487
|
when :browse
|
485
488
|
apifid = apifid_from_next_arg(top_file_id)
|
486
489
|
file_info = apifid[:api].read_with_cache("files/#{apifid[:file_id]}")
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
subpath: "files/#{apifid[:file_id]}/files",
|
491
|
-
headers: Api::Node.cache_control_headers,
|
492
|
-
query: query_read_delete)
|
493
|
-
items = result[:data]
|
494
|
-
formatter.display_item_count(result[:data].length, result[:http]['X-Total-Count'])
|
495
|
-
else
|
496
|
-
items = [file_info]
|
490
|
+
unless file_info['type'].eql?('folder')
|
491
|
+
# a single file
|
492
|
+
return {type: :object_list, data: [file_info], fields: GEN4_LS_FIELDS}
|
497
493
|
end
|
498
|
-
return {type: :object_list, data:
|
494
|
+
return {type: :object_list, data: apifid[:api].list_files(apifid[:file_id]), fields: GEN4_LS_FIELDS}
|
499
495
|
when :find
|
500
496
|
apifid = apifid_from_next_arg(top_file_id)
|
501
|
-
|
502
|
-
return {type: :object_list, data: @api_node.find_files(apifid[:file_id],
|
497
|
+
find_lambda = Api::Node.file_matcher_from_argument(options)
|
498
|
+
return {type: :object_list, data: @api_node.find_files(apifid[:file_id], find_lambda), fields: ['path']}
|
503
499
|
when :mkdir
|
504
500
|
containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
|
505
501
|
new_folder = containing_folder_path.pop
|
@@ -608,12 +604,12 @@ module Aspera
|
|
608
604
|
command_perm = options.get_next_command(%i[list create delete])
|
609
605
|
case command_perm
|
610
606
|
when :list
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
items = apifid[:api].read('permissions',
|
607
|
+
list_query = query_read_delete(default: {'include' => Rest.array_params(%w[access_level permission_count])})
|
608
|
+
# specify file to get permissions for unless not specified
|
609
|
+
list_query['file_id'] = apifid[:file_id] unless apifid[:file_id].to_s.empty?
|
610
|
+
list_query['inherited'] = false if list_query.key?('file_id') && !list_query.key?('inherited')
|
611
|
+
# NOTE: supports per_page and page and header X-Total-Count
|
612
|
+
items = apifid[:api].read('permissions', list_query)
|
617
613
|
return {type: :object_list, data: items}
|
618
614
|
when :delete
|
619
615
|
return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
|
@@ -802,42 +798,53 @@ module Aspera
|
|
802
798
|
end
|
803
799
|
case command
|
804
800
|
when :list
|
801
|
+
transfer_filter = query_read_delete(default: {})
|
802
|
+
last_iteration_token = nil
|
805
803
|
iteration_persistency = nil
|
806
|
-
iteration_data = []
|
807
804
|
if options.get_option(:once_only, mandatory: true)
|
808
805
|
iteration_persistency = PersistencyActionOnce.new(
|
809
806
|
manager: persistency,
|
810
|
-
data:
|
807
|
+
data: [],
|
811
808
|
id: IdGenerator.from_list([
|
812
809
|
'node_transfers',
|
813
810
|
options.get_option(:url, mandatory: true),
|
814
811
|
options.get_option(:username, mandatory: true)
|
815
812
|
]))
|
813
|
+
if transfer_filter.delete('reset')
|
814
|
+
iteration_persistency.data.clear
|
815
|
+
iteration_persistency.save
|
816
|
+
return Main.result_status('Persistency reset')
|
817
|
+
end
|
818
|
+
last_iteration_token = iteration_persistency.data.first
|
816
819
|
end
|
817
|
-
|
818
|
-
if transfer_filter.delete('reset')
|
819
|
-
iteration_data.clear
|
820
|
-
iteration_persistency&.save
|
821
|
-
return Main.result_status('Persistency reset')
|
822
|
-
end
|
820
|
+
raise 'reset only with once_only' if transfer_filter.key?('reset') && iteration_persistency.nil?
|
823
821
|
max_items = transfer_filter.delete(MAX_ITEMS)
|
824
|
-
transfer_filter['iteration_token'] = iteration_persistency.data[0] unless iteration_data.empty?
|
825
822
|
transfers_data = []
|
826
823
|
loop do
|
824
|
+
transfer_filter['iteration_token'] = last_iteration_token unless last_iteration_token.nil?
|
827
825
|
result = @api_node.call(operation: 'GET', subpath: res_class_path, query: transfer_filter)
|
828
|
-
|
829
|
-
|
830
|
-
|
826
|
+
# no data
|
827
|
+
break if result[:data].empty?
|
828
|
+
# get next iteration token from link
|
829
|
+
next_iteration_token = nil
|
830
|
+
link_info = result[:http]['Link']
|
831
|
+
unless link_info.nil?
|
832
|
+
m = link_info.match(/<([^>]+)>/)
|
833
|
+
raise "Cannot parse iteration in Link: #{link_info}" if m.nil?
|
834
|
+
next_iteration_token = CGI.parse(URI.parse(m[1]).query)['iteration_token']&.first
|
835
|
+
end
|
836
|
+
# same as last iteration: stop
|
837
|
+
break if next_iteration_token&.eql?(last_iteration_token)
|
838
|
+
last_iteration_token = next_iteration_token
|
839
|
+
transfers_data.concat(result[:data])
|
840
|
+
if max_items&.<=(transfers_data.length)
|
841
|
+
# if !max_items.nil? && (transfers_data.length >= max_items)
|
831
842
|
transfers_data = transfers_data.slice(0, max_items)
|
832
843
|
break
|
833
844
|
end
|
834
|
-
|
835
|
-
break if iteration_persistency.nil? || data.empty? || link_info.nil?
|
836
|
-
m = link_info.match(/<([^>]+)>/)
|
837
|
-
raise "Problem with iteration: #{link_info}" if m.nil?
|
838
|
-
iteration_token = CGI.parse(URI.parse(m[1]).query)['iteration_token']&.first
|
839
|
-
iteration_data[0] = transfer_filter['iteration_token'] = iteration_token
|
845
|
+
break if last_iteration_token.nil?
|
840
846
|
end
|
847
|
+
iteration_persistency&.data&.[]=(0, last_iteration_token)
|
841
848
|
iteration_persistency&.save
|
842
849
|
return {
|
843
850
|
type: :object_list,
|
@@ -1019,7 +1026,7 @@ module Aspera
|
|
1019
1026
|
raise 'Missing key: url' unless parameters.key?(:url)
|
1020
1027
|
uri = URI.parse(parameters[:url])
|
1021
1028
|
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
1022
|
-
server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials],
|
1029
|
+
server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], NodeSimulator.new)
|
1023
1030
|
server.start
|
1024
1031
|
return Main.result_status('Simulator terminated')
|
1025
1032
|
end
|
@@ -79,6 +79,8 @@ module Aspera
|
|
79
79
|
new_title = @sessions.length < 2 ? @title.to_s : "[#{@sessions.length}] #{@title}"
|
80
80
|
@progress_bar.title = new_title unless @progress_bar.title.eql?(new_title)
|
81
81
|
@progress_bar.increment if !progress_provided && !@completed
|
82
|
+
rescue ProgressBar::InvalidProgressError => e
|
83
|
+
Log.log.error{"Progress error: #{e}"}
|
82
84
|
end
|
83
85
|
|
84
86
|
private
|