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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +843 -304
  3. data/bin/dascli +13 -0
  4. data/docs/Makefile +4 -4
  5. data/docs/README.erb.md +805 -172
  6. data/docs/test_env.conf +22 -3
  7. data/examples/aoc.rb +14 -3
  8. data/examples/faspex4.rb +89 -0
  9. data/lib/aspera/aoc.rb +87 -108
  10. data/lib/aspera/cli/formater.rb +2 -0
  11. data/lib/aspera/cli/main.rb +89 -49
  12. data/lib/aspera/cli/plugin.rb +9 -4
  13. data/lib/aspera/cli/plugins/alee.rb +1 -1
  14. data/lib/aspera/cli/plugins/aoc.rb +188 -173
  15. data/lib/aspera/cli/plugins/ats.rb +2 -2
  16. data/lib/aspera/cli/plugins/config.rb +218 -145
  17. data/lib/aspera/cli/plugins/console.rb +2 -2
  18. data/lib/aspera/cli/plugins/faspex.rb +114 -61
  19. data/lib/aspera/cli/plugins/faspex5.rb +85 -43
  20. data/lib/aspera/cli/plugins/node.rb +3 -3
  21. data/lib/aspera/cli/plugins/preview.rb +59 -45
  22. data/lib/aspera/cli/plugins/server.rb +23 -8
  23. data/lib/aspera/cli/transfer_agent.rb +77 -49
  24. data/lib/aspera/cli/version.rb +1 -1
  25. data/lib/aspera/command_line_builder.rb +49 -31
  26. data/lib/aspera/cos_node.rb +33 -28
  27. data/lib/aspera/environment.rb +2 -2
  28. data/lib/aspera/fasp/connect.rb +28 -21
  29. data/lib/aspera/fasp/http_gw.rb +140 -28
  30. data/lib/aspera/fasp/installation.rb +93 -46
  31. data/lib/aspera/fasp/local.rb +88 -45
  32. data/lib/aspera/fasp/manager.rb +15 -0
  33. data/lib/aspera/fasp/node.rb +4 -4
  34. data/lib/aspera/fasp/parameters.rb +59 -101
  35. data/lib/aspera/fasp/parameters.yaml +531 -0
  36. data/lib/aspera/fasp/resume_policy.rb +13 -12
  37. data/lib/aspera/fasp/uri.rb +1 -1
  38. data/lib/aspera/log.rb +1 -1
  39. data/lib/aspera/node.rb +61 -1
  40. data/lib/aspera/oauth.rb +49 -46
  41. data/lib/aspera/persistency_folder.rb +9 -4
  42. data/lib/aspera/preview/file_types.rb +53 -21
  43. data/lib/aspera/preview/generator.rb +3 -3
  44. data/lib/aspera/rest.rb +29 -18
  45. data/lib/aspera/secrets.rb +20 -0
  46. data/lib/aspera/sync.rb +40 -35
  47. data/lib/aspera/temp_file_manager.rb +19 -0
  48. data/lib/aspera/web_auth.rb +105 -0
  49. metadata +54 -20
  50. data/docs/transfer_spec.html +0 -99
@@ -1,16 +1,20 @@
1
1
  require 'aspera/cli/basic_auth_plugin'
2
2
  require 'aspera/cli/extended_value'
3
3
  require 'aspera/fasp/installation'
4
+ require 'aspera/fasp/parameters'
4
5
  require 'aspera/api_detector'
5
6
  require 'aspera/open_application'
6
7
  require 'aspera/aoc'
7
8
  require 'aspera/proxy_auto_config'
8
9
  require 'aspera/uri_reader'
9
10
  require 'aspera/rest'
11
+ require 'aspera/persistency_action_once'
10
12
  require 'xmlsimple'
11
13
  require 'base64'
12
14
  require 'net/smtp'
13
15
  require 'open3'
16
+ require 'date'
17
+ require 'erb'
14
18
 
15
19
  module Aspera
16
20
  module Cli
@@ -25,6 +29,7 @@ module Aspera
25
29
  CONF_PRESET_CONFIG='config'
26
30
  CONF_PRESET_VERSION='version'
27
31
  CONF_PRESET_DEFAULT='default'
32
+ CONF_PRESET_GLOBAL='global_common_defaults'
28
33
  CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
29
34
  CONF_GLOBAL_SYM = :config
30
35
  # old tool name
@@ -41,20 +46,28 @@ module Aspera
41
46
  AOC_COMMAND_CURRENT=AOC_COMMAND_V3
42
47
  CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
43
48
  CONNECT_VERSIONS = 'connectversions.js'
49
+ TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_sdk'
44
50
  DEMO='demo'
51
+ DEMO_SERVER_PRESET='demoserver'
52
+ AOC_PATH_API_CLIENTS='admin/api-clients'
53
+ EMAIL_TEST_TEMPLATE=<<END_OF_TEMPLATE
54
+ From: <%=from_name%> <<%=from_email%>>
55
+ To: <<%=to%>>
56
+ Subject: Amelia email test
57
+
58
+ It worked !
59
+ END_OF_TEMPLATE
45
60
  def option_preset; nil; end
