예제 #1
0
def singlewriter(galera_cluster,
                 proxysql,
                 writer_hostgroup_id,
                 reader_hostgroup_id,
                 ignore_writer=None):
    """
    Implements singlewriter balancing mode.

    :param galera_cluster: GaleraCluster instance.
    :type galera_cluster: GaleraCluster
    :param proxysql: ProxySQL instance
    :type proxysql: ProxySQL
    :param writer_hostgroup_id: Writer hostgroup_id
    :type writer_hostgroup_id: int
    :param reader_hostgroup_id: Reader hostgroup_id
    :type reader_hostgroup_id: int
    :param ignore_writer: Do not make this backend writer
    :type ignore_writer: ProxySQLMySQLBackend
    """
    register_writer(galera_cluster,
                    proxysql,
                    writer_hostgroup_id,
                    reader_hostgroup_id,
                    ignore_writer=ignore_writer)
    register_readers(galera_cluster, proxysql, writer_hostgroup_id,
                     reader_hostgroup_id)

    LOG.debug('Register all missing backends')
    for galera_node in galera_cluster.find_synced_nodes():
        reader = ProxySQLMySQLBackend(galera_node.host,
                                      hostgroup_id=reader_hostgroup_id,
                                      port=galera_node.port,
                                      comment='Reader')
        writer = ProxySQLMySQLBackend(galera_node.host,
                                      hostgroup_id=writer_hostgroup_id,
                                      port=galera_node.port)
        if not (proxysql.backend_registered(reader)
                or proxysql.backend_registered(writer)):
            proxysql.register_backend(reader)
            LOG.info('Added backend %s to hostgroup %d', reader,
                     reader_hostgroup_id)

    LOG.debug('Make sure writer is not reader')
    writer = proxysql.find_backends(writer_hostgroup_id)[0]
    readers = proxysql.find_backends(reader_hostgroup_id)
    writer_as_reader = writer
    writer_as_reader.hostgroup_id = reader_hostgroup_id

    is_readers_offline = False
    if writer_as_reader in readers:
        readers_without_writer = readers[:]
        readers_without_writer.remove(writer_as_reader)

        is_readers_offline = all(x.status == BackendStatus.offline_soft
                                 for x in readers_without_writer)

    if len(readers) > 2 and proxysql.backend_registered(writer_as_reader) \
        and not is_readers_offline:
        proxysql.deregister_backend(writer_as_reader)
예제 #2
0
def test__galera_server_status(percona_xtradb_cluster_three_node,
                               proxysql_instance, tmpdir):
    wait_for_cluster_nodes_to_become_healthy(percona_xtradb_cluster_three_node)
    hostgroup_writer = 10
    hostgroup_reader = 11

    rw_map = {0: hostgroup_writer, 1: hostgroup_reader, 2: hostgroup_reader}
    for i in xrange(3):
        backend = ProxySQLMySQLBackend(
            hostname=percona_xtradb_cluster_three_node[i]['ip'],
            port=percona_xtradb_cluster_three_node[0]['mysql_port'],
            hostgroup_id=rw_map[i])
        proxysql_instance.register_backend(backend)

    blacklist = '{}:3306'.format(percona_xtradb_cluster_three_node[2]['ip'])
    nodes = [
        percona_xtradb_cluster_three_node[0]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[1]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[2]['ip'] + ':3306'
    ]
    config = proxysql_tools_config_2(proxysql_instance, nodes, 'root', 'r00t',
                                     hostgroup_writer, hostgroup_reader,
                                     blacklist, 'monitor', 'monitor')
    config_file = str(tmpdir.join('proxysql-tool.cfg'))
    with open(config_file, 'w') as fh:
        config.write(fh)
        proxysql_tools.LOG.debug('proxysql-tools config: \n%s', config)
    runner = CliRunner()
    result = runner.invoke(main,
                           ['--config', config_file, 'galera', 'register'])
    assert result.exit_code == 0

    result = runner.invoke(
        main, ['--config', config_file, 'galera', 'server', 'status'])
    assert result.exit_code == 0
