aspera-cli 4.1.0 → 4.2.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.
@@ -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
@@ -65,6 +66,8 @@ module Aspera
65
66
  Rest.user_agent=PROGRAM_NAME
66
67
  # must override help methods before parser called (in other constructors)
67
68
  init_global_options()
69
+ # secret manager
70
+ @plugin_env[:secret]=Aspera::Secrets.new
68
71
  # the Config plugin adds the @preset parser
69
72
  @plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,@help_url,Aspera::Cli::VERSION,app_main_folder)
70
73
  # the TransferAgent plugin may use the @preset parser
@@ -229,16 +232,6 @@ module Aspera
229
232
  # load global default options and process
230
233
  @plugin_env[:config].add_plugin_default_preset(Plugins::Config::CONF_GLOBAL_SYM)
231
234
  @opt_mgr.parse_options!
232
- # dual execution locking
233
- lock_port=@opt_mgr.get_option(:lock_port,:optional)
234
- if !lock_port.nil?
235
- begin
236
- # no need to close later, will be freed on process exit. must save in member else it is garbage collected
237
- @tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
238
- rescue => e
239
- raise CliError,"Another instance is already running (lock port=#{lock_port})."
240
- end
241
- end
242
235
  @plugin_env[:config].periodic_check_newer_gem_version
243
236
  if @option_show_config and @opt_mgr.command_or_arg_empty?
244
237
  command_sym=Plugins::Config::CONF_PLUGIN_SYM
@@ -263,6 +256,17 @@ module Aspera
263
256
  @plugin_env[:formater].display_results({:type=>:single_object,:data=>@opt_mgr.declared_options(false)})
264
257
  Process.exit(0)
265
258
  end
259
+ # locking for singkle execution (only after "per plugin" option, in case lock port is there)
260
+ lock_port=@opt_mgr.get_option(:lock_port,:optional)
261
+ if !lock_port.nil?
262
+ begin
263
+ # no need to close later, will be freed on process exit. must save in member else it is garbage collected
264
+ Log.log.debug("Opening lock port #{lock_port.to_i}")
265
+ @tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
266
+ rescue => e
267
+ raise CliError,"Another instance is already running (#{e.message})."
268
+ end
269
+ end
266
270
  # execute and display
267
271
  @plugin_env[:formater].display_results(command_plugin.execute_action)
268
272
  # finish
@@ -270,11 +274,11 @@ module Aspera
270
274
  rescue CliBadArgument => e; exception_info=[e,'Argument',:usage]
271
275
  rescue CliNoSuchId => e; exception_info=[e,'Identifier']
272
276
  rescue CliError => e; exception_info=[e,'Tool',:usage]
273
- rescue Fasp::Error => e; exception_info=[e,"FASP(ascp]"]
274
- rescue Aspera::RestCallError => e; exception_info=[e,"Rest"]
275
- rescue SocketError => e; exception_info=[e,"Network"]
276
- rescue StandardError => e; exception_info=[e,"Other",:debug]
277
- rescue Interrupt => e; exception_info=[e,"Interruption",:debug]
277
+ rescue Fasp::Error => e; exception_info=[e,'FASP(ascp)']
278
+ rescue Aspera::RestCallError => e; exception_info=[e,'Rest']
279
+ rescue SocketError => e; exception_info=[e,'Network']
280
+ rescue StandardError => e; exception_info=[e,'Other',:debug]
281
+ rescue Interrupt => e; exception_info=[e,'Interruption',:debug]
278
282
  end
279
283
  # cleanup file list files
280
284
  TempFileManager.instance.cleanup
@@ -15,7 +15,6 @@ module Aspera
15
15
  class Aoc < BasicAuthPlugin
16
16
  # special value for package id
17
17
  VAL_ALL='ALL'
18
- attr_reader :api_aoc
19
18
  def initialize(env)
20
19
  super(env)
21
20
  @default_workspace_id=nil
@@ -26,19 +25,20 @@ module Aspera
26
25
  @api_aoc=nil
27
26
  @url_token_data=nil
28
27
  @user_info=nil
29
- self.options.add_opt_list(:auth,Oauth.auth_types,'type of Oauth authentication')
28
+ @api_aoc=nil
29
+ self.options.add_opt_list(:auth,Oauth.auth_types,'OAuth type of authentication')
30
30
  self.options.add_opt_list(:operation,[:push,:pull],'client operation for transfers')
