aspera-cli 4.1.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +455 -229
  3. data/docs/Makefile +4 -4
  4. data/docs/README.erb.md +457 -126
  5. data/docs/test_env.conf +19 -2
  6. data/examples/aoc.rb +14 -3
  7. data/examples/faspex4.rb +89 -0
  8. data/lib/aspera/aoc.rb +38 -40
  9. data/lib/aspera/cli/main.rb +65 -33
  10. data/lib/aspera/cli/plugins/aoc.rb +54 -65
  11. data/lib/aspera/cli/plugins/ats.rb +2 -2
  12. data/lib/aspera/cli/plugins/config.rb +158 -137
  13. data/lib/aspera/cli/plugins/faspex.rb +111 -64
  14. data/lib/aspera/cli/plugins/faspex5.rb +35 -48
  15. data/lib/aspera/cli/plugins/node.rb +3 -2
  16. data/lib/aspera/cli/plugins/preview.rb +88 -55
  17. data/lib/aspera/cli/transfer_agent.rb +98 -62
  18. data/lib/aspera/cli/version.rb +1 -1
  19. data/lib/aspera/command_line_builder.rb +48 -31
  20. data/lib/aspera/cos_node.rb +34 -28
  21. data/lib/aspera/environment.rb +2 -2
  22. data/lib/aspera/fasp/aoc.rb +1 -1
  23. data/lib/aspera/fasp/installation.rb +68 -45
  24. data/lib/aspera/fasp/local.rb +89 -45
  25. data/lib/aspera/fasp/manager.rb +3 -0
  26. data/lib/aspera/fasp/node.rb +23 -1
  27. data/lib/aspera/fasp/parameters.rb +57 -86
  28. data/lib/aspera/fasp/parameters.yaml +531 -0
  29. data/lib/aspera/fasp/resume_policy.rb +13 -12
  30. data/lib/aspera/fasp/uri.rb +1 -1
  31. data/lib/aspera/id_generator.rb +22 -0
  32. data/lib/aspera/node.rb +14 -3
  33. data/lib/aspera/oauth.rb +135 -129
  34. data/lib/aspera/persistency_action_once.rb +11 -7
  35. data/lib/aspera/persistency_folder.rb +6 -26
  36. data/lib/aspera/rest.rb +3 -12
  37. data/lib/aspera/secrets.rb +20 -0
  38. data/lib/aspera/sync.rb +40 -35
  39. data/lib/aspera/timer_limiter.rb +22 -0
  40. data/lib/aspera/web_auth.rb +105 -0
  41. metadata +22 -3
  42. data/docs/transfer_spec.html +0 -99
@@ -1,6 +1,7 @@
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'
@@ -8,11 +9,13 @@ require 'aspera/proxy_auto_config'
8
9
  require 'aspera/uri_reader'
9
10
  require 'aspera/rest'
10
11
  require 'aspera/persistency_action_once'
12
+ require 'aspera/id_generator'
11
13
  require 'xmlsimple'
12
14
  require 'base64'
13
15
  require 'net/smtp'
14
16
  require 'open3'
15
17
  require 'date'
18
+ require 'erb'
16
19
 
17
20
  module Aspera
18
21
  module Cli
@@ -27,6 +30,7 @@ module Aspera
27
30
  CONF_PRESET_CONFIG='config'
28
31
  CONF_PRESET_VERSION='version'
29
32
  CONF_PRESET_DEFAULT='default'
33
+ CONF_PRESET_GLOBAL='global_common_defaults'
30
34
  CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
31
35
  CONF_GLOBAL_SYM = :config
32
36
  # old tool name
@@ -45,20 +49,26 @@ module Aspera
45
49
  CONNECT_VERSIONS = 'connectversions.js'
46
50
  TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_sdk'
47
51
  DEMO='demo'
52
+ DEMO_SERVER_PRESET='demoserver'
48
53
  AOC_PATH_API_CLIENTS='admin/api-clients'
54
+ EMAIL_TEST_TEMPLATE=<<END_OF_TEMPLATE
55
+ From: <%=from_name%> <<%=from_email%>>
56
+ To: <<%=to%>>
57
+ Subject: Amelia email test
58
+
59
+ It worked !
60
+ END_OF_TEMPLATE
49
61
  def option_preset; nil; end
50
62
 
51
63
  def option_preset=(value)
52
64
  self.options.add_option_preset(preset_by_name(value))
