Esempio n. 1
0
def _add_server(group_id, address, timeout, update_only):
    """Only add a server with a configuring status into a group.
    The next step is responsible for setting up the server though.
    For example, replication will be configured in the next step.
    """
    group = _retrieve_group(group_id)
    uuid = _lookup_uuid(address, timeout)
    _check_server_exists(uuid)
    server = _server.MySQLServer(uuid=_uuid.UUID(uuid), address=address)

    # Add server to the state store.
    _server.MySQLServer.add(server)

    # Add server as a member in the group.
    server.group_id = group_id

    _events.trigger_within_procedure(CONFIGURE_NEW_SERVER, group_id,
                                     str(server.uuid), update_only)
Esempio n. 2
0
    def configure_instances(self, topology, user, passwd):
        """Configure a replication topology using the MySQL Instances
        previously registerd.

        :param topology: Topology to be configured.
        :param user: MySQL Instances' user.
        :param passwd: MySQL Instances' password.

        This method can be used as follows::

          import tests.utils as _test_utils

          topology = {1 : [{2 : []}, {3 : []}]}
          instances = _test_utils.MySQLInstances()
          user = instances.user
          passwd = instances.passwd
          instances.configure_instances(topology, user, passwd)

        Each instance in the topology is represented as a dictionary whose
        keys are references to addresses that will be retrieved through
        the :meth:`get_address` method and values are a list of slaves.

        So after calling :meth:`configure_instances` method, one can get a
        reference to an object, MySQLServer, through the :meth:`get_instance`
        method.
        """
        for number in topology.keys():
            master_address = self.get_address(number)

            master_uuid = _server.MySQLServer.discover_uuid(
                address=master_address)
            master = _server.MySQLServer(uuid.UUID(master_uuid),
                                         master_address, user, passwd)
            master.connect()
            master.read_only = False
            self.__instances[number] = master
            for slave_topology in topology[number]:
                slave = self.configure_instances(slave_topology, user, passwd)
                slave.read_only = True
                _replication.switch_master(slave, master, user, passwd)
                _replication.start_slave(slave, wait=True)
            return master
Esempio n. 3
0
def _add_server(group_id, address, timeout, update_only):
    """Add a server into a group.
    """
    group = _retrieve_group(group_id)
    uuid = _lookup_uuid(address, timeout)
    _check_server_exists(uuid)
    server = _server.MySQLServer(uuid=_uuid.UUID(uuid), address=address)

    # Check if the server fulfils the necessary requirements to become
    # a member.
    _check_requirements(server)

    # Add server to the state store.
    _server.MySQLServer.add(server)

    # Add server as a member in the group.
    server.group_id = group_id

    if not update_only:
        # Configure the server as a slave if there is a master.
        _configure_as_slave(group, server)

    _LOGGER.debug("Added server (%s) to group (%s).", server, group)
Esempio n. 4
0
    def execute(self, group_id, destn_address, source_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)

        # Fetch config information

        backup_user = _services_utils.read_config_value(
                                self.config,
                                'servers',
                                'backup_user'
                            )
        backup_passwd = _services_utils.read_config_value(
                                self.config,
                                'servers',
                                'backup_password'
                            )
        restore_user = _services_utils.read_config_value(
                                self.config,
                                'servers',
                                'restore_user'
                            )
        restore_passwd = _services_utils.read_config_value(
                                self.config,
                                'servers',
                                'restore_password'
                            )

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

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

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

        # Check if the destination server has restore privileges.
        server = _server.MySQLServer(_uuid.UUID(destn_server_uuid), destn_address,
                                     restore_user, restore_passwd)
        _backup.MySQLDump.check_restore_privileges(server)

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

        # Check if the source server has backup privileges.
        server.user = backup_user
        server.passwd = backup_passwd
        _backup.MySQLDump.check_backup_privileges(server)

        # Schedule the clone operation through the executor.
        procedures = _events.trigger(
            BACKUP_SERVER,
            self.get_lockable_objects(),
            str(server.uuid),
            host,
            port
        )
        return self.wait_for_procedures(procedures, synchronous)
