Example #1
0
def reestablish_mysql_connection(cnx, attempt, delay):
    """Try to reconnect if it is not already connected.
    """
    try:
        cnx.reconnect(attempt, delay)
    except (AttributeError, mysql.connector.errors.InterfaceError):
        raise _errors.DatabaseError("Invalid database connection.")
Example #2
0
def wait_for_slave_gtid(server, gtids, timeout=0):
    """Wait until a slave executes GITDs.

    The function `SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS` is called until the
    slave catches up. If the timeout period expires prior to achieving
    the condition the :class:`~mysql.fabric.errors.TimeoutError` exception is
    raised. If any thread is stopped, the
    :class:`~mysql.fabric.errors.DatabaseError` exception is raised.

    :param server: MySQL Server.
    :param gtids: Gtid information.
    :param timeout: Timeout for waiting for slave to catch up.
    """
    # Check servers for GTID support
    if not server.gtid_enabled:
        raise _errors.ProgrammingError(
            "Global Transaction IDs are not supported.")

    res = server.exec_stmt(_GTID_WAIT, {"params": (gtids, timeout)})

    if res is None or res[0] is None or res[0][0] is None:
        raise _errors.DatabaseError("Error waiting for slave to catch up. "
                                    "GTID (%s)." % (gtids, ))
    elif res[0][0] == -1:
        raise _errors.TimeoutError("Error waiting for slave to catch up. "
                                   "GTID (%s)." % (gtids, ))

    assert (res[0][0] > -1)
Example #3
0
def wait_for_slave(server, binlog_file, binlog_pos, timeout=0):
    """Wait for the slave to read the master's binlog up to a specified
    position.

    This methods call the MySQL function `SELECT MASTER_POS_WAIT`. If
    the timeout period expires prior to achieving the condition the
    :class:`~mysql.fabric.errors.TimeoutError` exception is raised. If any
    thread is stopped, the :class:`~mysql.fabric.errors.DatabaseError`
    exception is raised.

    :param server: MySQL Server.
    :param binlog_file: Master's binlog file.
    :param binlog_pos: Master's binlog file position.
    :param timeout: Maximum number of seconds to wait for the condition to
                    be achieved.
    """
    # Wait for slave to read the master log file
    res = server.exec_stmt(_MASTER_POS_WAIT,
                           {"params": (binlog_file, binlog_pos, timeout)})

    if res is None or res[0] is None or res[0][0] is None:
        raise _errors.DatabaseError(
            "Error waiting for slave to catch up. Binary log (%s, %s)." %
            (binlog_file, binlog_pos))
    elif res[0][0] == -1:
        raise _errors.TimeoutError(
            "Error waiting for slave to catch up. Binary log (%s, %s)." %
            (binlog_file, binlog_pos))

    assert (res[0][0] > -1)
def create_mysql_connection(**kwargs):
    """Create a connection.
    """
    try:
        return mysql.connector.Connect(**kwargs)
    except mysql.connector.Error as error:
        raise _errors.DatabaseError(error)
Example #5
0
def _check_condition(server, threads, check_if_running):
    """Check if slave's threads are either running or stopped. If the
    `SQL_THREAD` or the `IO_THREAD` are stopped and there is an error,
    the :class:`~mysql.fabric.errors.DatabaseError` exception is raised.

    :param server: MySQL Server.
    :param threads: Which threads should be checked.
    :type threads: `SQL_THREAD` or `IO_THREAD`.
    :param check_if_running: If one should check whether threads are
                             running or stopped.
    :type check_if_running: Bool
    """
    if not threads:
        threads = (SQL_THREAD, IO_THREAD)
    assert (isinstance(threads, tuple))

    io_status = not check_if_running
    sql_status = not check_if_running
    check_stmt = "YES" if check_if_running else "NO"
    io_errno = sql_errno = 0
    io_error = sql_error = ""

    ret = get_slave_status(server)
    if ret:
        io_status = ret[0].Slave_IO_Running.upper() == check_stmt
        io_error = ret[0].Last_IO_Error
        io_errno = ret[0].Last_IO_Errno
        io_errno = io_errno if io_errno else 0

        sql_status = ret[0].Slave_SQL_Running.upper() == check_stmt
        sql_error = ret[0].Last_SQL_Error
        sql_errno = ret[0].Last_SQL_Errno
        sql_errno = sql_errno if sql_errno else 0

    achieved = True
    if SQL_THREAD in threads:
        achieved = achieved and sql_status
        if check_if_running and sql_errno != 0:
            raise _errors.DatabaseError(sql_error)

    if IO_THREAD in threads:
        achieved = achieved and io_status
        if check_if_running and io_errno != 0:
            raise _errors.DatabaseError(io_error)

    return achieved