53
65
  end
54
66
 
55
- private_constant :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,:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS
56
- attr_accessor :option_ak_secret,:option_secrets
67
+ 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
57
68
 
58
69
  def initialize(env,tool_name,help_url,version,main_folder)
59
70
  super(env)
60
- @option_ak_secret=nil
61
- @option_secrets={}
71
+ raise 'missing secret manager' if @agents[:secret].nil?
62
72
  @plugins={}
63
73
  @plugin_lookup_folders=[]
64
74
  @use_plugin_defaults=true
@@ -87,52 +97,45 @@ module Aspera
87
97
  self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
88
98
  self.options.set_obj_attr(:use_product,self,:option_use_product)
89
99
  self.options.set_obj_attr(:preset,self,:option_preset)
90
- self.options.set_obj_attr(:secret,self,:option_ak_secret)
91
- self.options.set_obj_attr(:secrets,self,:option_secrets)
92
- self.options.add_opt_boolean(:override,"override existing value")
93
- self.options.add_opt_switch(:no_default,"-N","do not load default configuration for plugin") { @use_plugin_defaults=false }
100
+ self.options.set_obj_attr(:secret,@agents[:secret],:default_secret)
101
+ self.options.set_obj_attr(:secrets,@agents[:secret],:all_secrets)
102
+ self.options.add_opt_boolean(:override,'override existing value')
103
+ self.options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults=false }
94
104
  self.options.add_opt_boolean(:use_generic_client,'wizard: AoC: use global or org specific jwt client id')
95
- self.options.add_opt_simple(:pkeypath,"path to private key for JWT (wizard)")
96
- self.options.add_opt_simple(:ascp_path,"path to ascp")
97
- self.options.add_opt_simple(:use_product,"use ascp from specified product")
98
- self.options.add_opt_simple(:smtp,"smtp configuration (extended value: hash)")
99
- self.options.add_opt_simple(:fpac,"proxy auto configuration URL")
100
- self.options.add_opt_simple(:preset,"-PVALUE","load the named option preset from current config file")
101
- self.options.add_opt_simple(:default,"set as default configuration for specified plugin")
102
- self.options.add_opt_simple(:secret,"access key secret for node")
103
- self.options.add_opt_simple(:secrets,"access key secret for node")
104
- self.options.add_opt_simple(:sdk_url,"URL to get SDK")
105
- self.options.add_opt_simple(:sdk_folder,"SDK folder location")
106
- self.options.add_opt_boolean(:test_mode,"skip user validation in wizard mode")
107
- self.options.add_opt_simple(:version_check_days,Integer,"period to check neew version in days (zero to disable)")
105
+ self.options.add_opt_simple(:pkeypath,'path to private key for JWT (wizard)')
106
+ self.options.add_opt_simple(:ascp_path,'path to ascp')
107
+ self.options.add_opt_simple(:use_product,'use ascp from specified product')
108
+ self.options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
109
+ self.options.add_opt_simple(:fpac,'proxy auto configuration URL')
110
+ self.options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
111
+ self.options.add_opt_simple(:default,'set as default configuration for specified plugin')
112
+ self.options.add_opt_simple(:secret,'default secret')
113
+ self.options.add_opt_simple(:secrets,'secret repository (Hash)')
114
+ self.options.add_opt_simple(:sdk_url,'URL to get SDK')
115
+ self.options.add_opt_simple(:sdk_folder,'SDK folder location')
116
+ self.options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
117
+ self.options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
118
+ self.options.add_opt_boolean(:test_mode,'skip user validation in wizard mode')
119
+ self.options.add_opt_simple(:version_check_days,Integer,'period to check neew version in days (zero to disable)')
108
120
  self.options.set_option(:use_generic_client,true)
109
121
  self.options.set_option(:test_mode,false)
110
122
  self.options.set_option(:version_check_days,7)
111
123
  self.options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
112
124
  self.options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
113
125
  self.options.parse_options!
114
- raise CliBadArgument,"secrets shall be Hash" unless @option_secrets.is_a?(Hash)
126
+ raise CliBadArgument,'secrets shall be Hash' unless @agents[:secret].all_secrets.is_a?(Hash)
115
127
  Fasp::Installation.instance.folder=self.options.get_option(:sdk_folder,:mandatory)
116
128
  end
117
129
 