46
61
 
47
62
  def option_preset=(value)
48
63
  self.options.add_option_preset(preset_by_name(value))
49
64
  end
50
65
 
51
- private_constant :ASPERA_HOME_FOLDER_NAME,:DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO
52
- attr_accessor :option_ak_secret,:option_secrets
66
+ private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE
53
67
 
54
- def initialize(env,tool_name,help_url,version)
68
+ def initialize(env,tool_name,help_url,version,main_folder)
55
69
  super(env)
56
- @option_ak_secret=nil
57
- @option_secrets={}
70
+ raise 'missing secret manager' if @agents[:secret].nil?
58
71
  @plugins={}
59
72
  @plugin_lookup_folders=[]
60
73
  @use_plugin_defaults=true
@@ -63,19 +76,11 @@ module Aspera
63
76
  @program_version=version
64
77
  @tool_name=tool_name
65
78
  @help_url=help_url
66
- tool_main_env_var="#{tool_name.upcase}_HOME"
67
- if ENV.has_key?(tool_main_env_var)
68
- @main_folder=ENV[tool_main_env_var]
69
- else
70
- user_home_folder=Dir.home
71
- raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{tool_main_env_var}." unless Dir.exist?(user_home_folder)
72
- @main_folder=File.join(user_home_folder,ASPERA_HOME_FOLDER_NAME,tool_name)
73
- end
79
+ @main_folder=main_folder
74
80
  @conf_file_default=File.join(@main_folder,DEFAULT_CONFIG_FILENAME)
75
81
  @option_config_file=@conf_file_default
76
82
  Log.log.debug("#{tool_name} folder: #{@main_folder}")
77
83
  # set folder for FASP SDK
78
- Fasp::Installation.instance.folder=File.join(@main_folder,'sdk')
79
84
  add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
80
85
  add_plugin_lookup_folder(self.class.gem_plugins_folder)
81
86
  # do file parameter first
@@ -91,35 +96,76 @@ module Aspera
91
96
  self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
92
97
  self.options.set_obj_attr(:use_product,self,:option_use_product)
93
98
  self.options.set_obj_attr(:preset,self,:option_preset)
94
- self.options.set_obj_attr(:secret,self,:option_ak_secret)
95
- self.options.set_obj_attr(:secrets,self,:option_secrets)
96
- self.options.add_opt_boolean(:override,"override existing value")
97
- self.options.add_opt_switch(:no_default,"-N","do not load default configuration for plugin") { @use_plugin_defaults=false }
99
+ self.options.set_obj_attr(:secret,@agents[:secret],:default_secret)
100
+ self.options.set_obj_attr(:secrets,@agents[:secret],:all_secrets)
101
+ self.options.add_opt_boolean(:override,'override existing value')
102
+ self.options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults=false }
98
103
  self.options.add_opt_boolean(:use_generic_client,'wizard: AoC: use global or org specific jwt client id')
99
- self.options.add_opt_simple(:pkeypath,"path to private key for JWT (wizard)")
100
- self.options.add_opt_simple(:ascp_path,"path to ascp")
101
- self.options.add_opt_simple(:use_product,"use ascp from specified product")
102
- self.options.add_opt_simple(:smtp,"smtp configuration (extended value: hash)")
103
- self.options.add_opt_simple(:fpac,"proxy auto configuration URL")
104
- self.options.add_opt_simple(:preset,"-PVALUE","load the named option preset from current config file")
105
- self.options.add_opt_simple(:default,"set as default configuration for specified plugin")
106
- self.options.add_opt_simple(:secret,"access key secret for node")
107
- self.options.add_opt_simple(:secrets,"access key secret for node")
108
- self.options.add_opt_boolean(:test_mode,"skip user validation in wizard mode")
104
+ self.options.add_opt_simple(:pkeypath,'path to private key for JWT (wizard)')
105
+ self.options.add_opt_simple(:ascp_path,'path to ascp')
106
+ self.options.add_opt_simple(:use_product,'use ascp from specified product')
107
+ self.options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
108
+ self.options.add_opt_simple(:fpac,'proxy auto configuration URL')
109
+ self.options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
110
+ self.options.add_opt_simple(:default,'set as default configuration for specified plugin')
111
+ self.options.add_opt_simple(:secret,'default secret')
112
+ self.options.add_opt_simple(:secrets,'secret repository (Hash)')
113
+ self.options.add_opt_simple(:sdk_url,'URL to get SDK')
114
+ self.options.add_opt_simple(:sdk_folder,'SDK folder location')
115
+ self.options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
116
+ self.options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
117
+ self.options.add_opt_boolean(:test_mode,'skip user validation in wizard mode')
118
+ self.options.add_opt_simple(:version_check_days,Integer,'period to check neew version in days (zero to disable)')
109
119
  self.options.set_option(:use_generic_client,true)
