Example #1
0
def _do_block_write_master(group_id, master_uuid, update_only=False):
    """Block and disable write access to the current master.

    Note that connections are not killed and blocking the master
    may take some time.
    """
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    assert (master.status == _server.MySQLServer.PRIMARY)
    master.mode = _server.MySQLServer.READ_ONLY
    master.status = _server.MySQLServer.SECONDARY

    if not update_only:
        master.connect()
        _utils.set_read_only(master, True)

    # Temporarily unset the master in this group.
    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, None)

    # At the end, we notify that a server was demoted.
    # Any function that implements this event should not
    # run any action that updates Fabric. The event was
    # designed to trigger external actions such as:
    #
    # . Updating an external entity.
    #
    # . Fencing off a server.
    _events.trigger("SERVER_DEMOTED", set([group_id]), group_id,
                    str(master.uuid))
def _do_block_write_master(group_id, master_uuid, update_only=False):
    """Block and disable write access to the current master.

    Note that connections are not killed and blocking the master
    may take some time.
    """
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    assert(master.status == _server.MySQLServer.PRIMARY)
    master.mode = _server.MySQLServer.READ_ONLY
    master.status = _server.MySQLServer.SECONDARY

    if not update_only:
        master.connect()
        _utils.set_read_only(master, True)
        _utils.set_offline_mode(master, True)

    # Temporarily unset the master in this group.
    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, None)

    # At the end, we notify that a server was demoted.
    # Any function that implements this event should not
    # run any action that updates Fabric. The event was
    # designed to trigger external actions such as:
    #
    # . Updating an external entity.
    #
    # . Fencing off a server.
    _events.trigger("SERVER_DEMOTED", set([group_id]),
        group_id, str(master.uuid)
    )
def _change_to_candidate(group_id, master_uuid, update_only=False):
    """Switch to candidate slave.
    """
    forbidden_status = (_server.MySQLServer.FAULTY, )
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    master.mode = _server.MySQLServer.READ_WRITE
    master.status = _server.MySQLServer.PRIMARY

    if not update_only:
        # Prepare the server to be the master
        master.connect()
        _utils.reset_slave(master)
        _utils.set_read_only(master, False)

    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, master.uuid, update_only)

    if not update_only:
        # Make slaves point to the master.
        for server in group.servers():
            if server.uuid != _uuid.UUID(master_uuid) and \
                server.status not in forbidden_status:
                try:
                    server.connect()
                    _utils.switch_master(server, master)
                except _errors.DatabaseError as error:
                    _LOGGER.debug(
                        "Error configuring slave (%s).", server.uuid,
                        exc_info=error
                    )

    # At the end, we notify that a server was promoted.
    _events.trigger("SERVER_PROMOTED", set([group_id]),
        group_id, master_uuid
    )
Example #4
0
def _change_to_candidate(group_id, master_uuid, update_only=False):
    """Switch to candidate slave.
    """
    forbidden_status = (_server.MySQLServer.FAULTY, )
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    master.mode = _server.MySQLServer.READ_WRITE
    master.status = _server.MySQLServer.PRIMARY

    if not update_only:
        # Prepare the server to be the master
        master.connect()
        _utils.reset_slave(master)
        _utils.set_read_only(master, False)

    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, master.uuid, update_only)

    if not update_only:
        # Make slaves point to the master.
        for server in group.servers():
            if server.uuid != _uuid.UUID(master_uuid) and \
                server.status not in forbidden_status:
                try:
                    server.connect()
                    _utils.switch_master(server, master)
                except _errors.DatabaseError as error:
                    _LOGGER.debug("Error configuring slave (%s): %s.",
                                  server.uuid, error)

    # At the end, we notify that a server was promoted.
    _events.trigger("SERVER_PROMOTED", set([group_id]), group_id, master_uuid)
def check_properties_5(param_01, param_02):
    """Check properties 5.
    """
    _events.trigger(
        EVENT_CHECK_PROPERTIES_2, set(["lock"]), "NEW 01", "NEW 02"
        )

    job = _executor.ExecutorThread.executor_object().current_job
    checkpoint = _checkpoint.Checkpoint.fetch(job.procedure.uuid)
    return checkpoint