118
- def get_secret(id=nil,mandatory=true)
119
- secret=self.options.get_option(:secret,:optional) || @option_secrets[id]
120
- raise "please provide secret for #{id}" if secret.nil? and mandatory
121
- return secret
122
- end
123
-
124
- def get_secrets
125
- return @option_secrets
126
- end
127
-
128
130
  def check_gem_version
129
131
  this_gem_name=File.basename(File.dirname(self.class.gem_root)).gsub(/-[0-9].*$/,'')
130
132
  latest_version=begin
131
- Rest.new(base_url: "https://rubygems.org/api/v1").read("versions/#{this_gem_name}/latest.json")[:data]['version']
133
+ Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{this_gem_name}/latest.json")[:data]['version']
132
134
  rescue
133
- nil
135
+ Log.log.warn('Could not retrieve latest gem version on rubygems.')
136
+ '0'
134
137
  end
135
- 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)}
138
+ 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)}
136
139
  end
137
140
 
138
141
  def periodic_check_newer_gem_version
@@ -146,22 +149,21 @@ module Aspera
146
149
  check_date_persist=PersistencyActionOnce.new(
147
150
  manager: persistency,
148
151
  data: last_check_array,
149
- ids: ['version_last_check'])
152
+ id: 'version_last_check')
150
153
  # get persisted date or nil
151
154
  last_check_date = begin
152
- Date.strptime(last_check_array.first, "%Y/%m/%d")
155
+ Date.strptime(last_check_array.first, '%Y/%m/%d')
153
156
  rescue
154
157
  nil
155
158
  end
156
159
  current_date=Date.today
157
- Log.log.info("last check: #{last_check_date.class}")
160
+ Log.log.debug("days elapsed: #{last_check_date.is_a?(Date) ? current_date - last_check_date : last_check_date.class.name}")
158
161
  if last_check_date.nil? or (current_date - last_check_date) > delay_days
159
- Log.log.info("days elapsed #{last_check_date.is_a?(Date) ? current_date - last_check_date : last_check_date.class.name}")
160
- last_check_array[0]=current_date.strftime("%Y/%m/%d")
162
+ last_check_array[0]=current_date.strftime('%Y/%m/%d')
161
163
  check_date_persist.save
162
164
  check_data=check_gem_version
163
165
  if check_data[:need_update]
164
- Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:nname]}")
166
+ Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}")
165
167
  end
166
168
  end
167
169
  end
@@ -200,7 +202,7 @@ module Aspera
200
202
  require 'openssl'
201
203
  priv_key = OpenSSL::PKey::RSA.new(4096)
202
204
  File.write(private_key_path,priv_key.to_s)
203
- File.write(private_key_path+".pub",priv_key.public_key.to_s)
205
+ File.write(private_key_path+'.pub',priv_key.public_key.to_s)
204
206
  nil
205
207
  end
206
208
 
@@ -226,7 +228,7 @@ module Aspera
226
228
  r=[]
227
229
  t.each do |k,v|
228
230
  v.each do |kk,vv|
229
- r.push({"config"=>k,"parameter"=>kk,"value"=>vv})
231
+ r.push({'config'=>k,'parameter'=>kk,'value'=>vv})
230
232
  end
231
233
  end
232
234
  return r
@@ -236,12 +238,12 @@ module Aspera
236
238
  # creates one if none already created
237
239
  # @return preset that contains global default
238
240
  def set_global_default(key,value)
239
- global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
240
- if global_default_preset_name.nil?
241
- global_default_preset_name='global_common_defaults'
242
- @config_presets[global_default_preset_name]={}
243
- end
241
+ # get default preset if it exists
242
+ global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM) || CONF_PRESET_GLOBAL
243
+ @config_presets[global_default_preset_name]||={}
244
244
  @config_presets[global_default_preset_name][key.to_s]=value
245
+ self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
246
+ save_presets_to_config_file
245
247
  return global_default_preset_name
246
248
  end
247
249
 
@@ -260,7 +262,7 @@ module Aspera
260
262
  # @return the hash from name (also expands possible includes)
261
263
  def preset_by_name(config_name, include_path=[])
262
264
  raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
263
- raise CliError,"loop in include" if include_path.include?(config_name)
265
+ raise CliError,'loop in include' if include_path.include?(config_name)
264
266
  return expanded_with_preset_includes(@config_presets[config_name],include_path.clone.push(config_name))
265
267
  end
266
268
 
