Class: Flydata::Parser::Mysql::CompatibilityCheck

Inherits:
Object
  • Object
show all
Defined in:
lib/flydata/parser/mysql/dump_parser.rb

Defined Under Namespace

Classes: CompatibilityError

Constant Summary collapse

SELECT_QUERY_TMPLT =
"SELECT %s"

Instance Method Summary collapse

Constructor Details

#initialize(de_hash, dump_dir = nil) ⇒ CompatibilityCheck

Returns a new instance of CompatibilityCheck.



582
583
584
585
586
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 582

def initialize(de_hash, dump_dir=nil)
  @db_opts = [:host, :port, :username, :password, :database].inject({}) {|h, sym| h[sym] = de_hash[sym.to_s]; h}
  @dump_dir = dump_dir
  @errors=[]
end

Instance Method Details

#checkObject



588
589
590
591
592
593
594
595
596
597
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 588

def check
  self.methods.grep(/^check_/).each do |m|
    begin
      send(m)
    rescue CompatibilityError => e
      @errors << e
    end
  end
  print_errors
end

#check_mysql_protocol_tcp_compatObject



631
632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 631

def check_mysql_protocol_tcp_compat
  query = "mysql -u #{@db_opts[:username]} -h #{@db_opts[:host]} -P #{@db_opts[:port]} #{@db_opts[:database]} -e \"SHOW GRANTS;\" --protocol=tcp"
  query << " -p#{@db_opts[:password]}" unless @db_opts[:password].to_s.empty?

  Open3.popen3(query) do |stdin, stdout, stderr|
    stdin.close
    while !stderr.eof?
      line = stderr.gets
      unless /Warning: Using a password on the command line interface can be insecure./ === line
        raise CompatibilityError, "Cannot connect to MySQL database. Please make sure you can connect with this command:\n      $ mysql -u #{@db_opts[:username]} -h #{@db_opts[:host]} -P #{@db_opts[:port]} #{@db_opts[:database]} --protocol=tcp -p"
      end
    end
  end
end

#check_mysql_row_mode_compatObject



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
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 646

def check_mysql_row_mode_compat
  sys_var_to_check = {'@@binlog_format'=>'ROW', '@@binlog_checksum'=>'NONE', '@@log_bin_use_v1_row_events'=>1}
  errors={}

  client = Mysql2::Client.new(@db_opts)

  begin
    sys_var_to_check.each_key do |sys_var|
      sel_query = SELECT_QUERY_TMPLT % sys_var
      begin
        result = client.query(sel_query)
        unless result.first[sys_var] == sys_var_to_check[sys_var]
          errors[sys_var]=result.first[sys_var]
        end
      rescue Mysql2::Error => e
        if e.message =~ /Unknown system variable/
          unless e.message =~ /(binlog_checksum|log_bin_use_v1_row_events)/
            errors[sys_var] = false
          end
        else
          raise e
        end
      end
    end
  ensure
    client.close
  end
  unless errors.empty?
    error_explanation = ""
    errors.each_key do |err_key|
      error_explanation << "\n    * #{err_key} is #{errors[err_key]} but should be #{sys_var_to_check[err_key]}"
    end
    raise CompatibilityError, "These system variable(s) are not the correct value: #{error_explanation}\n   Please change these system variables for FlyData Sync to run correctly"
  end
end

#check_mysql_user_compatObject

Raises:



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 608

def check_mysql_user_compat
  client = Mysql2::Client.new(@db_opts)
  grants_sql = "SHOW GRANTS"
  correct_db = ["ON (\\*|#{@db_opts[:database]})","TO '#{@db_opts[:username]}"]
  necessary_permission_fields= ["SELECT","RELOAD","LOCK TABLES","REPLICATION SLAVE","REPLICATION CLIENT"]
  all_privileges_field= ["ALL PRIVILEGES"]
  result = client.query(grants_sql)
  # Do not catch MySQL connection problem because check should stop if no MySQL connection can be made.
  client.close
  missing_priv = []
  result.each do |res|
    # SHOW GRANTS should only return one column
    res_value = res.values.first
    if correct_db.all? {|perm| res_value.match(perm)}
      necessary_permission_fields.each do |priv|
        missing_priv << priv unless res_value.match(priv)
      end
      return true if missing_priv.empty? or all_privileges_field.all? {|d| res_value.match(d)}
    end
  end
  raise CompatibilityError, "The user '#{@db_opts[:username]}' does not have the correct permissions to run FlyData Sync\n    * These privileges are missing: #{missing_priv.join(", ")}"
end

#check_writing_permissionsObject



682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 682

def check_writing_permissions
  write_errors = []
  paths_to_check = ["~/.flydata"]
  paths_to_check << @dump_dir unless @dump_dir.to_s.empty?
  paths_to_check.each do |path|
    full_path = File.expand_path(path)
    full_path = File.dirname(full_path) unless File.directory?(full_path)
    write_errors << full_path unless File.writable?(full_path)
  end
  unless write_errors.empty?
    error_dir = write_errors.join(", ")
    raise CompatibilityError, "We cannot access the directories: #{error_dir}"
  end
end


599
600
601
602
603
604
605
606
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 599

def print_errors
  return if @errors.empty?
  puts "There may be some compatibility issues with your MySQL credentials: "
  @errors.each do |error|
    puts "  * #{error.message}"
  end
  raise "Please correct these errors if you wish to run FlyData Sync"
end