110
120
  self.options.set_option(:test_mode,false)
121
+ self.options.set_option(:version_check_days,7)
122
+ self.options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
123
+ self.options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
111
124
  self.options.parse_options!
112
- raise CliBadArgument,"secrets shall be Hash" unless @option_secrets.is_a?(Hash)
125
+ raise CliBadArgument,'secrets shall be Hash' unless @agents[:secret].all_secrets.is_a?(Hash)
126
+ Fasp::Installation.instance.folder=self.options.get_option(:sdk_folder,:mandatory)
113
127
  end
114
128
 
115
- def get_secret(id=nil,mandatory=true)
116
- secret=self.options.get_option(:secret,:optional) || @option_secrets[id]
117
- raise "please provide secret for #{id}" if secret.nil? and mandatory
118
- return secret
129
+ def check_gem_version
130
+ this_gem_name=File.basename(File.dirname(self.class.gem_root)).gsub(/-[0-9].*$/,'')
131
+ latest_version=begin
132
+ Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{this_gem_name}/latest.json")[:data]['version']
133
+ rescue
134
+ Log.log.warn('Could not retrieve latest gem version on rubygems.')
135
+ '0'
136
+ end
137
+ return {name: this_gem_name, current: Aspera::Cli::VERSION, latest: latest_version, need_update: Gem::Version.new(Aspera::Cli::VERSION) < Gem::Version.new(latest_version)}
119
138
  end
120
139
 
121
- def get_secrets
122
- return @option_secrets
140
+ def periodic_check_newer_gem_version
141
+ # get verification period
142
+ delay_days=options.get_option(:version_check_days,:mandatory)
143
+ Log.log.info("check days: #{delay_days}")
144
+ # check only if not zero day
145
+ if !delay_days.eql?(0)
146
+ # get last date from persistency
147
+ last_check_array=[]
148
+ check_date_persist=PersistencyActionOnce.new(
149
+ manager: persistency,
150
+ data: last_check_array,
151
+ ids: ['version_last_check'])
152
+ # get persisted date or nil
153
+ last_check_date = begin
154
+ Date.strptime(last_check_array.first, '%Y/%m/%d')
155
+ rescue
156
+ nil
157
+ end
158
+ current_date=Date.today
159
+ Log.log.debug("days elapsed: #{last_check_date.is_a?(Date) ? current_date - last_check_date : last_check_date.class.name}")
160
+ if last_check_date.nil? or (current_date - last_check_date) > delay_days
161
+ last_check_array[0]=current_date.strftime('%Y/%m/%d')
162
+ check_date_persist.save
163
+ check_data=check_gem_version
164
+ if check_data[:need_update]
165
+ Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}")
166
+ end
167
+ end
168
+ end
123
169
  end
124
170
 
125
171
  # retrieve structure from cloud (CDN) with all versions available
@@ -155,7 +201,7 @@ module Aspera
155
201
  require 'openssl'
156
202
  priv_key = OpenSSL::PKey::RSA.new(4096)
157
203
  File.write(private_key_path,priv_key.to_s)
158
- File.write(private_key_path+".pub",priv_key.public_key.to_s)
204
+ File.write(private_key_path+'.pub',priv_key.public_key.to_s)
159
205
  nil
160
206
  end
161
207
 
@@ -181,7 +227,7 @@ module Aspera
181
227
  r=[]
182
228
  t.each do |k,v|
183
229
  v.each do |kk,vv|
184
- r.push({"config"=>k,"parameter"=>kk,"value"=>vv})
230
+ r.push({'config'=>k,'parameter'=>kk,'value'=>vv})
185
231
  end
186
232
  end
187
233
  return r
@@ -191,12 +237,12 @@ module Aspera
191
237
  # creates one if none already created
192
238
  # @return preset that contains global default
193
239
  def set_global_default(key,value)
194
- global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
195
- if global_default_preset_name.nil?
196
- global_default_preset_name='global_common_defaults'
197
- @config_presets[global_default_preset_name]={}
198
- end
240
+ # get default preset if it exists
241
+ global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM) || CONF_PRESET_GLOBAL
242
+ @config_presets[global_default_preset_name]||={}
199
243
  @config_presets[global_default_preset_name][key.to_s]=value
244
+ self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
245
+ save_presets_to_config_file
200
246
  return global_default_preset_name
201
247
  end
202
248
 
@@ -215,7 +261,7 @@ module Aspera
215
261
  # @return the hash from name (also expands possible includes)
216
262
  def preset_by_name(config_name, include_path=[])
217
263
  raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
218
- raise CliError,"loop in include" if include_path.include?(config_name)
264
+ raise CliError,'loop in include' if include_path.include?(config_name)
219
265
  return expanded_with_preset_includes(@config_presets[config_name],include_path.clone.push(config_name))
220
266
  end
221
267
 
@@ -250,7 +296,7 @@ module Aspera
250
296
  end
251
297
 
252
298
  def option_use_product
253
- "write-only value"
299
+ 'write-only value'
254
300
  end