@@ -295,7 +297,7 @@ module Aspera
295
297
  end
296
298
 
297
299
  def option_use_product
298
- "write-only value"
300
+ 'write-only value'
299
301
  end
300
302
 
301
303
  def convert_preset_path(old_name,new_name,files_to_copy)
@@ -339,22 +341,21 @@ module Aspera
339
341
  # if no file found, create default config
340
342
  if conf_file_to_load.nil?
341
343
  Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
342
- @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version},CONF_PRESET_DEFAULT=>{'server'=>'demoserver'},
343
- 'demoserver'=>{'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}}
344
+ @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version}}
344
345
  else
345
346
  Log.log.debug "loading #{@option_config_file}"
346
347
  @config_presets=YAML.load_file(conf_file_to_load)
347
348
  end
348
349
  files_to_copy=[]
349
350
  Log.log.debug "Available_presets: #{@config_presets}"
350
- raise "Expecting YAML Hash" unless @config_presets.is_a?(Hash)
351
+ raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
351
352
  # check there is at least the config section
352
353
  if !@config_presets.has_key?(CONF_PRESET_CONFIG)
353
354
  raise "Cannot find key: #{CONF_PRESET_CONFIG}"
354
355
  end
355
356
  version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
356
357
  if version.nil?
357
- raise "No version found in config section."
358
+ raise 'No version found in config section.'
358
359
  end
359
360
  # oldest compatible conf file format, update to latest version when an incompatible change is made
360
361
  # check compatibility of version of conf file
@@ -383,24 +384,24 @@ module Aspera
383
384
  end
384
385
  # Place new compatibility code here
385
386
  if save_required
386
- Log.log.warn("Saving automatic conversion.")
387
+ Log.log.warn('Saving automatic conversion.')
387
388
  @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@program_version
388
389
  save_presets_to_config_file
389
- Log.log.warn("Copying referenced files")
390
+ Log.log.warn('Copying referenced files')
390
391
  files_to_copy.each do |file|
391
392
  FileUtils.cp(file,@main_folder)
392
393
  Log.log.warn("..#{file} -> #{@main_folder}")
393
394
  end
394
395
  end
395
396
  rescue Psych::SyntaxError => e
396
- Log.log.error("YAML error in config file")
397
+ Log.log.error('YAML error in config file')
397
398
  raise e
398
399
  rescue => e
399
400
  Log.log.debug("-> #{e}")
400
401
  new_name="#{@option_config_file}.pre#{@program_version}.manual_conversion_needed"
401
402
  File.rename(@option_config_file,new_name)
402
403
  Log.log.warn("Renamed config file to #{new_name}.")
403
- Log.log.warn("Manual Conversion is required. Next time, a new empty file will be created.")
404
+ Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
404
405
  raise CliError,e.to_s
405
406
  end
406
407
  end
@@ -465,10 +466,10 @@ module Aspera
465
466
  fileurl = one_link['href']
466
467
  filename=fileurl.gsub(%r{.*/},'')
467
468
  api_connect_cdn.call({:operation=>'GET',:subpath=>fileurl,:save_to_file=>File.join(folder_dest,filename)})
468
- return Main.result_status("downloaded: #{filename}")
469
+ return Main.result_status("Downloaded: #{filename}")
469
470
  when :open #
470
471
  OpenApplication.instance.uri(one_link['href'])
471
- return Main.result_status("opened: #{one_link['href']}")
472
+ return Main.result_status("Opened: #{one_link['href']}")
472
473
  end
473
474
  end
474
475
  end
@@ -476,23 +477,21 @@ module Aspera
476
477
  end
477
478
 
478
479
  def execute_action_ascp
479
- command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install])
480
+ command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install,:spec])
480
481
  case command
481
482
  when :connect
482
483
  return execute_connect_action
483
484
  when :use
484
- default_ascp=self.options.get_next_argument('path to ascp')
485
- raise "file name must be ascp" unless File.basename(default_ascp).eql?('ascp')
486
- raise "no such file: #{default_ascp}" unless File.exist?(default_ascp)
487
- raise "not executable: #{default_ascp}" unless File.executable?(default_ascp)
488
- preset_name=set_global_default(:ascp_path,default_ascp)
489
- save_presets_to_config_file
490
- return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
485
+ ascp_path=self.options.get_next_argument('path to ascp')
486
+ ascp_version=Fasp::Installation.instance.get_ascp_version(ascp_path)
487
+ self.format.display_status("ascp version: #{ascp_version}")
488
+ preset_name=set_global_default(:ascp_path,ascp_path)
489
+ return Main.result_status("Saved to default global preset #{preset_name}")
491
490
  when :show # shows files used