31
- self.options.add_opt_simple(:client_id,'API client identifier in application')
32
- self.options.add_opt_simple(:client_secret,'API client passcode')
33
- self.options.add_opt_simple(:redirect_uri,'API client redirect URI')
34
- self.options.add_opt_simple(:private_key,'RSA private key PEM value for JWT (prefix file path with @val:@file:)')
31
+ self.options.add_opt_simple(:client_id,'OAuth API client identifier in application')
32
+ self.options.add_opt_simple(:client_secret,'OAuth API client passcode')
33
+ self.options.add_opt_simple(:redirect_uri,'OAuth API client redirect URI')
34
+ self.options.add_opt_simple(:private_key,'OAuth JWT RSA private key PEM value (prefix file path with @val:@file:)')
35
35
  self.options.add_opt_simple(:workspace,'name of workspace')
36
36
  self.options.add_opt_simple(:name,'resource name')
37
37
  self.options.add_opt_simple(:path,'file or folder path')
38
38
  self.options.add_opt_simple(:link,'public link to shared resource')
39
39
  self.options.add_opt_simple(:new_user_option,'new user creation option')
40
40
  self.options.add_opt_simple(:from_folder,'share to share source folder')
41
- self.options.add_opt_simple(:scope,'scope for AoC API calls')
41
+ self.options.add_opt_simple(:scope,'OAuth scope for AoC API calls')
42
42
  self.options.add_opt_simple(:notify,'notify users that file was received')
43
43
  self.options.add_opt_boolean(:bulk,'bulk operation')
44
44
  self.options.add_opt_boolean(:default_ports,'use standard FASP ports or get from node api')
@@ -52,19 +52,15 @@ module Aspera
52
52
  self.options.parse_options!
53
53
  AoC.set_use_default_ports(self.options.get_option(:default_ports))
54
54
  return if env[:man_only]
55
- @api_aoc=AoC.new(aoc_params('api/v1'))
56
- # add access key secrets
57
- @api_aoc.add_secrets(self.config.get_secrets)
58
55
  end
59
56
 
60
- # call this to populate single AK secret in AoC API object, from options
61
- # make sure secret is available
62
- def find_ak_secret(ak,mandatory=true)
63
- # secret hash is already provisioned
64
- # optionally override with specific secret
65
- @api_aoc.add_secrets({ak=>self.config.get_secret(ak,mandatory)})
66
- # check that secret was provided as single value or dictionary
67
- raise CliBadArgument,"Please provide option secret or entry in option secrets for: #{ak}" unless @api_aoc.has_secret(ak) or !mandatory
57
+ def get_api
58
+ if @api_aoc.nil?
59
+ @api_aoc=AoC.new(aoc_params(AoC::API_V1))
60
+ # add keychain for access key secrets
61
+ @api_aoc.key_chain=@agents[:secret]
62
+ end
63
+ return @api_aoc
68
64
  end
69
65
 
70
66
  # cached user information
@@ -111,14 +107,8 @@ module Aspera
111
107
  return {:type=>:object_list,:data=>items,:fields=>['name','type','recursive_size','size','modified_time','access_level']}
112
108
  when :find
113
109
  thepath=self.options.get_next_argument('path')
114
- exec_prefix='exec:'
115
- expression=self.options.get_option(:value,:optional)||"#{exec_prefix}true"
116
110
  node_file=@api_aoc.resolve_node_file(top_node_file,thepath)