255
301
 
256
302
  def convert_preset_path(old_name,new_name,files_to_copy)
@@ -294,22 +340,21 @@ module Aspera
294
340
  # if no file found, create default config
295
341
  if conf_file_to_load.nil?
296
342
  Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
297
- @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version},CONF_PRESET_DEFAULT=>{'server'=>'demoserver'},
298
- 'demoserver'=>{'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}}
343
+ @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version}}
299
344
  else
300
345
  Log.log.debug "loading #{@option_config_file}"
301
346
  @config_presets=YAML.load_file(conf_file_to_load)
302
347
  end
303
348
  files_to_copy=[]
304
349
  Log.log.debug "Available_presets: #{@config_presets}"
305
- raise "Expecting YAML Hash" unless @config_presets.is_a?(Hash)
350
+ raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
306
351
  # check there is at least the config section
307
352
  if !@config_presets.has_key?(CONF_PRESET_CONFIG)
308
353
  raise "Cannot find key: #{CONF_PRESET_CONFIG}"
309
354
  end
310
355
  version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
311
356
  if version.nil?
312
- raise "No version found in config section."
357
+ raise 'No version found in config section.'
313
358
  end
314
359
  # oldest compatible conf file format, update to latest version when an incompatible change is made
315
360
  # check compatibility of version of conf file
@@ -338,24 +383,24 @@ module Aspera
338
383
  end
339
384
  # Place new compatibility code here
340
385
  if save_required
341
- Log.log.warn("Saving automatic conversion.")
386
+ Log.log.warn('Saving automatic conversion.')
342
387
  @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@program_version
343
388
  save_presets_to_config_file
344
- Log.log.warn("Copying referenced files")
389
+ Log.log.warn('Copying referenced files')
345
390
  files_to_copy.each do |file|
346
391
  FileUtils.cp(file,@main_folder)
347
392
  Log.log.warn("..#{file} -> #{@main_folder}")
348
393
  end
349
394
  end
350
395
  rescue Psych::SyntaxError => e
351
- Log.log.error("YAML error in config file")
396
+ Log.log.error('YAML error in config file')
352
397
  raise e
353
398
  rescue => e
354
399
  Log.log.debug("-> #{e}")
355
400
  new_name="#{@option_config_file}.pre#{@program_version}.manual_conversion_needed"
356
401
  File.rename(@option_config_file,new_name)
357
402
  Log.log.warn("Renamed config file to #{new_name}.")
358
- Log.log.warn("Manual Conversion is required. Next time, a new empty file will be created.")
403
+ Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
359
404
  raise CliError,e.to_s
360
405
  end
361
406
  end
@@ -420,10 +465,10 @@ module Aspera
420
465
  fileurl = one_link['href']
421
466
  filename=fileurl.gsub(%r{.*/},'')
422
467
  api_connect_cdn.call({:operation=>'GET',:subpath=>fileurl,:save_to_file=>File.join(folder_dest,filename)})
423
- return Main.result_status("downloaded: #{filename}")
468
+ return Main.result_status("Downloaded: #{filename}")
424
469
  when :open #
425
470
  OpenApplication.instance.uri(one_link['href'])
426
- return Main.result_status("opened: #{one_link['href']}")
471
+ return Main.result_status("Opened: #{one_link['href']}")
427
472
  end
428
473
  end
429
474
  end
@@ -431,29 +476,29 @@ module Aspera
431
476
  end
432
477
 
433
478
  def execute_action_ascp
434
- command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install])
479
+ command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install,:spec])
435
480
  case command
436
481
  when :connect
437
482
  return execute_connect_action
438
483
  when :use
439
- default_ascp=self.options.get_next_argument('path to ascp')
440
- raise "file name must be ascp" unless File.basename(default_ascp).eql?('ascp')
441
- raise "no such file: #{default_ascp}" unless File.exist?(default_ascp)
442
- raise "not executable: #{default_ascp}" unless File.executable?(default_ascp)
443
- preset_name=set_global_default(:ascp_path,default_ascp)
444
- save_presets_to_config_file
445
- return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
484
+ ascp_path=self.options.get_next_argument('path to ascp')
485
+ ascp_version=Fasp::Installation.instance.get_ascp_version(ascp_path)
486
+ self.format.display_status("ascp version: #{ascp_version}")
487
+ preset_name=set_global_default(:ascp_path,ascp_path)
488
+ return Main.result_status("Saved to default global preset #{preset_name}")
446
489
  when :show # shows files used
447
490
  return {:type=>:status, :data=>Fasp::Installation.instance.path(:ascp)}
448
491
  when :info # shows files used
449
492
  data=Fasp::Installation::FILES.inject({}) do |m,v|
450
- m[v.to_s]=Fasp::Installation.instance.path(v) rescue "Not Found"
493
+ m[v.to_s]=Fasp::Installation.instance.path(v) rescue 'Not Found'
451
494
  m
452
495
  end
453
496
  # read PATHs from ascp directly, and pvcl modules as well