Example #6
0
    def execute(self, event, locks, *args, **kwargs):
        """Trigger the execution of an event.

        :param event: Event's identification.
        :type event: String
        :param args: Event's non-keyworded arguments.
        :param kwargs: Event's keyworded arguments.

        :return: :class:`CommandResult` instance with UUID of the
                 procedures that were triggered.

        """

        lockable_objects = set()
        for lock in locks.split(","):
            lockable_objects.add(lock.strip())

        rset = ResultSet(names=['uuid'], types=[str])

        # Trigger the event and add the UUID of all procedures queued
        # to the result.
        for proc in _events.trigger(event, lockable_objects, *args, **kwargs):
            rset.append_row([str(proc.uuid)])

        return CommandResult(None, results=rset)
Example #7
0
 def execute(self, param, synchronous=True):
     """Method that is remotely executed.
     """
     procedures = _events.trigger(
         NEW_PROCEDURE_GROUP_1, self.get_lockable_objects(), param
     )
     return self.wait_for_procedures(procedures, synchronous)
Example #8
0
    def execute(self, provider_id, username, password, url, tenant=None,
                provider_type="OPENSTACK", default_image=None,
                default_flavor=None, extra=None, synchronous=True):
        """Register a provider.

        :param provider_id: Provider's Id.
        :param username: User name to use during authentication.
        :param password: Password to use during authentication.
        :param url: URL that is used as an access point.
        :param tenant: Tenant's name, i.e. who will access resources
                       in the cloud.
        :param provider_type: Provider type.
        :param image: Default image's name that will be used upon creating
                      a machine if one is not provided.
        :param image: Default flavor's name that will be used upon creating
                      a machine if one is not provided.

        :param extra: Define parameters that are specific to a provider.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            REGISTER_PROVIDER, self.get_lockable_objects(), provider_id,
            provider_type, username, password, url, tenant, default_image,
            default_flavor, extra
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #9
0
    def execute(self,
                shard_id,
                group_id,
                split_value=None,
                update_only=False,
                synchronous=True):
        """Split the shard represented by the shard_id into the destination
        group.

        :param shard_id: The shard_id of the shard that needs to be split.
        :param group_id: The ID of the group into which the split data needs
                         to be moved.
        :param split_value: The value at which the range needs to be split.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes
        """
        mysqldump_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqldump_program')
        mysqlclient_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqlclient_program')
        prune_limit = _services_utils.read_config_value(
            self.config, 'sharding', 'prune_limit')
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(CHECK_SHARD_INFORMATION,
                                     self.get_lockable_objects(), shard_id,
                                     group_id, mysqldump_binary,
                                     mysqlclient_binary, split_value,
                                     config_file, prune_limit, "SPLIT",
                                     update_only)
        return self.wait_for_procedures(procedures, synchronous)
    def _report_failure(self, server):
        """Mark the server as faulty and report a failure.

        The thread is created to allow the built-in failure detector
        to continue monitoring the servers so that if the report failure
        hangs, it will kill all connections to faulty servers thus
        eventually freeing the thread.

        Not though that the report failure is not crash-safe so it might
        fail without promoting a new server to master. In the future, we
        will circumvent this limitation.
        """
        try:
            _persistence.init_thread()

            server.status = MySQLServer.FAULTY
            self.__connection_manager.purge_connections(server)

            procedures = trigger(
                "REPORT_FAILURE", None, str(server.uuid),
                threading.current_thread().name, MySQLServer.FAULTY, False
            )
            executor = _executor.Executor()
            for procedure in procedures:
                executor.wait_for_procedure(procedure)

            _persistence.deinit_thread()
        finally:
            self.__thread_report_failure = False
    def test_properties_5(self):
        """5 - Within a job, triggering a set of independent jobs.
        """
        procedures = _events.trigger(
            EVENT_CHECK_PROPERTIES_5, set(["lock"]), "PARAM 01", "PARAM 02"
            )

        # Get the result (Checkpoint object) from the procedure.
        self.assertEqual(len(procedures), 1)
        result = None
        procedure = None
        for procedure in procedures:
            procedure.wait()
            result = procedure.result

            # Fetch and check all the properties.
            self.assertEqual(len(result), 1)
            for checkpoint in result:
                self.assertEqual(checkpoint.param_args,
                    ("PARAM 01", "PARAM 02")
                )
                self.assertEqual(checkpoint.param_kwargs, {})
                self.assertNotEqual(checkpoint.started, None)
                self.assertEqual(checkpoint.finished, None)
                self.assertEqual(checkpoint.do_action, check_properties_5)

        # There should not be any entry for this procedure.
        self.assertEqual(len(_checkpoint.Checkpoint.fetch(procedure.uuid)), 0)
Example #12
0
    def execute(self, shard_id, group_id, split_value=None,
                update_only=False, synchronous=True):
        """Split the shard represented by the shard_id into the destination
        group.

        :param shard_id: The shard_id of the shard that needs to be split.
        :param group_id: The ID of the group into which the split data needs
                         to be moved.
        :param split_value: The value at which the range needs to be split.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes
        """
        mysqldump_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )
        prune_limit =   _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'prune_limit'
                            )
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(
            CHECK_SHARD_INFORMATION, self.get_lockable_objects(),
            shard_id, group_id, mysqldump_binary, mysqlclient_binary,
            split_value, config_file, prune_limit, "SPLIT", update_only)
        return self.wait_for_procedures(procedures, synchronous)
Example #13
0
    def execute(self, shard_id, group_id, update_only=False,
                synchronous=True):
        """Move the shard represented by the shard_id to the destination group.

        :param shard_id: The ID of the shard that needs to be moved.
        :param group_id: The ID of the group to which the shard needs to
                         be moved.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """
        mysqldump_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(
            CHECK_SHARD_INFORMATION, self.get_lockable_objects(), shard_id,
            group_id, mysqldump_binary, mysqlclient_binary, None, config_file,
            "", "MOVE", update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #14
0
    def execute(self,
                provider_id,
                username,
                password,
                url,
                tenant,
                provider_type="OPENSTACK",
                default_image=None,
                default_flavor=None,
                synchronous=True):
        """Register a provider.

        :param provider_id: Provider's Id.
        :param username: User name to use during authentication.
        :param password: Password to use during authentication.
        :param url: URL that is used as an access point.
        :param tenant: Tenant's name, i.e. who will access resources
                       in the cloud.
        :param provider_type: Provider type.
        :param image: Default image's name that will be used upon creating
                      a machine if one is not provided.
        :param image: Default flavor's name that will be used upon creating
                      a machine if one is not provided.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(REGISTER_PROVIDER,
                                     self.get_lockable_objects(), provider_id,
                                     provider_type, username, password, url,
                                     tenant, default_image, default_flavor)
        return self.wait_for_procedures(procedures, synchronous)