117
- if expression.start_with?(exec_prefix)
118
- test_block=eval "lambda{|f|#{expression[exec_prefix.length..-1]}}"
119
- else
120
- test_block=lambda{|f|f['name'].match(/#{expression}/)}
121
- end
111
+ test_block=Aspera::Node.file_matcher(self.options.get_option(:value,:optional))
122
112
  return {:type=>:object_list,:data=>@api_aoc.find_files(node_file,test_block),:fields=>['path']}
123
113
  when :mkdir
124
114
  thepath=self.options.get_next_argument('path')
@@ -646,7 +636,6 @@ module Aspera
646
636
  return Main.result_success
647
637
  when :v3,:v4
648
638
  res_data=@api_aoc.read(resource_instance_path)[:data]
649
- find_ak_secret(res_data['access_key'])
650
639
  api_node=@api_aoc.get_node_api(res_data)
651
640
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action if command.eql?(:v3)
652
641
  ak_data=api_node.call({:operation=>'GET',:subpath=>"access_keys/#{res_data['access_key']}",:headers=>{'Accept'=>'application/json'}})[:data]
@@ -704,16 +693,17 @@ module Aspera
704
693
  end
705
694
 
706
695
  # must be public
707
- ACTIONS=[ :apiinfo, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
696
+ ACTIONS=[ :reminder, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
708
697
 
709
698
  def execute_action
710
699
  command=self.options.get_next_command(ACTIONS)
700
+ get_api unless [:reminder,:servers].include?(command)
711
701
  case command
712
- when :apiinfo
713
- api_info={}
714
- num=1
715
- Resolv::DNS.open{|dns|dns.each_address('api.ibmaspera.com'){|a| api_info["api.#{num}"]=a;num+=1}}
716
- return {:type=>:single_object,:data=>api_info}
702
+ when :reminder
703
+ # send an email reminder with list of orgs
704
+ user_email=options.get_option(:username,:mandatory)
705
+ Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders',{email: user_email})[:data]
706
+ return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
717
707
  when :bearer_token
718
708
  return {:type=>:text,:data=>@api_aoc.oauth_token}
719
709
  when :organization
@@ -847,7 +837,6 @@ module Aspera
847
837
  # get workspace related information
848
838
  set_workspace_info
849
839
  set_home_node_file
850
- find_ak_secret(@home_node_file[:node_info]['access_key'],false)
851
840
  command_repo=self.options.get_next_command(NODE4_COMMANDS.clone.concat([:short_link]))
852
841
  case command_repo
853
842
  when *NODE4_COMMANDS; return execute_node_gen4_command(command_repo,@home_node_file)
@@ -957,17 +946,14 @@ module Aspera
957
946
  when :admin
958
947
  return execute_admin_action
959
948
  when :servers
960
- self.format.display_status("Beta feature: #{@api_aoc.params[:base_url]}")
961
- server_api=Rest.new(base_url: @api_aoc.params[:base_url])
962
- servers=server_api.read('servers')[:data]
963
- return {:type=>:object_list,:data=>servers}
949
+ return {:type=>:object_list,:data=>Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
964
950
  else
965
951
  raise "internal error: #{command}"
966
952
  end # action
967
953
  raise RuntimeError, "internal error: command shall return"
968
954
  end
969
955
 
970
- private :find_ak_secret,:c_user_info,:aoc_params,:set_workspace_info,:set_home_node_file,:do_bulk_operation,:resolve_package_recipients,:option_url_query,:assert_public_link_types,:execute_admin_action
956
+ private :c_user_info,:aoc_params,:set_workspace_info,:set_home_node_file,:do_bulk_operation,:resolve_package_recipients,:option_url_query,:assert_public_link_types,:execute_admin_action
971
957
  private_constant :VAL_ALL,:NODE4_COMMANDS
972
958
 
973
959
  end # AoC
@@ -107,7 +107,7 @@ module Aspera
107
107
  :auth => {
108
108
  :type => :basic,
109
109
  :username => access_key_id,
110
- :password => self.config.get_secret(access_key_id)}})
110
+ :password => @agents[:secret].get_secret(access_key_id)}})
111
111
  command=self.options.get_next_command(Node::COMMON_ACTIONS)
112
112
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command)
113
113
  when :cluster
@@ -116,7 +116,7 @@ module Aspera
116
116
  :auth => {
117
117
  :type => :basic,
118
118
  :username => access_key_id,
119
- :password => self.config.get_secret(access_key_id)
119
+ :password => @agents[:secret].get_secret(access_key_id)
120
120
  }}
121
121
  api_ak_auth=Rest.new(rest_params)
122
122
  return {:type=>:single_object, :data=>api_ak_auth.read("servers")[:data]}
@@ -27,6 +27,7 @@ module Aspera
27
27
  CONF_PRESET_CONFIG='config'
28
28
  CONF_PRESET_VERSION='version'
29
29
  CONF_PRESET_DEFAULT='default'
30
+ CONF_PRESET_GLOBAL='global_common_defaults'
30
31
  CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
31
32
  CONF_GLOBAL_SYM = :config
32
33
  # old tool name
@@ -45,6 +46,7 @@ module Aspera
45
46
  CONNECT_VERSIONS = 'connectversions.js'