Example #6
0
def destroy_mysql_connection(cnx):
    """Close the connection abruptly. Do not interact with the server.
    """
    try:
        if cnx:
            cnx.disconnect()
    except Exception as error:
        raise _errors.DatabaseError(
            "Error trying to disconnect abruptly from (%s). %s." %
            (mysql_address_from_cnx(cnx), error))
Example #7
0
def disconnect_mysql_connection(cnx):
    """Close the connection in a friendly way. Send a QUIT command.
    """
    try:
        if cnx:
            cnx.disconnect()
    except Exception as error:
        raise _errors.DatabaseError(
            "Error trying to disconnect friendly from (%s). %s." %
            (mysql_address_from_cnx(cnx), error))
Example #8
0
def connect_to_mysql(cnx=None, **kwargs):
    """Create a connection.
    """
    try:
        if cnx is None:
            return mysql.connector.Connect(**kwargs)
        else:
            return cnx.connect(**kwargs)
    except mysql.connector.Error as error:
        raise _errors.DatabaseError(error)
Example #9
0
def destroy_mysql_connection(cnx):
    """Close the connection.
    """
    try:
        if cnx:
            cnx.shutdown()
    except Exception as error:
        raise _errors.DatabaseError(
            "Error trying to disconnect from (%s). %s." %
            (mysql_address_from_cnx(cnx), error))
Example #10
0
def _check_status_condition(server, thread, status):
    """Check if a slave's thread has the requested status. If the `SQL_THREAD`
    or the `IO_THREAD` is stopped and there is an error, the following
    :class:`~mysql.fabric.errors.DatabaseError` exception is raised.

    :param server: MySQL Server.
    :param thread: Which thread should be checked.
    :type thread: `SQL_THREAD` or `IO_THREAD`.
    :param status: The status to be checked.
    """
    io_errno = sql_errno = 0
    io_error = sql_error = ""
    achieved = False

    ret = get_slave_status(server)
    if not ret:
        return achieved

    if SQL_THREAD == thread:
        sql_status = True if status in ret[0].Slave_SQL_Running_State else False
        sql_error = ret[0].Last_SQL_Error
        sql_errno = ret[0].Last_SQL_Errno

        if sql_errno and sql_errno != 0:
            raise _errors.DatabaseError(sql_error)

        achieved = sql_status

    elif IO_THREAD == thread:
        io_status = True if status in ret[0].Slave_IO_State else False
        io_error = ret[0].Last_IO_Error
        io_errno = ret[0].Last_IO_Errno

        if io_errno and io_errno != 0:
            raise _errors.DatabaseError(io_error)

        achieved = io_status

    return achieved
Example #11
0
def exec_mysql_stmt(cnx, stmt_str, options=None):
    """Execute a statement for the client and return a result set or a
    cursor.

    This is the singular method to execute queries. If something goes
    wrong while executing a statement, the exception
    :class:`~mysql.fabric.errors.DatabaseError` is raised.

    :param cnx: Database connection.
    :param stmt_str: The statement (e.g. query, updates, etc) to execute.
    :param options: Options to control behavior:

                    - params - Parameters for statement.
                    - columns - If true, return a rows as named tuples
                      (default is False).
                    - raw - If true, do not convert MySQL's types to
                      Python's types (default is True).
                    - fetch - If true, execute the fetch as part of the
                      operation (default is True).

    :return: Either a result set as list of tuples (either named or unnamed)
             or a cursor.
    """
    if cnx is None:
        raise _errors.DatabaseError("Invalid database connection.")

    options = options or {}
    params = options.get('params', ())
    columns = options.get('columns', False)
    fetch = options.get('fetch', True)
    raw = options.get('raw', False)

    if raw and columns:
        raise _errors.ProgrammingError(
            "No raw cursor available returning named tuple")

    _LOGGER.debug("Statement ({statement}, Params({parameters}).".format(
        statement=stmt_str.replace('\n', '').replace('\r', ''),
        parameters=params))

    cur = None
    try:
        cur = cnx.cursor(raw=raw, named_tuple=columns)
        cur.execute(stmt_str, params)
    except Exception as error:
        if cnx.unread_result:
            cnx.get_rows()
        if cur:
            cur.close()

        errno = getattr(error, 'errno', None)
        raise _errors.DatabaseError(
            "Command (%s, %s) failed accessing (%s). %s." %
            (stmt_str, params, mysql_address_from_cnx(cnx), error), errno)

    assert (cur is not None)
    if fetch:
        results = None
        try:
            if cnx.unread_result:
                results = cur.fetchall()
        except mysql.connector.errors.InterfaceError as error:
            raise _errors.DatabaseError(
                "Command (%s, %s) failed fetching data from (%s). %s." %
                (stmt_str, params, mysql_address_from_cnx(cnx), error))
        finally:
            cur.close()
        return results

    return cur