Example #15
0
    def execute(self, group_id, update_only=False, synchronous=True):
        """Demote the current master if there is one.

        :param uuid: Group's id.
        :param update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.

        In what follows, one will find a figure that depicts the sequence of
        event that happen during the demote operation. To ease the presentation
        some names are abbreivated:

        .. seqdiag::

          diagram {
            activation = none;
            === Schedule "block_write" ===
            demote --> executor [ label = "schedule(block_write)" ];
            demote <-- executor;
            === Execute "block_write" and schedule "wait_slaves" ===
            executor -> block_write [ label = "execute(block_write)" ];
            block_write --> executor [ label = "schedule(wait_slaves)" ];
            block_write <-- executor;
            executor <- block_write;
            === Execute "wait_slaves" ===
            executor -> wait_slaves [ label = "execute(wait_slaves)" ];
            wait_slaves --> executor;
            wait_slaves <-- executor;
            executor <- wait_slaves;
          }
        """
        procedures = _events.trigger(BLOCK_WRITE_DEMOTE,
                                     self.get_lockable_objects(), group_id,
                                     update_only)
        return self.wait_for_procedures(procedures, synchronous)
Example #16
0
    def execute(self,
                shard_mapping_id,
                table_name,
                column_name,
                range_check=False,
                update_only=False,
                synchronous=True):
        """Add a table to a shard mapping.

        :param shard_mapping_id: The shard mapping id to which the input
                                    table is attached.
        :param table_name: The table being sharded.
        :param column_name: The column whose value is used in the sharding
                            scheme being applied
        :param range_check: Indicates if range check should be turned on for
                            this table.
        :param update_only: Only update the state store and skip adding range checks.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """

        procedures = _events.trigger(ADD_SHARD_MAPPING,
                                     self.get_lockable_objects(),
                                     shard_mapping_id, table_name, column_name,
                                     range_check, update_only)
        return self.wait_for_procedures(procedures, synchronous)
 def execute(self, synchronous=True):
     """Method that is remotely executed.
     """
     procedures = _events.trigger(
         NEW_EXECUTION_EVENT_1, self.get_lockable_objects()
     )
     return self.wait_for_procedures(procedures, synchronous)