46
47
  TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_sdk'
47
48
  DEMO='demo'
49
+ DEMO_SERVER_PRESET='demoserver'
48
50
  AOC_PATH_API_CLIENTS='admin/api-clients'
49
51
  def option_preset; nil; end
50
52
 
@@ -52,13 +54,11 @@ module Aspera
52
54
  self.options.add_option_preset(preset_by_name(value))
53
55
  end
54
56
 
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
57
+ 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
57
58
 
58
59
  def initialize(env,tool_name,help_url,version,main_folder)
59
60
  super(env)
60
- @option_ak_secret=nil
61
- @option_secrets={}
61
+ raise 'missing secret manager' if @agents[:secret].nil?
62
62
  @plugins={}
63
63
  @plugin_lookup_folders=[]
64
64
  @use_plugin_defaults=true
@@ -87,52 +87,43 @@ module Aspera
87
87
  self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
88
88
  self.options.set_obj_attr(:use_product,self,:option_use_product)
89
89
  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 }
90
+ self.options.set_obj_attr(:secret,@agents[:secret],:default_secret)
91
+ self.options.set_obj_attr(:secrets,@agents[:secret],:all_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 }
94
94
  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)")
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,'default secret')
103
+ self.options.add_opt_simple(:secrets,'secret repository (Hash)')
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)')
108
108
  self.options.set_option(:use_generic_client,true)
109
109
  self.options.set_option(:test_mode,false)
110
110
  self.options.set_option(:version_check_days,7)
111
111
  self.options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
112
112
  self.options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
113
113
  self.options.parse_options!
114
- raise CliBadArgument,"secrets shall be Hash" unless @option_secrets.is_a?(Hash)
114
+ raise CliBadArgument,'secrets shall be Hash' unless @agents[:secret].all_secrets.is_a?(Hash)
115
115
  Fasp::Installation.instance.folder=self.options.get_option(:sdk_folder,:mandatory)
116
116
  end
117
117
 
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
118
  def check_gem_version
129
119
  this_gem_name=File.basename(File.dirname(self.class.gem_root)).gsub(/-[0-9].*$/,'')
130
120
  latest_version=begin
131
- Rest.new(base_url: "https://rubygems.org/api/v1").read("versions/#{this_gem_name}/latest.json")[:data]['version']
121
+ Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{this_gem_name}/latest.json")[:data]['version']
132
122
  rescue
133
- nil
123
+ Log.log.warn('Could not retrieve latest gem version on rubygems.')
124
+ '0'
134
125
  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)}
126
+ 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
127
  end
137
128
 
138
129
  def periodic_check_newer_gem_version
@@ -149,19 +140,18 @@ module Aspera
149
140
  ids: ['version_last_check'])
150
141
  # get persisted date or nil
151
142
  last_check_date = begin
152
- Date.strptime(last_check_array.first, "%Y/%m/%d")
143
+ Date.strptime(last_check_array.first, '%Y/%m/%d')
153
144
  rescue
154
145
  nil
155
146
  end
156
147
  current_date=Date.today
157
- Log.log.info("last check: #{last_check_date.class}")
148
+ Log.log.debug("days elapsed: #{last_check_date.is_a?(Date) ? current_date - last_check_date : last_check_date.class.name}")
158
149
  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")
150
+ last_check_array[0]=current_date.strftime('%Y/%m/%d')
161
151
  check_date_persist.save
162
152
  check_data=check_gem_version
163
153
  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]}")
154
+ Log.log.warn("A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}")
165
155
  end
166
156
  end
167
157
  end
@@ -200,7 +190,7 @@ module Aspera
200
190
  require 'openssl'
201
191
  priv_key = OpenSSL::PKey::RSA.new(4096)
202
192
  File.write(private_key_path,priv_key.to_s)
203
- File.write(private_key_path+".pub",priv_key.public_key.to_s)
193
+ File.write(private_key_path+'.pub',priv_key.public_key.to_s)
204
194
  nil
205
195
  end
206
196
 
@@ -226,7 +216,7 @@ module Aspera
226
216
  r=[]
227
217
  t.each do |k,v|
228
218
  v.each do |kk,vv|
229
- r.push({"config"=>k,"parameter"=>kk,"value"=>vv})
219
+ r.push({'config'=>k,'parameter'=>kk,'value'=>vv})
230
220
  end
231
221
  end