454
497
  Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |stdin, stdout, stderr, thread|
498
+ last_line=''
455
499
  while line=stderr.gets do
456
500
  line.chomp!
501
+ last_line=line
457
502
  case line
458
503
  when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$};data[$1]=$3
459
504
  when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$};data[$2]=$4
@@ -462,6 +507,9 @@ module Aspera
462
507
  when %r{^LOG Initializing FASP version ([^,]+),};data['ascp_version']=$1
463
508
  end
464
509
  end
510
+ if !thread.value.exitstatus.eql?(1) and !data.has_key?('root')
511
+ raise last_line
512
+ end
465
513
  end
466
514
  data['keypass']=Fasp::Installation.instance.bypass_pass
467
515
  return {:type=>:single_object, :data=>data}
@@ -474,17 +522,18 @@ module Aspera
474
522
  default_product=self.options.get_next_argument('product name')
475
523
  Fasp::Installation.instance.use_ascp_from_product(default_product)
476
524
  preset_name=set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
477
- save_presets_to_config_file
478
- return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
525
+ return Main.result_status("Saved to default global preset #{preset_name}")
479
526
  end
480
527
  when :install
481
- v=Fasp::Installation.instance.install_sdk
482
- return {:type=>:status, :data=>"Installed version #{v}"}
528
+ v=Fasp::Installation.instance.install_sdk(self.options.get_option(:sdk_url,:mandatory))
529
+ return Main.result_status("Installed version #{v}")
530
+ when :spec
531
+ return {type: :object_list, data: Fasp::Parameters.man_table, fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map{|i|i.to_s},'description'].flatten}
483
532
  end
484
533
  raise "unexpected case: #{command}"
485
534
  end
486
535
 
487
- ACTIONS=[:gem_path, :genkey,:plugins,:flush_tokens,:list,:overview,:open,:echo,:id,:documentation,:wizard,:export_to_cli,:detect,:coffee,:ascp,:email_test,:smtp_settings,:proxy_check,:folder,:file]
536
+ ACTIONS=[:gem_path, :genkey,:plugins,:flush_tokens,:list,:overview,:open,:echo,:id,:documentation,:wizard,:export_to_cli,:detect,:coffee,:ascp,:email_test,:smtp_settings,:proxy_check,:folder,:file,:check_update,:initdemo]
488
537
 
489
538
  # "config" plugin
490
539
  def execute_action
@@ -503,7 +552,7 @@ module Aspera
503
552
  when :delete
504
553
  @config_presets.delete(config_name)
505
554
  save_presets_to_config_file
506
- return Main.result_status("deleted: #{config_name}")
555
+ return Main.result_status("Deleted: #{config_name}")
507
556
  when :get
508
557
  param_name=self.options.get_next_argument('parameter name')
509
558
  value=selected_preset[param_name]
@@ -516,7 +565,7 @@ module Aspera
516
565
  param_name=self.options.get_next_argument('parameter name')
517
566
  selected_preset.delete(param_name)
518
567
  save_presets_to_config_file
519
- return Main.result_status("removed: #{config_name}: #{param_name}")
568
+ return Main.result_status("Removed: #{config_name}: #{param_name}")
520
569
  when :set
521
570
  param_name=self.options.get_next_argument('parameter name')
522
571
  param_value=self.options.get_next_argument('parameter value')
@@ -529,7 +578,7 @@ module Aspera
529
578
  end
530
579
  selected_preset[param_name]=param_value
531
580
  save_presets_to_config_file
532
- return Main.result_status("updated: #{config_name}: #{param_name} <- #{param_value}")
581
+ return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
533
582
  when :initialize
534
583
  config_value=self.options.get_next_argument('extended value (Hash)')
535
584
  if @config_presets.has_key?(config_name)
@@ -537,7 +586,7 @@ module Aspera
537
586
  end
538
587
  @config_presets[config_name]=config_value
539
588
  save_presets_to_config_file
540
- return Main.result_status("modified: #{@option_config_file}")
589
+ return Main.result_status("Modified: #{@option_config_file}")
541
590
  when :update
542
591
  default_for_plugin=self.options.get_option(:default,:optional)
543
592
  # get unprocessed options
@@ -550,7 +599,7 @@ module Aspera
550
599
  @config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
551
600
  end
552
601
  save_presets_to_config_file
553
- return Main.result_status("updated: #{config_name}")
602
+ return Main.result_status("Updated: #{config_name}")
554
603
  when :ask
555
604
  self.options.ask_missing_mandatory=:yes
556
605
  @config_presets[config_name]||={}
@@ -559,10 +608,12 @@ module Aspera
559
608
  @config_presets[config_name][optionname]=option_value
560
609
  end
561
610
  save_presets_to_config_file
562
- return Main.result_status("updated: #{config_name}")
611
+ return Main.result_status("Updated: #{config_name}")
563
612
  end
564
613
  when :documentation