Example #18
0
 def execute(self, group_id, synchronous=True):
     """Method that is remotely executed.
     """
     procedures = _events.trigger(
         NEW_PROCEDURE_SHARD_0, self.get_lockable_objects(), group_id
     )
     return self.wait_for_procedures(procedures, synchronous)
def _change_to_candidate(group_id, master_uuid, update_only=False):
    """Switch to candidate slave.
    """
    forbidden_status = (_server.MySQLServer.FAULTY, )
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    master.mode = _server.MySQLServer.READ_WRITE
    master.status = _server.MySQLServer.PRIMARY

    if not update_only:
        # Prepare the server to be the master
        master.connect()
        _utils.reset_slave(master)
        _utils.set_read_only(master, False)
        _utils.set_offline_mode(master, False)

    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, master.uuid, update_only)

    if not update_only:
        # Make slaves point to the master.
        for server in group.servers():
            if server.uuid != _uuid.UUID(master_uuid) and \
                server.status not in forbidden_status:
                try:
                    server.connect()
                    _utils.switch_master(server, master)
                except _errors.DatabaseError as error:
                    _LOGGER.debug(
                        "Error configuring slave (%s): %s.", server.uuid, error
                    )


    ### Restore FailureDetector's status before starting failover/switchover
    if _detector.FailureDetector.was_active:
        _detector.FailureDetector.was_active = None
        group.status = _server.Group.ACTIVE
        _detector.FailureDetector.register_group(group_id)

    # At the end, we notify that a server was promoted.
    # Any function that implements this event should not
    # run any action that updates Fabric. The event was
    # designed to trigger external actions such as:
    #
    # . Updating an external entity.
    _events.trigger("SERVER_PROMOTED", set([group_id]),
        group_id, master_uuid
    )
