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:
Beispiel #5
0
    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,
Beispiel #7
0
    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
Beispiel #8
0
    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":
                         "{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,