565
- OpenApplication.instance.uri(@help_url)
614
+ section=options.get_next_argument('private key file path',:single,:optional)
615
+ section='#'+section unless section.nil?
616
+ OpenApplication.instance.uri("#{@help_url}#{section}")
566
617
  return Main.result_nothing
567
618
  when :open
568
619
  OpenApplication.instance.uri("#{@option_config_file}") #file://
@@ -570,9 +621,9 @@ module Aspera
570
621
  when :genkey # generate new rsa key
571
622
  private_key_path=self.options.get_next_argument('private key file path')
572
623
  generate_new_key(private_key_path)
573
- return Main.result_status('generated key: '+private_key_path)
624
+ return Main.result_status('Generated key: '+private_key_path)
574
625
  when :echo # display the content of a value given on command line
575
- result={:type=>:other_struct, :data=>self.options.get_next_argument("value")}
626
+ result={:type=>:other_struct, :data=>self.options.get_next_argument('value')}
576
627
  # special for csv
577
628
  result[:type]=:object_list if result[:data].is_a?(Array) and result[:data].first.is_a?(Hash)
578
629
  return result
@@ -587,14 +638,13 @@ module Aspera
587
638
  return {:type=>:object_list,:data=>self.class.flatten_all_config(@config_presets)}
588
639
  when :wizard
589
640
  self.options.ask_missing_mandatory=true
590
- #self.options.set_option(:interactive,:yes)
591
641
  # register url option
592
642
  BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
593
643
  instance_url=self.options.get_option(:url,:mandatory)
594
644
  appli=ApiDetector.discover_product(instance_url)
595
645
  case appli[:product]
596
646
  when :aoc
597
- self.format.display_status("Detected: Aspera on Cloud".bold)
647
+ self.format.display_status('Detected: Aspera on Cloud'.bold)
598
648
  organization,instance_domain=AoC.parse_url(instance_url)
599
649
  aspera_preset_name='aoc_'+organization
600
650
  self.format.display_status("Preparing preset: #{aspera_preset_name}")
@@ -608,7 +658,7 @@ module Aspera
608
658
  private_key_path=self.options.get_option(:pkeypath,:optional)
609
659
  # give a chance to provide
610
660
  if private_key_path.nil?
611
- self.format.display_status("Please provide path to your private RSA key, or empty to generate one:")
661
+ self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
612
662
  private_key_path=self.options.get_option(:pkeypath,:mandatory).to_s
613
663
  end
614
664
  # else generate path
@@ -616,69 +666,69 @@ module Aspera
616
666
  private_key_path=File.join(@main_folder,'aspera_aoc_key')
617
667
  end
618
668
  if File.exist?(private_key_path)
619
- self.format.display_status("Using existing key:")
669
+ self.format.display_status('Using existing key:')
620
670
  else
621
- self.format.display_status("Generating key...")
671
+ self.format.display_status('Generating key...')
622
672
  generate_new_key(private_key_path)
623
- self.format.display_status("Created:")
673
+ self.format.display_status('Created:')
624
674
  end
625
675
  self.format.display_status("#{private_key_path}")
626
676
  pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
627
- # define options
677
+ # declare command line options for AoC
628
678
  require 'aspera/cli/plugins/aoc'
629
679
  # make username mandatory for jwt, this triggers interactive input
630
680
  self.options.get_option(:username,:mandatory)
