aspera-cli 4.0.0 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +843 -304
- data/bin/dascli +13 -0
- data/docs/Makefile +4 -4
- data/docs/README.erb.md +805 -172
- data/docs/test_env.conf +22 -3
- data/examples/aoc.rb +14 -3
- data/examples/faspex4.rb +89 -0
- data/lib/aspera/aoc.rb +87 -108
- data/lib/aspera/cli/formater.rb +2 -0
- data/lib/aspera/cli/main.rb +89 -49
- data/lib/aspera/cli/plugin.rb +9 -4
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +188 -173
- data/lib/aspera/cli/plugins/ats.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +218 -145
- data/lib/aspera/cli/plugins/console.rb +2 -2
- data/lib/aspera/cli/plugins/faspex.rb +114 -61
- data/lib/aspera/cli/plugins/faspex5.rb +85 -43
- data/lib/aspera/cli/plugins/node.rb +3 -3
- data/lib/aspera/cli/plugins/preview.rb +59 -45
- data/lib/aspera/cli/plugins/server.rb +23 -8
- data/lib/aspera/cli/transfer_agent.rb +77 -49
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +49 -31
- data/lib/aspera/cos_node.rb +33 -28
- data/lib/aspera/environment.rb +2 -2
- data/lib/aspera/fasp/connect.rb +28 -21
- data/lib/aspera/fasp/http_gw.rb +140 -28
- data/lib/aspera/fasp/installation.rb +93 -46
- data/lib/aspera/fasp/local.rb +88 -45
- data/lib/aspera/fasp/manager.rb +15 -0
- data/lib/aspera/fasp/node.rb +4 -4
- data/lib/aspera/fasp/parameters.rb +59 -101
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/resume_policy.rb +13 -12
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/log.rb +1 -1
- data/lib/aspera/node.rb +61 -1
- data/lib/aspera/oauth.rb +49 -46
- data/lib/aspera/persistency_folder.rb +9 -4
- data/lib/aspera/preview/file_types.rb +53 -21
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/rest.rb +29 -18
- data/lib/aspera/secrets.rb +20 -0
- data/lib/aspera/sync.rb +40 -35
- data/lib/aspera/temp_file_manager.rb +19 -0
- data/lib/aspera/web_auth.rb +105 -0
- metadata +54 -20
- data/docs/transfer_spec.html +0 -99
data/lib/aspera/cli/main.rb
CHANGED
@@ -10,6 +10,7 @@ require 'aspera/persistency_folder'
|
|
10
10
|
require 'aspera/log'
|
11
11
|
require 'aspera/rest'
|
12
12
|
require 'aspera/nagios'
|
13
|
+
require 'aspera/secrets'
|
13
14
|
|
14
15
|
module Aspera
|
15
16
|
module Cli
|
@@ -20,15 +21,17 @@ module Aspera
|
|
20
21
|
private
|
21
22
|
# name of application, also foldername where config is stored
|
22
23
|
PROGRAM_NAME = 'ascli'
|
24
|
+
# name of the containing gem, same as in <gem name>.gemspec
|
23
25
|
GEM_NAME = 'aspera-cli'
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
HELP_URL = "http://www.rubydoc.info/gems/#{GEM_NAME}"
|
27
|
+
GEM_URL = "https://rubygems.org/gems/#{GEM_NAME}"
|
28
|
+
SRC_URL = "https://github.com/IBM/aspera-cli"
|
29
|
+
STATUS_FIELD = 'status'
|
27
30
|
|
31
|
+
private_constant :PROGRAM_NAME,:GEM_NAME,:HELP_URL,:GEM_URL
|
28
32
|
# =============================================================
|
29
33
|
# Parameter handlers
|
30
34
|
#
|
31
|
-
|
32
35
|
def option_insecure; Rest.insecure ; end
|
33
36
|
|
34
37
|
def option_insecure=(value); Rest.insecure = value; end
|
@@ -39,32 +42,41 @@ module Aspera
|
|
39
42
|
|
40
43
|
# minimum initialization
|
41
44
|
def initialize(argv)
|
42
|
-
# first thing : manage debug level (allows debugging
|
45
|
+
# first thing : manage debug level (allows debugging of option parser)
|
43
46
|
early_debug_setup(argv)
|
47
|
+
# compare $0 with expected name
|
44
48
|
current_prog_name=File.basename($PROGRAM_NAME)
|
45
49
|
unless current_prog_name.eql?(PROGRAM_NAME)
|
46
50
|
@plugin_env[:formater].display_message(:error,"#{"WARNING".bg_red.blink.gray} Please use '#{PROGRAM_NAME}' instead of '#{current_prog_name}', '#{current_prog_name}' will be removed in a future version")
|
47
51
|
end
|
48
|
-
# overriding parameters on transfer spec
|
49
52
|
@option_help=false
|
50
53
|
@bash_completion=false
|
51
54
|
@option_show_config=false
|
55
|
+
# environment provided to plugin for various capabilities
|
52
56
|
@plugin_env={}
|
53
|
-
|
54
|
-
|
57
|
+
# find out application main folder
|
58
|
+
app_main_folder=ENV[conf_dir_env_var]
|
59
|
+
# if env var undefined or empty
|
60
|
+
if app_main_folder.nil? or app_main_folder.empty?
|
61
|
+
user_home_folder=Dir.home
|
62
|
+
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)
|
63
|
+
app_main_folder=File.join(user_home_folder,Plugins::Config::ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME)
|
64
|
+
end
|
55
65
|
# give command line arguments to option manager (no parsing)
|
56
|
-
@plugin_env[:options]=@opt_mgr=Manager.new(
|
66
|
+
@plugin_env[:options]=@opt_mgr=Manager.new(PROGRAM_NAME,argv,app_banner())
|
57
67
|
@plugin_env[:formater]=Formater.new(@plugin_env[:options])
|
58
|
-
Rest.user_agent=
|
59
|
-
#
|
68
|
+
Rest.user_agent=PROGRAM_NAME
|
69
|
+
# declare and parse global options
|
60
70
|
init_global_options()
|
71
|
+
# secret manager
|
72
|
+
@plugin_env[:secret]=Aspera::Secrets.new
|
61
73
|
# the Config plugin adds the @preset parser
|
62
|
-
@plugin_env[:config]=Plugins::Config.new(@plugin_env,
|
74
|
+
@plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,HELP_URL,Aspera::Cli::VERSION,app_main_folder)
|
63
75
|
# the TransferAgent plugin may use the @preset parser
|
64
76
|
@plugin_env[:transfer]=TransferAgent.new(@plugin_env)
|
65
|
-
Log.log.debug('created plugin env'.red)
|
66
77
|
# set application folder for modules
|
67
78
|
@plugin_env[:persistency]=PersistencyFolder.new(File.join(@plugin_env[:config].main_folder,'persist_store'))
|
79
|
+
Log.log.debug('plugin env created'.red)
|
68
80
|
Oauth.persist_mgr=@plugin_env[:persistency]
|
69
81
|
Fasp::Parameters.file_list_folder=File.join(@plugin_env[:config].main_folder,'filelists')
|
70
82
|
Aspera::RestErrorAnalyzer.instance.log_file=File.join(@plugin_env[:config].main_folder,'rest_exceptions.log')
|
@@ -73,21 +85,21 @@ module Aspera
|
|
73
85
|
end
|
74
86
|
|
75
87
|
def app_banner
|
76
|
-
banner = "NAME\n\t#{
|
88
|
+
banner = "NAME\n\t#{PROGRAM_NAME} -- a command line tool for Aspera Applications (v#{Aspera::Cli::VERSION})\n\n"
|
77
89
|
banner << "SYNOPSIS\n"
|
78
|
-
banner << "\t#{
|
79
|
-
banner << "\n"
|
80
|
-
banner << "DESCRIPTION\n"
|
90
|
+
banner << "\t#{PROGRAM_NAME} COMMANDS [OPTIONS] [ARGS]\n"
|
91
|
+
banner << "\nDESCRIPTION\n"
|
81
92
|
banner << "\tUse Aspera application to perform operations on command line.\n"
|
82
|
-
banner << "\tDocumentation and examples: #{
|
83
|
-
banner << "\texecute: #{
|
84
|
-
banner << "\tor visit: #{
|
85
|
-
banner << "\n"
|
86
|
-
banner << "
|
87
|
-
banner << "\
|
93
|
+
banner << "\tDocumentation and examples: #{GEM_URL}\n"
|
94
|
+
banner << "\texecute: #{PROGRAM_NAME} conf doc\n"
|
95
|
+
banner << "\tor visit: #{HELP_URL}\n"
|
96
|
+
banner << "\nENVIRONMENT VARIABLES\n"
|
97
|
+
banner << "\t#{conf_dir_env_var} config folder, default: $HOME/#{Plugins::Config::ASPERA_HOME_FOLDER_NAME}/#{PROGRAM_NAME}\n"
|
98
|
+
banner << "\t#any option can be set as an environment variable, refer to the manual\n"
|
99
|
+
banner << "\nCOMMANDS\n"
|
100
|
+
banner << "\tTo list first level commands, execute: #{PROGRAM_NAME}\n"
|
88
101
|
banner << "\tNote that commands can be written shortened (provided it is unique).\n"
|
89
|
-
banner << "\n"
|
90
|
-
banner << "OPTIONS\n"
|
102
|
+
banner << "\nOPTIONS\n"
|
91
103
|
banner << "\tOptions begin with a '-' (minus), and value is provided on command line.\n"
|
92
104
|
banner << "\tSpecial values are supported beginning with special prefix, like: #{ExtendedValue.instance.modifiers.map{|m|"@#{m}:"}.join(' ')}.\n"
|
93
105
|
banner << "\tDates format is 'DD-MM-YY HH:MM:SS', or 'now' or '-<num>h'\n\n"
|
@@ -167,7 +179,7 @@ module Aspera
|
|
167
179
|
# override main option parser with a brand new, to avoid having global options
|
168
180
|
plugin_env=@plugin_env.clone
|
169
181
|
plugin_env[:man_only]=true
|
170
|
-
plugin_env[:options]=Manager.new(
|
182
|
+
plugin_env[:options]=Manager.new(PROGRAM_NAME,[],'')
|
171
183
|
get_plugin_instance_with_options(plugin_name_sym,plugin_env)
|
172
184
|
# display generated help for plugin options
|
173
185
|
@plugin_env[:formater].display_message(:error,plugin_env[:options].parser.to_s)
|
@@ -178,10 +190,16 @@ module Aspera
|
|
178
190
|
|
179
191
|
protected
|
180
192
|
|
193
|
+
# env var name to override the app's main folder
|
194
|
+
# default main folder is $HOME/<vendor main app folder>/<program name>
|
195
|
+
def conf_dir_env_var
|
196
|
+
return "#{PROGRAM_NAME}_home".upcase
|
197
|
+
end
|
198
|
+
|
181
199
|
# early debug for parser
|
182
200
|
# Note: does not accept shortcuts
|
183
201
|
def early_debug_setup(argv)
|
184
|
-
Log.instance.program_name=
|
202
|
+
Log.instance.program_name=PROGRAM_NAME
|
185
203
|
argv.each do |arg|
|
186
204
|
case arg
|
187
205
|
when '--'
|
@@ -205,14 +223,28 @@ module Aspera
|
|
205
223
|
return Main.result_nothing
|
206
224
|
end
|
207
225
|
|
208
|
-
|
209
|
-
|
210
|
-
|
226
|
+
# used when one command executes several transfer jobs (each job being possibly multi session)
|
227
|
+
# @param status_table [Array] [{STATUS_FIELD=>[status array],...},...]
|
228
|
+
# each element has a key STATUS_FIELD which contains the result of possibly mulmtiple sessions
|
229
|
+
def self.result_transfer_multiple(status_table)
|
230
|
+
global_status=:success
|
231
|
+
# transform status into string and find if there was problem
|
232
|
+
status_table.each do |item|
|
233
|
+
worst=TransferAgent.session_status(item[STATUS_FIELD])
|
234
|
+
global_status=worst unless worst.eql?(:success)
|
235
|
+
item[STATUS_FIELD]=item[STATUS_FIELD].map{|i|i.to_s}.join(',')
|
236
|
+
end
|
237
|
+
raise global_status unless global_status.eql?(:success)
|
238
|
+
return {:type=>:object_list,:data=>status_table}
|
239
|
+
end
|
211
240
|
|
212
241
|
# this is the main function called by initial script just after constructor
|
213
242
|
def process_command_line
|
214
243
|
Log.log.debug('process_command_line')
|
244
|
+
# catch exception information , if any
|
215
245
|
exception_info=nil
|
246
|
+
# false if command shall not be executed ("once_only")
|
247
|
+
execute_command=true
|
216
248
|
begin
|
217
249
|
# find plugins, shall be after parse! ?
|
218
250
|
@plugin_env[:config].add_plugins_from_lookup_folders
|
@@ -222,16 +254,7 @@ module Aspera
|
|
222
254
|
# load global default options and process
|
223
255
|
@plugin_env[:config].add_plugin_default_preset(Plugins::Config::CONF_GLOBAL_SYM)
|
224
256
|
@opt_mgr.parse_options!
|
225
|
-
|
226
|
-
lock_port=@opt_mgr.get_option(:lock_port,:optional)
|
227
|
-
if !lock_port.nil?
|
228
|
-
begin
|
229
|
-
# no need to close later, will be freed on process exit. must save in member else it is garbage collected
|
230
|
-
@tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
|
231
|
-
rescue => e
|
232
|
-
raise CliError,"Another instance is already running (lock port=#{lock_port})."
|
233
|
-
end
|
234
|
-
end
|
257
|
+
@plugin_env[:config].periodic_check_newer_gem_version
|
235
258
|
if @option_show_config and @opt_mgr.command_or_arg_empty?
|
236
259
|
command_sym=Plugins::Config::CONF_PLUGIN_SYM
|
237
260
|
else
|
@@ -255,18 +278,30 @@ module Aspera
|
|
255
278
|
@plugin_env[:formater].display_results({:type=>:single_object,:data=>@opt_mgr.declared_options(false)})
|
256
279
|
Process.exit(0)
|
257
280
|
end
|
258
|
-
#
|
259
|
-
|
281
|
+
# locking for single execution (only after "per plugin" option, in case lock port is there)
|
282
|
+
lock_port=@opt_mgr.get_option(:lock_port,:optional)
|
283
|
+
if !lock_port.nil?
|
284
|
+
begin
|
285
|
+
# no need to close later, will be freed on process exit. must save in member else it is garbage collected
|
286
|
+
Log.log.debug("Opening lock port #{lock_port.to_i}")
|
287
|
+
@tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
|
288
|
+
rescue => e
|
289
|
+
execute_command=false
|
290
|
+
Log.log.warn("Another instance is already running (#{e.message}).")
|
291
|
+
end
|
292
|
+
end
|
293
|
+
# execute and display (if not exclusive execution)
|
294
|
+
@plugin_env[:formater].display_results(command_plugin.execute_action) if execute_command
|
260
295
|
# finish
|
261
296
|
@plugin_env[:transfer].shutdown
|
262
297
|
rescue CliBadArgument => e; exception_info=[e,'Argument',:usage]
|
263
298
|
rescue CliNoSuchId => e; exception_info=[e,'Identifier']
|
264
299
|
rescue CliError => e; exception_info=[e,'Tool',:usage]
|
265
|
-
rescue Fasp::Error => e; exception_info=[e,
|
266
|
-
rescue Aspera::RestCallError => e;
|
267
|
-
rescue SocketError => e; exception_info=[e,
|
268
|
-
rescue StandardError => e; exception_info=[e,
|
269
|
-
rescue Interrupt => e; exception_info=[e,
|
300
|
+
rescue Fasp::Error => e; exception_info=[e,'FASP(ascp)']
|
301
|
+
rescue Aspera::RestCallError => e; exception_info=[e,'Rest']
|
302
|
+
rescue SocketError => e; exception_info=[e,'Network']
|
303
|
+
rescue StandardError => e; exception_info=[e,'Other',:debug]
|
304
|
+
rescue Interrupt => e; exception_info=[e,'Interruption',:debug]
|
270
305
|
end
|
271
306
|
# cleanup file list files
|
272
307
|
TempFileManager.instance.cleanup
|
@@ -274,10 +309,15 @@ module Aspera
|
|
274
309
|
unless exception_info.nil?
|
275
310
|
@plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" "+exception_info[1]+": "+exception_info[0].message)
|
276
311
|
@plugin_env[:formater].display_message(:error,"Use '-h' option to get help.") if exception_info[2].eql?(:usage)
|
312
|
+
if exception_info.first.is_a?(Fasp::Error) and exception_info.first.message.eql?('Remote host is not who we expected')
|
313
|
+
@plugin_env[:formater].display_message(:error,"For this specific error, refer to:\n#{SRC_URL}#error-remote-host-is-not-who-we-expected\nAdd this to arguments:\n--ts=@json:'{\"sshfp\":null}'")
|
314
|
+
end
|
277
315
|
end
|
278
316
|
# 2- processing of command not processed (due to exception or bad command line)
|
279
|
-
|
280
|
-
@
|
317
|
+
if execute_command
|
318
|
+
@opt_mgr.final_errors.each do |msg|
|
319
|
+
@plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" Argument: "+msg)
|
320
|
+
end
|
281
321
|
end
|
282
322
|
# 3- in case of error, fail the process status
|
283
323
|
unless exception_info.nil?
|
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -67,7 +67,10 @@ module Aspera
|
|
67
67
|
when :delete
|
68
68
|
rest_api.delete(one_res_path)
|
69
69
|
return Main.result_status("deleted")
|
70
|
+
else
|
71
|
+
raise "unknown action: #{command}"
|
70
72
|
end
|
73
|
+
raise "internal error should not reach here"
|
71
74
|
end
|
72
75
|
|
73
76
|
# implement generic rest operations on given resource path
|
@@ -77,13 +80,15 @@ module Aspera
|
|
77
80
|
return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,subkey)
|
78
81
|
end
|
79
82
|
|
80
|
-
def options
|
83
|
+
def options; return @agents[:options];end
|
81
84
|
|
82
|
-
def transfer
|
85
|
+
def transfer; return @agents[:transfer];end
|
83
86
|
|
84
|
-
def config;return @agents[:config];end
|
87
|
+
def config; return @agents[:config];end
|
85
88
|
|
86
|
-
def format;return @agents[:formater];end
|
89
|
+
def format; return @agents[:formater];end
|
90
|
+
|
91
|
+
def persistency; return @agents[:persistency];end
|
87
92
|
|
88
93
|
end # Plugin
|
89
94
|
end # Cli
|
@@ -12,7 +12,7 @@ module Aspera
|
|
12
12
|
command=self.options.get_next_command(ACTIONS)
|
13
13
|
case command
|
14
14
|
when :entitlement
|
15
|
-
entitlement_id = self.options.get_option(:username,:mandatory)
|
15
|
+
entitlement_id = self.options.get_option(:username,:mandatory)
|
16
16
|
customer_id = self.options.get_option(:password,:mandatory)
|
17
17
|
api_metering=AoC.metering_api(entitlement_id,customer_id)
|
18
18
|
return {:type=>:single_object, :data=>api_metering.read('entitlement')[:data]}
|