Example #1
0
def _check_candidate_fail(group_id, slave_id):
    """Check if the candidate has all the prerequisites to become the new
    master.
    """
    allowed_status = (_server.MySQLServer.SECONDARY, _server.MySQLServer.SPARE)
    group = _server.Group.fetch(group_id)

    slave = _retrieve_server(slave_id, group_id)
    slave.connect()

    if group.master == slave.uuid:
        raise _errors.ServerError("Candidate slave (%s) is already master." %
                                  (slave_id, ))

    master_issues, why_master_issues = _replication.check_master_issues(slave)
    if master_issues:
        raise _errors.ServerError("Server (%s) is not a valid candidate slave "
                                  "due to the following reason(s): (%s)." %
                                  (slave.uuid, why_master_issues))

    if slave.status not in allowed_status:
        raise _errors.ServerError("Server (%s) is faulty." % (slave_id, ))

    _events.trigger_within_procedure(WAIT_SLAVE_FAIL, group_id,
                                     str(slave.uuid))
Example #2
0
    def execute(self,
                group_id,
                destn_address,
                server_id=None,
                timeout=None,
                synchronous=True):
        """Clone the objects of a given server into a destination server.

        :param group_id: The ID of the source group.
        :param destn_address: The address of the destination MySQL Server.
        :param source_id: The address or UUID of the source MySQL Server.
        :param timeout: Time in seconds after which an error is reported
                        if the destination server is unreachable.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        # If the destination server is already part of a Fabric Group, raise
        # an error
        destn_server_uuid = _lookup_uuid(destn_address, timeout)
        _check_server_not_in_any_group(destn_server_uuid)
        host, port = split_host_port(destn_address,
                                     _backup.MySQLDump.MYSQL_DEFAULT_PORT)

        # Fetch information on backup and restore programs.
        config_file = self.config.config_file if self.config.config_file else ""

        mysqldump_binary = _utils.read_config_value(self.config, 'sharding',
                                                    'mysqldump_program')
        mysqlclient_binary = _utils.read_config_value(self.config, 'sharding',
                                                      'mysqlclient_program')

        if not _utils.is_valid_binary(mysqldump_binary):
            raise _errors.ServerError(MYSQLDUMP_NOT_FOUND % mysqldump_binary)

        if not _utils.is_valid_binary(mysqlclient_binary):
            raise _errors.ServerError(MYSQLCLIENT_NOT_FOUND %
                                      mysqlclient_binary)

        # Fetch a reference to source server.
        if server_id:
            server = _retrieve_server(server_id, group_id)
        else:
            group = _retrieve_group(group_id)
            server = _utils.fetch_backup_server(group)

        # Schedule the clone operation through the executor.
        procedures = _events.trigger(BACKUP_SERVER,
                                     self.get_lockable_objects(),
                                     str(server.uuid), host, port,
                                     mysqldump_binary, mysqlclient_binary,
                                     config_file)
        return self.wait_for_procedures(procedures, synchronous)
Example #3
0
def _set_server_weight(server_id, weight):
    """Set server's weight.
    """
    server = _retrieve_server(server_id)

    try:
        weight = float(weight)
    except ValueError:
        raise _errors.ServerError("Value (%s) must be a float." % (weight, ))

    if weight <= 0.0:
        raise _errors.ServerError(
            "Cannot set the server's weight (%s) to a value lower "
            "than or equal to 0.0" % (weight, ))
    server.weight = weight
Example #4
0
def _restore_server(source_uuid, host, port, backup_image):
    """Restore the backup on the destination Server.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    :param backup_image: The backup image path.
    """
    restore_user = _services_utils.read_config_value(_config.global_config,
                                                     'servers', 'restore_user')
    restore_passwd = _services_utils.read_config_value(_config.global_config,
                                                       'servers',
                                                       'restore_password')

    mysqlclient_binary = _services_utils.read_config_value(
        _config.global_config, 'sharding', 'mysqlclient_program')

    source_server = _server.MySQLServer.fetch(source_uuid)
    if not source_server:
        raise _errors.ServerError(SERVER_NOT_FOUND % source_uuid)
    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)
    _backup.MySQLDump.restore_server(host, port, restore_user, restore_passwd,
                                     bk_img, mysqlclient_binary)
    _LOGGER.debug("Done with restore of server with host = %s, port = %s",
                  host, port)
Example #5
0
def _retrieve_server_mode(mode):
    """Check whether the server's mode is valid or not and if an integer was
    provided retrieve the correspondent string.
    """
    valid = False
    try:
        idx = int(mode)
        try:
            mode = _server.MySQLServer.get_mode(idx)
            valid = True
        except IndexError:
            pass
    except ValueError:
        try:
            mode = str(mode).upper()
            _server.MySQLServer.get_mode_idx(mode)
            valid = True
        except ValueError:
            pass

    if not valid:
        values = [ str((_server.MySQLServer.get_mode_idx(value), value))
                   for value in _server.MySQLServer.SERVER_MODE ]
        raise _errors.ServerError("Trying to use an invalid mode (%s). "
            "Possible values are: %s." % (mode, ", ".join(values))
        )

    return mode
Example #6
0
def _retrieve_server_status(status):
    """Check whether the server's status is valid or not and
    if an integer was provided retrieve the correspondent
    string.
    """
    valid = False
    try:
        idx = int(status)
        try:
            status = _server.MySQLServer.get_status(idx)
            valid = True
        except IndexError:
            pass
    except ValueError:
        try:
            status = str(status).upper()
            _server.MySQLServer.get_status_idx(status)
            valid = True
        except ValueError:
            pass

    if not valid:
        values = [ str((_server.MySQLServer.get_status_idx(value), value))
                   for value in _server.MySQLServer.SERVER_STATUS ]
        raise _errors.ServerError("Trying to use an invalid status (%s). "
            "Possible values are %s." % (status, ", ".join(values))
        )

    return status
Example #7
0
def _set_server_status_primary(server, update_only):
    """Set server's status to primary.
    """
    raise _errors.ServerError(
        "If you want to make a server (%s) primary, please, use the "
        "group.promote function." % (server.uuid, )
    )
Example #8
0
def _check_requirements(server):
    """Check if the server fulfils some requirements.
    """
    # Being able to connect to the server is the first requirment.
    server.connect()

    if not server.check_version_compat((5, 6, 8)):
        raise _errors.ServerError(
            "Server (%s) has an outdated version (%s). 5.6.8 or greater "
            "is required." % (server.uuid, server.version))

    server.check_server_privileges()

    if not server.gtid_enabled or not server.binlog_enabled:
        raise _errors.ServerError(
            "Server (%s) does not have the binary log or gtid enabled." %
            (server.uuid, ))
Example #9
0
def _do_set_server_mode(server, mode, allowed_mode):
    """Set server's mode.
    """
    if mode not in allowed_mode:
        raise _errors.ServerError(
            "Cannot set mode to (%s) when the server's (%s) status is (%s)." %
            (mode, server.uuid, server.status))
    server.mode = mode
Example #10
0
def _check_server_exists(server_id):
    """Check whether a MySQLServer instance exists or not.

    :param server_id: The UUID or the host:port for the server.
    """
    server = _server.MySQLServer.fetch(server_id)

    if server:
        raise _errors.ServerError("Server (%s) already exists." % (server_id, ))
Example #11
0
def _lookup_uuid(address, timeout):
    """Return server's uuid.
    """
    timeout = timeout or DEFAULT_UNREACHABLE_TIMEOUT
    try:
        return _server.MySQLServer.discover_uuid(address=address,
                                                 connection_timeout=timeout)
    except _errors.DatabaseError as error:
        raise _errors.ServerError("Error accessing server (%s): %s." %
                                  (address, error))
Example #12
0
def _configure_as_slave(group, server):
    """Configure the server as a slave.
    """
    try:
        ### When master has been already elected, throw CREATE USER into master.
        if group.master:
            master = _server.MySQLServer.fetch(group.master)
            master.connect()
            host, port = split_host_port(server.address)
            master.exec_stmt(_server.MySQLServer.DROP_REPLICATION_USER,
                             {"params": (server.repl_user, host,)})
            master.exec_stmt(_server.MySQLServer.CREATE_REPLICATION_USER,
                             {"params": (server.repl_user, host,
                                         server.repl_pass,)})
            master.exec_stmt(_server.MySQLServer.GRANT_REPLICATION_USER,
                             {"params": (server.repl_user, host,)})
            _services_utils.switch_master(server, master)
        else:
            
            ### When master hasn't been elected yet and adding server is very first server in the group,
            ### throw CREATE USER into server itself.
            _LOGGER.critical(group.servers())

            if len(group.servers()) == 1:
                server.connect()
                host, port = split_host_port(server.address)
                server.exec_stmt(_server.MySQLServer.DROP_REPLICATION_USER,
                                 {"params": (server.repl_user, host,)})
                server.exec_stmt(_server.MySQLServer.CREATE_REPLICATION_USER,
                                 {"params": (server.repl_user, host,
                                             server.repl_pass,)})
                server.exec_stmt(_server.MySQLServer.GRANT_REPLICATION_USER,
                                 {"params": (server.repl_user, host,)})
            else:
                ### This means group has at least 1 server but master doesn't elect yet.
                raise _errors.ServerError("Master server doesn't elect yet")
            
    except _errors.DatabaseError as error:
        msg = "Error trying to configure server ({0}) as slave: {1}.".format(
            server.uuid, error)
        _LOGGER.debug(msg)
        raise _errors.ServerError(msg)
Example #13
0
def _check_candidate_switch(group_id, slave_id):
    """Check if the candidate has all the features to become the new
    master.
    """
    allowed_status = (_server.MySQLServer.SECONDARY, _server.MySQLServer.SPARE)
    group = _server.Group.fetch(group_id)

    if not group.master:
        raise _errors.GroupError("Group (%s) does not contain a valid "
                                 "master. Please, run a promote or failover." %
                                 (group_id, ))

    slave = _retrieve_server(slave_id, group_id)
    slave.connect()

    if group.master == slave.uuid:
        raise _errors.ServerError("Candidate slave (%s) is already master." %
                                  (slave_id, ))

    master_issues, why_master_issues = _replication.check_master_issues(slave)
    if master_issues:
        raise _errors.ServerError("Server (%s) is not a valid candidate slave "
                                  "due to the following reason(s): (%s)." %
                                  (slave.uuid, why_master_issues))

    slave_issues, why_slave_issues = _replication.check_slave_issues(slave)
    if slave_issues:
        raise _errors.ServerError("Server (%s) is not a valid candidate slave "
                                  "due to the following reason: (%s)." %
                                  (slave.uuid, why_slave_issues))

    master_uuid = _replication.slave_has_master(slave)
    if master_uuid is None or group.master != _uuid.UUID(master_uuid):
        raise _errors.GroupError(
            "The group's master (%s) is different from the candidate's "
            "master (%s)." % (group.master, master_uuid))

    if slave.status not in allowed_status:
        raise _errors.ServerError("Server (%s) is faulty." % (slave_id, ))

    _events.trigger_within_procedure(BLOCK_WRITE_SWITCH, group_id, master_uuid,
                                     str(slave.uuid))
Example #14
0
def _check_server_not_in_any_group(server_id):
    """Check for both the presence of the server object and its associated
       group. If the server belongs to a group an error is raised.

    :param server_id: The UUID or the host:port for the server.
    """
    server = _server.MySQLServer.fetch(server_id)
    if server and server.group_id:
        raise _errors.ServerError(
            "Destination server (%s) is already part of group (%s)" %
            (server.address, server.group_id))
Example #15
0
def _check_requirements(server):
    """Check if the server fulfils some requirements.
    """
    # Being able to connect to the server is the first requirement.
    server.connect()

    if not server.check_version_compat((5, 6, 8)):
        raise _errors.ServerError(
            "Server (%s) has an outdated version (%s). 5.6.8 or greater "
            "is required." % (server.uuid, server.version))

    if not server.has_required_privileges():
        raise _errors.ServerError(
            "User (%s) does not have appropriate privileges (%s) on server "
            "(%s, %s)." %
            (server.user, ", ".join(_server.MySQLServer.ALL_PRIVILEGES),
             server.address, server.uuid))

    if not server.gtid_enabled or not server.binlog_enabled:
        raise _errors.ServerError(
            "Server (%s) does not have the binary log or gtid enabled." %
            (server.uuid, ))
Example #16
0
def _configure_as_slave(group, server):
    """Configure the server as a slave.
    """
    try:
        if group.master:
            master = _server.MySQLServer.fetch(group.master)
            master.connect()
            _utils.switch_master(server, master)
    except _errors.DatabaseError as error:
        msg = "Error trying to configure server ({0}) as slave: {1}.".format(
            server.uuid, error)
        _LOGGER.debug(msg)
        raise _errors.ServerError(msg)
Example #17
0
def _remove_server(group_id, server_id):
    """Remove a server from a group.
    """
    group = _retrieve_group(group_id)
    server = _retrieve_server(server_id, group_id)

    if group.master == server.uuid:
        raise _errors.ServerError(
            "Cannot remove server (%s), which is master in group (%s). "
            "Please, demote it first." % (server.uuid, group_id))

    _server.MySQLServer.remove(server)
    server.disconnect()
Example #18
0
def _append_error_log(server_id, reporter, error):
    """Check whether the server exist and is not faulty and register
    error log.
    """
    server = _retrieve_server(server_id)
    if server.status == _server.MySQLServer.FAULTY:
        raise _errors.ServerError("Server (%s) is already marked as faulty." %
                                  (server.uuid, ))

    _LOGGER.warning("Reported issue (%s) for server (%s).", error, server.uuid)

    now = get_time()
    _error_log.ErrorLog.add(server, now, reporter, error)

    return (now, server)
Example #19
0
def _do_set_status(server, allowed_status, status, mode, update_only):
    """Set server's status.
    """
    allowed_transition = server.status in allowed_status
    previous_status = server.status
    if allowed_transition:
        server.status = status
        server.mode = mode
    else:
        raise _errors.ServerError(
            "Cannot change server's (%s) status from (%s) to (%s)." %
            (str(server.uuid), server.status, status))

    _LOGGER.debug(
        "Changed server's status (%s) from (%s) to (%s). Update-only "
        "state store parameter is (%s).", str(server.uuid), previous_status,
        server.status, update_only)
Example #20
0
def _retrieve_server(server_id, group_id=None):
    """Return a MySQLServer object from a UUID or a HOST:PORT.
    """
    server = _server.MySQLServer.fetch(server_id)

    if not server:
        raise _errors.ServerError("Server (%s) does not exist." %
                                  (server_id, ))

    if not server.group_id:
        raise _errors.GroupError("Server (%s) does not belong to a group." %
                                 (server_id, ))

    if group_id is not None and group_id != server.group_id:
        raise _errors.GroupError("Group (%s) does not contain server (%s)." %
                                 (group_id, server_id))

    return server
Example #21
0
def _define_ha_operation(group_id, slave_id, update_only):
    """Define which operation must be called based on the master's status
    and whether the candidate slave is provided or not.
    """
    fail_over = True

    group = _server.Group.fetch(group_id)
    if not group:
        raise _errors.GroupError("Group (%s) does not exist." % (group_id, ))

    if update_only and not slave_id:
        raise _errors.ServerError(
            "The new master must be specified through --slave-uuid if "
            "--update-only is set.")

    if group.master:
        master = _server.MySQLServer.fetch(group.master)
        if master.status != _server.MySQLServer.FAULTY:
            if update_only:
                _do_block_write_master(group_id, str(group.master),
                                       update_only)
            fail_over = False

    if update_only:
        # Check whether the server is registered or not.
        _retrieve_server(slave_id, group_id)
        _change_to_candidate(group_id, slave_id, update_only)
        return

    if fail_over:
        if not slave_id:
            _events.trigger_within_procedure(FIND_CANDIDATE_FAIL, group_id)
        else:
            _events.trigger_within_procedure(CHECK_CANDIDATE_FAIL, group_id,
                                             slave_id)
    else:
        if not slave_id:
            _events.trigger_within_procedure(FIND_CANDIDATE_SWITCH, group_id)
        else:
            _events.trigger_within_procedure(CHECK_CANDIDATE_SWITCH, group_id,
                                             slave_id)
Example #22
0
def _restore_server(source_uuid, host, port, backup_image, mysqlclient_binary,
                    config_file):
    """Restore the backup on the destination Server.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    :param userid: The User Name to be used to connect to the destn server.
    :param passwd: The password to be used to connect to the destn server.
    :param mysqldump_binary: The MySQL Dump Binary path.
    :param mysqlclient_binary: The MySQL Client Binary path.
    :param config_file: The complete path to the fabric configuration
        file.
    """
    source_server = _server.MySQLServer.fetch(source_uuid)
    if not source_server:
        raise _errors.ServerError(SERVER_NOT_FOUND % source_uuid)
    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)
    _backup.MySQLDump.restore_server(host, port, source_server.USER,
                                     source_server.PASSWD, bk_img, config_file,
                                     mysqlclient_binary)
    _LOGGER.debug("Done with restore of server with host = %s, port = %s" %\
                  (host, port,))
Example #23
0
def _set_server_status_faulty(server, update_only):
    raise _errors.ServerError(
        "If you want to set a server (%s) to faulty, please, use the "
        "threat.report_faulty interface." % (server.uuid, )
    )