Example #20
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 #21
0
    def execute(self, shard_id, synchronous=True):
        """Enable the Shard represented by the shard_id.

        :param shard_id: The shard ID of the shard that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """
        procedures = _events.trigger(SHARD_ENABLE, self.get_lockable_objects(),
                                     shard_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #22
0
    def execute(self, provider_id, synchronous=True):
        """Unregister a provider.

        :param provider_id: Provider's Id.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(UNREGISTER_PROVIDER,
                                     self.get_lockable_objects(), provider_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #23
0
 def execute(self,
             table_name,
             shard_mapping_id,
             shard_id,
             synchronous=True):
     """Method that is remotely executed.
     """
     procedures = _events.trigger(NEW_PROCEDURE_SHARD_1,
                                  self.get_lockable_objects(), table_name,
                                  shard_mapping_id, shard_id)
     return self.wait_for_procedures(procedures, synchronous)
Example #24
0
    def execute(self, shard_id, synchronous=True):
        """Enable the Shard represented by the shard_id.

        :param shard_id: The shard ID of the shard that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """
        procedures = _events.trigger(
            SHARD_ENABLE, self.get_lockable_objects(), shard_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #25
0
    def execute(self, synchronous=True):
        """Deactivate all groups.

        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            DEACTIVATE_ALL, self.get_lockable_objects()
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #26
0
    def execute(self, group_id, synchronous=True):
        """Activate a group.

        :param group_id: Group's id.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(ACTIVATE_GROUP,
                                     self.get_lockable_objects(), group_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #27
0
    def execute(self, provider_id, synchronous=True):
        """Unregister a provider.

        :param provider_id: Provider's Id.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            UNREGISTER_PROVIDER, self.get_lockable_objects(), provider_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #28
0
    def execute(self, group_id, synchronous=True):
        """Activate a group.

        :param group_id: Group's id.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            ACTIVATE_GROUP, self.get_lockable_objects(), group_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #29
0
    def execute(self, shard_id, synchronous=True):
        """Remove the RANGE specification mapping represented by the current
        RANGE shard specification object.

        :param shard_id: The shard ID of the shard that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """

        procedures = _events.trigger(REMOVE_SHARD, self.get_lockable_objects(),
                                     shard_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #30
0
    def execute(self, server_id, mode, synchronous=True):
        """Set a server's mode.

        :param server_id: Servers's UUID or HOST:PORT.
        :param weight: Server's weight.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        procedures = _events.trigger(
            SET_SERVER_MODE, self.get_lockable_objects(), server_id, mode
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #31
0
    def execute(self, group_id, description=None, synchronous=True):
        """Update group's description.

        :param group_id: Group's id.
        :param description: Group's description.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(UPDATE_GROUP, self.get_lockable_objects(),
                                     group_id, description)
        return self.wait_for_procedures(procedures, synchronous)
Example #32
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 #33
0
    def execute(self, group_id, description=None, synchronous=True):
        """Update group's description.

        :param group_id: Group's id.
        :param description: Group's description.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            UPDATE_GROUP, self.get_lockable_objects(), group_id, description
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #34
0
def _do_block_write_master(group_id, master_uuid, update_only=False):
    """Block and disable write access to the current master.

    Note that connections are not killed and blocking the master
    may take some time.
    """
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    assert (master.status == _server.MySQLServer.PRIMARY)
    master.mode = _server.MySQLServer.READ_ONLY
    master.status = _server.MySQLServer.SECONDARY

    if not update_only:
        master.connect()
        _utils.set_read_only(master, True)

    # Temporarily unset the master in this group.
    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, None)

    # At the end, we notify that a server was demoted.
    _events.trigger("SERVER_DEMOTED", set([group_id]), group_id,
                    str(master.uuid))
Example #35
0
    def execute(self, group_id, force=False, synchronous=True):
        """Remove a group.

        :param group_id: Group's id.
        :param force: If the group is not empty, remove it serves.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(
            DESTROY_GROUP, self.get_lockable_objects(), group_id, force
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #36
0
    def execute(self, shard_id, synchronous=True):
        """Remove the RANGE specification mapping represented by the current
        RANGE shard specification object.

        :param shard_id: The shard ID of the shard that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """

        procedures = _events.trigger(
            REMOVE_SHARD, self.get_lockable_objects(), shard_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #37
0
    def execute(self, server_id, status, update_only=False, synchronous=True):
        """Set a server's status.

        :param server_id: Servers's UUID or HOST:PORT.
        :param status: Server's status.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        procedures = _events.trigger(SET_SERVER_STATUS,
                                     self.get_lockable_objects(), server_id,
                                     status, update_only)
        return self.wait_for_procedures(procedures, synchronous)
Example #38
0
    def execute(self, group_id, server_id, synchronous=True):
        """Remove a server from a group.

        :param group_id: Group's id.
        :param server_id: Servers's UUID or HOST:PORT.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(REMOVE_SERVER, self.get_lockable_objects(),
            group_id, server_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #39
0
    def execute(self, type_name, group_id, synchronous=True):
        """Define a shard mapping.

        :param type_name: The type of sharding scheme - RANGE, HASH, LIST etc
        :param group_id: Every shard mapping is associated with a global group
                         that stores the global updates and the schema changes
                         for this shard mapping and dissipates these to the
                         shards.
        """
        procedures = _events.trigger(DEFINE_SHARD_MAPPING,
                                     self.get_lockable_objects(), type_name,
                                     group_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #40
0
    def execute(self, table_name, synchronous=True):
        """Remove the shard mapping corresponding to the table passed as input.
        This method is exposed through the XML-RPC framework and creates a job
        and enqueues it in the executor.

        :param table_name: The name of the table whose sharding specification is
                            being removed.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        procedures = _events.trigger(REMOVE_SHARD_MAPPING,
                                     self.get_lockable_objects(), table_name)
        return self.wait_for_procedures(procedures, synchronous)