232
222
  return r
@@ -236,12 +226,12 @@ module Aspera
236
226
  # creates one if none already created
237
227
  # @return preset that contains global default
238
228
  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
229
+ # get default preset if it exists
230
+ global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM) || CONF_PRESET_GLOBAL
231
+ @config_presets[global_default_preset_name]||={}
244
232
  @config_presets[global_default_preset_name][key.to_s]=value
233
+ self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
234
+ save_presets_to_config_file
245
235
  return global_default_preset_name
246
236
  end
247
237
 
@@ -260,7 +250,7 @@ module Aspera
260
250
  # @return the hash from name (also expands possible includes)
261
251
  def preset_by_name(config_name, include_path=[])
262
252
  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)
253
+ raise CliError,'loop in include' if include_path.include?(config_name)
264
254
  return expanded_with_preset_includes(@config_presets[config_name],include_path.clone.push(config_name))
265
255
  end
266
256
 
@@ -295,7 +285,7 @@ module Aspera
295
285
  end
296
286
 
297
287
  def option_use_product
298
- "write-only value"
288
+ 'write-only value'
299
289
  end
300
290
 
301
291
  def convert_preset_path(old_name,new_name,files_to_copy)
@@ -339,22 +329,21 @@ module Aspera
339
329
  # if no file found, create default config
340
330
  if conf_file_to_load.nil?
341
331
  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}}
332
+ @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version}}
344
333
  else
345
334
  Log.log.debug "loading #{@option_config_file}"
346
335
  @config_presets=YAML.load_file(conf_file_to_load)
347
336
  end
348
337
  files_to_copy=[]
349
338
  Log.log.debug "Available_presets: #{@config_presets}"
350
- raise "Expecting YAML Hash" unless @config_presets.is_a?(Hash)
339
+ raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
351
340
  # check there is at least the config section
352
341
  if !@config_presets.has_key?(CONF_PRESET_CONFIG)
353
342
  raise "Cannot find key: #{CONF_PRESET_CONFIG}"
354
343
  end
355
344
  version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
356
345
  if version.nil?
357
- raise "No version found in config section."
346
+ raise 'No version found in config section.'
358
347
  end
359
348
  # oldest compatible conf file format, update to latest version when an incompatible change is made
360
349
  # check compatibility of version of conf file
@@ -383,24 +372,24 @@ module Aspera
383
372
  end
384
373
  # Place new compatibility code here
385
374
  if save_required
386
- Log.log.warn("Saving automatic conversion.")
375
+ Log.log.warn('Saving automatic conversion.')
387
376
  @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@program_version
388
377
  save_presets_to_config_file
389
- Log.log.warn("Copying referenced files")
378
+ Log.log.warn('Copying referenced files')
390
379
  files_to_copy.each do |file|
391
380
  FileUtils.cp(file,@main_folder)
392
381
  Log.log.warn("..#{file} -> #{@main_folder}")
393
382
  end
394
383
  end
395
384
  rescue Psych::SyntaxError => e
396
- Log.log.error("YAML error in config file")
385
+ Log.log.error('YAML error in config file')
397
386
  raise e
398
387
  rescue => e
399
388
  Log.log.debug("-> #{e}")
400
389
  new_name="#{@option_config_file}.pre#{@program_version}.manual_conversion_needed"
401
390
  File.rename(@option_config_file,new_name)
402
391
  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.")
392
+ Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
404
393
  raise CliError,e.to_s
405
394
  end
406
395
  end
@@ -465,10 +454,10 @@ module Aspera
465
454
  fileurl = one_link['href']
466
455
  filename=fileurl.gsub(%r{.*/},'')
467
456
  api_connect_cdn.call({:operation=>'GET',:subpath=>fileurl,:save_to_file=>File.join(folder_dest,filename)})
468
- return Main.result_status("downloaded: #{filename}")
457
+ return Main.result_status("Downloaded: #{filename}")
469
458
  when :open #
470
459
  OpenApplication.instance.uri(one_link['href'])
471
- return Main.result_status("opened: #{one_link['href']}")
460
+ return Main.result_status("Opened: #{one_link['href']}")
472
461
  end
473
462
  end
474
463
  end
@@ -481,18 +470,16 @@ module Aspera
481
470
  when :connect
482
471
  return execute_connect_action
483
472
  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}"}
