aspera-cli 4.4.0 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|