예제 #3
0
def register_synced_backends(
        galera_cluster,
        proxysql,  # pylint: disable=too-many-arguments
        hostgroup_id,
        comment=None,
        limit=None,
        ignore_backend=None):
    """
    Find SYNCED node and register it as a backend.

    :param galera_cluster: GaleraCluster instance.
    :type galera_cluster: GaleraCluster
    :param proxysql: ProxySQL instance
    :type proxysql: ProxySQL
    :param hostgroup_id: hostgroup_id
    :type hostgroup_id: int
    :param comment: Optional comment to add to mysql_server
    :type comment: str
    :param limit: Register not more than limit number of backends
    :type limit: int
    :param ignore_backend: Do not register this backend
    :type ignore_backend: ProxySQLMySQLBackend
    """
    try:
        galera_nodes = galera_cluster.find_synced_nodes()

        if ignore_backend:
            node = GaleraNode(ignore_backend.hostname,
                              port=ignore_backend.port)
            LOG.debug('Ignoring backend %s', ignore_backend)
            if node in galera_nodes:
                LOG.debug('Remove %s from candidates', ignore_backend)
                galera_nodes.remove(node)

        if limit:
            candidate_nodes = galera_nodes[:limit]
        else:
            candidate_nodes = galera_nodes

        for galera_node in candidate_nodes:
            backend = ProxySQLMySQLBackend(galera_node.host,
                                           hostgroup_id=hostgroup_id,
                                           port=galera_node.port,
                                           comment=comment)
            proxysql.register_backend(backend)
            LOG.info('Added backend %s to hostgroup %d', backend, hostgroup_id)

    except GaleraClusterSyncedNodeNotFound as err:
        LOG.error(err)
def test_deregister_backend(mock_execute, mock_runtime, proxysql):
    """

    :param mock_execute:
    :param mock_runtime:
    :param comment:
    :param query:
    :param proxysql:
    :type proxysql: ProxySQL
    """
    backend = ProxySQLMySQLBackend('foo', hostgroup_id=10, port=3307)
    proxysql.deregister_backend(backend)
    query = "DELETE FROM mysql_servers WHERE hostgroup_id=10 AND hostname='foo' AND port=3307"
    mock_execute.assert_called_once_with(query)
    mock_runtime.assert_called_once_with()
def test_register_backend(mock_execute, mock_runtime, comment, query,
                          proxysql):
    """

    :param mock_execute:
    :param mock_runtime:
    :param comment:
    :param query:
    :param proxysql:
    :type proxysql: ProxySQL
    """
    backend = ProxySQLMySQLBackend('foo', comment=comment)
    proxysql.register_backend(backend)
    mock_execute.assert_called_once_with(query)
    mock_runtime.assert_called_once_with()
예제 #6
0
def galera_register(cfg):
    """Registers Galera cluster nodes with ProxySQL."""

    kwargs = {}
    try:
        kwargs['user'] = cfg.get('galera', 'cluster_username')
    except NoOptionError:
        pass
    try:
        kwargs['password'] = cfg.get('galera', 'cluster_password')
    except NoOptionError:
        pass

    LOG.debug('Galera config %r', kwargs)
    galera_cluster = GaleraCluster(cfg.get('galera', 'cluster_host'), **kwargs)

    kwargs = get_proxysql_options(cfg)
    LOG.debug('ProxySQL config %r', kwargs)
    proxysql = ProxySQL(**kwargs)

    load_balancing_mode = cfg.get('galera', 'load_balancing_mode')
    writer_hostgroup_id = int(cfg.get('galera', 'writer_hostgroup_id'))
    reader_hostgroup_id = int(cfg.get('galera', 'reader_hostgroup_id'))

    if load_balancing_mode == 'singlewriter':
        kwargs = {}
        try:
            host, port = cfg.get('galera', 'writer_blacklist').split(':')
            bcknd = ProxySQLMySQLBackend(host,
                                         hostgroup_id=writer_hostgroup_id,
                                         port=port)
            kwargs['ignore_writer'] = bcknd
        except NoOptionError:
            pass
        singlewriter(galera_cluster, proxysql, writer_hostgroup_id,
                     reader_hostgroup_id, **kwargs)
    else:
        raise NotImplementedError('Balancing mode %s not implemented yet.' %
                                  load_balancing_mode)