Example #41
0
    def execute(self, table_name, synchronous=True):
        """Remove the shard mapping corresponding to the table passed as input.
        This method is exposed through the XML-RPC framework and creates a job
        and enqueues it in the executor.

        :param table_name: The name of the table whose sharding specification is
                            being removed.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        procedures = _events.trigger(
            REMOVE_SHARD_MAPPING, self.get_lockable_objects(), table_name
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #42
0
    def execute(self, server_id, status, update_only=False, synchronous=True):
        """Set a server's status.

        :param server_id: Servers's UUID or HOST:PORT.
        :param status: Server's status.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        procedures = _events.trigger(
            SET_SERVER_STATUS, self.get_lockable_objects(), server_id, status,
            update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #43
0
    def execute(self, shard_mapping_id, synchronous=True):
        """Remove the shard mapping definition represented by the Shard Mapping
        ID. This method is exposed through the XML-RPC framework and creates a
        job and enqueues it in the executor.

        :param shard_mapping_id: The shard mapping ID of the shard mapping
                                definition that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        procedures = _events.trigger(REMOVE_SHARD_MAPPING_DEFN,
                                     self.get_lockable_objects(),
                                     shard_mapping_id)
        return self.wait_for_procedures(procedures, synchronous)
Example #44
0
    def execute(self, shard_mapping_id, synchronous=True):
        """Remove the shard mapping definition represented by the Shard Mapping
        ID. This method is exposed through the XML-RPC framework and creates a
        job and enqueues it in the executor.

        :param shard_mapping_id: The shard mapping ID of the shard mapping
                                definition that needs to be removed.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        procedures = _events.trigger(
            REMOVE_SHARD_MAPPING_DEFN, self.get_lockable_objects(), shard_mapping_id
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #45
0
    def execute(self, type_name, group_id, synchronous=True):
        """Define a shard mapping.

        :param type_name: The type of sharding scheme - RANGE, HASH, LIST etc
        :param group_id: Every shard mapping is associated with a global group
                         that stores the global updates and the schema changes
                         for this shard mapping and dissipates these to the
                         shards.
        """
        procedures = _events.trigger(
            DEFINE_SHARD_MAPPING, self.get_lockable_objects(),
            type_name, group_id
        )
        return self.wait_for_procedures(procedures, synchronous)
def _do_block_write_master(group_id, master_uuid, update_only=False):
    """Block and disable write access to the current master.

    Note that connections are not killed and blocking the master
    may take some time.
    """
    master = _server.MySQLServer.fetch(_uuid.UUID(master_uuid))
    assert(master.status == _server.MySQLServer.PRIMARY)
    master.mode = _server.MySQLServer.READ_ONLY
    master.status = _server.MySQLServer.SECONDARY

    if not update_only:
        master.connect()
        _utils.set_read_only(master, True)

    # Temporarily unset the master in this group.
    group = _server.Group.fetch(group_id)
    _set_group_master_replication(group, None)

    # At the end, we notify that a server was demoted.
    _events.trigger("SERVER_DEMOTED", set([group_id]),
        group_id, str(master.uuid)
    )
Example #47
0
    def execute(self, table_name, synchronous=True):
        """Given the table name prune the tables according to the defined
        sharding specification for the table. The command prunes all the
        tables that are part of this shard. There might be multiple tables that
        are part of the same shard, these tables will be related together by
        the same sharding key.

        :param table_name: The table that needs to be sharded.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        procedures = _events.trigger(
            PRUNE_SHARD_TABLES, self.get_lockable_objects(), table_name
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #48
0
    def execute(self, server_id, reporter="unknown", error="unknown",
                update_only=False, synchronous=True):
        """Report a server issue.

        :param server_id: Servers's UUID or HOST:PORT.
        :param reporter: Who has reported the issue, usually an IP address or a
                         host name.
        :param error: Error that has been reported.
        :param update_only: Only update the state store and skip provisioning.
        """
        procedures = _events.trigger(
            REPORT_FAILURE, self.get_lockable_objects(), server_id, reporter,
            error, update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #49
0
    def execute(self, event, locks, *args, **kwargs):
        """Trigger the execution of an event.

        :param event: Event's identification.
        :type event: String
        :param args: Event's non-keyworded arguments.
        :param kwargs: Event's keyworded arguments.
        :return: List of the procedures' uuids that were created.
        """
        lockable_objects = set()
        for lock in locks.split(","):
            lockable_objects.add(lock.strip())
        return [ str(proc.uuid) \
                 for proc in _events.trigger(event, lockable_objects,
                                             *args, **kwargs)
               ]
Example #50
0
    def execute(self, table_name, synchronous=True):
        """Given the table name prune the tables according to the defined
        sharding specification for the table. The command prunes all the
        tables that are part of this shard. There might be multiple tables that
        are part of the same shard, these tables will be related together by
        the same sharding key.

        :param table_name: The table that needs to be sharded.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        prune_limit = _services_utils.read_config_value(
            self.config, 'sharding', 'prune_limit')
        procedures = _events.trigger(PRUNE_SHARD_TABLES,
                                     self.get_lockable_objects(), table_name,
                                     prune_limit)
        return self.wait_for_procedures(procedures, synchronous)
Example #51
0
    def execute(self,
                server_id,
                reporter="unknown",
                error="unknown",
                update_only=False,
                synchronous=True):
        """Report a server issue.

        :param server_id: Servers's UUID or HOST:PORT.
        :param reporter: Who has reported the issue, usually an IP address or a
                         host name.
        :param error: Error that has been reported.
        :param update_only: Only update the state store and skip provisioning.
        """
        procedures = _events.trigger(REPORT_ERROR, self.get_lockable_objects(),
                                     server_id, reporter, error, update_only)
        return self.wait_for_procedures(procedures, synchronous)
Example #52
0
    def execute(self, shard_id, group_id, update_only=False,
                synchronous=True):
        """Move the shard represented by the shard_id to the destination group.

        :param shard_id: The ID of the shard that needs to be moved.
        :param group_id: The ID of the group to which the shard needs to
                         be moved.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """

        procedures = _events.trigger(
            CHECK_SHARD_INFORMATION, self.get_lockable_objects(), shard_id,
            group_id, None, "", "MOVE", update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #53
0
    def execute(self, group_id, address, timeout=None, update_only=False,
                synchronous=True):
        """Add a server into a group.

        :param group_id: Group's id.
        :param address: Server's address.
        :param timeout: Time in seconds after which an error is reported
                        if one cannot access the server.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        procedures = _events.trigger(ADD_SERVER, self.get_lockable_objects(),
            group_id, address, timeout, update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #54
0
    def execute(self, group_id, address, timeout=None, update_only=False,
                synchronous=True):
        """Add a server into a group.

        :param group_id: Group's id.
        :param address: Server's address.
        :param timeout: Time in seconds after which an error is reported
                        if one cannot access the server.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        :return: Tuple with job's uuid and status.
        """
        _LOGGER.debug("executing group add.")
        procedures = _events.trigger(ADD_SERVER, self.get_lockable_objects(),
            group_id, address, timeout, update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Example #55
0
    def execute(self, event, locks=None, args=None, kwargs=None):
        """Trigger the execution of an event.

        :param event: Event's identification.
        :type event: String
        :param args: Event's non-keyworded arguments.
        :param kwargs: Event's keyworded arguments.

        :return: :class:`CommandResult` instance with UUID of the
                 procedures that were triggered.
        """
        # Prepare lockable objects.
        lockable_objects = None
        if locks:
            lockable_objects = set()
            for lock in locks:
                lockable_objects.add(lock.strip())

        # Prepare list arguments.
        param_args = []
        if args is not None:
            param_args = args

        # Prepare key word arguments.
        param_kwargs = {}
        if kwargs is not None:
            param_kwargs = kv_to_dict(kwargs)

        # Define the result set format.
        rset = ResultSet(names=['uuid'], types=[str])

        _LOGGER.debug("Triggering event (%s) with arguments: %s, %s.", event,
                      param_args, param_kwargs)

        # Trigger the event and add the UUID of all procedures queued
        # to the result.
        procedures = _events.trigger(event, lockable_objects, *param_args,
                                     **param_kwargs)
        for procedure in procedures:
            rset.append_row([str(procedure.uuid)])

        return CommandResult(None, results=rset)