def _check_server_versions(self): """Checks the server versions. """ if self.verbosity > 0: print("# Checking server versions.\n#") # Connection dictionary conn_dict = { "conn_info": None, "quiet": True, "verbose": self.verbosity > 0, } # Check masters version for master_vals in self.masters_vals: conn_dict["conn_info"] = master_vals master = Master(conn_dict) master.connect() if not master.check_version_compat(*_MIN_SERVER_VERSION): raise UtilRplError( ERROR_MIN_SERVER_VERSIONS.format( utility="mysqlrplms", min_version=".".join([str(val) for val in _MIN_SERVER_VERSION]), host=master.host, port=master.port ) ) master.disconnect() # Check slave version conn_dict["conn_info"] = self.slave_vals slave = Slave(conn_dict) slave.connect() if not slave.check_version_compat(*_MIN_SERVER_VERSION): raise UtilRplError( ERROR_MIN_SERVER_VERSIONS.format( utility="mysqlrplms", min_version=".".join([str(val) for val in _MIN_SERVER_VERSION]), host=slave.host, port=slave.port ) ) slave.disconnect()
def _check_server_versions(self): """Checks the server versions. """ if self.verbosity > 0: print("# Checking server versions.\n#") # Connection dictionary conn_dict = { "conn_info": None, "quiet": True, "verbose": self.verbosity > 0, } # Check masters version for master_vals in self.masters_vals: conn_dict["conn_info"] = master_vals master = Master(conn_dict) master.connect() if not master.check_version_compat(*_MIN_SERVER_VERSION): raise UtilRplError( ERROR_MIN_SERVER_VERSIONS.format( utility="mysqlrplms", min_version=".".join([str(val) for val in _MIN_SERVER_VERSION]), host=master.host, port=master.port ) ) master.disconnect() # Check slave version conn_dict["conn_info"] = self.slave_vals slave = Slave(conn_dict) slave.connect() if not slave.check_version_compat(*_MIN_SERVER_VERSION): raise UtilRplError( ERROR_MIN_SERVER_VERSIONS.format( utility="mysqlrplms", min_version=".".join([str(val) for val in _MIN_SERVER_VERSION]), host=slave.host, port=slave.port ) ) slave.disconnect()
def _get_slaves(self, max_depth, seed_conn=None, masters_found=None): """Find the attached slaves for a list of server connections. This method connects to each server in the list and retrieves its slaves. It can be called recursively if the recurse option is True. max_depth[in] Maximum depth of recursive search seed_conn[in] Current master connection dictionary. Initially, this is the seed server (original master defined in constructor) masters_found[in] a list of all servers in master roles - used to detect a circular replication topology. Initially, this is an empty list as the master detection must occur as the topology is traversed. Returns list - list of slaves connected to each server in list """ if not masters_found: masters_found = [] topology = [] if seed_conn is None: seed_conn = self.seed_server master, master_info = self._connect(seed_conn) if master is None: return [] # Check user permissions self._check_permissions(master, "REPLICATION SLAVE") # Save the master for circular replication identification masters_found.append(master_info) if not self.quiet: print "# Finding slaves for master: %s" % master_info # See if the user wants us to discover slaves. discover = self.options.get("discover", None) if discover is None: return # Get user and password (supports login-paths) try: user, password = parse_user_password(discover, options=self.options) except FormatError: raise UtilError(USER_PASSWORD_FORMAT.format("--discover-slaves")) # Get replication topology slaves = master.get_slaves(user, password) slave_list = [] depth = 0 if len(slaves) > 0: for slave in slaves: if slave.find(":") > 0: host, port = slave.split(":", 1) else: host = slave port = _START_PORT # Use the default slave_conn = self.seed_server.copy() slave_conn['host'] = host slave_conn['port'] = port io_sql_running = None # If verbose then get slave threads (IO and SQL) status if self.verbose: # Create slave instance conn_dict = { 'conn_info': { 'user': user, 'passwd': password, 'host': host, 'port': port, 'socket': None }, 'role': slave, 'verbose': self.verbose } slave_obj = Slave(conn_dict) # Get IO and SQL status try: slave_obj.connect() thread_status = slave_obj.get_thread_status() if thread_status: io_sql_running = (thread_status[1], thread_status[2]) except UtilError: # Connection error io_sql_running = ('ERROR', 'ERROR') # Now check for circular replication topology - do not recurse # if slave is also a master. if self.recurse and slave not in masters_found and \ ((max_depth is None) or (depth < max_depth)): new_list = self._get_slaves(max_depth, slave_conn, masters_found) if new_list == []: slave_list.append((slave, [], io_sql_running)) else: # Add IO and SQL state to slave from recursion if io_sql_running: new_list = [(new_list[0][0], new_list[0][1], io_sql_running)] slave_list.append(new_list) depth += 1 else: slave_list.append((slave, [], io_sql_running)) topology.append((master_info, slave_list)) return topology
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()
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()
def _get_slaves(self, max_depth, seed_conn=None, masters_found=None): """Find the attached slaves for a list of server connections. This method connects to each server in the list and retrieves its slaves. It can be called recursively if the recurse option is True. max_depth[in] Maximum depth of recursive search seed_conn[in] Current master connection dictionary. Initially, this is the seed server (original master defined in constructor) masters_found[in] a list of all servers in master roles - used to detect a circular replication topology. Initially, this is an empty list as the master detection must occur as the topology is traversed. Returns list - list of slaves connected to each server in list """ if not masters_found: masters_found = [] topology = [] if seed_conn is None: seed_conn = self.seed_server master, master_info = self._connect(seed_conn) if master is None: return [] # Check user permissions self._check_permissions(master, "REPLICATION SLAVE") # Save the master for circular replication identification masters_found.append(master_info) if not self.quiet: print "# Finding slaves for master: %s" % master_info # See if the user wants us to discover slaves. discover = self.options.get("discover", None) if discover is None: return # Get user and password (supports login-paths) user, password = parse_user_password(discover, options=self.options) # Get replication topology slaves = master.get_slaves(user, password) slave_list = [] depth = 0 if len(slaves) > 0: for slave in slaves: if slave.find(":") > 0: host, port = slave.split(":", 1) else: host = slave port = _START_PORT # Use the default slave_conn = self.seed_server.copy() slave_conn['host'] = host slave_conn['port'] = port io_sql_running = None # If verbose then get slave threads (IO and SQL) status if self.verbose: # Create slave instance conn_dict = { 'conn_info': {'user': user, 'passwd': password, 'host': host, 'port': port, 'socket': None}, 'role': slave, 'verbose': self.verbose } slave_obj = Slave(conn_dict) # Get IO and SQL status try: slave_obj.connect() thread_status = slave_obj.get_thread_status() if thread_status: io_sql_running = (thread_status[1], thread_status[2]) except UtilError: # Connection error io_sql_running = ('ERROR', 'ERROR') # Now check for circular replication topology - do not recurse # if slave is also a master. if self.recurse and not slave in masters_found and \ ((max_depth is None) or (depth < max_depth)): new_list = self._get_slaves(max_depth, slave_conn, masters_found) if new_list == []: slave_list.append((slave, [], io_sql_running)) else: # Add IO and SQL state to slave from recursion if io_sql_running: new_list = [(new_list[0][0], new_list[0][1], io_sql_running)] slave_list.append(new_list) depth += 1 else: slave_list.append((slave, [], io_sql_running)) topology.append((master_info, slave_list)) return topology