473
+ ascp_path=self.options.get_next_argument('path to ascp')
474
+ ascp_version=Fasp::Installation.instance.get_ascp_version(ascp_path)
475
+ self.format.display_status("ascp version: #{ascp_version}")
476
+ preset_name=set_global_default(:ascp_path,ascp_path)
477
+ return Main.result_status("Saved to default global preset #{preset_name}")
491
478
  when :show # shows files used
492
479
  return {:type=>:status, :data=>Fasp::Installation.instance.path(:ascp)}
493
480
  when :info # shows files used
494
481
  data=Fasp::Installation::FILES.inject({}) do |m,v|
495
- m[v.to_s]=Fasp::Installation.instance.path(v) rescue "Not Found"
482
+ m[v.to_s]=Fasp::Installation.instance.path(v) rescue 'Not Found'
496
483
  m
497
484
  end
498
485
  # read PATHs from ascp directly, and pvcl modules as well
@@ -524,17 +511,16 @@ module Aspera
524
511
  default_product=self.options.get_next_argument('product name')
525
512
  Fasp::Installation.instance.use_ascp_from_product(default_product)
526
513
  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}"}
514
+ return Main.result_status("Saved to default global preset #{preset_name}")
529
515
  end
530
516
  when :install
531
517
  v=Fasp::Installation.instance.install_sdk(self.options.get_option(:sdk_url,:mandatory))
532
- return {:type=>:status, :data=>"Installed version #{v}"}
518
+ return Main.result_status("Installed version #{v}")
533
519
  end
534
520
  raise "unexpected case: #{command}"
535
521
  end
536
522
 
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]
523
+ 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
524
 
539
525
  # "config" plugin
540
526
  def execute_action
@@ -553,7 +539,7 @@ module Aspera
553
539
  when :delete
554
540
  @config_presets.delete(config_name)
555
541
  save_presets_to_config_file
556
- return Main.result_status("deleted: #{config_name}")
542
+ return Main.result_status("Deleted: #{config_name}")
557
543
  when :get
558
544
  param_name=self.options.get_next_argument('parameter name')
559
545
  value=selected_preset[param_name]
@@ -566,7 +552,7 @@ module Aspera
566
552
  param_name=self.options.get_next_argument('parameter name')
567
553
  selected_preset.delete(param_name)
568
554
  save_presets_to_config_file
569
- return Main.result_status("removed: #{config_name}: #{param_name}")
555
+ return Main.result_status("Removed: #{config_name}: #{param_name}")
570
556
  when :set
571
557
  param_name=self.options.get_next_argument('parameter name')
572
558
  param_value=self.options.get_next_argument('parameter value')
@@ -579,7 +565,7 @@ module Aspera
579
565
  end
580
566
  selected_preset[param_name]=param_value
581
567
  save_presets_to_config_file
582
- return Main.result_status("updated: #{config_name}: #{param_name} <- #{param_value}")
568
+ return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
583
569
  when :initialize
584
570
  config_value=self.options.get_next_argument('extended value (Hash)')
585
571
  if @config_presets.has_key?(config_name)
@@ -587,7 +573,7 @@ module Aspera
587
573
  end
588
574
  @config_presets[config_name]=config_value
589
575
  save_presets_to_config_file
590
- return Main.result_status("modified: #{@option_config_file}")
576
+ return Main.result_status("Modified: #{@option_config_file}")
591
577
  when :update
592
578
  default_for_plugin=self.options.get_option(:default,:optional)
593
579
  # get unprocessed options
@@ -600,7 +586,7 @@ module Aspera
600
586
  @config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
601
587
  end
602
588
  save_presets_to_config_file
603
- return Main.result_status("updated: #{config_name}")
589
+ return Main.result_status("Updated: #{config_name}")
604
590
  when :ask
605
591
  self.options.ask_missing_mandatory=:yes
606
592
  @config_presets[config_name]||={}
@@ -609,7 +595,7 @@ module Aspera
609
595
  @config_presets[config_name][optionname]=option_value
610
596
  end
611
597
  save_presets_to_config_file
612
- return Main.result_status("updated: #{config_name}")
598
+ return Main.result_status("Updated: #{config_name}")
613
599
  end
614
600
  when :documentation
615
601
  section=options.get_next_argument('private key file path',:single,:optional)
@@ -622,9 +608,9 @@ module Aspera
622
608
  when :genkey # generate new rsa key