Esempio n. 5
0
    def test_promote(self):
        # Create topology: M1 ---> S2, M1 ---> S3, M1 ---> S4
        instances = tests.utils.MySQLInstances()
        user = instances.user
        passwd = instances.passwd
        instances.configure_instances({0: [{
            1: []
        }, {
            2: []
        }, {
            3: []
        }]}, user, passwd)
        master = instances.get_instance(0)
        slave_1 = instances.get_instance(1)
        slave_2 = instances.get_instance(2)
        slave_3 = instances.get_instance(3)

        # Try to use a group that does not exist.
        status = self.proxy.group.promote("group_id")
        self.check_xmlrpc_command_result(status, has_error=True)

        # Try to use a group without candidates.
        self.proxy.group.create("group_id", "")
        status = self.proxy.group.promote("group_id")
        self.check_xmlrpc_command_result(status, has_error=True)

        # Try to use a group with an invalid candidate (simulating that a
        # server went down).
        invalid_server = _server.MySQLServer(
            _uuid.UUID("FD0AC9BB-1431-11E2-8137-11DEF124DCC5"),
            "unknown_host:32274", user, passwd)
        _server.MySQLServer.add(invalid_server)
        group = _server.Group.fetch("group_id")
        group.add_server(invalid_server)
        status = self.proxy.group.promote("group_id")
        self.check_xmlrpc_command_result(status, has_error=True)
        group.remove_server(invalid_server)
        _server.MySQLServer.remove(invalid_server)

        # Configure master, an invalid candidate and make a slave point to
        # a different master.
        self.proxy.group.add("group_id", master.address)
        self.proxy.group.add("group_id", slave_1.address)
        self.proxy.group.add("group_id", slave_2.address)
        self.proxy.group.add("group_id", slave_3.address)
        tests.utils.configure_decoupled_master(group, master)
        invalid_server = _server.MySQLServer(
            _uuid.UUID("FD0AC9BB-1431-11E2-8137-11DEF124DCC5"),
            "unknown_host:32274", user, passwd)
        _server.MySQLServer.add(invalid_server)
        group = _server.Group.fetch("group_id")
        group.add_server(invalid_server)
        _repl.stop_slave(slave_3, wait=True)
        _repl.switch_master(slave_3, slave_2, user, passwd)

        # Look up servers.
        expected = [
            [
                str(master.uuid), master.address, _server.MySQLServer.PRIMARY,
                _server.MySQLServer.READ_WRITE,
                _server.MySQLServer.DEFAULT_WEIGHT
            ],
            [
                str(slave_1.uuid), slave_1.address,
                _server.MySQLServer.SECONDARY, _server.MySQLServer.READ_ONLY,
                _server.MySQLServer.DEFAULT_WEIGHT
            ],
            [
                str(slave_2.uuid), slave_2.address,
                _server.MySQLServer.SECONDARY, _server.MySQLServer.READ_ONLY,
                _server.MySQLServer.DEFAULT_WEIGHT
            ],
            [
                str(slave_3.uuid), slave_3.address,
                _server.MySQLServer.SECONDARY, _server.MySQLServer.READ_ONLY,
                _server.MySQLServer.DEFAULT_WEIGHT
            ],
            [
                str(invalid_server.uuid), invalid_server.address,
                _server.MySQLServer.SECONDARY, _server.MySQLServer.READ_ONLY,
                _server.MySQLServer.DEFAULT_WEIGHT
            ],
        ]
        expected.sort()
        expected = tests.utils.make_servers_lookup_result(expected)
        servers = self.proxy.group.lookup_servers("group_id")
        self.check_xmlrpc_result(servers, expected)

        # Do the promote.
        status = self.proxy.group.promote("group_id")
        self.check_xmlrpc_command_result(status)

        # Look up servers.
        # servers = self.proxy.group.lookup_servers("group_id")
        # self.check_xmlrpc_result(servers, expected)

        # Do the promote without a current master.
        tests.utils.configure_decoupled_master(group, None)
        status = self.proxy.group.promote("group_id")
        self.check_xmlrpc_command_result(status)
Esempio n. 6
0
def cleanup_environment():
    """Clean up the existing environment
    """
    #Clean up information on instances.
    MySQLInstances().__instances = {}

    #Clean up information in the state store.
    uuid_server = _server.MySQLServer.discover_uuid(
        MySQLInstances().state_store_address,
        MySQLInstances().user,
        MySQLInstances().passwd)
    server = _server.MySQLServer(uuid.UUID(uuid_server),
                                 MySQLInstances().state_store_address,
                                 MySQLInstances().user,
                                 MySQLInstances().passwd)
    server.connect()

    server.set_foreign_key_checks(False)
    tables = server.exec_stmt(
        "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE "
        "TABLE_SCHEMA = '%s' and TABLE_TYPE = 'BASE TABLE'" %
        (MySQLInstances().store_db, ))
    for table in tables:
        server.exec_stmt("TRUNCATE %s.%s" % (
            MySQLInstances().store_db,
            table[0],
        ))
    server.set_foreign_key_checks(True)

    #Remove all the databases from the running MySQL instances
    #other than the standard ones
    server_count = MySQLInstances().get_number_addresses()

    for i in range(0, server_count):
        uuid_server = _server.MySQLServer.discover_uuid(
            MySQLInstances().get_address(i),
            MySQLInstances().user,
            MySQLInstances().passwd)
        server = _server.MySQLServer(uuid.UUID(uuid_server),
                                     MySQLInstances().get_address(i),
                                     MySQLInstances().user,
                                     MySQLInstances().passwd)
        server.connect()
        server.read_only = False
        _replication.stop_slave(server, wait=True)

        server.set_foreign_key_checks(False)
        databases = server.exec_stmt("SHOW DATABASES")
        for database in databases:
            if database[0] not in _server.MySQLServer.NO_USER_DATABASES:
                server.exec_stmt("DROP DATABASE IF EXISTS %s" %
                                 (database[0], ))
        server.set_foreign_key_checks(True)

        _replication.reset_master(server)
        _replication.reset_slave(server, clean=True)

        server.disconnect()

    for __file in glob.glob(os.path.join(os.getcwd(), "*.sql")):
        os.remove(__file)
