Class: Aspera::Cli::Plugins::Config

Inherits:
Aspera::Cli::Plugin show all
Defined in:
lib/aspera/cli/plugins/config.rb

Overview

manage the CLI config file

Constant Summary collapse

CONF_PLUGIN_SYM =

Plugins::Config.name.split(‘::’).last.downcase.to_sym

:config
CONF_GLOBAL_SYM =
:config
CONNECT_WEB_URL =
'https://d3gcli72yxqn2z.cloudfront.net/connect'
CONNECT_VERSIONS =
'connectversions.js'
EXTV_INCLUDE_PRESETS =
'incps'
EXTV_PRESET =
'preset'
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]

Constants inherited from Aspera::Cli::Plugin

Aspera::Cli::Plugin::ALL_OPS, Aspera::Cli::Plugin::GLOBAL_OPS, Aspera::Cli::Plugin::INSTANCE_OPS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Aspera::Cli::Plugin

#config, #entity_action, #entity_command, #format, #options, #transfer

Constructor Details

#initialize(env, tool_name, help_url, version) ⇒ Config

Returns a new instance of Config.

Raises:



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/aspera/cli/plugins/config.rb', line 54

def initialize(env,tool_name,help_url,version)
  super(env)
  @option_ak_secret=nil
  @option_secrets={}
  @plugins={}
  @plugin_lookup_folders=[]
  @use_plugin_defaults=true
  @config_presets=nil
  @connect_versions=nil
  @program_version=version
  @tool_name=tool_name
  @help_url=help_url
  tool_main_env_var="#{tool_name.upcase}_HOME"
  if ENV.has_key?(tool_main_env_var)
    @main_folder=ENV[tool_main_env_var]
  else
    user_home_folder=Dir.home
    raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{tool_main_env_var}." unless Dir.exist?(user_home_folder)
    @main_folder=File.join(user_home_folder,ASPERA_HOME_FOLDER_NAME,tool_name)
  end
  @conf_file_default=File.join(@main_folder,DEFAULT_CONFIG_FILENAME)
  @option_config_file=@conf_file_default
  Log.log.debug("#{tool_name} folder: #{@main_folder}")
  # set folder for FASP SDK
  Fasp::Installation.instance.folder=File.join(@main_folder,'sdk')
  add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
  add_plugin_lookup_folder(self.class.gem_plugins_folder)
  # do file parameter first
  self.options.set_obj_attr(:config_file,self,:option_config_file)
  self.options.add_opt_simple(:config_file,"read parameters from file in YAML format, current=#{@option_config_file}")
  self.options.parse_options!
  # read correct file
  read_config_file
  # add preset handler (needed for smtp)
  ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
  ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
  self.options.set_obj_attr(:override,self,:option_override,:no)
  self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
  self.options.set_obj_attr(:use_product,self,:option_use_product)
  self.options.set_obj_attr(:preset,self,:option_preset)
  self.options.set_obj_attr(:secret,self,:option_ak_secret)
  self.options.set_obj_attr(:secrets,self,:option_secrets)
  self.options.add_opt_boolean(:override,"override existing value")
  self.options.add_opt_switch(:no_default,"-N","do not load default configuration for plugin") { @use_plugin_defaults=false }
  self.options.add_opt_boolean(:use_generic_client,'wizard: AoC: use global or org specific jwt client id')
  self.options.add_opt_simple(:pkeypath,"path to private key for JWT (wizard)")
  self.options.add_opt_simple(:ascp_path,"path to ascp")
  self.options.add_opt_simple(:use_product,"use ascp from specified product")
  self.options.add_opt_simple(:smtp,"smtp configuration (extended value: hash)")
  self.options.add_opt_simple(:fpac,"proxy auto configuration URL")
  self.options.add_opt_simple(:preset,"-PVALUE","load the named option preset from current config file")
  self.options.add_opt_simple(:default,"set as default configuration for specified plugin")
  self.options.add_opt_simple(:secret,"access key secret for node")
  self.options.add_opt_simple(:secrets,"access key secret for node")
  self.options.add_opt_boolean(:test_mode,"skip user validation in wizard mode")
  self.options.set_option(:use_generic_client,true)
  self.options.set_option(:test_mode,false)
  self.options.parse_options!
  raise CliBadArgument,"secrets shall be Hash" unless @option_secrets.is_a?(Hash)
end

Instance Attribute Details

#gem_urlObject (readonly)

Returns the value of attribute gem_url.



207
208
209
# File 'lib/aspera/cli/plugins/config.rb', line 207