def test_proxysql_mysql_backend():
    be = ProxySQLMySQLBackend('foo',
                              hostgroup_id='0',
                              port='3307',
                              status=BackendStatus.offline_hard,
                              weight='1',
                              compression='1',
                              max_connections='10',
                              max_replication_lag='20',
                              use_ssl=100,
                              max_latency_ms='30',
                              comment='bar')

    assert be.hostgroup_id == 0
    assert be.port == 3307
    assert be.status == 'OFFLINE_HARD'
    assert be.weight == 1
    assert be.compression == 1
    assert be.max_connections == 10
    assert be.max_replication_lag == 20
    assert be.use_ssl is True
    assert be.max_latency_ms == 30
    assert be.comment == 'bar'
        mock_pymysql.connect.assert_called_once_with(**kwargs_out)


@pytest.mark.parametrize('response, backend', [([{
    u'status': 'ONLINE',
    u'comment': '',
    u'compression': '0',
    u'weight': '1',
    u'hostname': '192.168.90.2',
    u'hostgroup_id': '10',
    u'use_ssl': '0',
    u'max_replication_lag': '0',
    u'port': '3306',
    u'max_latency_ms': '0',
    u'max_connections': '10000'
}], ProxySQLMySQLBackend('192.168.90.2', hostgroup_id=10, port=3306))])
@mock.patch.object(ProxySQL, 'execute')
def test_find_backends(mock_execute, proxysql, response, backend):
    mock_execute.return_value = response
    assert proxysql.find_backends(10)[0] == backend


@mock.patch.object(ProxySQL, 'execute')
def test_find_backends_raises(mock_execute, proxysql):
    mock_execute.return_value = ()
    with pytest.raises(ProxySQLBackendNotFound):
        proxysql.find_backends(10)