623
609
  private_key_path=self.options.get_next_argument('private key file path')
624
610
  generate_new_key(private_key_path)
625
- return Main.result_status('generated key: '+private_key_path)
611
+ return Main.result_status('Generated key: '+private_key_path)
626
612
  when :echo # display the content of a value given on command line
627
- result={:type=>:other_struct, :data=>self.options.get_next_argument("value")}
613
+ result={:type=>:other_struct, :data=>self.options.get_next_argument('value')}
628
614
  # special for csv
629
615
  result[:type]=:object_list if result[:data].is_a?(Array) and result[:data].first.is_a?(Hash)
630
616
  return result
@@ -645,7 +631,7 @@ module Aspera
645
631
  appli=ApiDetector.discover_product(instance_url)
646
632
  case appli[:product]
647
633
  when :aoc
648
- self.format.display_status("Detected: Aspera on Cloud".bold)
634
+ self.format.display_status('Detected: Aspera on Cloud'.bold)
649
635
  organization,instance_domain=AoC.parse_url(instance_url)
650
636
  aspera_preset_name='aoc_'+organization
651
637
  self.format.display_status("Preparing preset: #{aspera_preset_name}")
@@ -659,7 +645,7 @@ module Aspera
659
645
  private_key_path=self.options.get_option(:pkeypath,:optional)
660
646
  # give a chance to provide
661
647
  if private_key_path.nil?
662
- self.format.display_status("Please provide path to your private RSA key, or empty to generate one:")
648
+ self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
663
649
  private_key_path=self.options.get_option(:pkeypath,:mandatory).to_s
664
650
  end
665
651
  # else generate path
@@ -667,11 +653,11 @@ module Aspera
667
653
  private_key_path=File.join(@main_folder,'aspera_aoc_key')
668
654
  end
669
655
  if File.exist?(private_key_path)
670
- self.format.display_status("Using existing key:")
656
+ self.format.display_status('Using existing key:')
671
657
  else
672
- self.format.display_status("Generating key...")
658
+ self.format.display_status('Generating key...')
673
659
  generate_new_key(private_key_path)
674
- self.format.display_status("Created:")
660
+ self.format.display_status('Created:')
675
661
  end
676
662
  self.format.display_status("#{private_key_path}")
677
663
  pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
@@ -681,32 +667,32 @@ module Aspera
681
667
  self.options.get_option(:username,:mandatory)
682
668
  # instanciate AoC plugin, so that command line options are known
683
669
  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
670
+ aoc_api=files_plugin.get_api
685
671
  auto_set_pub_key=false
686
672
  auto_set_jwt=false
687
673
  use_browser_authentication=false
688
674
  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)
675
+ self.format.display_status('Using global client_id.')
676
+ self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
677
+ self.format.display_status('Navigate to your "Account Settings"'.red)
678
+ self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
693
679
  self.format.display_status("#{pub_key_pem}")
694
680
  if ! self.options.get_option(:test_mode)
695
- self.format.display_status("Once updated or validated, press enter.")
681
+ self.format.display_status('Once updated or validated, press enter.')
696
682
  OpenApplication.instance.uri(instance_url)
697
683
  STDIN.gets
698
684
  end
699
685
  else
700
- self.format.display_status("Using organization specific client_id.")
686
+ self.format.display_status('Using organization specific client_id.')
701
687
  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:")
688
+ self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
689
+ self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
690
+ self.format.display_status('Create or check if there is an existing integration named:')
705
691
  self.format.display_status("- name: #{@tool_name}")
706
692
  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)
693
+ self.format.display_status('- origin: localhost')
694
+ self.format.display_status('Once created or identified,')
695
+ self.format.display_status('Please enter:'.red)
710
696
  end
711
697
  OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
712
698
  self.options.get_option(:client_id,:mandatory)
@@ -714,7 +700,7 @@ module Aspera
714
700
  use_browser_authentication=true
715
701
  end
716
702
  if use_browser_authentication
717
- self.format.display_status("We will use web authentication to bootstrap.")
703
+ self.format.display_status('We will use web authentication to bootstrap.')
718
704
  auto_set_pub_key=true
719
705
  auto_set_jwt=true
720
706
  @api_aoc.oauth.params[:auth]=:web
@@ -728,7 +714,7 @@ module Aspera
728
714
  aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
729
715
  end
730
716
  if auto_set_jwt
