aspera-cli 4.4.0 → 4.7.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
- data/README.md +2095 -1503
- data/bin/ascli +2 -1
- data/bin/asession +4 -5
- data/docs/test_env.conf +3 -0
- data/examples/aoc.rb +4 -3
- data/examples/faspex4.rb +25 -25
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +17 -17
- data/lib/aspera/aoc.rb +238 -185
- data/lib/aspera/ascmd.rb +93 -83
- data/lib/aspera/ats_api.rb +11 -10
- data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
- data/lib/aspera/cli/extended_value.rb +42 -33
- data/lib/aspera/cli/formater.rb +142 -108
- data/lib/aspera/cli/info.rb +17 -0
- data/lib/aspera/cli/listener/line_dump.rb +3 -2
- data/lib/aspera/cli/listener/logger.rb +2 -1
- data/lib/aspera/cli/listener/progress.rb +16 -18
- data/lib/aspera/cli/listener/progress_multi.rb +18 -21
- data/lib/aspera/cli/main.rb +173 -149
- data/lib/aspera/cli/manager.rb +163 -168
- data/lib/aspera/cli/plugin.rb +43 -31
- data/lib/aspera/cli/plugins/alee.rb +6 -6
- data/lib/aspera/cli/plugins/aoc.rb +405 -370
- data/lib/aspera/cli/plugins/ats.rb +86 -79
- data/lib/aspera/cli/plugins/bss.rb +14 -16
- data/lib/aspera/cli/plugins/config.rb +580 -362
- data/lib/aspera/cli/plugins/console.rb +23 -19
- data/lib/aspera/cli/plugins/cos.rb +18 -18
- data/lib/aspera/cli/plugins/faspex.rb +201 -158
- data/lib/aspera/cli/plugins/faspex5.rb +80 -57
- data/lib/aspera/cli/plugins/node.rb +183 -166
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -67
- data/lib/aspera/cli/plugins/preview.rb +92 -96
- data/lib/aspera/cli/plugins/server.rb +79 -75
- data/lib/aspera/cli/plugins/shares.rb +35 -19
- data/lib/aspera/cli/plugins/sync.rb +20 -22
- data/lib/aspera/cli/transfer_agent.rb +76 -113
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +35 -27
- data/lib/aspera/command_line_builder.rb +48 -34
- data/lib/aspera/cos_node.rb +29 -21
- data/lib/aspera/data_repository.rb +3 -2
- data/lib/aspera/environment.rb +50 -45
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +28 -25
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +52 -43
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +58 -72
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +37 -43
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +35 -16
- data/lib/aspera/fasp/agent_trsdk.rb +104 -0
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +68 -52
- data/lib/aspera/fasp/installation.rb +152 -124
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +87 -92
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +11 -14
- data/lib/aspera/fasp/transfer_spec.rb +26 -0
- data/lib/aspera/fasp/uri.rb +22 -21
- data/lib/aspera/faspex_gw.rb +55 -89
- data/lib/aspera/hash_ext.rb +4 -3
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +121 -0
- data/lib/aspera/keychain/macos_security.rb +90 -0
- data/lib/aspera/log.rb +55 -37
- data/lib/aspera/nagios.rb +13 -12
- data/lib/aspera/node.rb +30 -25
- data/lib/aspera/oauth.rb +175 -226
- data/lib/aspera/open_application.rb +4 -3
- data/lib/aspera/persistency_action_once.rb +6 -6
- data/lib/aspera/persistency_folder.rb +5 -9
- data/lib/aspera/preview/file_types.rb +6 -5
- data/lib/aspera/preview/generator.rb +25 -24
- data/lib/aspera/preview/options.rb +16 -14
- data/lib/aspera/preview/utils.rb +98 -98
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +111 -20
- data/lib/aspera/rest.rb +154 -135
- data/lib/aspera/rest_call_error.rb +2 -2
- data/lib/aspera/rest_error_analyzer.rb +23 -25
- data/lib/aspera/rest_errors_aspera.rb +15 -14
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +42 -41
- data/lib/aspera/temp_file_manager.rb +18 -14
- data/lib/aspera/timer_limiter.rb +2 -1
- data/lib/aspera/uri_reader.rb +7 -5
- data/lib/aspera/web_auth.rb +79 -76
- metadata +116 -29
- data/docs/Makefile +0 -66
- data/docs/README.erb.md +0 -3973
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/secrets.rb +0 -20
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/cli/basic_auth_plugin'
|
|
2
3
|
require 'aspera/cli/extended_value'
|
|
4
|
+
require 'aspera/cli/version'
|
|
3
5
|
require 'aspera/fasp/installation'
|
|
4
6
|
require 'aspera/fasp/parameters'
|
|
5
|
-
require 'aspera/
|
|
6
|
-
require 'aspera/
|
|
7
|
-
require 'aspera/aoc'
|
|
7
|
+
require 'aspera/fasp/transfer_spec'
|
|
8
|
+
require 'aspera/fasp/error_info'
|
|
8
9
|
require 'aspera/proxy_auto_config'
|
|
9
|
-
require 'aspera/
|
|
10
|
-
require 'aspera/rest'
|
|
10
|
+
require 'aspera/open_application'
|
|
11
11
|
require 'aspera/persistency_action_once'
|
|
12
12
|
require 'aspera/id_generator'
|
|
13
|
+
require 'aspera/keychain/encrypted_hash'
|
|
14
|
+
require 'aspera/keychain/macos_security'
|
|
15
|
+
require 'aspera/aoc'
|
|
16
|
+
require 'aspera/rest'
|
|
13
17
|
require 'xmlsimple'
|
|
14
18
|
require 'base64'
|
|
15
19
|
require 'net/smtp'
|
|
@@ -31,6 +35,7 @@ module Aspera
|
|
|
31
35
|
CONF_PRESET_VERSION='version'
|
|
32
36
|
CONF_PRESET_DEFAULT='default'
|
|
33
37
|
CONF_PRESET_GLOBAL='global_common_defaults'
|
|
38
|
+
CONF_PRESET_SECRETS='default_secrets' # pragma: allowlist secret
|
|
34
39
|
CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
|
|
35
40
|
CONF_GLOBAL_SYM = :config
|
|
36
41
|
# old tool name
|
|
@@ -48,113 +53,127 @@ module Aspera
|
|
|
48
53
|
SERVER_COMMAND='server'
|
|
49
54
|
CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
|
|
50
55
|
CONNECT_VERSIONS = 'connectversions.js'
|
|
51
|
-
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/
|
|
56
|
+
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_transfer_sdk'
|
|
52
57
|
DEMO='demo'
|
|
53
58
|
DEMO_SERVER_PRESET='demoserver'
|
|
54
59
|
AOC_PATH_API_CLIENTS='admin/api-clients'
|
|
55
|
-
EMAIL_TEST_TEMPLATE
|
|
56
|
-
From: <%=from_name%> <<%=from_email%>>
|
|
57
|
-
To: <<%=to%>>
|
|
58
|
-
Subject: Amelia email test
|
|
60
|
+
EMAIL_TEST_TEMPLATE=<<~END_OF_TEMPLATE
|
|
61
|
+
From: <%=from_name%> <<%=from_email%>>
|
|
62
|
+
To: <<%=to%>>
|
|
63
|
+
Subject: Amelia email test
|
|
59
64
|
|
|
60
|
-
It worked !
|
|
61
|
-
END_OF_TEMPLATE
|
|
65
|
+
It worked !
|
|
66
|
+
END_OF_TEMPLATE
|
|
62
67
|
# special extended values
|
|
63
|
-
EXTV_INCLUDE_PRESETS
|
|
64
|
-
EXTV_PRESET
|
|
68
|
+
EXTV_INCLUDE_PRESETS=:incps
|
|
69
|
+
EXTV_PRESET=:preset
|
|
70
|
+
PRESET_DIG_SEPARATOR='.'
|
|
65
71
|
DEFAULT_CHECK_NEW_VERSION_DAYS=7
|
|
66
|
-
DEFAULT_PRIV_KEY_FILENAME='aspera_aoc_key'
|
|
72
|
+
DEFAULT_PRIV_KEY_FILENAME='aspera_aoc_key' # pragma: allowlist secret
|
|
67
73
|
DEFAULT_PRIVKEY_LENGTH=4096
|
|
68
74
|
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,
|
|
69
75
|
:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
|
|
70
76
|
:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
|
|
71
77
|
:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
|
|
72
|
-
:EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
when String
|
|
78
|
-
self.options.add_option_preset(preset_by_name(value))
|
|
79
|
-
when Hash
|
|
80
|
-
self.options.add_option_preset(value)
|
|
81
|
-
else
|
|
82
|
-
raise "Preset definition must be a String for name, or Hash for value"
|
|
83
|
-
end
|
|
84
|
-
nil
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def initialize(env,tool_name,help_url,version,main_folder)
|
|
78
|
+
:EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,:CONF_PRESET_SECRETS,
|
|
79
|
+
:PRESET_DIG_SEPARATOR
|
|
80
|
+
def initialize(env,params)
|
|
81
|
+
raise 'env and params must be Hash' unless env.is_a?(Hash) && params.is_a?(Hash)
|
|
82
|
+
raise 'missing param' unless [:name,:help,:version,:gem].sort.eql?(params.keys.sort)
|
|
88
83
|
super(env)
|
|
89
|
-
|
|
84
|
+
@info=params
|
|
85
|
+
@main_folder=default_app_main_folder
|
|
90
86
|
@plugins={}
|
|
91
87
|
@plugin_lookup_folders=[]
|
|
92
88
|
@use_plugin_defaults=true
|
|
93
89
|
@config_presets=nil
|
|
94
90
|
@connect_versions=nil
|
|
95
|
-
@
|
|
96
|
-
@tool_name=tool_name
|
|
97
|
-
@help_url=help_url
|
|
98
|
-
@main_folder=main_folder
|
|
91
|
+
@vault=nil
|
|
99
92
|
@conf_file_default=File.join(@main_folder,DEFAULT_CONFIG_FILENAME)
|
|
100
93
|
@option_config_file=@conf_file_default
|
|
101
|
-
|
|
94
|
+
@pac_exec=nil
|
|
95
|
+
Log.log.debug("#{@info[:name]} folder: #{@main_folder}")
|
|
102
96
|
# set folder for FASP SDK
|
|
103
|
-
add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
|
|
104
97
|
add_plugin_lookup_folder(self.class.gem_plugins_folder)
|
|
98
|
+
add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
|
|
105
99
|
# do file parameter first
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
options.set_obj_attr(:config_file,self,:option_config_file)
|
|
101
|
+
options.add_opt_simple(:config_file,"read parameters from file in YAML format, current=#{@option_config_file}")
|
|
102
|
+
options.parse_options!
|
|
109
103
|
# read correct file
|
|
110
104
|
read_config_file
|
|
111
105
|
# add preset handler (needed for smtp)
|
|
112
106
|
ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
|
|
113
107
|
ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
108
|
+
# load defaults before it can be overriden
|
|
109
|
+
add_plugin_default_preset(CONF_GLOBAL_SYM)
|
|
110
|
+
options.parse_options!
|
|
111
|
+
options.set_obj_attr(:ascp_path,Fasp::Installation.instance,:ascp_path)
|
|
112
|
+
options.set_obj_attr(:sdk_folder,Fasp::Installation.instance,:sdk_folder)
|
|
113
|
+
options.set_obj_attr(:use_product,self,:option_use_product)
|
|
114
|
+
options.set_obj_attr(:preset,self,:option_preset)
|
|
115
|
+
options.set_obj_attr(:plugin_folder,self,:option_plugin_folder)
|
|
116
|
+
options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults=false }
|
|
117
|
+
options.add_opt_boolean(:override,'Wizard: override existing value')
|
|
118
|
+
options.add_opt_boolean(:use_generic_client,'Wizard: AoC: use global or org specific jwt client id')
|
|
119
|
+
options.add_opt_boolean(:default,'Wizard: set as default configuration for specified plugin (also: update)')
|
|
120
|
+
options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
|
|
121
|
+
options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
|
|
122
|
+
options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
|
|
123
|
+
options.add_opt_simple(:ascp_path,'path to ascp')
|
|
124
|
+
options.add_opt_simple(:use_product,'use ascp from specified product')
|
|
125
|
+
options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
|
|
126
|
+
options.add_opt_simple(:fpac,'proxy auto configuration script')
|
|
127
|
+
options.add_opt_simple(:secret,'default secret')
|
|
128
|
+
options.add_opt_simple(:secrets,'secret vault')
|
|
129
|
+
options.add_opt_simple(:sdk_url,'URL to get SDK')
|
|
130
|
+
options.add_opt_simple(:sdk_folder,'SDK folder path')
|
|
131
|
+
options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
|
|
132
|
+
options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
|
|
133
|
+
options.add_opt_simple(:version_check_days,Integer,'period in days to check new version (zero to disable)')
|
|
134
|
+
options.add_opt_simple(:plugin_folder,'folder where to find additional plugins')
|
|
135
|
+
options.set_option(:use_generic_client,true)
|
|
136
|
+
options.set_option(:test_mode,false)
|
|
137
|
+
options.set_option(:default,true)
|
|
138
|
+
options.set_option(:version_check_days,DEFAULT_CHECK_NEW_VERSION_DAYS)
|
|
139
|
+
options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
|
|
140
|
+
options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
|
|
141
|
+
options.set_option(:override,:no)
|
|
142
|
+
options.parse_options!
|
|
143
|
+
pac_script=options.get_option(:fpac,:optional)
|
|
144
|
+
# create PAC executor
|
|
145
|
+
@pac_exec=Aspera::ProxyAutoConfig.new(pac_script).register_uri_generic unless pac_script.nil?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# env var name to override the app's main folder
|
|
149
|
+
# default main folder is $HOME/<vendor main app folder>/<program name>
|
|
150
|
+
def conf_dir_env_var
|
|
151
|
+
return "#{@info[:name]}_home".upcase
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def default_app_main_folder
|
|
155
|
+
# find out application main folder
|
|
156
|
+
app_folder=ENV[conf_dir_env_var]
|
|
157
|
+
# if env var undefined or empty
|
|
158
|
+
if app_folder.nil? || app_folder.empty?
|
|
159
|
+
user_home_folder=Dir.home
|
|
160
|
+
raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
|
|
161
|
+
app_folder=File.join(user_home_folder,ASPERA_HOME_FOLDER_NAME,@info[:name])
|
|
162
|
+
end
|
|
163
|
+
return app_folder
|
|
147
164
|
end
|
|
148
165
|
|
|
149
166
|
def check_gem_version
|
|
150
|
-
this_gem_name=File.basename(File.dirname(self.class.gem_root)).gsub(/-[0-9].*$/,'')
|
|
151
167
|
latest_version=begin
|
|
152
|
-
Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{
|
|
153
|
-
rescue
|
|
168
|
+
Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{@info[:gem]}/latest.json")[:data]['version']
|
|
169
|
+
rescue StandardError
|
|
154
170
|
Log.log.warn('Could not retrieve latest gem version on rubygems.')
|
|
155
171
|
'0'
|
|
156
172
|
end
|
|
157
|
-
|
|
173
|
+
if Gem::Version.new(Environment.ruby_version) < Gem::Version.new(RUBY_FUTURE_MINIMUM_VERSION)
|
|
174
|
+
Log.log.warn("Note that a future version will require Ruby version #{RUBY_FUTURE_MINIMUM_VERSION} at minimum, you are using #{Environment.ruby_version}")
|
|
175
|
+
end
|
|
176
|
+
return {name: @info[:gem], current: Aspera::Cli::VERSION, latest: latest_version, need_update: Gem::Version.new(Aspera::Cli::VERSION) < Gem::Version.new(latest_version)}
|
|
158
177
|
end
|
|
159
178
|
|
|
160
179
|
def periodic_check_newer_gem_version
|
|
@@ -162,37 +181,36 @@ END_OF_TEMPLATE
|
|
|
162
181
|
delay_days=options.get_option(:version_check_days,:mandatory)
|
|
163
182
|
Log.log.info("check days: #{delay_days}")
|
|
164
183
|
# check only if not zero day
|
|
165
|
-
if
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
Log.log.debug("days elapsed: #{last_check_date.is_a?(Date) ? current_date - last_check_date : last_check_date.class.name}")
|
|
180
|
-
if last_check_date.nil? or (current_date - last_check_date) > delay_days
|
|
181
|
-
last_check_array[0]=current_date.strftime('%Y/%m/%d')
|
|
182
|
-
check_date_persist.save
|
|
183
|
-
check_data=check_gem_version
|
|
184
|
-
if check_data[:need_update]
|
|
185
|
-
Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}")
|
|
186
|
-
end
|
|
187
|
-
end
|
|
184
|
+
return if delay_days.eql?(0)
|
|
185
|
+
# get last date from persistency
|
|
186
|
+
last_check_array=[]
|
|
187
|
+
check_date_persist=PersistencyActionOnce.new(
|
|
188
|
+
manager: persistency,
|
|
189
|
+
data: last_check_array,
|
|
190
|
+
id: 'version_last_check')
|
|
191
|
+
# get persisted date or nil
|
|
192
|
+
current_date=Date.today
|
|
193
|
+
last_check_days = begin
|
|
194
|
+
current_date-Date.strptime(last_check_array.first, '%Y/%m/%d')
|
|
195
|
+
rescue StandardError
|
|
196
|
+
# negative value will force check
|
|
197
|
+
-1
|
|
188
198
|
end
|
|
199
|
+
Log.log.debug("days elapsed: #{last_check_days}")
|
|
200
|
+
return if last_check_days < delay_days
|
|
201
|
+
# generate timestamp
|
|
202
|
+
last_check_array[0]=current_date.strftime('%Y/%m/%d')
|
|
203
|
+
check_date_persist.save
|
|
204
|
+
# compare this version and the one on internet
|
|
205
|
+
check_data=check_gem_version
|
|
206
|
+
Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}") if check_data[:need_update]
|
|
189
207
|
end
|
|
190
208
|
|
|
191
209
|
# retrieve structure from cloud (CDN) with all versions available
|
|
192
210
|
def connect_versions
|
|
193
211
|
if @connect_versions.nil?
|
|
194
|
-
api_connect_cdn=Rest.new({:
|
|
195
|
-
javascript=api_connect_cdn.call({:
|
|
212
|
+
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
|
213
|
+
javascript=api_connect_cdn.call({operation: 'GET',subpath: CONNECT_VERSIONS})
|
|
196
214
|
# get result on one line
|
|
197
215
|
connect_versions_javascript=javascript[:http].body.gsub(/\r?\n\s*/,'')
|
|
198
216
|
Log.log.debug("javascript=[\n#{connect_versions_javascript}\n]")
|
|
@@ -212,9 +230,10 @@ END_OF_TEMPLATE
|
|
|
212
230
|
def add_plugin_default_preset(plugin_name_sym)
|
|
213
231
|
default_config_name=get_plugin_default_config_name(plugin_name_sym)
|
|
214
232
|
Log.log.debug("add_plugin_default_preset:#{plugin_name_sym}:#{default_config_name}")
|
|
215
|
-
|
|
233
|
+
options.add_option_preset(preset_by_name(default_config_name),:unshift) unless default_config_name.nil?
|
|
216
234
|
return nil
|
|
217
235
|
end
|
|
236
|
+
|
|
218
237
|
private
|
|
219
238
|
|
|
220
239
|
def generate_rsa_private_key(private_key_path,length)
|
|
@@ -225,40 +244,53 @@ END_OF_TEMPLATE
|
|
|
225
244
|
nil
|
|
226
245
|
end
|
|
227
246
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
247
|
+
class << self
|
|
248
|
+
# folder containing plugins in the gem's main folder
|
|
249
|
+
def gem_plugins_folder
|
|
250
|
+
File.dirname(File.expand_path(__FILE__))
|
|
251
|
+
end
|
|
232
252
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
253
|
+
# name of englobin module
|
|
254
|
+
# @return "Aspera::Cli::Plugins"
|
|
255
|
+
def module_full_name
|
|
256
|
+
return Module.nesting[2].to_s
|
|
257
|
+
end
|
|
238
258
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
end
|
|
259
|
+
# @return main folder where code is, i.e. .../lib
|
|
260
|
+
# go up as many times as englobing modules (not counting class, as it is a file)
|
|
261
|
+
def gem_src_root
|
|
262
|
+
File.expand_path(module_full_name.gsub('::','/').gsub(%r{[^/]+},'..'),gem_plugins_folder)
|
|
263
|
+
end
|
|
245
264
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
265
|
+
# instanciate a plugin
|
|
266
|
+
# plugins must be Capitalized
|
|
267
|
+
def plugin_class(plugin_name_sym)
|
|
268
|
+
# Module.nesting[2] is Aspera::Cli::Plugins
|
|
269
|
+
return Object.const_get("#{module_full_name}::#{plugin_name_sym.to_s.capitalize}")
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def flatten_all_config(t)
|
|
273
|
+
r=[]
|
|
274
|
+
t.each do |k,v|
|
|
275
|
+
v.each do |kk,vv|
|
|
276
|
+
r.push({'config'=>k,'parameter'=>kk,'value'=>vv})
|
|
277
|
+
end
|
|
251
278
|
end
|
|
279
|
+
return r
|
|
252
280
|
end
|
|
253
|
-
return r
|
|
254
281
|
end
|
|
255
282
|
|
|
256
283
|
# set parameter and value in global config
|
|
257
284
|
# creates one if none already created
|
|
258
|
-
# @return preset that contains global default
|
|
285
|
+
# @return preset name that contains global default
|
|
259
286
|
def set_global_default(key,value)
|
|
260
287
|
# get default preset if it exists
|
|
261
|
-
global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
|
288
|
+
global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
|
289
|
+
if global_default_preset_name.nil?
|
|
290
|
+
global_default_preset_name=CONF_PRESET_GLOBAL
|
|
291
|
+
@config_presets[CONF_PRESET_DEFAULT]||={}
|
|
292
|
+
@config_presets[CONF_PRESET_DEFAULT][CONF_GLOBAL_SYM.to_s]=global_default_preset_name
|
|
293
|
+
end
|
|
262
294
|
@config_presets[global_default_preset_name]||={}
|
|
263
295
|
@config_presets[global_default_preset_name][key.to_s]=value
|
|
264
296
|
self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
|
|
@@ -270,27 +302,41 @@ END_OF_TEMPLATE
|
|
|
270
302
|
|
|
271
303
|
# $HOME/.aspera/`program_name`
|
|
272
304
|
attr_reader :main_folder
|
|
273
|
-
attr_reader :gem_url
|
|
274
|
-
attr_reader :plugins
|
|
305
|
+
attr_reader :gem_url, :plugins
|
|
275
306
|
attr_accessor :option_config_file
|
|
276
307
|
|
|
277
308
|
# @return the hash from name (also expands possible includes)
|
|
309
|
+
# @param config_name name of the preset in config file
|
|
310
|
+
# @param include_path used to detect and avoid include loops
|
|
278
311
|
def preset_by_name(config_name, include_path=[])
|
|
279
|
-
raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
|
|
280
312
|
raise CliError,'loop in include' if include_path.include?(config_name)
|
|
281
|
-
|
|
313
|
+
include_path=include_path.clone # avoid messing up if there are multiple branches
|
|
314
|
+
current=@config_presets
|
|
315
|
+
config_name.split(PRESET_DIG_SEPARATOR).each do |name|
|
|
316
|
+
raise CliError,"not a Hash: #{include_path} (#{current.class})" unless current.is_a?(Hash)
|
|
317
|
+
include_path.push(name)
|
|
318
|
+
current=current[name]
|
|
319
|
+
raise CliError,"no such config preset: #{include_path}" if nil?
|
|
320
|
+
end
|
|
321
|
+
case current
|
|
322
|
+
when Hash then return expanded_with_preset_includes(current,include_path)
|
|
323
|
+
when String then return ExtendedValue.instance.evaluate(current)
|
|
324
|
+
else return current
|
|
325
|
+
end
|
|
282
326
|
end
|
|
283
327
|
|
|
328
|
+
# @return the hash value with 'incps' keys expanced to include other presets
|
|
284
329
|
# @param hash_val
|
|
330
|
+
# @param include_path to avoid inclusion loop
|
|
285
331
|
def expanded_with_preset_includes(hash_val, include_path=[])
|
|
286
|
-
raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash" unless hash_val.is_a?(Hash)
|
|
332
|
+
raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash, have #{hash_val.class}" unless hash_val.is_a?(Hash)
|
|
287
333
|
if hash_val.has_key?(EXTV_INCLUDE_PRESETS)
|
|
288
334
|
memory=hash_val.clone
|
|
289
335
|
includes=memory[EXTV_INCLUDE_PRESETS]
|
|
290
336
|
memory.delete(EXTV_INCLUDE_PRESETS)
|
|
291
337
|
hash_val={}
|
|
292
338
|
raise "#{EXTV_INCLUDE_PRESETS} must be an Array" unless includes.is_a?(Array)
|
|
293
|
-
raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map
|
|
339
|
+
raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map(&:class).uniq.eql?([String])
|
|
294
340
|
includes.each do |preset_name|
|
|
295
341
|
hash_val.merge!(preset_by_name(preset_name,include_path))
|
|
296
342
|
end
|
|
@@ -299,20 +345,37 @@ END_OF_TEMPLATE
|
|
|
299
345
|
return hash_val
|
|
300
346
|
end
|
|
301
347
|
|
|
302
|
-
def
|
|
303
|
-
Fasp::Installation.instance.
|
|
348
|
+
def option_use_product=(value)
|
|
349
|
+
Fasp::Installation.instance.use_ascp_from_product(value)
|
|
304
350
|
end
|
|
305
351
|
|
|
306
|
-
def
|
|
307
|
-
|
|
352
|
+
def option_use_product
|
|
353
|
+
'write-only option, see value of ascp_path'
|
|
308
354
|
end
|
|
309
355
|
|
|
310
|
-
def
|
|
311
|
-
|
|
356
|
+
def option_plugin_folder=(value)
|
|
357
|
+
case value
|
|
358
|
+
when String then add_plugin_lookup_folder(value)
|
|
359
|
+
when Array then value.each{|f|add_plugin_lookup_folder(f)}
|
|
360
|
+
else raise "folder shall be Array or String, not #{value.class}"
|
|
361
|
+
end
|
|
312
362
|
end
|
|
313
363
|
|
|
314
|
-
def
|
|
315
|
-
|
|
364
|
+
def option_plugin_folder
|
|
365
|
+
return @plugin_lookup_folders
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def option_preset; 'write-only option'; end
|
|
369
|
+
|
|
370
|
+
def option_preset=(value)
|
|
371
|
+
case value
|
|
372
|
+
when String
|
|
373
|
+
options.add_option_preset(preset_by_name(value))
|
|
374
|
+
when Hash
|
|
375
|
+
options.add_option_preset(value)
|
|
376
|
+
else
|
|
377
|
+
raise 'Preset definition must be a String for name, or Hash for value'
|
|
378
|
+
end
|
|
316
379
|
end
|
|
317
380
|
|
|
318
381
|
def convert_preset_path(old_name,new_name,files_to_copy)
|
|
@@ -323,7 +386,7 @@ END_OF_TEMPLATE
|
|
|
323
386
|
preset.values.select{|v|v.is_a?(String) and v.include?(old_subpath)}.each do |value|
|
|
324
387
|
old_val=value.clone
|
|
325
388
|
included_path=File.expand_path(old_val.gsub(/^@file:/,''))
|
|
326
|
-
files_to_copy.push(included_path) unless files_to_copy.include?(included_path)
|
|
389
|
+
files_to_copy.push(included_path) unless files_to_copy.include?(included_path) || !File.exist?(included_path)
|
|
327
390
|
value.gsub!(old_subpath,new_subpath)
|
|
328
391
|
Log.log.warn("Converted config value: #{old_val} -> #{value}")
|
|
329
392
|
end
|
|
@@ -331,11 +394,11 @@ END_OF_TEMPLATE
|
|
|
331
394
|
end
|
|
332
395
|
|
|
333
396
|
def convert_preset_plugin_name(old_name,new_name)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
397
|
+
default_preset=@config_presets[CONF_PRESET_DEFAULT]
|
|
398
|
+
return unless default_preset.is_a?(Hash) && default_preset.has_key?(old_name)
|
|
399
|
+
default_preset[new_name]=default_preset[old_name]
|
|
400
|
+
default_preset.delete(old_name)
|
|
401
|
+
Log.log.warn("Converted plugin default: #{old_name} -> #{new_name}")
|
|
339
402
|
end
|
|
340
403
|
|
|
341
404
|
# read config file and validate format
|
|
@@ -352,11 +415,11 @@ END_OF_TEMPLATE
|
|
|
352
415
|
# find first existing file (or nil)
|
|
353
416
|
conf_file_to_load=search_files.select{|f| File.exist?(f)}.first
|
|
354
417
|
# require save if old version of file
|
|
355
|
-
save_required
|
|
418
|
+
save_required= !@option_config_file.eql?(conf_file_to_load)
|
|
356
419
|
# if no file found, create default config
|
|
357
420
|
if conf_file_to_load.nil?
|
|
358
421
|
Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
|
|
359
|
-
@config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@
|
|
422
|
+
@config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@info[:version]}}
|
|
360
423
|
else
|
|
361
424
|
Log.log.debug("loading #{@option_config_file}")
|
|
362
425
|
@config_presets=YAML.load_file(conf_file_to_load)
|
|
@@ -393,14 +456,15 @@ END_OF_TEMPLATE
|
|
|
393
456
|
config_tested_version='1.0'
|
|
394
457
|
if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
|
|
395
458
|
convert_preset_plugin_name(AOC_COMMAND_V2,AOC_COMMAND_V3)
|
|
396
|
-
convert_preset_path(PROGRAM_NAME_V2,@
|
|
459
|
+
convert_preset_path(PROGRAM_NAME_V2,@info[:name],files_to_copy)
|
|
397
460
|
version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=config_tested_version
|
|
398
461
|
save_required=true
|
|
399
462
|
end
|
|
463
|
+
Log.log.debug("conf version: #{version}")
|
|
400
464
|
# Place new compatibility code here
|
|
401
465
|
if save_required
|
|
402
466
|
Log.log.warn('Saving automatic conversion.')
|
|
403
|
-
@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@
|
|
467
|
+
@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@info[:version]
|
|
404
468
|
save_presets_to_config_file
|
|
405
469
|
Log.log.warn('Copying referenced files')
|
|
406
470
|
files_to_copy.each do |file|
|
|
@@ -411,9 +475,9 @@ END_OF_TEMPLATE
|
|
|
411
475
|
rescue Psych::SyntaxError => e
|
|
412
476
|
Log.log.error('YAML error in config file')
|
|
413
477
|
raise e
|
|
414
|
-
rescue => e
|
|
478
|
+
rescue StandardError => e
|
|
415
479
|
Log.log.debug("-> #{e}")
|
|
416
|
-
new_name="#{@option_config_file}.pre#{@
|
|
480
|
+
new_name="#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
|
|
417
481
|
File.rename(@option_config_file,new_name)
|
|
418
482
|
Log.log.warn("Renamed config file to #{new_name}.")
|
|
419
483
|
Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
|
|
@@ -424,18 +488,17 @@ END_OF_TEMPLATE
|
|
|
424
488
|
# find plugins in defined paths
|
|
425
489
|
def add_plugins_from_lookup_folders
|
|
426
490
|
@plugin_lookup_folders.each do |folder|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
end
|
|
491
|
+
next unless File.directory?(folder)
|
|
492
|
+
#TODO: add gem root to load path ? and require short folder ?
|
|
493
|
+
#$LOAD_PATH.push(folder) if i[:add_path]
|
|
494
|
+
Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
|
|
495
|
+
add_plugin_info(File.join(folder,source))
|
|
433
496
|
end
|
|
434
497
|
end
|
|
435
498
|
end
|
|
436
499
|
|
|
437
500
|
def add_plugin_lookup_folder(folder)
|
|
438
|
-
@plugin_lookup_folders.
|
|
501
|
+
@plugin_lookup_folders.unshift(folder)
|
|
439
502
|
end
|
|
440
503
|
|
|
441
504
|
def add_plugin_info(path)
|
|
@@ -446,245 +509,319 @@ END_OF_TEMPLATE
|
|
|
446
509
|
Log.log.warn("skipping plugin already registered: #{plugin_symbol}")
|
|
447
510
|
return
|
|
448
511
|
end
|
|
449
|
-
@plugins[plugin_symbol]={:
|
|
512
|
+
@plugins[plugin_symbol]={source: path,require_stanza: req}
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def identify_plugin_for_url(url)
|
|
516
|
+
plugins.each do |plugin_name_sym,plugin_info|
|
|
517
|
+
# no detection for internal plugin
|
|
518
|
+
next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
|
|
519
|
+
# load plugin class
|
|
520
|
+
require plugin_info[:require_stanza]
|
|
521
|
+
c=self.class.plugin_class(plugin_name_sym)
|
|
522
|
+
next unless c.respond_to?(:detect)
|
|
523
|
+
current_url=url
|
|
524
|
+
detection_info=nil
|
|
525
|
+
# first try : direct
|
|
526
|
+
begin
|
|
527
|
+
detection_info=c.detect(current_url)
|
|
528
|
+
rescue StandardError => e
|
|
529
|
+
Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.message}")
|
|
530
|
+
end
|
|
531
|
+
# second try : is there a redirect ?
|
|
532
|
+
if detection_info.nil?
|
|
533
|
+
begin
|
|
534
|
+
# TODO: check if redirect ?
|
|
535
|
+
new_url=Rest.new(base_url: url).call(operation: 'GET',subpath: '',redirect_max: 1)[:http].uri.to_s
|
|
536
|
+
unless url.eql?(new_url)
|
|
537
|
+
detection_info=c.detect(new_url)
|
|
538
|
+
current_url=new_url
|
|
539
|
+
end
|
|
540
|
+
rescue StandardError => e
|
|
541
|
+
Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.message}")
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
return detection_info.merge(product: plugin_name_sym, url: current_url) unless detection_info.nil?
|
|
545
|
+
end # loop
|
|
546
|
+
raise "No known application found at #{url}"
|
|
450
547
|
end
|
|
451
548
|
|
|
452
549
|
def execute_connect_action
|
|
453
|
-
command=
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return {:type=>:object_list, :data=>connect_versions, :fields => ['id','title','version']}
|
|
457
|
-
when :id
|
|
458
|
-
connect_id=self.options.get_next_argument('id or title')
|
|
550
|
+
command=options.get_next_command([:list,:info,:version])
|
|
551
|
+
if [:info,:version].include?(command)
|
|
552
|
+
connect_id=options.get_next_argument('id or title')
|
|
459
553
|
one_res=connect_versions.select{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}.first
|
|
460
554
|
raise CliNoSuchId.new(:connect,connect_id) if one_res.nil?
|
|
461
|
-
|
|
555
|
+
end
|
|
556
|
+
case command
|
|
557
|
+
when :list
|
|
558
|
+
return {type: :object_list, data: connect_versions, fields: ['id','title','version']}
|
|
559
|
+
when :info # shows files used
|
|
560
|
+
one_res.delete('links')
|
|
561
|
+
return {type: :single_object, data: one_res}
|
|
562
|
+
when :version # shows files used
|
|
563
|
+
all_links=one_res['links']
|
|
564
|
+
command=options.get_next_command([:list,:download,:open])
|
|
565
|
+
if [:download,:open].include?(command)
|
|
566
|
+
link_title=options.get_next_argument('title or rel')
|
|
567
|
+
one_link=all_links.select {|i| i['title'].eql?(link_title) or i['rel'].eql?(link_title)}.first
|
|
568
|
+
raise 'no such value' if one_link.nil?
|
|
569
|
+
end
|
|
462
570
|
case command
|
|
463
|
-
when :
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
case command
|
|
477
|
-
when :download #
|
|
478
|
-
folder_dest=self.transfer.destination_folder('receive')
|
|
479
|
-
#folder_dest=self.options.get_next_argument('destination folder')
|
|
480
|
-
api_connect_cdn=Rest.new({:base_url=>CONNECT_WEB_URL})
|
|
481
|
-
fileurl = one_link['href']
|
|
482
|
-
filename=fileurl.gsub(%r{.*/},'')
|
|
483
|
-
api_connect_cdn.call({:operation=>'GET',:subpath=>fileurl,:save_to_file=>File.join(folder_dest,filename)})
|
|
484
|
-
return Main.result_status("Downloaded: #{filename}")
|
|
485
|
-
when :open #
|
|
486
|
-
OpenApplication.instance.uri(one_link['href'])
|
|
487
|
-
return Main.result_status("Opened: #{one_link['href']}")
|
|
488
|
-
end
|
|
489
|
-
end
|
|
571
|
+
when :list # shows files used
|
|
572
|
+
return {type: :object_list, data: all_links}
|
|
573
|
+
when :download
|
|
574
|
+
folder_dest=transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE)
|
|
575
|
+
#folder_dest=self.options.get_next_argument('destination folder')
|
|
576
|
+
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
|
577
|
+
fileurl = one_link['href']
|
|
578
|
+
filename=fileurl.gsub(%r{.*/},'')
|
|
579
|
+
api_connect_cdn.call({operation: 'GET',subpath: fileurl,save_to_file: File.join(folder_dest,filename)})
|
|
580
|
+
return Main.result_status("Downloaded: #{filename}")
|
|
581
|
+
when :open
|
|
582
|
+
OpenApplication.instance.uri(one_link['href'])
|
|
583
|
+
return Main.result_status("Opened: #{one_link['href']}")
|
|
490
584
|
end
|
|
491
585
|
end
|
|
492
586
|
end
|
|
493
587
|
|
|
494
588
|
def execute_action_ascp
|
|
495
|
-
command=
|
|
589
|
+
command=options.get_next_command([:connect,:use,:show,:products,:info,:install,:spec,:errors])
|
|
496
590
|
case command
|
|
497
591
|
when :connect
|
|
498
592
|
return execute_connect_action
|
|
499
593
|
when :use
|
|
500
|
-
ascp_path=
|
|
594
|
+
ascp_path=options.get_next_argument('path to ascp')
|
|
501
595
|
ascp_version=Fasp::Installation.instance.get_ascp_version(ascp_path)
|
|
502
596
|
self.format.display_status("ascp version: #{ascp_version}")
|
|
503
597
|
preset_name=set_global_default(:ascp_path,ascp_path)
|
|
504
598
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
|
505
599
|
when :show # shows files used
|
|
506
|
-
return {:
|
|
600
|
+
return {type: :status, data: Fasp::Installation.instance.path(:ascp)}
|
|
507
601
|
when :info # shows files used
|
|
508
|
-
data=Fasp::Installation::FILES.
|
|
602
|
+
data=Fasp::Installation::FILES.each_with_object({}) do |v,m|
|
|
509
603
|
m[v.to_s]=Fasp::Installation.instance.path(v) rescue 'Not Found'
|
|
510
|
-
m
|
|
511
604
|
end
|
|
512
605
|
# read PATHs from ascp directly, and pvcl modules as well
|
|
513
|
-
Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |
|
|
606
|
+
Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |_stdin, _stdout, stderr, thread|
|
|
514
607
|
last_line=''
|
|
515
|
-
while line=stderr.gets
|
|
608
|
+
while (line=stderr.gets)
|
|
516
609
|
line.chomp!
|
|
517
610
|
last_line=line
|
|
518
611
|
case line
|
|
519
|
-
when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$}
|
|
520
|
-
when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$}
|
|
521
|
-
when %r{^DBG License result \(/license/(\S+)\): (.+)$}
|
|
522
|
-
when %r{^LOG (.+) version ([0-9.]+)$}
|
|
523
|
-
when %r{^LOG Initializing FASP version ([^,]+),}
|
|
612
|
+
when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$} then data[Regexp.last_match(1)]=Regexp.last_match(3)
|
|
613
|
+
when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$} then data[Regexp.last_match(2)]=Regexp.last_match(4)
|
|
614
|
+
when %r{^DBG License result \(/license/(\S+)\): (.+)$} then data[Regexp.last_match(1)]=Regexp.last_match(2)
|
|
615
|
+
when %r{^LOG (.+) version ([0-9.]+)$} then data['product_name']=Regexp.last_match(1);data['product_version']=Regexp.last_match(2)
|
|
616
|
+
when %r{^LOG Initializing FASP version ([^,]+),} then data['ascp_version']=Regexp.last_match(1)
|
|
524
617
|
end
|
|
525
618
|
end
|
|
526
|
-
if !thread.value.exitstatus.eql?(1)
|
|
619
|
+
if !thread.value.exitstatus.eql?(1) && !data.has_key?('root')
|
|
527
620
|
raise last_line
|
|
528
621
|
end
|
|
529
622
|
end
|
|
530
623
|
data['keypass']=Fasp::Installation.instance.bypass_pass
|
|
531
|
-
return {:
|
|
624
|
+
return {type: :single_object, data: data}
|
|
532
625
|
when :products
|
|
533
|
-
command=
|
|
626
|
+
command=options.get_next_command([:list,:use])
|
|
534
627
|
case command
|
|
535
628
|
when :list
|
|
536
|
-
return {:
|
|
629
|
+
return {type: :object_list, data: Fasp::Installation.instance.installed_products, fields: ['name','app_root']}
|
|
537
630
|
when :use
|
|
538
|
-
default_product=
|
|
631
|
+
default_product=options.get_next_argument('product name')
|
|
539
632
|
Fasp::Installation.instance.use_ascp_from_product(default_product)
|
|
540
633
|
preset_name=set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
|
|
541
634
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
|
542
635
|
end
|
|
543
636
|
when :install
|
|
544
|
-
v=Fasp::Installation.instance.install_sdk(
|
|
637
|
+
v=Fasp::Installation.instance.install_sdk(options.get_option(:sdk_url,:mandatory))
|
|
545
638
|
return Main.result_status("Installed version #{v}")
|
|
546
639
|
when :spec
|
|
547
|
-
return {type: :object_list, data: Fasp::Parameters.man_table, fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map
|
|
640
|
+
return {type: :object_list, data: Fasp::Parameters.man_table, fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s),'description'].flatten}
|
|
641
|
+
when :errors
|
|
642
|
+
error_data=[]
|
|
643
|
+
Fasp::ERROR_INFO.each_pair do |code,prop|
|
|
644
|
+
error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
|
|
645
|
+
end
|
|
646
|
+
return {type: :object_list, data: error_data}
|
|
548
647
|
end
|
|
549
648
|
raise "unexpected case: #{command}"
|
|
550
649
|
end
|
|
551
650
|
|
|
552
|
-
|
|
651
|
+
# legacy actions available globally
|
|
652
|
+
PRESET_GBL_ACTIONS=[:list,:overview].freeze
|
|
653
|
+
# require existing preset
|
|
654
|
+
PRESET_EXST_ACTIONS=[:show,:delete,:get,:unset].freeze
|
|
655
|
+
# require id
|
|
656
|
+
PRESET_INSTANCE_ACTIONS=[PRESET_EXST_ACTIONS,:initialize,:update,:ask,:set].flatten.freeze
|
|
657
|
+
PRESET_ALL_ACTIONS=[PRESET_GBL_ACTIONS,PRESET_INSTANCE_ACTIONS].flatten.freeze
|
|
658
|
+
|
|
659
|
+
def execute_file_action(action,config_name)
|
|
660
|
+
action=options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
|
|
661
|
+
config_name=instance_identifier() if config_name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
|
|
662
|
+
# those operations require existing option
|
|
663
|
+
raise "no such preset: #{config_name}" if PRESET_EXST_ACTIONS.include?(action) && !@config_presets.has_key?(config_name)
|
|
664
|
+
selected_preset=@config_presets[config_name]
|
|
665
|
+
case action
|
|
666
|
+
when :list
|
|
667
|
+
return {type: :value_list, data: @config_presets.keys, name: 'name'}
|
|
668
|
+
when :overview
|
|
669
|
+
return {type: :object_list, data: self.class.flatten_all_config(@config_presets)}
|
|
670
|
+
when :show
|
|
671
|
+
raise "no such config: #{config_name}" if selected_preset.nil?
|
|
672
|
+
return {type: :single_object, data: selected_preset}
|
|
673
|
+
when :delete
|
|
674
|
+
@config_presets.delete(config_name)
|
|
675
|
+
save_presets_to_config_file
|
|
676
|
+
return Main.result_status("Deleted: #{config_name}")
|
|
677
|
+
when :get
|
|
678
|
+
param_name=options.get_next_argument('parameter name')
|
|
679
|
+
value=selected_preset[param_name]
|
|
680
|
+
raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
|
|
681
|
+
case value
|
|
682
|
+
when Numeric,String then return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
|
|
683
|
+
end
|
|
684
|
+
return {type: :single_object, data: value}
|
|
685
|
+
when :unset
|
|
686
|
+
param_name=options.get_next_argument('parameter name')
|
|
687
|
+
selected_preset.delete(param_name)
|
|
688
|
+
save_presets_to_config_file
|
|
689
|
+
return Main.result_status("Removed: #{config_name}: #{param_name}")
|
|
690
|
+
when :set
|
|
691
|
+
param_name=options.get_next_argument('parameter name')
|
|
692
|
+
param_value=options.get_next_argument('parameter value')
|
|
693
|
+
if !@config_presets.has_key?(config_name)
|
|
694
|
+
Log.log.debug("no such config name: #{config_name}, initializing")
|
|
695
|
+
selected_preset=@config_presets[config_name]={}
|
|
696
|
+
end
|
|
697
|
+
if selected_preset.has_key?(param_name)
|
|
698
|
+
Log.log.warn("overwriting value: #{selected_preset[param_name]}")
|
|
699
|
+
end
|
|
700
|
+
selected_preset[param_name]=param_value
|
|
701
|
+
save_presets_to_config_file
|
|
702
|
+
return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
|
|
703
|
+
when :initialize
|
|
704
|
+
config_value=options.get_next_argument('extended value (Hash)')
|
|
705
|
+
if @config_presets.has_key?(config_name)
|
|
706
|
+
Log.log.warn("configuration already exists: #{config_name}, overwriting")
|
|
707
|
+
end
|
|
708
|
+
@config_presets[config_name]=config_value
|
|
709
|
+
save_presets_to_config_file
|
|
710
|
+
return Main.result_status("Modified: #{@option_config_file}")
|
|
711
|
+
when :update
|
|
712
|
+
# get unprocessed options
|
|
713
|
+
theopts=options.get_options_table
|
|
714
|
+
Log.log.debug("opts=#{theopts}")
|
|
715
|
+
@config_presets[config_name]||={}
|
|
716
|
+
@config_presets[config_name].merge!(theopts)
|
|
717
|
+
# fix bug in 4.4 (creating key "true" in "default" preset)
|
|
718
|
+
@config_presets[CONF_PRESET_DEFAULT].delete(true) if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash)
|
|
719
|
+
save_presets_to_config_file
|
|
720
|
+
return Main.result_status("Updated: #{config_name}")
|
|
721
|
+
when :ask
|
|
722
|
+
options.ask_missing_mandatory=:yes
|
|
723
|
+
@config_presets[config_name]||={}
|
|
724
|
+
options.get_next_argument('option names',:multiple).each do |optionname|
|
|
725
|
+
option_value=options.get_interactive(:option,optionname)
|
|
726
|
+
@config_presets[config_name][optionname]=option_value
|
|
727
|
+
end
|
|
728
|
+
save_presets_to_config_file
|
|
729
|
+
return Main.result_status("Updated: #{config_name}")
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
ACTIONS=[PRESET_GBL_ACTIONS,:id,:preset,:open,:documentation,:genkey,:gem,:plugin,:flush_tokens,:echo,:wizard,:export_to_cli,:detect,:coffee,:ascp,:email_test,
|
|
734
|
+
:smtp_settings,:proxy_check,:folder,:file,:check_update,:initdemo,:vault].flatten.freeze
|
|
553
735
|
|
|
554
736
|
# "config" plugin
|
|
555
737
|
def execute_action
|
|
556
|
-
action=
|
|
738
|
+
action=options.get_next_command(ACTIONS)
|
|
557
739
|
case action
|
|
558
|
-
when
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
return {:type=>:single_object,:data=>selected_preset}
|
|
568
|
-
when :delete
|
|
569
|
-
@config_presets.delete(config_name)
|
|
570
|
-
save_presets_to_config_file
|
|
571
|
-
return Main.result_status("Deleted: #{config_name}")
|
|
572
|
-
when :get
|
|
573
|
-
param_name=self.options.get_next_argument('parameter name')
|
|
574
|
-
value=selected_preset[param_name]
|
|
575
|
-
raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
|
|
576
|
-
case value
|
|
577
|
-
when Numeric,String; return {:type=>:text,:data=>ExtendedValue.instance.evaluate(value.to_s)}
|
|
578
|
-
end
|
|
579
|
-
return {:type=>:single_object,:data=>value}
|
|
580
|
-
when :unset
|
|
581
|
-
param_name=self.options.get_next_argument('parameter name')
|
|
582
|
-
selected_preset.delete(param_name)
|
|
583
|
-
save_presets_to_config_file
|
|
584
|
-
return Main.result_status("Removed: #{config_name}: #{param_name}")
|
|
585
|
-
when :set
|
|
586
|
-
param_name=self.options.get_next_argument('parameter name')
|
|
587
|
-
param_value=self.options.get_next_argument('parameter value')
|
|
588
|
-
if !@config_presets.has_key?(config_name)
|
|
589
|
-
Log.log.debug("no such config name: #{config_name}, initializing")
|
|
590
|
-
selected_preset=@config_presets[config_name]={}
|
|
591
|
-
end
|
|
592
|
-
if selected_preset.has_key?(param_name)
|
|
593
|
-
Log.log.warn("overwriting value: #{selected_preset[param_name]}")
|
|
594
|
-
end
|
|
595
|
-
selected_preset[param_name]=param_value
|
|
596
|
-
save_presets_to_config_file
|
|
597
|
-
return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
|
|
598
|
-
when :initialize
|
|
599
|
-
config_value=self.options.get_next_argument('extended value (Hash)')
|
|
600
|
-
if @config_presets.has_key?(config_name)
|
|
601
|
-
Log.log.warn("configuration already exists: #{config_name}, overwriting")
|
|
602
|
-
end
|
|
603
|
-
@config_presets[config_name]=config_value
|
|
604
|
-
save_presets_to_config_file
|
|
605
|
-
return Main.result_status("Modified: #{@option_config_file}")
|
|
606
|
-
when :update
|
|
607
|
-
default_for_plugin=self.options.get_option(:default,:mandatory)
|
|
608
|
-
# get unprocessed options
|
|
609
|
-
theopts=self.options.get_options_table
|
|
610
|
-
Log.log.debug("opts=#{theopts}")
|
|
611
|
-
@config_presets[config_name]||={}
|
|
612
|
-
@config_presets[config_name].merge!(theopts)
|
|
613
|
-
if ! default_for_plugin.nil?
|
|
614
|
-
@config_presets[CONF_PRESET_DEFAULT]||=Hash.new
|
|
615
|
-
@config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
|
|
616
|
-
end
|
|
617
|
-
save_presets_to_config_file
|
|
618
|
-
return Main.result_status("Updated: #{config_name}")
|
|
619
|
-
when :ask
|
|
620
|
-
self.options.ask_missing_mandatory=:yes
|
|
621
|
-
@config_presets[config_name]||={}
|
|
622
|
-
self.options.get_next_argument('option names',:multiple).each do |optionname|
|
|
623
|
-
option_value=self.options.get_interactive(:option,optionname)
|
|
624
|
-
@config_presets[config_name][optionname]=option_value
|
|
625
|
-
end
|
|
626
|
-
save_presets_to_config_file
|
|
627
|
-
return Main.result_status("Updated: #{config_name}")
|
|
628
|
-
end
|
|
740
|
+
when *PRESET_GBL_ACTIONS # older syntax
|
|
741
|
+
return execute_file_action(action,nil)
|
|
742
|
+
when :id # older syntax
|
|
743
|
+
return execute_file_action(nil,options.get_next_argument('config name'))
|
|
744
|
+
when :preset # newer syntax
|
|
745
|
+
return execute_file_action(nil,nil)
|
|
746
|
+
when :open
|
|
747
|
+
OpenApplication.instance.uri(@option_config_file.to_s) #file://
|
|
748
|
+
return Main.result_nothing
|
|
629
749
|
when :documentation
|
|
630
750
|
section=options.get_next_argument('private key file path',:single,:optional)
|
|
631
751
|
section='#'+section unless section.nil?
|
|
632
|
-
OpenApplication.instance.uri("#{@
|
|
633
|
-
return Main.result_nothing
|
|
634
|
-
when :open
|
|
635
|
-
OpenApplication.instance.uri("#{@option_config_file}") #file://
|
|
752
|
+
OpenApplication.instance.uri("#{@info[:help]}#{section}")
|
|
636
753
|
return Main.result_nothing
|
|
637
754
|
when :genkey # generate new rsa key
|
|
638
|
-
private_key_path=
|
|
755
|
+
private_key_path=options.get_next_argument('private key file path')
|
|
639
756
|
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
|
640
757
|
return Main.result_status('Generated key: '+private_key_path)
|
|
641
758
|
when :echo # display the content of a value given on command line
|
|
642
|
-
result={:
|
|
759
|
+
result={type: :other_struct, data: options.get_next_argument('value')}
|
|
643
760
|
# special for csv
|
|
644
|
-
result[:type]=:object_list if result[:data].is_a?(Array)
|
|
761
|
+
result[:type]=:object_list if result[:data].is_a?(Array) && result[:data].first.is_a?(Hash)
|
|
645
762
|
return result
|
|
646
763
|
when :flush_tokens
|
|
647
764
|
deleted_files=Oauth.flush_tokens
|
|
648
|
-
return {:
|
|
649
|
-
when :
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
765
|
+
return {type: :value_list, data: deleted_files, name: 'file'}
|
|
766
|
+
when :plugin
|
|
767
|
+
case options.get_next_command([:list,:create])
|
|
768
|
+
when :list
|
|
769
|
+
return {type: :object_list, data: @plugins.keys.map { |i| { 'plugin' => i.to_s, 'path' => @plugins[i][:source] } }, fields: ['plugin','path']}
|
|
770
|
+
when :create
|
|
771
|
+
plugin_name=options.get_next_argument('name',:single,:mandatory).downcase
|
|
772
|
+
plugin_folder=options.get_next_argument('folder',:single,:optional) || File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME)
|
|
773
|
+
plugin_file=File.join(plugin_folder,"#{plugin_name}.rb")
|
|
774
|
+
content=<<~END_OF_PLUGIN_CODE
|
|
775
|
+
require 'aspera/cli/plugin'
|
|
776
|
+
module Aspera
|
|
777
|
+
module Cli
|
|
778
|
+
module Plugins
|
|
779
|
+
class #{plugin_name.capitalize} < Plugin
|
|
780
|
+
ACTIONS=[]
|
|
781
|
+
def execute_action; return Main.result_status('You called plugin #{plugin_name}'); end
|
|
782
|
+
end # #{plugin_name.capitalize}
|
|
783
|
+
end # Plugins
|
|
784
|
+
end # Cli
|
|
785
|
+
end # Aspera
|
|
786
|
+
END_OF_PLUGIN_CODE
|
|
787
|
+
File.write(plugin_file,content)
|
|
788
|
+
return Main.result_status("Created #{plugin_file}")
|
|
789
|
+
end
|
|
655
790
|
when :wizard
|
|
656
791
|
# interactive mode
|
|
657
|
-
|
|
792
|
+
options.ask_missing_mandatory=true
|
|
658
793
|
# register url option
|
|
659
794
|
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
|
660
795
|
# get from option, or ask
|
|
661
|
-
instance_url=
|
|
796
|
+
instance_url=options.get_option(:url,:mandatory)
|
|
662
797
|
# allow user to tell the preset name
|
|
663
|
-
preset_name=
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
798
|
+
preset_name=options.get_option(:id,:optional)
|
|
799
|
+
# allow user to specify type of application
|
|
800
|
+
application=options.get_option(:value,:optional)
|
|
801
|
+
application=application.nil? ? identify_plugin_for_url(instance_url)[:product] : application.to_sym
|
|
802
|
+
plugin_name='<replace per app>'
|
|
803
|
+
test_args='<replace per app>'
|
|
804
|
+
case application
|
|
668
805
|
when :aoc
|
|
669
806
|
self.format.display_status('Detected: Aspera on Cloud'.bold)
|
|
670
807
|
plugin_name=AOC_COMMAND_CURRENT
|
|
671
|
-
organization
|
|
808
|
+
organization=AoC.parse_url(instance_url).first
|
|
672
809
|
# if not defined by user, generate name
|
|
673
|
-
preset_name=[
|
|
810
|
+
preset_name=[application,organization].join('_') if preset_name.nil?
|
|
674
811
|
self.format.display_status("Preparing preset: #{preset_name}")
|
|
675
812
|
# init defaults if necessary
|
|
676
813
|
@config_presets[CONF_PRESET_DEFAULT]||={}
|
|
677
|
-
option_override=
|
|
678
|
-
option_default=
|
|
814
|
+
option_override=options.get_option(:override,:mandatory)
|
|
815
|
+
option_default=options.get_option(:default,:mandatory)
|
|
679
816
|
Log.log.error("override=#{option_override} -> #{option_override.class}")
|
|
680
|
-
raise CliError,"A default configuration already exists for plugin '#{plugin_name}' (use --override=yes or --default=no)" if !option_override
|
|
681
|
-
raise CliError,"Preset already exists: #{preset_name} (use --override=yes or --id=<name>)" if !option_override
|
|
817
|
+
raise CliError,"A default configuration already exists for plugin '#{plugin_name}' (use --override=yes or --default=no)" if !option_override && option_default && @config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_name)
|
|
818
|
+
raise CliError,"Preset already exists: #{preset_name} (use --override=yes or --id=<name>)" if !option_override && @config_presets.has_key?(preset_name)
|
|
682
819
|
# lets see if path to priv key is provided
|
|
683
|
-
private_key_path=
|
|
820
|
+
private_key_path=options.get_option(:pkeypath,:optional)
|
|
684
821
|
# give a chance to provide
|
|
685
822
|
if private_key_path.nil?
|
|
686
823
|
self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
|
687
|
-
private_key_path=
|
|
824
|
+
private_key_path=options.get_option(:pkeypath,:mandatory).to_s
|
|
688
825
|
end
|
|
689
826
|
# else generate path
|
|
690
827
|
if private_key_path.empty?
|
|
@@ -702,74 +839,73 @@ END_OF_TEMPLATE
|
|
|
702
839
|
# declare command line options for AoC
|
|
703
840
|
require 'aspera/cli/plugins/aoc'
|
|
704
841
|
# make username mandatory for jwt, this triggers interactive input
|
|
705
|
-
|
|
842
|
+
options.get_option(:username,:mandatory)
|
|
706
843
|
# instanciate AoC plugin, so that command line options are known
|
|
707
|
-
|
|
708
|
-
aoc_api=files_plugin.get_api
|
|
844
|
+
aoc_api=self.class.plugin_class(plugin_name).new(@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path})).aoc_api
|
|
709
845
|
auto_set_pub_key=false
|
|
710
846
|
auto_set_jwt=false
|
|
711
847
|
use_browser_authentication=false
|
|
712
|
-
if
|
|
848
|
+
if options.get_option(:use_generic_client)
|
|
713
849
|
self.format.display_status('Using global client_id.')
|
|
714
850
|
self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
|
|
715
851
|
self.format.display_status('Navigate to your "Account Settings"'.red)
|
|
716
852
|
self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
|
|
717
|
-
self.format.display_status(
|
|
718
|
-
if !
|
|
853
|
+
self.format.display_status(pub_key_pem.to_s)
|
|
854
|
+
if !options.get_option(:test_mode)
|
|
719
855
|
self.format.display_status('Once updated or validated, press enter.')
|
|
720
856
|
OpenApplication.instance.uri(instance_url)
|
|
721
|
-
|
|
857
|
+
$stdin.gets
|
|
722
858
|
end
|
|
723
859
|
else
|
|
724
860
|
self.format.display_status('Using organization specific client_id.')
|
|
725
|
-
if
|
|
861
|
+
if options.get_option(:client_id,:optional).nil? || options.get_option(:client_secret,:optional).nil?
|
|
726
862
|
self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
|
|
727
863
|
self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
|
|
728
864
|
self.format.display_status('Create or check if there is an existing integration named:')
|
|
729
|
-
self.format.display_status("- name: #{@
|
|
865
|
+
self.format.display_status("- name: #{@info[:name]}")
|
|
730
866
|
self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
|
731
867
|
self.format.display_status('- origin: localhost')
|
|
732
868
|
self.format.display_status('Once created or identified,')
|
|
733
869
|
self.format.display_status('Please enter:'.red)
|
|
734
870
|
end
|
|
735
871
|
OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
|
|
736
|
-
|
|
737
|
-
|
|
872
|
+
options.get_option(:client_id,:mandatory)
|
|
873
|
+
options.get_option(:client_secret,:mandatory)
|
|
738
874
|
use_browser_authentication=true
|
|
739
875
|
end
|
|
740
876
|
if use_browser_authentication
|
|
741
877
|
self.format.display_status('We will use web authentication to bootstrap.')
|
|
742
878
|
auto_set_pub_key=true
|
|
743
879
|
auto_set_jwt=true
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
880
|
+
aoc_api.oauth.params[:crtype]=:web
|
|
881
|
+
aoc_api.oauth.params[:web][:redirect_uri]=DEFAULT_REDIRECT
|
|
882
|
+
aoc_api.oauth.params[:scope]=AoC::SCOPE_FILES_ADMIN
|
|
747
883
|
end
|
|
748
884
|
myself=aoc_api.read('self')[:data]
|
|
749
885
|
if auto_set_pub_key
|
|
750
|
-
raise CliError,'Public key is already set in profile (use --override=yes)'
|
|
886
|
+
raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
|
|
751
887
|
self.format.display_status('Updating profile with new key')
|
|
752
888
|
aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
|
|
753
889
|
end
|
|
754
890
|
if auto_set_jwt
|
|
755
891
|
self.format.display_status('Enabling JWT for client')
|
|
756
|
-
aoc_api.update("clients/#{
|
|
892
|
+
aoc_api.update("clients/#{options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
|
|
757
893
|
end
|
|
758
894
|
self.format.display_status("Creating new config preset: #{preset_name}")
|
|
759
895
|
@config_presets[preset_name]={
|
|
760
|
-
:url.to_s =>
|
|
896
|
+
:url.to_s =>options.get_option(:url),
|
|
761
897
|
:username.to_s =>myself['email'],
|
|
762
898
|
:auth.to_s =>:jwt.to_s,
|
|
763
|
-
:private_key.to_s =>'@file:'+private_key_path
|
|
899
|
+
:private_key.to_s =>'@file:'+private_key_path
|
|
764
900
|
}
|
|
765
901
|
# set only if non nil
|
|
766
902
|
[:client_id,:client_secret].each do |s|
|
|
767
|
-
o=
|
|
903
|
+
o=options.get_option(s)
|
|
768
904
|
@config_presets[preset_name][s.to_s] = o unless o.nil?
|
|
769
905
|
end
|
|
770
|
-
test_args="#{plugin_name} user
|
|
906
|
+
test_args="#{plugin_name} user profile show"
|
|
771
907
|
else
|
|
772
|
-
raise CliBadArgument,"Supports only: aoc. Detected: #{
|
|
908
|
+
raise CliBadArgument,"Supports only: aoc. Detected: #{application}"
|
|
773
909
|
end # product
|
|
774
910
|
if option_default
|
|
775
911
|
self.format.display_status("Setting config preset as default for #{plugin_name}")
|
|
@@ -779,29 +915,29 @@ END_OF_TEMPLATE
|
|
|
779
915
|
end
|
|
780
916
|
self.format.display_status('Saving config file.')
|
|
781
917
|
save_presets_to_config_file
|
|
782
|
-
return Main.result_status("Done.\nYou can test with:\n#{@
|
|
918
|
+
return Main.result_status("Done.\nYou can test with:\n#{@info[:name]} #{test_args}")
|
|
783
919
|
when :export_to_cli
|
|
784
920
|
self.format.display_status('Exporting: Aspera on Cloud')
|
|
785
921
|
require 'aspera/cli/plugins/aoc'
|
|
786
922
|
# need url / username
|
|
787
923
|
add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
|
|
788
924
|
# instanciate AoC plugin
|
|
789
|
-
|
|
790
|
-
url=
|
|
925
|
+
self.class.plugin_class(AOC_COMMAND_CURRENT).new(@agents) # TODO: is this line needed ? get options ?
|
|
926
|
+
url=options.get_option(:url,:mandatory)
|
|
791
927
|
cli_conf_file=Fasp::Installation.instance.cli_conf_file
|
|
792
928
|
data=JSON.parse(File.read(cli_conf_file))
|
|
793
929
|
organization,instance_domain=AoC.parse_url(url)
|
|
794
930
|
key_basename='org_'+organization+'.pem'
|
|
795
931
|
key_file=File.join(File.dirname(File.dirname(cli_conf_file)),'etc',key_basename)
|
|
796
|
-
File.write(key_file,
|
|
932
|
+
File.write(key_file,options.get_option(:private_key,:mandatory))
|
|
797
933
|
new_conf={
|
|
798
934
|
'organization' => organization,
|
|
799
935
|
'hostname' => [organization,instance_domain].join('.'),
|
|
800
936
|
'privateKeyFilename' => key_basename,
|
|
801
|
-
'username' =>
|
|
937
|
+
'username' => options.get_option(:username,:mandatory)
|
|
802
938
|
}
|
|
803
|
-
new_conf['clientId']=
|
|
804
|
-
new_conf['clientSecret']=
|
|
939
|
+
new_conf['clientId']=options.get_option(:client_id,:optional)
|
|
940
|
+
new_conf['clientSecret']=options.get_option(:client_secret,:optional)
|
|
805
941
|
if new_conf['clientId'].nil?
|
|
806
942
|
new_conf['clientId'],new_conf['clientSecret']=AoC.get_client_info()
|
|
807
943
|
end
|
|
@@ -818,14 +954,18 @@ END_OF_TEMPLATE
|
|
|
818
954
|
when :detect
|
|
819
955
|
# need url / username
|
|
820
956
|
BasicAuthPlugin.new(@agents)
|
|
821
|
-
return
|
|
957
|
+
return {type: :single_object, data: identify_plugin_for_url(options.get_option(:url,:mandatory))}
|
|
822
958
|
when :coffee
|
|
823
959
|
OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
|
|
824
960
|
return Main.result_nothing
|
|
825
961
|
when :ascp
|
|
826
962
|
execute_action_ascp
|
|
827
|
-
when :
|
|
828
|
-
|
|
963
|
+
when :gem
|
|
964
|
+
case options.get_next_command([:path,:version,:name])
|
|
965
|
+
when :path then return Main.result_status(self.class.gem_src_root)
|
|
966
|
+
when :version then return Main.result_status(Aspera::Cli::VERSION)
|
|
967
|
+
when :name then return Main.result_status(@info[:gem])
|
|
968
|
+
end
|
|
829
969
|
when :folder
|
|
830
970
|
return Main.result_status(@main_folder)
|
|
831
971
|
when :file
|
|
@@ -834,19 +974,21 @@ END_OF_TEMPLATE
|
|
|
834
974
|
send_email_template({},EMAIL_TEST_TEMPLATE)
|
|
835
975
|
return Main.result_nothing
|
|
836
976
|
when :smtp_settings
|
|
837
|
-
return {:
|
|
977
|
+
return {type: :single_object, data: email_settings}
|
|
838
978
|
when :proxy_check
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
979
|
+
# ensure fpac was provided
|
|
980
|
+
options.get_option(:fpac,:mandatory)
|
|
981
|
+
server_url=options.get_next_argument('server url')
|
|
982
|
+
return Main.result_status(@pac_exec.find_proxy_for_url(server_url))
|
|
842
983
|
when :check_update
|
|
843
|
-
return {:
|
|
984
|
+
return {type: :single_object, data: check_gem_version}
|
|
844
985
|
when :initdemo
|
|
845
986
|
if @config_presets.has_key?(DEMO_SERVER_PRESET)
|
|
846
987
|
Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
|
|
847
988
|
else
|
|
848
989
|
Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
|
|
849
|
-
@config_presets[DEMO_SERVER_PRESET]=
|
|
990
|
+
@config_presets[DEMO_SERVER_PRESET]=
|
|
991
|
+
{'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
|
|
850
992
|
end
|
|
851
993
|
@config_presets[CONF_PRESET_DEFAULT]||={}
|
|
852
994
|
if @config_presets[CONF_PRESET_DEFAULT].has_key?(SERVER_COMMAND)
|
|
@@ -857,16 +999,56 @@ END_OF_TEMPLATE
|
|
|
857
999
|
Log.log.info("Setting server default preset to : #{DEMO_SERVER_PRESET}")
|
|
858
1000
|
end
|
|
859
1001
|
save_presets_to_config_file
|
|
860
|
-
return Main.result_status(
|
|
1002
|
+
return Main.result_status('Done')
|
|
1003
|
+
when :vault
|
|
1004
|
+
command=options.get_next_command([:init,:list,:get,:set,:delete])
|
|
1005
|
+
case command
|
|
1006
|
+
when :init
|
|
1007
|
+
type=options.get_option(:value,:optional)
|
|
1008
|
+
case type
|
|
1009
|
+
when 'config',NilClass
|
|
1010
|
+
raise 'default secrets already exists' if @config_presets.has_key?(CONF_PRESET_SECRETS)
|
|
1011
|
+
@config_presets[CONF_PRESET_SECRETS]={}
|
|
1012
|
+
set_global_default(:secrets,"@preset:#{CONF_PRESET_SECRETS}")
|
|
1013
|
+
else raise 'no such vault type'
|
|
1014
|
+
end
|
|
1015
|
+
return Main.result_status('Done')
|
|
1016
|
+
when :list
|
|
1017
|
+
return {type: :object_list, data: vault.list}
|
|
1018
|
+
when :set
|
|
1019
|
+
# register url option
|
|
1020
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
|
1021
|
+
username=options.get_option(:username,:mandatory)
|
|
1022
|
+
url=options.get_option(:url,:mandatory)
|
|
1023
|
+
description=options.get_option(:value,:optional)
|
|
1024
|
+
secret=options.get_next_argument('secret')
|
|
1025
|
+
vault.set(username: username, url: url, description: description, secret: secret)
|
|
1026
|
+
save_presets_to_config_file if vault.is_a?(Keychain::EncryptedHash)
|
|
1027
|
+
return Main.result_status('Done')
|
|
1028
|
+
when :get
|
|
1029
|
+
# register url option
|
|
1030
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
|
1031
|
+
username=options.get_option(:username,:mandatory)
|
|
1032
|
+
url=options.get_option(:url,:optional)
|
|
1033
|
+
result=vault.get(username: username, url: url)
|
|
1034
|
+
return {type: :single_object, data: result}
|
|
1035
|
+
when :delete
|
|
1036
|
+
# register url option
|
|
1037
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
|
1038
|
+
username=options.get_option(:username,:mandatory)
|
|
1039
|
+
url=options.get_option(:url,:optional)
|
|
1040
|
+
vault.delete(username: username, url: url)
|
|
1041
|
+
return Main.result_status('Done')
|
|
1042
|
+
end
|
|
861
1043
|
else raise 'INTERNAL ERROR: wrong case'
|
|
862
1044
|
end
|
|
863
1045
|
end
|
|
864
1046
|
|
|
865
1047
|
# @return email server setting with defaults if not defined
|
|
866
1048
|
def email_settings
|
|
867
|
-
smtp=
|
|
1049
|
+
smtp=options.get_option(:smtp,:mandatory)
|
|
868
1050
|
# change string keys into symbol keys
|
|
869
|
-
smtp=smtp.keys.
|
|
1051
|
+
smtp=smtp.keys.each_with_object({}){|v,m|m[v.to_sym]=smtp[v];}
|
|
870
1052
|
# defaults
|
|
871
1053
|
smtp[:tls]||=true
|
|
872
1054
|
smtp[:port]||=smtp[:tls]?587:25
|
|
@@ -896,7 +1078,7 @@ END_OF_TEMPLATE
|
|
|
896
1078
|
raise "Missing email parameter: #{n}" unless vars.has_key?(n)
|
|
897
1079
|
end
|
|
898
1080
|
start_options=[mail_conf[:domain]]
|
|
899
|
-
start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username)
|
|
1081
|
+
start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) && mail_conf.has_key?(:password)
|
|
900
1082
|
# create a binding with only variables defined in vars
|
|
901
1083
|
template_binding=empty_binding
|
|
902
1084
|
# add variables to binding
|
|
@@ -909,8 +1091,8 @@ END_OF_TEMPLATE
|
|
|
909
1091
|
Log.dump(:msg_with_headers,msg_with_headers)
|
|
910
1092
|
smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
|
|
911
1093
|
smtp.enable_starttls if mail_conf[:tls]
|
|
912
|
-
smtp.start(*start_options) do |
|
|
913
|
-
|
|
1094
|
+
smtp.start(*start_options) do |smtp_session|
|
|
1095
|
+
smtp_session.send_message(msg_with_headers, vars[:from_email], vars[:to])
|
|
914
1096
|
end
|
|
915
1097
|
end
|
|
916
1098
|
|
|
@@ -924,16 +1106,16 @@ END_OF_TEMPLATE
|
|
|
924
1106
|
# returns [String] name if config_presets has default
|
|
925
1107
|
# returns nil if there is no config or bypass default params
|
|
926
1108
|
def get_plugin_default_config_name(plugin_sym)
|
|
927
|
-
raise
|
|
1109
|
+
raise 'internal error: config_presets shall be defined' if @config_presets.nil?
|
|
928
1110
|
if !@use_plugin_defaults
|
|
929
1111
|
Log.log.debug('skip default config')
|
|
930
1112
|
return nil
|
|
931
1113
|
end
|
|
932
|
-
if @config_presets.has_key?(CONF_PRESET_DEFAULT)
|
|
1114
|
+
if @config_presets.has_key?(CONF_PRESET_DEFAULT) &&
|
|
933
1115
|
@config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_sym.to_s)
|
|
934
1116
|
default_config_name=@config_presets[CONF_PRESET_DEFAULT][plugin_sym.to_s]
|
|
935
1117
|
if !@config_presets.has_key?(default_config_name)
|
|
936
|
-
Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym
|
|
1118
|
+
Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym}], but it does not exist in config file.\nPlease fix the issue: either create preset with one parameter (#{@info[:name]} config id #{default_config_name} init @json:'{}') or remove default (#{@info[:name]} config id default remove #{plugin_sym}).")
|
|
937
1119
|
end
|
|
938
1120
|
raise CliError,"Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
|
|
939
1121
|
return default_config_name
|
|
@@ -941,6 +1123,42 @@ END_OF_TEMPLATE
|
|
|
941
1123
|
return nil
|
|
942
1124
|
end # get_plugin_default_config_name
|
|
943
1125
|
|
|
1126
|
+
def vault
|
|
1127
|
+
if @vault.nil?
|
|
1128
|
+
vault_info=options.get_option(:secrets,:optional)
|
|
1129
|
+
case vault_info
|
|
1130
|
+
when Hash
|
|
1131
|
+
@vault=Keychain::EncryptedHash.new(vault_info)
|
|
1132
|
+
when /^system/
|
|
1133
|
+
name=vault_info.start_with?('system:') ? vault_info[7..-1] : nil
|
|
1134
|
+
case Environment.os
|
|
1135
|
+
when Environment::OS_X
|
|
1136
|
+
@vault=Keychain::MacosSecurity.new(name)
|
|
1137
|
+
when Environment::OS_WINDOWS,Environment::OS_LINUX,Environment::OS_AIX
|
|
1138
|
+
raise 'not implemented'
|
|
1139
|
+
else raise 'Error'
|
|
1140
|
+
end
|
|
1141
|
+
when NilClass
|
|
1142
|
+
# keep nil
|
|
1143
|
+
else
|
|
1144
|
+
raise CliBadArgument,'secrets shall be Hash'
|
|
1145
|
+
end
|
|
1146
|
+
end
|
|
1147
|
+
raise 'No vault defined' if @vault.nil?
|
|
1148
|
+
@vault
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
def get_secret(options)
|
|
1152
|
+
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
1153
|
+
raise 'options shall have username' unless options.has_key?(:username)
|
|
1154
|
+
secret=self.options.get_option(:secret,:optional)
|
|
1155
|
+
if secret.nil?
|
|
1156
|
+
secret=vault.get(options) rescue nil
|
|
1157
|
+
# mandatory by default
|
|
1158
|
+
raise "please provide secret for #{options[:username]}" if secret.nil? && (options[:mandatory].nil? || options[:mandatory])
|
|
1159
|
+
end
|
|
1160
|
+
return secret
|
|
1161
|
+
end
|
|
944
1162
|
end
|
|
945
1163
|
end
|
|
946
1164
|
end
|