@pytest.mark.parametrize('response', [([{
    u'username': '******',
예제 #9
0
def proxysql_mysql_backend():
    return ProxySQLMySQLBackend('127.0.0.1')
예제 #10
0
def test_writer(proxysql):
    backend = ProxySQLMySQLBackend('192.168.90.2', hostgroup_id=10)
    proxysql.register_backend(backend)
    assert backend == proxysql.find_backends(10)[0]
예제 #11
0
def test_register_backend(proxysql):
    backend = ProxySQLMySQLBackend('192.168.90.2', hostgroup_id=10)
    proxysql.register_backend(backend)
    proxysql.deregister_backend(backend)
예제 #12
0
def test__galera_user_set_password_if_user_is_exist(
        percona_xtradb_cluster_three_node, proxysql_instance, tmpdir):
    wait_for_cluster_nodes_to_become_healthy(percona_xtradb_cluster_three_node)
    hostgroup_writer = 10
    hostgroup_reader = 11

    rw_map = {0: hostgroup_writer, 1: hostgroup_reader, 2: hostgroup_reader}
    for i in xrange(3):
        backend = ProxySQLMySQLBackend(
            hostname=percona_xtradb_cluster_three_node[i]['ip'],
            port=percona_xtradb_cluster_three_node[0]['mysql_port'],
            hostgroup_id=rw_map[i])
        proxysql_instance.register_backend(backend)

    blacklist = '{}:3306'.format(percona_xtradb_cluster_three_node[2]['ip'])
    nodes = [
        percona_xtradb_cluster_three_node[0]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[1]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[2]['ip'] + ':3306'
    ]
    config = proxysql_tools_config_2(proxysql_instance, nodes, 'root', 'r00t',
                                     hostgroup_writer, hostgroup_reader,
                                     blacklist, 'monitor', 'monitor')
    config_file = str(tmpdir.join('proxysql-tool.cfg'))
    with open(config_file, 'w') as fh:
        config.write(fh)
        proxysql_tools.LOG.debug('proxysql-tools config: \n%s', config)
    runner = CliRunner()
    result = runner.invoke(main,
                           ['--config', config_file, 'galera', 'register'])
    assert result.exit_code == 0

    result = runner.invoke(
        main, ['--config', config_file, 'galera', 'user', 'create', 'foo'])
    assert result.exit_code == 0

    connection = pymysql.connect(host=proxysql_instance.host,
                                 port=proxysql_instance.port,
                                 user=proxysql_instance.user,
                                 passwd=proxysql_instance.password,
                                 connect_timeout=20,
                                 cursorclass=DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT * FROM mysql_users WHERE username = '******'".
                format(username='******'))
            assert cursor.fetchall() != ()

    finally:
        connection.close()

    result = runner.invoke(
        main,
        ['--config', config_file, 'galera', 'user', 'set_password', 'foo'],
        input='test\ntest\n')

    assert result.exit_code == 0

    connection = pymysql.connect(host=proxysql_instance.host,
                                 port=proxysql_instance.port,
                                 user=proxysql_instance.user,
                                 passwd=proxysql_instance.password,
                                 connect_timeout=20,
                                 cursorclass=DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT * FROM mysql_users WHERE username = '******'".
                format(username='******'))

            row = cursor.fetchall()[0]
            user = ProxySQLMySQLUser(
                username=row['username'],
                password=row['password'],
                active=row['active'],
                use_ssl=row['use_ssl'],
                default_hostgroup=row['default_hostgroup'],
                default_schema=row['default_schema'],
                schema_locked=row['schema_locked'],
                transaction_persistent=row['transaction_persistent'],
                fast_forward=row['fast_forward'],
                backend=row['backend'],
                frontend=row['frontend'],
                max_connections=row['max_connections'])
            assert user.password
            assert user.active
            assert not user.use_ssl
            assert user.default_hostgroup == 0
            assert user.default_schema == 'information_schema'
            assert not user.schema_locked
            assert not user.transaction_persistent
            assert not user.fast_forward
            assert user.backend
            assert user.frontend
            assert user.max_connections == 10000
    finally:
        connection.close()
예제 #13
0
def test__galera_server_set_sync(percona_xtradb_cluster_three_node,
                                 proxysql_instance, tmpdir):
    wait_for_cluster_nodes_to_become_healthy(percona_xtradb_cluster_three_node)
    hostgroup_writer = 10
    hostgroup_reader = 11

    rw_map = {0: hostgroup_writer, 1: hostgroup_reader, 2: hostgroup_reader}
    for i in xrange(3):
        backend = ProxySQLMySQLBackend(
            hostname=percona_xtradb_cluster_three_node[i]['ip'],
            port=percona_xtradb_cluster_three_node[0]['mysql_port'],
            hostgroup_id=rw_map[i])
        proxysql_instance.register_backend(backend)

    blacklist = '{}:3306'.format(percona_xtradb_cluster_three_node[2]['ip'])
    nodes = [
        percona_xtradb_cluster_three_node[0]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[1]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[2]['ip'] + ':3306'
    ]
    config = proxysql_tools_config_2(proxysql_instance, nodes, 'root', 'r00t',
                                     hostgroup_writer, hostgroup_reader,
                                     blacklist, 'monitor', 'monitor')
    config_file = str(tmpdir.join('proxysql-tool.cfg'))
    with open(config_file, 'w') as fh:
        config.write(fh)
        proxysql_tools.LOG.debug('proxysql-tools config: \n%s', config)
    runner = CliRunner()
    result = runner.invoke(main,
                           ['--config', config_file, 'galera', 'register'])
    assert result.exit_code == 0

    result = runner.invoke(main, [
        '--config', config_file, 'galera', 'server', 'set_sync',
        percona_xtradb_cluster_three_node[1]['ip'], '3306'
    ])
    assert result.exit_code == 0

    result = runner.invoke(main,
                           ['--config', config_file, 'galera', 'register'])
    assert result.exit_code == 0

    connection = pymysql.connect(host=proxysql_instance.host,
                                 port=proxysql_instance.port,
                                 user=proxysql_instance.user,
                                 passwd=proxysql_instance.password,
                                 connect_timeout=20,
                                 cursorclass=DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(
                'SELECT `hostgroup_id`, `hostname`, '
                '`port`, `status`, `weight`, `compression`, '
                '`max_connections`, `max_replication_lag`, '
                '`use_ssl`, `max_latency_ms`, `comment`'
                ' FROM `mysql_servers`'
                ' WHERE hostgroup_id = %s'
                ' AND hostname = %s',
                (hostgroup_reader, percona_xtradb_cluster_three_node[1]['ip']))
            row = cursor.fetchall()[0]
            assert row['status'] == BackendStatus.online
    finally:
        connection.close()
예제 #14
0
def test__galera_register_shutdowned_writer_is_deregistered(
        percona_xtradb_cluster_three_node, proxysql_instance, tmpdir):
    wait_for_cluster_nodes_to_become_healthy(percona_xtradb_cluster_three_node)
    hostgroup_writer = 10
    hostgroup_reader = 11

    backend_unreg = ProxySQLMySQLBackend(
        hostname=percona_xtradb_cluster_three_node[0]['ip'],
        port=percona_xtradb_cluster_three_node[0]['mysql_port'],
        hostgroup_id=hostgroup_writer)
    proxysql_instance.register_backend(backend_unreg)

    backend = ProxySQLMySQLBackend(
        hostname=percona_xtradb_cluster_three_node[1]['ip'],
        port=percona_xtradb_cluster_three_node[1]['mysql_port'],
        hostgroup_id=hostgroup_reader)
    proxysql_instance.register_backend(backend)

    backend = ProxySQLMySQLBackend(
        hostname=percona_xtradb_cluster_three_node[2]['ip'],
        port=percona_xtradb_cluster_three_node[2]['mysql_port'],
        hostgroup_id=hostgroup_reader)
    proxysql_instance.register_backend(backend)

    blacklist = '{}:3306'.format(percona_xtradb_cluster_three_node[2]['ip'])
    nodes = [
        percona_xtradb_cluster_three_node[0]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[1]['ip'] + ':3306',
        percona_xtradb_cluster_three_node[2]['ip'] + ':3306'
    ]

    shutdown_container(percona_xtradb_cluster_three_node[0]['id'])
    config = proxysql_tools_config_2(proxysql_instance, nodes, 'root', 'r00t',
                                     hostgroup_writer, hostgroup_reader,
                                     blacklist, 'monitor', 'monitor')
    config_file = str(tmpdir.join('proxysql-tool.cfg'))
    with open(config_file, 'w') as fh:
        config.write(fh)
        proxysql_tools.LOG.debug('proxysql-tools config: \n%s', config)
    runner = CliRunner()
    result = runner.invoke(main,
                           ['--config', config_file, 'galera', 'register'])
    assert result.exit_code == 0

    connection = pymysql.connect(host=proxysql_instance.host,
                                 port=proxysql_instance.port,
                                 user=proxysql_instance.user,
                                 passwd=proxysql_instance.password,
                                 connect_timeout=20,
                                 cursorclass=DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(
                'SELECT `hostgroup_id`, `hostname`, '
                '`port`'
                ' FROM `mysql_servers`'
                ' WHERE hostgroup_id = %s '
                ' AND `hostname` = %s '
                ' AND `port` = %s',
                (backend_unreg.hostgroup_id, backend_unreg.hostname,
                 backend_unreg.port))
            assert cursor.fetchall() == ()

            cursor.execute(
                'SELECT `hostgroup_id`, `hostname`, '
                '`port`'
                ' FROM `mysql_servers`'
                ' WHERE hostgroup_id = %s ', (backend_unreg.hostgroup_id, ))
            assert cursor.fetchall() != ()

    finally:
        connection.close()