Esempio n. 7
0
    def test_update_only(self):
        """Test the update_only parameter while adding a slave.
        """
        # Prepare group and servers
        self.proxy.group.create("group", "Testing group...")
        address_1 = tests.utils.MySQLInstances().get_address(0)
        address_2 = tests.utils.MySQLInstances().get_address(1)
        address_3 = tests.utils.MySQLInstances().get_address(2)
        user = tests.utils.MySQLInstances().user
        passwd = tests.utils.MySQLInstances().passwd

        status = self.proxy.server.lookup_uuid(address_1)
        uuid_1 = self.check_xmlrpc_get_uuid(status, False)
        server_1 = _server.MySQLServer(_uuid.UUID(uuid_1), address_1, user,
                                       passwd)
        server_1.connect()

        status = self.proxy.server.lookup_uuid(address_2)
        uuid_2 = self.check_xmlrpc_get_uuid(status, False)
        server_2 = _server.MySQLServer(_uuid.UUID(uuid_2), address_2, user,
                                       passwd)
        server_2.connect()

        status = self.proxy.server.lookup_uuid(address_3)
        uuid_3 = self.check_xmlrpc_get_uuid(status, False)
        server_3 = _server.MySQLServer(_uuid.UUID(uuid_3), address_3, user,
                                       passwd)
        server_3.connect()

        # Add a server and check that replication is not configured. Since
        # there is no master configured, it does not matter whether the
        # update_only parameter is set or not.
        self.proxy.group.add("group", address_1, 5, True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            'status': _server.MySQLServer.SECONDARY,
            'is_not_configured': True,
        })

        self.proxy.group.remove("group", uuid_1)
        self.proxy.group.add("group", address_1, 5, False)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SECONDARY,
            "is_not_configured": True,
        })

        # Try to make the previous server a master, i.e. --update-only = False.
        status = self.proxy.server.set_status(uuid_1,
                                              _server.MySQLServer.PRIMARY)
        self.check_xmlrpc_command_result(status, True)

        # Try to make the previous server a master, i.e. --update-only = True.
        status = self.proxy.server.set_status(uuid_1,
                                              _server.MySQLServer.PRIMARY,
                                              True)
        self.check_xmlrpc_command_result(status, True)
        self.proxy.group.promote("group", uuid_1)

        # Add a slave but notice that it is not properly configured, i.e.
        # --update-only = True.
        self.proxy.group.add("group", address_2, 5, True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SECONDARY,
            "is_not_configured": True,
        },
                                 rowcount=2,
                                 index=1)

        # Properly configure the previous slave.
        _replication.switch_master(slave=server_2,
                                   master=server_1,
                                   master_user=server_1.user,
                                   master_passwd=server_1.passwd)
        _replication.start_slave(server_2, wait=True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SECONDARY,
        },
                                 rowcount=2,
                                 index=1)

        # Add a slave but notice that it is properly configured, i.e.
        # --update-only = False.
        self.proxy.group.add("group", address_3)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SECONDARY,
        },
                                 index=1)

        # Stop replication, set slave's status to faulty and add it
        # back as a spare, --update-only = False. Note that it is
        # properly configured.
        _replication.stop_slave(server_3, wait=True)
        server_3.status = _server.MySQLServer.FAULTY
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            'status': _server.MySQLServer.FAULTY,
            "io_not_running": True,
            "sql_not_running": True,
        },
                                 rowcount=3,
                                 index=2)
        status = self.proxy.server.set_status(uuid_3,
                                              _server.MySQLServer.SPARE)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SPARE,
        },
                                 rowcount=3,
                                 index=2)

        # Stop replication, set slave's status to faulty and add it
        # back as a spare, --update-only = True. Note that it is not
        # properly configured.
        _replication.stop_slave(server_3, wait=True)
        server_3.status = _server.MySQLServer.FAULTY
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.FAULTY,
            "io_not_running": True,
            "sql_not_running": True,
        },
                                 rowcount=3,
                                 index=2)
        status = self.proxy.server.set_status(uuid_3,
                                              _server.MySQLServer.SPARE, True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SPARE,
            "io_not_running": True,
            "sql_not_running": True,
        },
                                 rowcount=3,
                                 index=2)

        # Try to set slave's status to faulty, i.e. --update-only = False.
        status = self.proxy.server.set_status(uuid_3,
                                              _server.MySQLServer.FAULTY)
        self.check_xmlrpc_command_result(status, True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SPARE,
            "io_not_running": True,
            "sql_not_running": True,
        },
                                 rowcount=3,
                                 index=2)

        # Try to set slave's status to faulty, i.e. --update-only = True.
        status = self.proxy.server.set_status(uuid_3,
                                              _server.MySQLServer.FAULTY, True)
        self.check_xmlrpc_command_result(status, has_error=True)
        status = self.proxy.group.health("group")
        self.check_xmlrpc_simple(status, {
            "status": _server.MySQLServer.SPARE,
            "io_not_running": True,
            "sql_not_running": True,
        },
                                 rowcount=3,
                                 index=2)