aspera-cli 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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