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



585
586
587
588
589
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 585

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



591
592
593
594
595
596
597
598
599
600
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 591

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



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

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



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

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:



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

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



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

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


602
603
604
605
606
607
608
609
# File 'lib/flydata/parser/mysql/dump_parser.rb', line 602

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