631
- # instanciate AoC plugin
681
+ # instanciate AoC plugin, so that command line options are known
632
682
  files_plugin=self.class.plugin_new(AOC_COMMAND_CURRENT,@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
683
+ aoc_api=files_plugin.get_api
633
684
  auto_set_pub_key=false
634
685
  auto_set_jwt=false
635
686
  use_browser_authentication=false
636
687
  if self.options.get_option(:use_generic_client)
637
- self.format.display_status("Using global client_id.")
638
- self.format.display_status("Please Login to your Aspera on Cloud instance.".red)
639
- self.format.display_status("Navigate to your \"Account Settings\"".red)
640
- self.format.display_status("Check or update the value of \"Public Key\" to be:".red.blink)
688
+ self.format.display_status('Using global client_id.')
689
+ self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
690
+ self.format.display_status('Navigate to your "Account Settings"'.red)
691
+ self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
641
692
  self.format.display_status("#{pub_key_pem}")
642
693
  if ! self.options.get_option(:test_mode)
643
- self.format.display_status("Once updated or validated, press enter.")
694
+ self.format.display_status('Once updated or validated, press enter.')
644
695
  OpenApplication.instance.uri(instance_url)
645
696
  STDIN.gets
646
697
  end
647
698
  else
648
- self.format.display_status("Using organization specific client_id.")
699
+ self.format.display_status('Using organization specific client_id.')
649
700
  if self.options.get_option(:client_id,:optional).nil? or self.options.get_option(:client_secret,:optional).nil?
650
- self.format.display_status("Please login to your Aspera on Cloud instance.".red)
651
- self.format.display_status("Go to: Apps->Admin->Organization->Integrations")
652
- self.format.display_status("Create or check if there is an existing integration named:")
701
+ self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
702
+ self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
703
+ self.format.display_status('Create or check if there is an existing integration named:')
653
704
  self.format.display_status("- name: #{@tool_name}")
654
705
  self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
655
- self.format.display_status("- origin: localhost")
656
- self.format.display_status("Once created or identified,")
657
- self.format.display_status("Please enter:".red)
706
+ self.format.display_status('- origin: localhost')
707
+ self.format.display_status('Once created or identified,')
708
+ self.format.display_status('Please enter:'.red)
658
709
  end
659
- OpenApplication.instance.uri(instance_url+"/admin/org/integrations")
710
+ OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
660
711
  self.options.get_option(:client_id,:mandatory)
661
712
  self.options.get_option(:client_secret,:mandatory)
662
713
  use_browser_authentication=true
663
714
  end
664
715
  if use_browser_authentication
665
- self.format.display_status("We will use web authentication to bootstrap.")
666
- self.options.set_option(:auth,:web)
667
- self.options.set_option(:redirect_uri,DEFAULT_REDIRECT)
716
+ self.format.display_status('We will use web authentication to bootstrap.')
668
717
  auto_set_pub_key=true
669
718
  auto_set_jwt=true
670
- self.options.set_option(:scope,AoC::SCOPE_FILES_ADMIN)
719
+ @api_aoc.oauth.params[:auth]=:web
720
+ @api_aoc.oauth.params[:redirect_uri]=DEFAULT_REDIRECT
721
+ @api_aoc.oauth.params[:scope]=AoC::SCOPE_FILES_ADMIN
671
722
  end
672
- files_plugin.update_aoc_api
673
- myself=files_plugin.api_aoc.read('self')[:data]
723
+ myself=aoc_api.read('self')[:data]
674
724
  if auto_set_pub_key
675
- raise CliError,"public key is already set in profile (use --override=yes)" unless myself['public_key'].empty? or option_override
676
- self.format.display_status("Updating profile with new key")
677
- files_plugin.api_aoc.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
725
+ raise CliError,'public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? or option_override
726
+ self.format.display_status('Updating profile with new key')
727
+ aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
678
728
  end
679
729
  if auto_set_jwt
680
- self.format.display_status("Enabling JWT for client")
681
- files_plugin.api_aoc.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
730
+ self.format.display_status('Enabling JWT for client')
731
+ aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
682
732
  end
683
733
  self.format.display_status("creating new config preset: #{aspera_preset_name}")
684
734
  @config_presets[aspera_preset_name]={
@@ -694,14 +744,14 @@ module Aspera
694
744
  end
695
745
  self.format.display_status("Setting config preset as default for #{AOC_COMMAND_CURRENT}")
696
746
  @config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
697
- self.format.display_status("saving config file")
747
+ self.format.display_status('saving config file')
698
748
  save_presets_to_config_file
699
749
  return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
700
750
  else
701
751
  raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
702
752
  end
703
753
  when :export_to_cli
704
- self.format.display_status("Exporting: Aspera on Cloud")
754
+ self.format.display_status('Exporting: Aspera on Cloud')
705
755
  require 'aspera/cli/plugins/aoc'
706
756
  # need url / username
707
757
  add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
@@ -734,11 +784,11 @@ module Aspera
734
784
  entry.merge!(new_conf)
735
785
  end
736
786
  File.write(cli_conf_file,JSON.pretty_generate(data))
737
- return Main.result_status("updated: #{cli_conf_file}")
787
+ return Main.result_status("Updated: #{cli_conf_file}")
738
788
  when :detect
739
789
  # need url / username
740
790
  BasicAuthPlugin.new(@agents)
741
- return Main.result_status("found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
791
+ return Main.result_status("Found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
742
792
  when :coffee
743
793
  OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
744
794
  return Main.result_nothing
@@ -751,26 +801,41 @@ module Aspera
751
801
  when :file
752
802
  return Main.result_status(@option_config_file)
753
803
  when :email_test
754
- dest_email=self.options.get_next_argument("destination email")
755
- send_email({
756
- to: dest_email,
757
- subject: 'Amelia email test',
758
- body: 'It worked !',
759
- })
804
+ send_email_template({},EMAIL_TEST_TEMPLATE)
760
805
  return Main.result_nothing
761
806
  when :smtp_settings
762
807
  return {:type=>:single_object,:data=>email_settings}
763
808
  when :proxy_check
764
809
  pac_url=self.options.get_option(:fpac,:mandatory)
765
- server_url=self.options.get_next_argument("server url")
810
+ server_url=self.options.get_next_argument('server url')
766
811
  return Main.result_status(Aspera::ProxyAutoConfig.new(UriReader.read(pac_url)).get_proxy(server_url))
767
- else raise "error"
812
+ when :check_update
813
+ return {:type=>:single_object, :data=>check_gem_version}
814
+ when :initdemo
815
+ if @config_presets.has_key?(DEMO_SERVER_PRESET)
816
+ Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
817
+ else
818
+ Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
819
+ @config_presets[DEMO_SERVER_PRESET]={'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
820
+ end
821
+ @config_presets[CONF_PRESET_DEFAULT]||={}
822
+ if @config_presets[CONF_PRESET_DEFAULT].has_key?('server')
823
+ Log.log.warn("server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT]['server']}")
824
+ Log.log.warn("use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT]['server'])
825
+ else
826
+ @config_presets[CONF_PRESET_DEFAULT]['server']=DEMO_SERVER_PRESET
827
+ Log.log.info("setting server default preset to : #{DEMO_SERVER_PRESET}")
828
+ end
829
+ save_presets_to_config_file
830
+ return Main.result_status("Done")
831
+ else raise 'error'
768
832
  end
769
833
  end
770
834
 
835
+ # @return email server setting with defaults if not defined
771
836
  def email_settings
772
837
  smtp=self.options.get_option(:smtp,:mandatory)
773
- # change string keys into symbols
838
+ # change string keys into symbol keys
774
839
  smtp=smtp.keys.inject({}){|m,v|m[v.to_sym]=smtp[v];m}
775
840
  # defaults
776
841
  smtp[:tls]||=true
@@ -780,39 +845,47 @@ module Aspera
780
845
  smtp[:domain]||=smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
781
846
  # check minimum required
782
847
  [:server,:port,:domain].each do |n|
783
- raise "missing smtp parameter: #{n}" unless smtp.has_key?(n)
848
+ raise "Missing smtp parameter: #{n}" unless smtp.has_key?(n)
784
849
  end
785
850
  Log.log.debug("smtp=#{smtp}")
786
851
  return smtp
787
852
  end
788
853
 
789
- def send_email(email={})
790
- opts=email_settings
791
- email[:from_name]||=opts[:from_name]
792
- email[:from_email]||=opts[:from_email]
793
- # check minimum required
794
- [:from_name,:from_email,:to,:subject].each do |n|
795
- raise "missing email parameter: #{n}" unless email.has_key?(n)
854
+ # create a clean binding (ruby variable environment)
855
+ def empty_binding
856
+ Kernel.binding
857
+ end
858
+
859
+ def send_email_template(vars,email_template_default=nil)
860
+ vars[:to]||=options.get_option(:notif_to,:mandatory)
861
+ notif_template=options.get_option(:notif_template,email_template_default.nil? ? :mandatory : :optional) || email_template_default
862
+ mail_conf=email_settings
863
+ vars[:from_name]||=mail_conf[:from_name]
864
+ vars[:from_email]||=mail_conf[:from_email]
865
+ [:from_name,:from_email].each do |n|
866
+ raise "Missing email parameter: #{n}" unless vars.has_key?(n)
867
+ end
868
+ start_options=[mail_conf[:domain]]
869
+ start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) and mail_conf.has_key?(:password)
870
+ # create a binding with only variables defined in vars
871
+ template_binding=empty_binding
872
+ # add variables to binding
873
+ vars.each do |k,v|
874
+ raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
875
+ template_binding.local_variable_set(k,v)
796
876
  end
797
- msg = <<END_OF_MESSAGE
798
- From: #{email[:from_name]} <#{email[:from_email]}>
799
- To: <#{email[:to]}>
800
- Subject: #{email[:subject]}
801
-
802
- #{email[:body]}
803
- END_OF_MESSAGE
804
- start_options=[opts[:domain]]
805
- start_options.push(opts[:username],opts[:password],:login) if opts.has_key?(:username) and opts.has_key?(:password)
806
-
807
- smtp = Net::SMTP.new(opts[:server], opts[:port])
808
- smtp.enable_starttls if opts[:tls]
877
+ # execute template
878
+ msg_with_headers=ERB.new(notif_template).result(template_binding)
879
+ Log.dump(:msg_with_headers,msg_with_headers)
880
+ smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
881
+ smtp.enable_starttls if mail_conf[:tls]
809
882
  smtp.start(*start_options) do |smtp|
810
- smtp.send_message(msg, email[:from_email], email[:to])
883
+ smtp.send_message(msg_with_headers, vars[:from_email], vars[:to])
811
884
  end
812
885
  end
813
886
 
814
887
  def save_presets_to_config_file
815
- raise "no configuration loaded" if @config_presets.nil?
888
+ raise 'no configuration loaded' if @config_presets.nil?
816
889
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
817
890
  Log.log.debug "writing #{@option_config_file}"
818
891
  File.write(@option_config_file,@config_presets.to_yaml)
@@ -823,7 +896,7 @@ END_OF_MESSAGE
823
896
  def get_plugin_default_config_name(plugin_sym)
824
897
  raise "internal error: config_presets shall be defined" if @config_presets.nil?
825
898
  if !@use_plugin_defaults
826
- Log.log.debug("skip default config")
899
+ Log.log.debug('skip default config')
827
900
  return nil
828
901
  end
829
902
  if @config_presets.has_key?(CONF_PRESET_DEFAULT) and