492
491
  return {:type=>:status, :data=>Fasp::Installation.instance.path(:ascp)}
493
492
  when :info # shows files used
494
493
  data=Fasp::Installation::FILES.inject({}) do |m,v|
495
- m[v.to_s]=Fasp::Installation.instance.path(v) rescue "Not Found"
494
+ m[v.to_s]=Fasp::Installation.instance.path(v) rescue 'Not Found'
496
495
  m
497
496
  end
498
497
  # read PATHs from ascp directly, and pvcl modules as well
@@ -524,17 +523,18 @@ module Aspera
524
523
  default_product=self.options.get_next_argument('product name')
525
524
  Fasp::Installation.instance.use_ascp_from_product(default_product)
526
525
  preset_name=set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
527
- save_presets_to_config_file
528
- return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
526
+ return Main.result_status("Saved to default global preset #{preset_name}")
529
527
  end
530
528
  when :install
531
529
  v=Fasp::Installation.instance.install_sdk(self.options.get_option(:sdk_url,:mandatory))
532
- return {:type=>:status, :data=>"Installed version #{v}"}
530
+ return Main.result_status("Installed version #{v}")
531
+ when :spec
532
+ return {type: :object_list, data: Fasp::Parameters.man_table, fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map{|i|i.to_s},'description'].flatten}
533
533
  end
534
534
  raise "unexpected case: #{command}"
535
535
  end
536
536
 
537
- 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]
537
+ 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]
538
538
 
539
539
  # "config" plugin
540
540
  def execute_action
@@ -553,7 +553,7 @@ module Aspera
553
553
  when :delete
554
554
  @config_presets.delete(config_name)
555
555
  save_presets_to_config_file
556
- return Main.result_status("deleted: #{config_name}")
556
+ return Main.result_status("Deleted: #{config_name}")
557
557
  when :get
558
558
  param_name=self.options.get_next_argument('parameter name')
559
559
  value=selected_preset[param_name]
@@ -566,7 +566,7 @@ module Aspera
566
566
  param_name=self.options.get_next_argument('parameter name')
567
567
  selected_preset.delete(param_name)
568
568
  save_presets_to_config_file
569
- return Main.result_status("removed: #{config_name}: #{param_name}")
569
+ return Main.result_status("Removed: #{config_name}: #{param_name}")
570
570
  when :set
571
571
  param_name=self.options.get_next_argument('parameter name')
572
572
  param_value=self.options.get_next_argument('parameter value')
@@ -579,7 +579,7 @@ module Aspera
579
579
  end
580
580
  selected_preset[param_name]=param_value
581
581
  save_presets_to_config_file
582
- return Main.result_status("updated: #{config_name}: #{param_name} <- #{param_value}")
582
+ return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
583
583
  when :initialize
584
584
  config_value=self.options.get_next_argument('extended value (Hash)')
585
585
  if @config_presets.has_key?(config_name)
@@ -587,7 +587,7 @@ module Aspera
587
587
  end
588
588
  @config_presets[config_name]=config_value
589
589
  save_presets_to_config_file
590
- return Main.result_status("modified: #{@option_config_file}")
590
+ return Main.result_status("Modified: #{@option_config_file}")
591
591
  when :update
592
592
  default_for_plugin=self.options.get_option(:default,:optional)
593
593
  # get unprocessed options
@@ -600,7 +600,7 @@ module Aspera
600
600
  @config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
601
601
  end
602
602
  save_presets_to_config_file
603
- return Main.result_status("updated: #{config_name}")
603
+ return Main.result_status("Updated: #{config_name}")
604
604
  when :ask
605
605
  self.options.ask_missing_mandatory=:yes
606
606
  @config_presets[config_name]||={}
@@ -609,7 +609,7 @@ module Aspera
609
609
  @config_presets[config_name][optionname]=option_value
610
610
  end
611
611
  save_presets_to_config_file
612
- return Main.result_status("updated: #{config_name}")
612
+ return Main.result_status("Updated: #{config_name}")
613
613
  end
614
614
  when :documentation
615
615
  section=options.get_next_argument('private key file path',:single,:optional)
