lib/flydata/compatibility_check.rb in flydata-0.3.18 vs lib/flydata/compatibility_check.rb in flydata-0.3.19

- old
+ new

@@ -98,30 +98,47 @@ end raise "Please correct these errors if you wish to run FlyData Sync" end def check_mysql_user_compat - client = Mysql2::Client.new(@db_opts) + databases = ['mysql', @db_opts[:database]] + get_grant_regex = /GRANT (?<privs>.*) ON (`)?(?<db_name>[^`]*)(`)?\.\* TO '#{@db_opts[:username]}/ + necessary_permission_fields = ["SELECT","RELOAD","LOCK TABLES","REPLICATION SLAVE","REPLICATION CLIENT"] + all_privileges_field = ["ALL PRIVILEGES"] + + # Do not catch MySQL connection problem because check should stop if no MySQL connection can be made. 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"] + client = Mysql2::Client.new(@db_opts) result = client.query(grants_sql) - # Do not catch MySQL connection problem because check should stop if no MySQL connection can be made. client.close - found_priv = [] + + found_priv = Hash[databases.map {|d| [d,[]]}] + 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| - found_priv << priv if res_value.match(priv) + matched_values = res_value.match(get_grant_regex) + next unless matched_values + line_priv = matched_values["privs"].split(", ") + if matched_values["db_name"] == "*" + return true if (all_privileges_field - line_priv).empty? + databases.each {|d| found_priv[d] << line_priv } + elsif databases.include? matched_values["db_name"] + if (all_privileges_field - line_priv).empty? + found_priv[matched_values["db_name"]] = necessary_permission_fields + else + found_priv[matched_values["db_name"]] << line_priv end - return true if (necessary_permission_fields-found_priv).empty? or all_privileges_field.all? {|d| res_value.match(d)} end + missing_priv = get_missing_privileges(found_priv, necessary_permission_fields) + return true if missing_priv.empty? end - raise MysqlCompatibilityError, "The user '#{@db_opts[:username]}' does not have the correct permissions to run FlyData Sync\n * These privileges are missing: #{(necessary_permission_fields-found_priv).join(", ")}" + error_text = "The user '#{@db_opts[:username]}' does not have the correct permissions to run FlyData Sync\n" + error_text << " * These privileges are missing...\n" + missing_priv.each_key {|db| error_text << " for the database '#{db}': #{missing_priv[db].join(", ")}\n"} + raise MysqlCompatibilityError, error_text end def check_mysql_protocol_tcp_compat query = Mysql::MysqlUtil.generate_mysql_show_grants_cmd(@db_opts) @@ -217,9 +234,18 @@ end raise MysqlCompatibilityError, "FlyData does not support VIEW and MEMORY ENGINE table. Remove following tables from data entry: #{invalid_tables.join(", ")}" unless invalid_tables.empty? ensure client.close end + end + + def get_missing_privileges(found_priv, all_priv) + return_hash = {} + found_priv.each_key do |key| + missing_priv = all_priv - found_priv[key].flatten.uniq + return_hash[key] = missing_priv unless missing_priv.empty? + end + return_hash end def run_mysql_retention_check(mysql_client) expire_logs_days_limit = BINLOG_RETENTION_HOURS / 24 sel_query = SELECT_QUERY_TMPLT % '@@expire_logs_days'