def _check_privileges(server, options): """Check required privileges to move binary logs from server. This method check if the used user possess the required privileges to relocate binary logs from the server. More specifically, the following privilege is required: RELOAD (to flush the binary logs). An exception is thrown if the user doesn't have enough privileges. server[in] Server instance to check. options[in] Dictionary of options (skip_flush_binlogs, verbosity). """ skip_flush = options['skip_flush_binlogs'] if not skip_flush: # Only need to check privileges if flush is not skipped. verbosity = options['verbosity'] if verbosity > 0: print("# Checking user permission to move binary logs...\n" "#") # Check privileges user_obj = User(server, "{0}@{1}".format(server.user, server.host)) if not user_obj.has_privilege('*', '*', 'RELOAD'): raise UtilError( ERROR_USER_WITHOUT_PRIVILEGES.format( user=server.user, host=server.host, port=server.port, operation='perform binary log move', req_privileges='RELOAD'))
def check_privileges(server, operation, privileges, description, verbosity=0, reporter=None): """Check required privileges. This method check if the used user possess the required privileges to execute a statement or operation. An exception is thrown if the user doesn't have enough privileges. server[in] Server instance to check. operation[in] The name of tha task that requires the privileges, used in the error message if an exception is thrown. privileges[in] List of the required privileges. description[in] Description of the operation requiring the User's privileges, used in the message if verbosity if given. verbosity[in] Verbosity. reporter[in] A method to invoke with messages and warnings (by default print). """ # print message with the given reporter. if reporter is None and verbosity > 0: print("# Checking user permission to {0}...\n" "#".format(description)) elif reporter is not None and verbosity > 0: reporter("# Checking user permission to {0}...\n" "#".format(description)) # Check privileges user_obj = User(server, "{0}@{1}".format(server.user, server.host)) need_privileges = [] for privilege in privileges: if not user_obj.has_privilege('*', '*', privilege): need_privileges.append(privilege) if len(need_privileges) > 0: if len(need_privileges) > 1: privileges_needed = "{0} and {1}".format( ", ".join(need_privileges[:-1]), need_privileges[-1]) else: privileges_needed = need_privileges[0] raise UtilError( ERROR_USER_WITHOUT_PRIVILEGES.format( user=server.user, host=server.host, port=server.port, operation=operation, req_privileges=privileges_needed))
def check_privileges(server, operation, privileges, description, verbosity=0, reporter=None): """Check required privileges. This method check if the used user possess the required privileges to execute a statement or operation. An exception is thrown if the user doesn't have enough privileges. server[in] Server instance to check. operation[in] The name of tha task that requires the privileges, used in the error message if an exception is thrown. privileges[in] List of the required privileges. description[in] Description of the operation requiring the User's privileges, used in the message if verbosity if given. verbosity[in] Verbosity. reporter[in] A method to invoke with messages and warnings (by default print). """ # print message with the given reporter. if reporter is None and verbosity > 0: print("# Checking user permission to {0}...\n" "#".format(description)) elif reporter is not None and verbosity > 0: reporter("# Checking user permission to {0}...\n" "#".format(description)) # Check privileges user_obj = User(server, "{0}@{1}".format(server.user, server.host)) need_privileges = [] for privilege in privileges: if not user_obj.has_privilege('*', '*', privilege): need_privileges.append(privilege) if len(need_privileges) > 0: if len(need_privileges) > 1: privileges_needed = "{0} and {1}".format( ", ".join(need_privileges[:-1]), need_privileges[-1] ) else: privileges_needed = need_privileges[0] raise UtilError(ERROR_USER_WITHOUT_PRIVILEGES.format( user=server.user, host=server.host, port=server.port, operation=operation, req_privileges=privileges_needed ))
def _check_privileges(server): """Verify required privileges to check grantee privileges. server[in] Instance of Server class. This method checks if the used User for the server possesses the required privileges get the list of grantees and respective grants for the objects. Specifically, the following privilege is required: SELECT on mysql.* An exception is thrown if the user doesn't have this privilege. """ user_obj = User(server, "{0}@{1}".format(server.user, server.host)) has_privilege = user_obj.has_privilege('mysql', '*', 'SELECT') if not has_privilege: raise UtilError(ERROR_USER_WITHOUT_PRIVILEGES.format( user=server.user, host=server.host, port=server.port, operation='read the available grants', req_privileges="SELECT on mysql.*" ))
def skip_slaves_trx(gtid_set, slaves_cnx_val, options): """Skip transactions on slaves. This method skips the given transactions (GTID set) on all the specified slaves. That is, an empty transaction is injected for each GTID in the given set for one of each slaves. In case a slave already has an executed transaction for a given GTID then that GTID is ignored for this slave. gtid_set[in] String representing the set of GTIDs to skip. slaves_cnx_val[in] List of the dictionaries with the connection values for each target slave. options[in] Dictionary of options (dry_run, verbosity). Throws an UtilError exception if an error occurs during the execution. """ verbosity = options.get('verbosity') dryrun = options.get('dry_run') # Connect to slaves. rpl_topology = Topology(None, slaves_cnx_val, options) # Check required privileges. errors = rpl_topology.check_privileges(skip_master=True) if errors: err_details = '' for err in errors: err_msg = ERROR_USER_WITHOUT_PRIVILEGES.format( user=err[0], host=err[1], port=err[2], operation='inject empty transactions', req_privileges=err[3]) err_details = '{0}{1}\n'.format(err_details, err_msg) err_details.strip() raise UtilRplError("Not enough privileges.\n{0}".format(err_details)) # GTID must be enabled on all servers. srv_list = rpl_topology.get_servers_with_gtid_not_on() if srv_list: if verbosity: print("# Slaves with GTID not enabled:") for srv in srv_list: msg = "# - GTID_MODE={0} on {1}:{2}".format(srv[2], srv[0], srv[1]) print(msg) raise UtilRplError(_GTID_ON_REQ.format(action='Transaction skip')) if dryrun: print("#") print("# WARNING: Executing utility in dry run mode (read only).") # Get GTID set that can be skipped, i.e., not in GTID_EXECUTED. gtids_by_slave = rpl_topology.slaves_gtid_subtract_executed(gtid_set) # Output GTID set that will be skipped. print("#") print("# GTID set to be skipped for each server:") has_gtid_to_skip = False for host, port, gtids_to_skip in gtids_by_slave: if not gtids_to_skip: gtids_to_skip = 'None' else: # Set flag to indicate that there is at least one GTID to skip. has_gtid_to_skip = True print("# - {0}@{1}: {2}".format(host, port, gtids_to_skip)) # Create dictionary to directly access the slaves instances. slaves_dict = rpl_topology.get_slaves_dict() # Skip transactions for the given list of slaves. print("#") if has_gtid_to_skip: for host, port, gtids_to_skip in gtids_by_slave: if gtids_to_skip: # Decompose GTID set into a list of single transactions. gtid_items = gtid_set_itemize(gtids_to_skip) dryrun_mark = '(dry run) ' if dryrun else '' print("# {0}Injecting empty transactions for '{1}:{2}'" "...".format(dryrun_mark, host, port)) slave_key = '{0}@{1}'.format(host, port) slave_srv = slaves_dict[slave_key]['instance'] for uuid, trx_list in gtid_items: for trx_num in trx_list: trx_to_skip = '{0}:{1}'.format(uuid, trx_num) if verbosity: print("# - {0}".format(trx_to_skip)) if not dryrun: # Inject empty transaction. slave_srv.inject_empty_trx( trx_to_skip, gtid_next_automatic=False) if not dryrun: slave_srv.set_gtid_next_automatic() else: print("# No transaction to skip.") print("#\n#...done.\n#")
def _check_privileges(self): """Check required privileges to perform the multi-source replication. This method check if the used users for the slave and masters have the required privileges to perform the multi-source replication. The following privileges are required: - on slave: SUPER, SELECT, INSERT, UPDATE, REPLICATION SLAVE AND GRANT OPTION; - on the master: SUPER, SELECT, INSERT, UPDATE, REPLICATION SLAVE AND GRANT OPTION. An exception is thrown if users doesn't have enough privileges. """ if self.verbosity > 0: print("# Checking users privileges for replication.\n#") # Connection dictionary conn_dict = { "conn_info": None, "quiet": True, "verbose": self.verbosity > 0, } # Check privileges for master. master_priv = [('SUPER',), ('SELECT',), ('INSERT',), ('UPDATE',), ('REPLICATION SLAVE',), ('GRANT OPTION',)] master_priv_str = ("SUPER, SELECT, INSERT, UPDATE, REPLICATION SLAVE " "AND GRANT OPTION") for master_vals in self.masters_vals: conn_dict["conn_info"] = master_vals master = Master(conn_dict) master.connect() user_obj = User(master, "{0}@{1}".format(master.user, master.host)) for any_priv_tuple in master_priv: has_privilege = any( [user_obj.has_privilege('*', '*', priv) for priv in any_priv_tuple] ) if not has_privilege: msg = ERROR_USER_WITHOUT_PRIVILEGES.format( user=master.user, host=master.host, port=master.port, operation='perform replication', req_privileges=master_priv_str ) self._report(msg, logging.CRITICAL, False) raise UtilRplError(msg) master.disconnect() # Check privileges for slave slave_priv = [('SUPER',), ('SELECT',), ('INSERT',), ('UPDATE',), ('REPLICATION SLAVE',), ('GRANT OPTION',)] slave_priv_str = ("SUPER, SELECT, INSERT, UPDATE, REPLICATION SLAVE " "AND GRANT OPTION") conn_dict["conn_info"] = self.slave_vals slave = Slave(conn_dict) slave.connect() user_obj = User(slave, "{0}@{1}".format(slave.user, slave.host)) for any_priv_tuple in slave_priv: has_privilege = any( [user_obj.has_privilege('*', '*', priv) for priv in any_priv_tuple] ) if not has_privilege: msg = ("User '{0}' on '{1}@{2}' does not have sufficient " "privileges to perform replication (required: {3})." "".format(slave.user, slave.host, slave.port, slave_priv_str)) self._report(msg, logging.CRITICAL, False) raise UtilRplError(msg) slave.disconnect()