@@ -622,9 +622,9 @@ module Aspera
622
622
  when :genkey # generate new rsa key
623
623
  private_key_path=self.options.get_next_argument('private key file path')
624
624
  generate_new_key(private_key_path)
625
- return Main.result_status('generated key: '+private_key_path)
625
+ return Main.result_status('Generated key: '+private_key_path)
626
626
  when :echo # display the content of a value given on command line
627
- result={:type=>:other_struct, :data=>self.options.get_next_argument("value")}
627
+ result={:type=>:other_struct, :data=>self.options.get_next_argument('value')}
628
628
  # special for csv
629
629
  result[:type]=:object_list if result[:data].is_a?(Array) and result[:data].first.is_a?(Hash)
630
630
  return result
@@ -645,7 +645,7 @@ module Aspera
645
645
  appli=ApiDetector.discover_product(instance_url)
646
646
  case appli[:product]
647
647
  when :aoc
648
- self.format.display_status("Detected: Aspera on Cloud".bold)
648
+ self.format.display_status('Detected: Aspera on Cloud'.bold)
649
649
  organization,instance_domain=AoC.parse_url(instance_url)
650
650
  aspera_preset_name='aoc_'+organization
651
651
  self.format.display_status("Preparing preset: #{aspera_preset_name}")
@@ -659,7 +659,7 @@ module Aspera
659
659
  private_key_path=self.options.get_option(:pkeypath,:optional)
660
660
  # give a chance to provide
661
661
  if private_key_path.nil?
662
- self.format.display_status("Please provide path to your private RSA key, or empty to generate one:")
662
+ self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
663
663
  private_key_path=self.options.get_option(:pkeypath,:mandatory).to_s
664
664
  end
665
665
  # else generate path
@@ -667,11 +667,11 @@ module Aspera
667
667
  private_key_path=File.join(@main_folder,'aspera_aoc_key')
668
668
  end
669
669
  if File.exist?(private_key_path)
670
- self.format.display_status("Using existing key:")
670
+ self.format.display_status('Using existing key:')
671
671
  else
672
- self.format.display_status("Generating key...")
672
+ self.format.display_status('Generating key...')
673
673
  generate_new_key(private_key_path)
674
- self.format.display_status("Created:")
674
+ self.format.display_status('Created:')
675
675
  end
676
676
  self.format.display_status("#{private_key_path}")
677
677
  pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
@@ -681,32 +681,32 @@ module Aspera
681
681
  self.options.get_option(:username,:mandatory)
682
682
  # instanciate AoC plugin, so that command line options are known
