def run(self): for i in range(0, len(_TEST_CASES)): if self.debug: print "\nTest case {0} - {1}".format(i + 1, _TEST_CASES[i][0]) try: src_val = get_connection_dictionary(_TEST_CASES[i][1]) server_options = {'quiet': True, 'version': None, 'src_name': "test", 'dest_name': None, } connect_servers(src_val, None, server_options) except UtilError as err: self.results.append((True, err.errmsg)) except ConnectionValuesError as err: self.results.append((True, err.errmsg)) except FormatError as err: self.results.append((True, err)) else: self.results.append((False, '')) if self.debug: print "Test results:", self.results[i][0], self.results[i][1] test_num = len(_TEST_CASES) + 1 comment = "Compare dictionaries with socket only" if self.debug: print "\nTest case {0} - {1}".format(test_num, comment) server1_vals = get_connection_dictionary("test_server1") server1_vals['port'] = None server2_vals = get_connection_dictionary("test_server2") server2_vals['port'] = None res = check_hostname_alias(server1_vals, server2_vals) # Add test case so that results match. _TEST_CASES.append((comment, "test_server1", False)) self.results.append((res, '')) if self.debug: print "Test results:", res, False self.remove_login_path_data('test_server1') self.remove_login_path_data('test_server2') return True
except UtilError: _, err, _ = sys.exc_info() parser.error("Master connection values invalid: {0}." "".format(err.errmsg)) # Parse source connection values try: s_values = parse_connection(opt.slave, None, opt) except FormatError: _, err, _ = sys.exc_info() parser.error("Slave connection values invalid: %s." % err) except UtilError: _, err, _ = sys.exc_info() parser.error("Slave connection values invalid: %s." % err.errmsg) # Check hostname alias if check_hostname_alias(m_values, s_values): parser.error("The master and slave are the same host and port.") # Check required --master-log-file for --master-log-pos if opt.master_log_pos >= 0 and opt.master_log_file is None: parser.error("You must specify a master log file to use the master " "log file position option.") if (opt.master_log_pos >= 0 or (opt.master_log_file is not None)) and opt.from_beginning: parser.error( "The --start-from-beginning option is not valid in " "combination with --master-log-file or --master-log-pos." ) # Create dictionary of options options = { "verbosity": opt.verbosity,
for master in masters: try: masters_vals.append(parse_connection(master, config_reader, opt)) except FormatError as err: msg = ("Masters connection values invalid or cannot be parsed: " "{0} ({1})".format(master, err)) raise UtilRplError(msg) except UtilError as err: msg = ("Masters connection values invalid or cannot be parsed: " "{0} ({1})".format(master, err.errmsg)) raise UtilRplError(msg) # Check hostname alias for master_vals in masters_vals: if check_hostname_alias(slave_vals, master_vals): parser.error("The master and slave are the same host and port.") # Check the daemon options if opt.daemon: # Check if a POSIX system if os.name != "posix": parser.error("Running mysqlfailover with --daemon is only " "available for POSIX systems.") # Check the presence of --log if opt.daemon != "stop" and not opt.log_file: parser.error("The option --log is required when using --daemon.") # Test pidfile if opt.daemon != "nodetach":
# Check slaves list (master cannot be included in slaves list). if opt.master: check_server_lists(parser, opt.master, opt.slaves) # Parse the master and slaves connection parameters (no candidates). try: master_val, slaves_val, _ = parse_topology_connections(opt, parse_candidates=False) except UtilRplError: _, err, _ = sys.exc_info() sys.stderr.write("ERROR: {0}\n".format(err.errmsg)) sys.exit(1) # Check host aliases (master cannot be included in slaves list). if master_val: for slave_val in slaves_val: if check_hostname_alias(master_val, slave_val): master = Server({"conn_info": master_val}) slave = Server({"conn_info": slave_val}) parser.error( ERROR_MASTER_IN_SLAVES.format( master_host=master.host, master_port=master.port, slaves_candidates="slaves", slave_host=slave.host, slave_port=slave.port, ) ) # Process list of databases/tables to exclude (check format errors). data_to_exclude = {} if opt.exclude:
if opt.fail_retry and opt.fail_retry < 1: parser.error("The --master-fail-retry option must be a positive " "integer > 0.") # Parse the master, slaves, and candidates connection parameters try: master_val, slaves_val, candidates_val = parse_topology_connections( opt) except UtilRplError: _, e, _ = sys.exc_info() print("ERROR: {0}".format(e.errmsg)) sys.exit(1) # Check hostname alias for slave_val in slaves_val: if check_hostname_alias(master_val, slave_val): parser.error("The master and one of the slaves are the same " "host and port.") for cand_val in candidates_val: if check_hostname_alias(master_val, cand_val): parser.error("The master and one of the candidates are the same " "host and port.") # Create dictionary of options options = { 'candidates': candidates_val, 'ping': 3 if opt.ping is None else opt.ping, 'verbosity': 0 if opt.verbosity is None else opt.verbosity, 'before': opt.exec_before, 'after': opt.exec_after, 'exec_fail': opt.exec_fail,
_, err, _ = sys.exc_info() parser.error("Master connection values invalid: {0}." "".format(err.errmsg)) # Parse source connection values try: s_values = parse_connection(opt.slave, None, opt) except FormatError: _, err, _ = sys.exc_info() parser.error("Slave connection values invalid: %s." % err) except UtilError: _, err, _ = sys.exc_info() parser.error("Slave connection values invalid: %s." % err.errmsg) # Check hostname alias if check_hostname_alias(m_values, s_values): parser.error("The master and slave are the same host and port.") # Check required --master-log-file for --master-log-pos if opt.master_log_pos >= 0 and opt.master_log_file is None: parser.error("You must specify a master log file to use the master " "log file position option.") if ((opt.master_log_pos >= 0 or (opt.master_log_file is not None)) and opt.from_beginning): parser.error("The --start-from-beginning option is not valid in " "combination with --master-log-file or --master-log-pos.") # Create dictionary of options options = { 'verbosity': opt.verbosity,
def _switchover(self): """Perform switchover from master to candidate slave This method switches the role of master to a candidate slave. The candidate is specified via the --candidate option. Returns bool - True = no errors, False = errors reported. """ # Check new master is not actual master - need valid candidate candidate = self.options.get("new_master", None) if check_hostname_alias(self.master_vals, candidate): err_msg = ERROR_SAME_MASTER.format( n_master_host=candidate['host'], n_master_port=candidate['port'], master_host=self.master_vals['host'], master_port=self.master_vals['port']) self._report(err_msg, logging.CRITICAL) raise UtilRplError(err_msg) # Check for --master-info-repository=TABLE if rpl_user is None if not self._check_master_info_type(): return False # Check for mixing IP and hostnames if not self._check_host_references(): print("# WARNING: {0}".format(HOST_IP_WARNING)) self._report(HOST_IP_WARNING, logging.WARN, False) # Check prerequisites if candidate is None: msg = "No candidate specified." self._report(msg, logging.CRITICAL) raise UtilRplError(msg) # Can only check errant transactions if GTIDs are enabled. if self.topology.gtid_enabled(): # Check existence of errant transactions on slaves errant_tnx = self.topology.find_errant_transactions() if errant_tnx: force = self.options.get('force') print("# ERROR: {0}".format(_ERRANT_TNX_ERROR)) self._report(_ERRANT_TNX_ERROR, logging.ERROR, False) for host, port, tnx_set in errant_tnx: errant_msg = (" - For slave '{0}@{1}': " "{2}".format(host, port, ", ".join(tnx_set))) print("# {0}".format(errant_msg)) self._report(errant_msg, logging.ERROR, False) # Raise an exception (to stop) if tolerant mode is OFF if not force: raise UtilRplError("{0} Note: If you want to ignore this " "issue, although not advised, please " "use the utility with the --force " "option.".format(_ERRANT_TNX_ERROR)) else: warn_msg = ("Errant transactions check skipped (GTID not enabled " "for the whole topology).") print("# WARNING: {0}".format(warn_msg)) self._report(warn_msg, logging.WARN, False) # Fix ports before continuing. candidate_port = candidate['port'] if os.name == "posix": if self.topology.master.socket: self.master_vals['port'] = self.topology.master.port # Requires quick connection to server to get correct port port = get_port(candidate) if port: candidate_port = port self._report(" ".join([ "# Performing switchover from master at", "%s:%s" % (self.master_vals['host'], self.master_vals['port']), "to slave at %s:%s." % (candidate['host'], candidate_port) ])) if not self.topology.switchover(candidate): self._report("# Errors found. Switchover aborted.", logging.ERROR) return False return True
"{0}.".format(err.errmsg)) else: new_master_val = None # Parse the master, slaves, and candidates connection parameters try: master_val, slaves_val, candidates_val = parse_topology_connections( opt) except UtilRplError: _, e, _ = sys.exc_info() print("ERROR: {0}".format(e.errmsg)) sys.exit(1) # Check hostname alias if new_master_val: if check_hostname_alias(master_val, new_master_val): master = Server({'conn_info': master_val}) new_master = Server({'conn_info': new_master_val}) parser.error(ERROR_SAME_MASTER.format( n_master_host=new_master.host, n_master_port=new_master.port, master_host=master.host, master_port=master.port)) if master_val: for slave_val in slaves_val: if check_hostname_alias(master_val, slave_val): master = Server({'conn_info': master_val}) slave = Server({'conn_info': slave_val}) msg = ERROR_MASTER_IN_SLAVES.format(master_host=master.host, master_port=master.port,