731
- self.format.display_status("Enabling JWT for client")
717
+ self.format.display_status('Enabling JWT for client')
732
718
  aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
733
719
  end
734
720
  self.format.display_status("creating new config preset: #{aspera_preset_name}")
@@ -745,14 +731,14 @@ module Aspera
745
731
  end
746
732
  self.format.display_status("Setting config preset as default for #{AOC_COMMAND_CURRENT}")
747
733
  @config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
748
- self.format.display_status("saving config file")
734
+ self.format.display_status('saving config file')
749
735
  save_presets_to_config_file
750
736
  return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
751
737
  else
752
738
  raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
753
739
  end
754
740
  when :export_to_cli
755
- self.format.display_status("Exporting: Aspera on Cloud")
741
+ self.format.display_status('Exporting: Aspera on Cloud')
756
742
  require 'aspera/cli/plugins/aoc'
757
743
  # need url / username
758
744
  add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
@@ -785,11 +771,11 @@ module Aspera
785
771
  entry.merge!(new_conf)
786
772
  end
787
773
  File.write(cli_conf_file,JSON.pretty_generate(data))
788
- return Main.result_status("updated: #{cli_conf_file}")
774
+ return Main.result_status("Updated: #{cli_conf_file}")
789
775
  when :detect
790
776
  # need url / username
791
777
  BasicAuthPlugin.new(@agents)
792
- return Main.result_status("found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
778
+ return Main.result_status("Found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
793
779
  when :coffee
794
780
  OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
795
781
  return Main.result_nothing
@@ -802,7 +788,7 @@ module Aspera
802
788
  when :file
803
789
  return Main.result_status(@option_config_file)
804
790
  when :email_test
805
- dest_email=self.options.get_next_argument("destination email")
791
+ dest_email=self.options.get_next_argument('destination email')
806
792
  send_email({
807
793
  to: dest_email,
808
794
  subject: 'Amelia email test',
@@ -813,11 +799,28 @@ module Aspera
813
799
  return {:type=>:single_object,:data=>email_settings}
814
800
  when :proxy_check
815
801
  pac_url=self.options.get_option(:fpac,:mandatory)
816
- server_url=self.options.get_next_argument("server url")
802
+ server_url=self.options.get_next_argument('server url')
817
803
  return Main.result_status(Aspera::ProxyAutoConfig.new(UriReader.read(pac_url)).get_proxy(server_url))
818
804
  when :check_update
819
805
  return {:type=>:single_object, :data=>check_gem_version}
820
- else raise "error"
806
+ when :initdemo
807
+ if @config_presets.has_key?(DEMO_SERVER_PRESET)
808
+ Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
809
+ else
810
+ Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
811
+ @config_presets[DEMO_SERVER_PRESET]={'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
812
+ end
813
+ @config_presets[CONF_PRESET_DEFAULT]||={}
814
+ if @config_presets[CONF_PRESET_DEFAULT].has_key?('server')
815
+ Log.log.warn("server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT]['server']}")
816
+ Log.log.warn("use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT]['server'])
817
+ else
818
+ @config_presets[CONF_PRESET_DEFAULT]['server']=DEMO_SERVER_PRESET
819
+ Log.log.info("setting server default preset to : #{DEMO_SERVER_PRESET}")
820
+ end
821
+ save_presets_to_config_file
822
+ return Main.result_status("Done")
823
+ else raise 'error'
821
824
  end
822
825
  end
823
826
 
@@ -865,7 +868,7 @@ END_OF_MESSAGE
865
868
  end
866
869
 
867
870
  def save_presets_to_config_file
868
- raise "no configuration loaded" if @config_presets.nil?
871
+ raise 'no configuration loaded' if @config_presets.nil?
869
872
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
870
873
  Log.log.debug "writing #{@option_config_file}"
871
874
  File.write(@option_config_file,@config_presets.to_yaml)
@@ -876,7 +879,7 @@ END_OF_MESSAGE
876
879
  def get_plugin_default_config_name(plugin_sym)
877
880
  raise "internal error: config_presets shall be defined" if @config_presets.nil?
878
881
  if !@use_plugin_defaults
879
- Log.log.debug("skip default config")
882
+ Log.log.debug('skip default config')
880
883
  return nil
881
884
  end
882
885
  if @config_presets.has_key?(CONF_PRESET_DEFAULT) and