683
683
  files_plugin=self.class.plugin_new(AOC_COMMAND_CURRENT,@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
684
- aoc_api=files_plugin.api_aoc
684
+ aoc_api=files_plugin.get_api
685
685
  auto_set_pub_key=false
686
686
  auto_set_jwt=false
687
687
  use_browser_authentication=false
688
688
  if self.options.get_option(:use_generic_client)
689
- self.format.display_status("Using global client_id.")
690
- self.format.display_status("Please Login to your Aspera on Cloud instance.".red)
691
- self.format.display_status("Navigate to your \"Account Settings\"".red)
692
- self.format.display_status("Check or update the value of \"Public Key\" to be:".red.blink)
689
+ self.format.display_status('Using global client_id.')
690
+ self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
691
+ self.format.display_status('Navigate to your "Account Settings"'.red)
692
+ self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
693
693
  self.format.display_status("#{pub_key_pem}")
694
694
  if ! self.options.get_option(:test_mode)
695
- self.format.display_status("Once updated or validated, press enter.")
695
+ self.format.display_status('Once updated or validated, press enter.')
696
696
  OpenApplication.instance.uri(instance_url)
697
697
  STDIN.gets
698
698
  end
699
699
  else
700
- self.format.display_status("Using organization specific client_id.")
700
+ self.format.display_status('Using organization specific client_id.')
701
701
  if self.options.get_option(:client_id,:optional).nil? or self.options.get_option(:client_secret,:optional).nil?
702
- self.format.display_status("Please login to your Aspera on Cloud instance.".red)
703
- self.format.display_status("Go to: Apps->Admin->Organization->Integrations")
704
- self.format.display_status("Create or check if there is an existing integration named:")
702
+ self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
703
+ self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
704
+ self.format.display_status('Create or check if there is an existing integration named:')
705
705
  self.format.display_status("- name: #{@tool_name}")
706
706
  self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
707
- self.format.display_status("- origin: localhost")
708
- self.format.display_status("Once created or identified,")
709
- self.format.display_status("Please enter:".red)
707
+ self.format.display_status('- origin: localhost')
708
+ self.format.display_status('Once created or identified,')
709
+ self.format.display_status('Please enter:'.red)
710
710
  end
711
711
  OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
712
712
  self.options.get_option(:client_id,:mandatory)
@@ -714,7 +714,7 @@ module Aspera
714
714
  use_browser_authentication=true
715
715
  end
716
716
  if use_browser_authentication
717
- self.format.display_status("We will use web authentication to bootstrap.")
717
+ self.format.display_status('We will use web authentication to bootstrap.')
718
718
  auto_set_pub_key=true
719
719
  auto_set_jwt=true
720
720
  @api_aoc.oauth.params[:auth]=:web
@@ -728,7 +728,7 @@ module Aspera
728
728
  aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
729
729
  end
730
730
  if auto_set_jwt
731
- self.format.display_status("Enabling JWT for client")
731
+ self.format.display_status('Enabling JWT for client')
732
732
  aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
733
733
  end
734
734
  self.format.display_status("creating new config preset: #{aspera_preset_name}")
@@ -745,14 +745,14 @@ module Aspera
745
745
  end
746
746
  self.format.display_status("Setting config preset as default for #{AOC_COMMAND_CURRENT}")
747
747
  @config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
748
- self.format.display_status("saving config file")
748
+ self.format.display_status('saving config file')
749
749
  save_presets_to_config_file
750
750
  return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
751
751
  else
752
752
  raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
753
753
  end
754
754
  when :export_to_cli
755
- self.format.display_status("Exporting: Aspera on Cloud")
755
+ self.format.display_status('Exporting: Aspera on Cloud')
756
756
  require 'aspera/cli/plugins/aoc'
757
757
  # need url / username
758
758
  add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
@@ -785,11 +785,11 @@ module Aspera
785
785
  entry.merge!(new_conf)
786
786
  end
787
787
  File.write(cli_conf_file,JSON.pretty_generate(data))
788
- return Main.result_status("updated: #{cli_conf_file}")
788
+ return Main.result_status("Updated: #{cli_conf_file}")
789
789
  when :detect
790
790
  # need url / username
791
791
  BasicAuthPlugin.new(@agents)
792
- return Main.result_status("found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
792
+ return Main.result_status("Found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
793
793
  when :coffee
794
794
  OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
795
795
  return Main.result_nothing
@@ -802,28 +802,41 @@ module Aspera
802
802
  when :file
803
803
  return Main.result_status(@option_config_file)
804
804
  when :email_test
805
- dest_email=self.options.get_next_argument("destination email")
806
- send_email({
807
- to: dest_email,
808
- subject: 'Amelia email test',
809
- body: 'It worked !',
810
- })
805
+ send_email_template({},EMAIL_TEST_TEMPLATE)
811
806
  return Main.result_nothing
812
807
  when :smtp_settings
813
808
  return {:type=>:single_object,:data=>email_settings}
814
809
  when :proxy_check
815
810
  pac_url=self.options.get_option(:fpac,:mandatory)
816
- server_url=self.options.get_next_argument("server url")
811
+ server_url=self.options.get_next_argument('server url')
817
812
  return Main.result_status(Aspera::ProxyAutoConfig.new(UriReader.read(pac_url)).get_proxy(server_url))
818
813
  when :check_update
819
814
  return {:type=>:single_object, :data=>check_gem_version}
820
- else raise "error"
815
+ when :initdemo
816
+ if @config_presets.has_key?(DEMO_SERVER_PRESET)
817
+ Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
818
+ else
819
+ Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
820
+ @config_presets[DEMO_SERVER_PRESET]={'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
821
+ end
822
+ @config_presets[CONF_PRESET_DEFAULT]||={}
823
+ if @config_presets[CONF_PRESET_DEFAULT].has_key?('server')
824
+ Log.log.warn("server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT]['server']}")
825
+ Log.log.warn("use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT]['server'])
826
+ else
827
+ @config_presets[CONF_PRESET_DEFAULT]['server']=DEMO_SERVER_PRESET
828
+ Log.log.info("setting server default preset to : #{DEMO_SERVER_PRESET}")
829
+ end
830
+ save_presets_to_config_file
831
+ return Main.result_status("Done")
832
+ else raise 'error'
821
833
  end
822
834
  end
823
835
 
836
+ # @return email server setting with defaults if not defined
824
837
  def email_settings
825
838
  smtp=self.options.get_option(:smtp,:mandatory)
826
- # change string keys into symbols
839
+ # change string keys into symbol keys
827
840
  smtp=smtp.keys.inject({}){|m,v|m[v.to_sym]=smtp[v];m}
828
841
  # defaults
829
842
  smtp[:tls]||=true
@@ -833,39 +846,47 @@ module Aspera
833
846
  smtp[:domain]||=smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
834
847
  # check minimum required
835
848
  [:server,:port,:domain].each do |n|
836
- raise "missing smtp parameter: #{n}" unless smtp.has_key?(n)
849
+ raise "Missing smtp parameter: #{n}" unless smtp.has_key?(n)
837
850
  end
838
851
  Log.log.debug("smtp=#{smtp}")
839
852
  return smtp
840
853
  end
841
854
 
842
- def send_email(email={})
843
- opts=email_settings
844
- email[:from_name]||=opts[:from_name]
845
- email[:from_email]||=opts[:from_email]
846
- # check minimum required
847
- [:from_name,:from_email,:to,:subject].each do |n|
848
- raise "missing email parameter: #{n}" unless email.has_key?(n)
855
+ # create a clean binding (ruby variable environment)
856
+ def empty_binding
857
+ Kernel.binding
858
+ end
859
+
860
+ def send_email_template(vars,email_template_default=nil)
861
+ vars[:to]||=options.get_option(:notif_to,:mandatory)
862
+ notif_template=options.get_option(:notif_template,email_template_default.nil? ? :mandatory : :optional) || email_template_default
863
+ mail_conf=email_settings
864
+ vars[:from_name]||=mail_conf[:from_name]
865
+ vars[:from_email]||=mail_conf[:from_email]
866
+ [:from_name,:from_email].each do |n|
867
+ raise "Missing email parameter: #{n}" unless vars.has_key?(n)
868
+ end
869
+ start_options=[mail_conf[:domain]]
870
+ start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) and mail_conf.has_key?(:password)
871
+ # create a binding with only variables defined in vars
872
+ template_binding=empty_binding
873
+ # add variables to binding
874
+ vars.each do |k,v|
875
+ raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
876
+ template_binding.local_variable_set(k,v)
849
877
  end
850
- msg = <<END_OF_MESSAGE
851
- From: #{email[:from_name]} <#{email[:from_email]}>
852
- To: <#{email[:to]}>
853
- Subject: #{email[:subject]}
854
-
855
- #{email[:body]}
856
- END_OF_MESSAGE
857
- start_options=[opts[:domain]]
858
- start_options.push(opts[:username],opts[:password],:login) if opts.has_key?(:username) and opts.has_key?(:password)
859
-
860
- smtp = Net::SMTP.new(opts[:server], opts[:port])
861
- smtp.enable_starttls if opts[:tls]
878
+ # execute template
879
+ msg_with_headers=ERB.new(notif_template).result(template_binding)
880
+ Log.dump(:msg_with_headers,msg_with_headers)
881
+ smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
882
+ smtp.enable_starttls if mail_conf[:tls]
862
883
  smtp.start(*start_options) do |smtp|
863
- smtp.send_message(msg, email[:from_email], email[:to])
884
+ smtp.send_message(msg_with_headers, vars[:from_email], vars[:to])
864
885
  end
865
886
  end
866
887
 
867
888
  def save_presets_to_config_file
868
- raise "no configuration loaded" if @config_presets.nil?
889
+ raise 'no configuration loaded' if @config_presets.nil?
869
890
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
870
891
  Log.log.debug "writing #{@option_config_file}"
871
892
  File.write(@option_config_file,@config_presets.to_yaml)
@@ -876,7 +897,7 @@ END_OF_MESSAGE
876
897
  def get_plugin_default_config_name(plugin_sym)
877
898
  raise "internal error: config_presets shall be defined" if @config_presets.nil?
878
899
  if !@use_plugin_defaults
879
- Log.log.debug("skip default config")
900
+ Log.log.debug('skip default config')
880
901
  return nil
881
902
  end
882
903
  if @config_presets.has_key?(CONF_PRESET_DEFAULT) and