def gem_url
  @gem_url
end

#main_folderObject (readonly)

$HOME/.aspera/‘program_name`



206
207
208
# File 'lib/aspera/cli/plugins/config.rb', line 206

def main_folder
  @main_folder
end

#option_ak_secretObject

Returns the value of attribute option_ak_secret.



52
53
54
# File 'lib/aspera/cli/plugins/config.rb', line 52

def option_ak_secret
  @option_ak_secret
end

#option_config_fileObject

Returns the value of attribute option_config_file.



210
211
212
# File 'lib/aspera/cli/plugins/config.rb', line 210

def option_config_file
  @option_config_file
end

#option_overrideObject

Returns the value of attribute option_override.



209
210
211
# File 'lib/aspera/cli/plugins/config.rb', line 209

def option_override
  @option_override
end

#option_secretsObject

Returns the value of attribute option_secrets.



52
53
54
# File 'lib/aspera/cli/plugins/config.rb', line 52

def option_secrets
  @option_secrets
end

#pluginsObject (readonly)

Returns the value of attribute plugins.



208
209
210
# File 'lib/aspera/cli/plugins/config.rb', line 208

def plugins
  @plugins
end

Instance Method Details

#add_plugin_default_preset(plugin_name_sym) ⇒ Object

loads default parameters of plugin if no -P parameter and if there is a section defined for the plugin in the “default” section try to find: conffile[conffile[plugin_str]]

Parameters:

  • plugin_name_sym

    : symbol for plugin name



146
147
148
149
150
151
# File 'lib/aspera/cli/plugins/config.rb', line 146

def add_plugin_default_preset(plugin_name_sym)
  default_config_name=get_plugin_default_config_name(plugin_name_sym)
  Log.log.debug("add_plugin_default_preset:#{plugin_name_sym}:#{default_config_name}")
  self.options.add_option_preset(preset_by_name(default_config_name),:unshift) unless default_config_name.nil?
  return nil
end

#add_plugin_info(path) ⇒ Object



380
381
382
383
384
385
386
387
388
389
# File 'lib/aspera/cli/plugins/config.rb', line 380

def add_plugin_info(path)
  raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
  plugin_symbol=File.basename(path,RUBY_FILE_EXT).to_sym
  req=path.gsub(/#{RUBY_FILE_EXT}$/,'')
  if @plugins.has_key?(plugin_symbol)
    Log.log.warn("skipping plugin already registered: #{plugin_symbol}")
    return
  end
  @plugins[plugin_symbol]={:source=>path,:require_stanza=>req}
end

#add_plugin_lookup_folder(folder) ⇒ Object



376
377
378
# File 'lib/aspera/cli/plugins/config.rb', line 376

def add_plugin_lookup_folder(folder)
  @plugin_lookup_folders.push(folder)
end

#add_plugins_from_lookup_foldersObject

find plugins in defined paths



364
365
366
367
368
369
370
371
372
373
374
# File 'lib/aspera/cli/plugins/config.rb', line 364

def add_plugins_from_lookup_folders
  @plugin_lookup_folders.each do |folder|
    if File.directory?(folder)
      #TODO: add gem root to load path ? and require short folder ?
      #$LOAD_PATH.push(folder) if i[:add_path]
      Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
        add_plugin_info(File.join(folder,source))
      end
    end
  end
end

#connect_versionsObject

retrieve structure from cloud (CDN) with all versions available



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/aspera/cli/plugins/config.rb', line 126

def connect_versions
  if @connect_versions.nil?
    api_connect_cdn=Rest.new({:base_url=>CONNECT_WEB_URL})
    javascript=api_connect_cdn.call({:operation=>'GET',:subpath=>CONNECT_VERSIONS})
    # get result on one line
    connect_versions_javascript=javascript[:http].body.gsub(/\r?\n\s*/,'')
    Log.log.debug("javascript=[\n#{connect_versions_javascript}\n]")
    # get javascript object only
    found=connect_versions_javascript.match(/^.*? = (.*);/)
    raise CliError,'Problen when getting connect versions from internet' if found.nil?
    alldata=JSON.parse(found[1])
    @connect_versions=alldata['entries']
  end
  return @connect_versions
end

#convert_preset_path(old_name, new_name, files_to_copy) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/aspera/cli/plugins/config.rb', line 256

def convert_preset_path(old_name,new_name,files_to_copy)
  old_subpath=File.join('',ASPERA_HOME_FOLDER_NAME,old_name,'')
  new_subpath=File.join('',ASPERA_HOME_FOLDER_NAME,new_name,'')
  # convert possible keys located in config folder
  @config_presets.values.select{|p|p.is_a?(Hash)}.each do |preset|
    preset.values.select{|v|v.is_a?(String) and v.include?(old_subpath)}.each do |value|
      old_val=value.clone
      included_path=File.expand_path(old_val.gsub(/^@file:/,''))
      files_to_copy.push(included_path) unless files_to_copy.include?(included_path) or !File.exist?(included_path)
      value.gsub!(old_subpath,new_subpath)
      Log.log.warn("Converted config value: #{old_val} -> #{value}")
    end
  end
end

#convert_preset_plugin_name(old_name, new_name) ⇒ Object



271
272
273
274
275
276
277
# File 'lib/aspera/cli/plugins/config.rb', line 271

def convert_preset_plugin_name(old_name,new_name)
  if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash) and @config_presets[CONF_PRESET_DEFAULT].has_key?(old_name)
    @config_presets[CONF_PRESET_DEFAULT][new_name]=@config_presets[CONF_PRESET_DEFAULT][old_name]
    @config_presets[CONF_PRESET_DEFAULT].delete(old_name)
    Log.log.warn("Converted plugin default: #{old_name} -> #{new_name}")
  end
end

#email_settingsObject



771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'lib/aspera/cli/plugins/config.rb', line 771

def email_settings
  smtp=self.options.get_option(:smtp,:mandatory)
  # change string keys into symbols
  smtp=smtp.keys.inject({}){|m,v|m[v.to_sym]=smtp[v];m}
  # defaults
  smtp[:tls]||=true
  smtp[:port]||=smtp[:tls]?587:25
  smtp[:from_email]||=smtp[:username] if smtp.has_key?(:username)
  smtp[:from_name]||=smtp[:from_email].gsub(/@.*$/,'').gsub(/[^a-zA-Z]/,' ').capitalize if smtp.has_key?(:username)
  smtp[:domain]||=smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
  # check minimum required
  [:server,:port,:domain].each do |n|
    raise "missing smtp parameter: #{n}" unless smtp.has_key?(n)
  end
  Log.log.debug("smtp=#{smtp}")
  return smtp
end

#execute_actionObject

“config” plugin



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
# File 'lib/aspera/cli/plugins/config.rb', line 490

def execute_action
  action=self.options.get_next_command(ACTIONS)
  case action
  when :id
    config_name=self.options.get_next_argument('config name')
    action=self.options.get_next_command([:show,:delete,:set,:get,:unset,:initialize,:update,:ask])
    # those operations require existing option
    raise "no such preset: #{config_name}" if [:show,:delete,:get,:unset].include?(action) and !@config_presets.has_key?(config_name)
    selected_preset=@config_presets[config_name]
    case action
    when :show
      raise "no such config: #{config_name}" if selected_preset.nil?
      return {:type=>:single_object,:data=>selected_preset}
    when :delete
      @config_presets.delete(config_name)
      save_presets_to_config_file
      return Main.result_status("deleted: #{config_name}")
    when :get
      param_name=self.options.get_next_argument('parameter name')
      value=selected_preset[param_name]
      raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
      case value
      when Numeric,String; return {:type=>:text,:data=>ExtendedValue.instance.evaluate(value.to_s)}
      end
      return {:type=>:single_object,:data=>value}
    when :unset
      param_name=self.options.get_next_argument('parameter name')
      selected_preset.delete(param_name)
      save_presets_to_config_file
      return Main.result_status("removed: #{config_name}: #{param_name}")
    when :set
      param_name=self.options.get_next_argument('parameter name')
      param_value=self.options.get_next_argument('parameter value')
      if !@config_presets.has_key?(config_name)
        Log.log.debug("no such config name: #{config_name}, initializing")
        selected_preset=@config_presets[config_name]={}
      end
      if selected_preset.has_key?(param_name)
        Log.log.warn("overwriting value: #{selected_preset[param_name]}")
      end
      selected_preset[param_name]=param_value
      save_presets_to_config_file
      return Main.result_status("updated: #{config_name}: #{param_name} <- #{param_value}")
    when :initialize
      config_value=self.options.get_next_argument('extended value (Hash)')
      if @config_presets.has_key?(config_name)
        Log.log.warn("configuration already exists: #{config_name}, overwriting")
      end
      @config_presets[config_name]=config_value
      save_presets_to_config_file
      return Main.result_status("modified: #{@option_config_file}")
    when :update
      default_for_plugin=self.options.get_option(:default,:optional)
      #  get unprocessed options
      theopts=self.options.get_options_table
      Log.log.debug("opts=#{theopts}")
      @config_presets[config_name]||={}
      @config_presets[config_name].merge!(theopts)
      if ! default_for_plugin.nil?
        @config_presets[CONF_PRESET_DEFAULT]||=Hash.new
        @config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
      end
      save_presets_to_config_file
      return Main.result_status("updated: #{config_name}")
    when :ask
      self.options.ask_missing_mandatory=:yes
      @config_presets[config_name]||={}
      self.options.get_next_argument('option names',:multiple).each do |optionname|
        option_value=self.options.get_interactive(:option,optionname)
        @config_presets[config_name][optionname]=option_value
      end
      save_presets_to_config_file
      return Main.result_status("updated: #{config_name}")
    end
  when :documentation
    OpenApplication.instance.uri(@help_url)
    return Main.result_nothing
  when :open
    OpenApplication.instance.uri("#{@option_config_file}") #file://
    return Main.result_nothing
  when :genkey # generate new rsa key
    private_key_path=self.options.get_next_argument('private key file path')
    generate_new_key(private_key_path)
    return Main.result_status('generated key: '+private_key_path)
  when :echo # display the content of a value given on command line
    result={:type=>:other_struct, :data=>self.options.get_next_argument("value")}
    # special for csv
    result[:type]=:object_list if result[:data].is_a?(Array) and result[:data].first.is_a?(Hash)
    return result
  when :flush_tokens
    deleted_files=Oauth.flush_tokens
    return {:type=>:value_list, :name=>'file',:data=>deleted_files}
  when :plugins
    return {:data => @plugins.keys.map { |i| { 'plugin' => i.to_s, 'path' => @plugins[i][:source] } } , :fields => ['plugin','path'], :type => :object_list }
  when :list
    return {:data => @config_presets.keys, :type => :value_list, :name => 'name'}
  when :overview
    return {:type=>:object_list,:data=>self.class.flatten_all_config(@config_presets)}
  when :wizard
    self.options.ask_missing_mandatory=true
    #self.options.set_option(:interactive,:yes)
    # register url option
    BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
    instance_url=self.options.get_option(:url,:mandatory)
    appli=ApiDetector.discover_product(instance_url)
    case appli[:product]
    when :aoc
      self.format.display_status("Detected: Aspera on Cloud".bold)
      organization,instance_domain=AoC.parse_url(instance_url)
      aspera_preset_name='aoc_'+organization
      self.format.display_status("Preparing preset: #{aspera_preset_name}")
      # init defaults if necessary
      @config_presets[CONF_PRESET_DEFAULT]||=Hash.new
      if !option_override
        raise CliError,"a default configuration already exists for plugin '#{AOC_COMMAND_CURRENT}' (use --override=yes)" if @config_presets[CONF_PRESET_DEFAULT].has_key?(AOC_COMMAND_CURRENT)
        raise CliError,"preset already exists: #{aspera_preset_name}  (use --override=yes)" if @config_presets.has_key?(aspera_preset_name)
      end
      # lets see if path to priv key is provided
      private_key_path=self.options.get_option(:pkeypath,:optional)
      # give a chance to provide
      if private_key_path.nil?
        self.format.display_status("Please provide path to your private RSA key, or empty to generate one:")
        private_key_path=self.options.get_option(:pkeypath,:mandatory).to_s
      end
      # else generate path
      if private_key_path.empty?
        private_key_path=File.join(@main_folder,'aspera_aoc_key')
      end
      if File.exist?(private_key_path)
        self.format.display_status("Using existing key:")
      else
        self.format.display_status("Generating key...")
        generate_new_key(private_key_path)
        self.format.display_status("Created:")
      end
      self.format.display_status("#{private_key_path}")
      pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
      # define options
      require 'aspera/cli/plugins/aoc'
      # make username mandatory for jwt, this triggers interactive input
      self.options.get_option(:username,:mandatory)
      # instanciate AoC plugin
      files_plugin=self.class.plugin_new(AOC_COMMAND_CURRENT,@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
      auto_set_pub_key=false
      auto_set_jwt=false
      use_browser_authentication=false
      if self.options.get_option(:use_generic_client)
        self.format.display_status("Using global client_id.")
        self.format.display_status("Please Login to your Aspera on Cloud instance.".red)
        self.format.display_status("Navigate to your \"Account Settings\"".red)
        self.format.display_status("Check or update the value of \"Public Key\" to be:".red.blink)
        self.format.display_status("#{pub_key_pem}")
        if ! self.options.get_option(:test_mode)
          self.format.display_status("Once updated or validated, press enter.")
          OpenApplication.instance.uri(instance_url)
          STDIN.gets
        end
      else
        self.format.display_status("Using organization specific client_id.")
        if self.options.get_option(:client_id,:optional).nil? or self.options.get_option(:client_secret,:optional).nil?
          self.format.display_status("Please login to your Aspera on Cloud instance.".red)
          self.format.display_status("Go to: Apps->Admin->Organization->Integrations")
          self.format.display_status("Create or check if there is an existing integration named:")
          self.format.display_status("- name: #{@tool_name}")
          self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
          self.format.display_status("- origin: localhost")
          self.format.display_status("Once created or identified,")
          self.format.display_status("Please enter:".red)
        end
        OpenApplication.instance.uri(instance_url+"/admin/org/integrations")
        self.options.get_option(:client_id,:mandatory)
        self.options.get_option(:client_secret,:mandatory)
        use_browser_authentication=true
      end
      if use_browser_authentication
        self.format.display_status("We will use web authentication to bootstrap.")
        self.options.set_option(:auth,:web)
        self.options.set_option(:redirect_uri,DEFAULT_REDIRECT)
        auto_set_pub_key=true
        auto_set_jwt=true
        self.options.set_option(:scope,AoC::SCOPE_FILES_ADMIN)
      end
      files_plugin.update_aoc_api
      myself=files_plugin.api_aoc.read('self')[:data]
      if auto_set_pub_key
        raise CliError,"public key is already set in profile (use --override=yes)"  unless myself['public_key'].empty? or option_override
        self.format.display_status("Updating profile with new key")
        files_plugin.api_aoc.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
      end
      if auto_set_jwt
        self.format.display_status("Enabling JWT for client")
        files_plugin.api_aoc.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
      end
      self.format.display_status("creating new config preset: #{aspera_preset_name}")
      @config_presets[aspera_preset_name]={
        :url.to_s           =>self.options.get_option(:url),
        :username.to_s      =>myself['email'],
        :auth.to_s          =>:jwt.to_s,
        :private_key.to_s   =>'@file:'+private_key_path,
      }
      # set only if non nil
      [:client_id,:client_secret].each do |s|
        o=self.options.get_option(s)
        @config_presets[s.to_s] = o unless o.nil?
      end
      self.format.display_status("Setting config preset as default for #{AOC_COMMAND_CURRENT}")
      @config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
      self.format.display_status("saving config file")
      save_presets_to_config_file
      return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
    else
      raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
    end
  when :export_to_cli
    self.format.display_status("Exporting: Aspera on Cloud")
    require 'aspera/cli/plugins/aoc'
    # need url / username
    add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
    # instanciate AoC plugin
    files_plugin=self.class.plugin_new(AOC_COMMAND_CURRENT,@agents) # TODO: is this line needed ?
    url=self.options.get_option(:url,:mandatory)
    cli_conf_file=Fasp::Installation.instance.cli_conf_file
    data=JSON.parse(File.read(cli_conf_file))
    organization,instance_domain=AoC.parse_url(url)
    key_basename='org_'+organization+'.pem'
    key_file=File.join(File.dirname(File.dirname(cli_conf_file)),'etc',key_basename)
    File.write(key_file,self.options.get_option(:private_key,:mandatory))
    new_conf={
      'organization'       => organization,
      'hostname'           => [organization,instance_domain].join('.'),
      'privateKeyFilename' => key_basename,
      'username'           => self.options.get_option(:username,:mandatory)
    }
    new_conf['clientId']=self.options.get_option(:client_id,:optional)
    new_conf['clientSecret']=self.options.get_option(:client_secret,:optional)
    if new_conf['clientId'].nil?
      new_conf['clientId'],new_conf['clientSecret']=AoC.get_client_info()
    end
    entry=data['AoCAccounts'].select{|i|i['organization'].eql?(organization)}.first
    if entry.nil?
      data['AoCAccounts'].push(new_conf)
      self.format.display_status("Creating new aoc entry: #{organization}")
    else
      self.format.display_status("Updating existing aoc entry: #{organization}")
      entry.merge!(new_conf)
    end
    File.write(cli_conf_file,JSON.pretty_generate(data))
    return Main.result_status("updated: #{cli_conf_file}")
  when :detect
    # need url / username
    BasicAuthPlugin.new(@agents)
    return Main.result_status("found: #{ApiDetector.discover_product(self.options.get_option(:url,:mandatory))}")
  when :coffee
    OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
    return Main.result_nothing
  when :ascp
    execute_action_ascp
  when :gem_path
    return Main.result_status(self.class.gem_root)
  when :folder
    return Main.result_status(@main_folder)
  when :file
    return Main.result_status(@option_config_file)
  when :email_test
    dest_email=self.options.get_next_argument("destination email")
    send_email({
      to:         dest_email,
      subject:    'Amelia email test',
      body:       'It worked !',
    })
    return Main.result_nothing
  when :smtp_settings
    return {:type=>:single_object,:data=>email_settings}
  when :proxy_check
    pac_url=self.options.get_option(:fpac,:mandatory)
    server_url=self.options.get_next_argument("server url")
    return Main.result_status(Aspera::ProxyAutoConfig.new(UriReader.read(pac_url)).get_proxy(server_url))
  else raise "error"
  end
end

#execute_action_ascpObject



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/aspera/cli/plugins/config.rb', line 433

def execute_action_ascp
  command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install])
  case command
  when :connect
    return execute_connect_action
  when :use
    default_ascp=self.options.get_next_argument('path to ascp')
    raise "file name must be ascp" unless File.basename(default_ascp).eql?('ascp')
    raise "no such file: #{default_ascp}" unless File.exist?(default_ascp)
    raise "not executable: #{default_ascp}" unless File.executable?(default_ascp)
    preset_name=set_global_default(:ascp_path,default_ascp)
    save_presets_to_config_file
    return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
  when :show # shows files used
    return {:type=>:status, :data=>Fasp::Installation.instance.path(:ascp)}
  when :info # shows files used
    data=Fasp::Installation::FILES.inject({}) do |m,v|
      m[v.to_s]=Fasp::Installation.instance.path(v) rescue "Not Found"
      m
    end
    # read PATHs from ascp directly, and pvcl modules as well
    Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |stdin, stdout, stderr, thread|
      while line=stderr.gets do
        line.chomp!
        case line
        when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$};data[$1]=$3
        when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$};data[$2]=$4
        when %r{^DBG License result \(/license/(\S+)\): (.+)$};data[$1]=$2
        when %r{^LOG (.+) version ([0-9.]+)$};data['product_name']=$1;data['product_version']=$2
        when %r{^LOG Initializing FASP version ([^,]+),};data['ascp_version']=$1
        end
      end
    end
    data['keypass']=Fasp::Installation.instance.bypass_pass
    return {:type=>:single_object, :data=>data}
  when :products
    command=self.options.get_next_command([:list,:use])
    case command
    when :list
      return {:type=>:object_list, :data=>Fasp::Installation.instance.installed_products, :fields=>['name','app_root']}
    when :use
      default_product=self.options.get_next_argument('product name')
      Fasp::Installation.instance.use_ascp_from_product(default_product)
      preset_name=set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
      save_presets_to_config_file
      return {:type=>:status, :data=>"saved to default global preset #{preset_name}"}
    end
  when :install
    v=Fasp::Installation.instance.install_sdk
    return {:type=>:status, :data=>"Installed version #{v}"}
  end
  raise "unexpected case: #{command}"
end

#execute_connect_actionObject



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/aspera/cli/plugins/config.rb', line 391

def execute_connect_action
  command=self.options.get_next_command([:list,:id])
  case command
  when :list
    return {:type=>:object_list, :data=>connect_versions, :fields => ['id','title','version']}
  when :id
    connect_id=self.options.get_next_argument('id or title')
    one_res=connect_versions.select{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}.first
    raise CliNoSuchId.new(:connect,connect_id) if one_res.nil?
    command=self.options.get_next_command([:info,:links])
    case command
    when :info # shows files used
      one_res.delete('links')
      return {:type=>:single_object, :data=>one_res}
    when :links # shows files used
      command=self.options.get_next_command([:list,:id])
      all_links=one_res['links']
      case command
      when :list # shows files used
        return {:type=>:object_list, :data=>all_links}
      when :id
        link_title=self.options.get_next_argument('title')
        one_link=all_links.select {|i| i['title'].eql?(link_title)}.first
        command=self.options.get_next_command([:download,:open])
        case command
        when :download #
          folder_dest=self.transfer.destination_folder('receive')
          #folder_dest=self.options.get_next_argument('destination folder')
          api_connect_cdn=Rest.new({:base_url=>CONNECT_WEB_URL})
          fileurl = one_link['href']
          filename=fileurl.gsub(%r{.*/},'')
          api_connect_cdn.call({:operation=>'GET',:subpath=>fileurl,:save_to_file=>File.join(folder_dest,filename)})
          return Main.result_status("downloaded: #{filename}")
        when :open #
          OpenApplication.instance.uri(one_link['href'])
          return Main.result_status("opened: #{one_link['href']}")
        end
      end
    end
  end
end

#expanded_with_preset_includes(hash_val, include_path = []) ⇒ Object

Parameters:

  • hash_val

Raises:



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/aspera/cli/plugins/config.rb', line 223

def expanded_with_preset_includes(hash_val, include_path=[])
  raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash" unless hash_val.is_a?(Hash)
  if hash_val.has_key?(EXTV_INCLUDE_PRESETS)
    memory=hash_val.clone
    includes=memory[EXTV_INCLUDE_PRESETS]
    memory.delete(EXTV_INCLUDE_PRESETS)
    hash_val={}
    raise "#{EXTV_INCLUDE_PRESETS} must be an Array" unless includes.is_a?(Array)
    raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map{|i|i.class}.uniq.eql?([String])
    includes.each do |preset_name|
      hash_val.merge!(preset_by_name(preset_name,include_path))
    end
    hash_val.merge!(memory)
  end
  return hash_val
end

#get_plugin_default_config_name(plugin_sym) ⇒ Object

returns [String] name if config_presets has default returns nil if there is no config or bypass default params



823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
# File 'lib/aspera/cli/plugins/config.rb', line 823

def get_plugin_default_config_name(plugin_sym)
  raise "internal error: config_presets shall be defined" if @config_presets.nil?
  if !@use_plugin_defaults
    Log.log.debug("skip default config")
    return nil
  end
  if @config_presets.has_key?(CONF_PRESET_DEFAULT) and
  @config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_sym.to_s)
    default_config_name=@config_presets[CONF_PRESET_DEFAULT][plugin_sym.to_s]
    if !@config_presets.has_key?(default_config_name)
      Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym.to_s}], but it does not exist in config file.\nPlease fix the issue: either create preset with one parameter (#{@tool_name} config id #{default_config_name} init @json:'{}') or remove default (#{@tool_name} config id default remove #{plugin_sym.to_s}).")
    end
    raise CliError,"Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
    return default_config_name
  end
  return nil
end

#get_secret(id = nil, mandatory = true) ⇒ Object



115
116
117
118
119
# File 'lib/aspera/cli/plugins/config.rb', line 115

def get_secret(id=nil,mandatory=true)
  secret=self.options.get_option(:secret,:optional) || @option_secrets[id]
  raise "please provide secret for #{id}" if secret.nil? and mandatory
  return secret
end

#get_secretsObject



121
122
123
# File 'lib/aspera/cli/plugins/config.rb', line 121

def get_secrets
  return @option_secrets
end

#option_ascp_pathObject



244
245
246
# File 'lib/aspera/cli/plugins/config.rb', line 244

def option_ascp_path
  Fasp::Installation.instance.path(:ascp)
end

#option_ascp_path=(new_value) ⇒ Object



240
241
242
# File 'lib/aspera/cli/plugins/config.rb', line 240

def option_ascp_path=(new_value)
  Fasp::Installation.instance.ascp_path=new_value
end

#option_presetObject



45
# File 'lib/aspera/cli/plugins/config.rb', line 45

def option_preset; nil; end

#option_preset=(value) ⇒ Object



47
48
49
# File 'lib/aspera/cli/plugins/config.rb', line 47

def option_preset=(value)
  self.options.add_option_preset(preset_by_name(value))
end

#option_use_productObject



252
253
254
# File 'lib/aspera/cli/plugins/config.rb', line 252

def option_use_product
  "write-only value"
end

#option_use_product=(value) ⇒ Object



248
249
250
# File 'lib/aspera/cli/plugins/config.rb', line 248

def option_use_product=(value)
  Fasp::Installation.instance.use_ascp_from_product(value)
end

#preset_by_name(config_name, include_path = []) ⇒ Object

Returns the hash from name (also expands possible includes).

Returns:

  • the hash from name (also expands possible includes)

Raises:



216
217
218
219
220
# File 'lib/aspera/cli/plugins/config.rb', line 216

def preset_by_name(config_name, include_path=[])
  raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
  raise CliError,"loop in include" if include_path.include?(config_name)
  return expanded_with_preset_includes(@config_presets[config_name],include_path.clone.push(config_name))
end

#read_config_fileObject

read config file and validate format tries to convert from older version if possible and required



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/aspera/cli/plugins/config.rb', line 281

def read_config_file
  begin
    Log.log.debug("config file is: #{@option_config_file}".red)
    conf_file_v1=File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V1,DEFAULT_CONFIG_FILENAME)
    conf_file_v2=File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V2,DEFAULT_CONFIG_FILENAME)
    # files search for configuration, by default the one given by user
    search_files=[@option_config_file]
    # if default file, then also look for older versions
    search_files.push(conf_file_v2,conf_file_v1) if @option_config_file.eql?(@conf_file_default)
    # find first existing file (or nil)
    conf_file_to_load=search_files.select{|f| File.exist?(f)}.first
    # require save if old version of file
    save_required=!@option_config_file.eql?(conf_file_to_load)
    # if no file found, create default config
    if conf_file_to_load.nil?
      Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
      @config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version},CONF_PRESET_DEFAULT=>{'server'=>'demoserver'},
        'demoserver'=>{'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}}
    else
      Log.log.debug "loading #{@option_config_file}"
      @config_presets=YAML.load_file(conf_file_to_load)
    end
    files_to_copy=[]
    Log.log.debug "Available_presets: #{@config_presets}"
    raise "Expecting YAML Hash" unless @config_presets.is_a?(Hash)
    # check there is at least the config section
    if !@config_presets.has_key?(CONF_PRESET_CONFIG)
      raise "Cannot find key: #{CONF_PRESET_CONFIG}"
    end
    version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
    if version.nil?
      raise "No version found in config section."
    end
    # oldest compatible conf file format, update to latest version when an incompatible change is made
    # check compatibility of version of conf file
    config_tested_version='0.4.5'
    if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
      raise "Unsupported config file version #{version}. Expecting min version #{config_tested_version}"
    end
    config_tested_version='0.6.15'
    if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
      convert_preset_plugin_name(AOC_COMMAND_V1,AOC_COMMAND_V2)
      version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=config_tested_version
      save_required=true
    end
    config_tested_version='0.8.10'
    if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
      convert_preset_path(PROGRAM_NAME_V1,PROGRAM_NAME_V2,files_to_copy)
      version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=config_tested_version
      save_required=true
    end
    config_tested_version='1.0'
    if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
      convert_preset_plugin_name(AOC_COMMAND_V2,AOC_COMMAND_V3)
      convert_preset_path(PROGRAM_NAME_V2,@tool_name,files_to_copy)
      version=@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=config_tested_version
      save_required=true
    end
    # Place new compatibility code here
    if save_required
      Log.log.warn("Saving automatic conversion.")
      @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]=@program_version
      save_presets_to_config_file
      Log.log.warn("Copying referenced files")
      files_to_copy.each do |file|
        FileUtils.cp(file,@main_folder)
        Log.log.warn("..#{file} -> #{@main_folder}")
      end
    end
  rescue Psych::SyntaxError => e
    Log.log.error("YAML error in config file")
    raise e
  rescue => e
    Log.log.debug("-> #{e}")
    new_name="#{@option_config_file}.pre#{@program_version}.manual_conversion_needed"
    File.rename(@option_config_file,new_name)
    Log.log.warn("Renamed config file to #{new_name}.")
    Log.log.warn("Manual Conversion is required. Next time, a new empty file will be created.")
    raise CliError,e.to_s
  end
end

#save_presets_to_config_fileObject



814
815
816
817
818
819
# File 'lib/aspera/cli/plugins/config.rb', line 814

def save_presets_to_config_file
  raise "no configuration loaded" if @config_presets.nil?
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
  Log.log.debug "writing #{@option_config_file}"
  File.write(@option_config_file,@config_presets.to_yaml)
end

#send_email(email = {}) ⇒ Object



789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/aspera/cli/plugins/config.rb', line 789

def send_email(email={})
  opts=email_settings
  email[:from_name]||=opts[:from_name]
  email[:from_email]||=opts[:from_email]
  # check minimum required
  [:from_name,:from_email,:to,:subject].each do |n|
    raise "missing email parameter: #{n}" unless email.has_key?(n)
  end
  msg = "From: \#{email[:from_name]} <\#{email[:from_email]}>\nTo: <\#{email[:to]}>\nSubject: \#{email[:subject]}\n\n\#{email[:body]}\n"
  start_options=[opts[:domain]]
  start_options.push(opts[:username],opts[:password],:login) if opts.has_key?(:username) and opts.has_key?(:password)

  smtp = Net::SMTP.new(opts[:server], opts[:port])
  smtp.enable_starttls if opts[:tls]
  smtp.start(*start_options) do |smtp|
    smtp.send_message(msg, email[:from_email], email[:to])
  end
end