196 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
 * MXS-2167: Monitors should be able to use extra_port
 | 
						|
 */
 | 
						|
 | 
						|
#include <maxtest/testconnections.hh>
 | 
						|
#include <iostream>
 | 
						|
 | 
						|
using std::cout;
 | 
						|
using std::endl;
 | 
						|
using std::string;
 | 
						|
 | 
						|
int main(int argc, char** argv)
 | 
						|
{
 | 
						|
    TestConnections test(argc, argv);
 | 
						|
 | 
						|
    // The test requires at least three nodes.
 | 
						|
    auto N = test.repl->N;
 | 
						|
    if (N < 3)
 | 
						|
    {
 | 
						|
        test.expect(false, "Too few nodes, need at least 3.");
 | 
						|
        return test.global_result;
 | 
						|
    }
 | 
						|
 | 
						|
    test.tprintf("Stopping MaxScale");
 | 
						|
    test.maxscales->stop();
 | 
						|
 | 
						|
    // Configure extra-port on servers 1&2.
 | 
						|
    const int N_extra_port = 2;
 | 
						|
    const int extra_port = 33066;
 | 
						|
    const string extra_port_str = std::to_string(extra_port);
 | 
						|
    const string iptables_cmd =
 | 
						|
        "iptables -I INPUT -p tcp --dport " + extra_port_str + " -j ACCEPT;"
 | 
						|
        + "ip6tables -I INPUT -p tcp --dport " + extra_port_str + " -j ACCEPT";
 | 
						|
 | 
						|
    const string iptables_remove_cmd =
 | 
						|
        "iptables -D INPUT -p tcp --dport " + extra_port_str + " -j ACCEPT;"
 | 
						|
        + "ip6tables -D INPUT -p tcp --dport " + extra_port_str + " -j ACCEPT";
 | 
						|
 | 
						|
    const string extra_port_sett = "extra_port=" + extra_port_str;
 | 
						|
 | 
						|
    string user = test.repl->user_name;
 | 
						|
    string pw = test.repl->password;
 | 
						|
 | 
						|
    for (int i = 0; i < N_extra_port; i++)
 | 
						|
    {
 | 
						|
        test.tprintf("Configuring node %i for extra port.", i);
 | 
						|
        // Temporary workaround for firewall issues
 | 
						|
        test.repl->ssh_node_f(i, true, "%s", iptables_cmd.c_str());
 | 
						|
 | 
						|
        test.repl->stash_server_settings(i);
 | 
						|
        test.repl->add_server_setting(i, extra_port_sett.c_str());
 | 
						|
        test.repl->add_server_setting(i, "extra_max_connections=5");
 | 
						|
        test.repl->ssh_node_f(i, true, "systemctl restart mariadb || service mariadb restart");
 | 
						|
 | 
						|
        // Test a direct connection to the server through the extra port, it should work.
 | 
						|
        auto conn = open_conn_db_timeout(extra_port, test.repl->ip(i), "", user, pw, 4, false);
 | 
						|
        int rc = test.try_query(conn, "SELECT 1;");
 | 
						|
        test.expect(rc == 0, "Connection from host machine to node %i through port %i failed.",
 | 
						|
                    i, extra_port);
 | 
						|
        if (rc == 0)
 | 
						|
        {
 | 
						|
            test.tprintf("Extra port working on node %i.", i);
 | 
						|
        }
 | 
						|
        mysql_close(conn);
 | 
						|
    }
 | 
						|
 | 
						|
    if (test.ok())
 | 
						|
    {
 | 
						|
        // Limit the number of connections on servers 1&2. Resets on restart.
 | 
						|
        const int max_conns = 10;   // 10 is minimum allowed by server.
 | 
						|
        const string set_max_conns = "SET GLOBAL max_connections=" + std::to_string(max_conns) + ";";
 | 
						|
        test.repl->connect();
 | 
						|
        for (int i = 0; i < N_extra_port; i++)
 | 
						|
        {
 | 
						|
            test.try_query(test.repl->nodes[i], "%s", set_max_conns.c_str());
 | 
						|
            if (test.ok())
 | 
						|
            {
 | 
						|
                test.tprintf("Max connections limit set on node %i.", i);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        test.repl->disconnect();
 | 
						|
 | 
						|
        if (test.ok())
 | 
						|
        {
 | 
						|
            // Then, open connections until the limit is met. Should open a total of 20.
 | 
						|
            // It seems this setting is not entirely accurate as sometimes one can open a few more.
 | 
						|
            const int max_conns_limit = max_conns + 5;
 | 
						|
            std::vector<MYSQL*> connections;
 | 
						|
            for (int i = 0; i < N_extra_port; i++)
 | 
						|
            {
 | 
						|
                test.tprintf("Opening connections on node %i until maximum reached.", i);
 | 
						|
                int normal_port = test.repl->port[i];
 | 
						|
                auto host = test.repl->ip(i);
 | 
						|
 | 
						|
                int conn_count = 0;
 | 
						|
                while (conn_count < max_conns_limit)
 | 
						|
                {
 | 
						|
                    auto conn = open_conn_db_timeout(normal_port, host, "", user, pw, 4, false);
 | 
						|
                    if (conn && execute_query_silent(conn, "SELECT 1") == 0)
 | 
						|
                    {
 | 
						|
                        connections.push_back(conn);
 | 
						|
                        conn_count++;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                bool conns_ok = conn_count >= max_conns && conn_count <= max_conns_limit;
 | 
						|
                if (conns_ok)
 | 
						|
                {
 | 
						|
                    test.tprintf("Opened %i connections to node %i.", conn_count, i);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    test.expect(false, "Opened %i connections to node %i when %i--%i expected.",
 | 
						|
                                conn_count, i, max_conns, max_conns_limit);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (test.ok())
 | 
						|
            {
 | 
						|
                // Finally, start MaxScale. The monitor should use extra port to connect to nodes 0&1,
 | 
						|
                // and normal port to connect to 2&3. All servers should be running.
 | 
						|
                cout << "Starting MaxScale" << endl;
 | 
						|
                test.maxscales->start();
 | 
						|
                sleep(3);   // Give maxscale some time to start properly.
 | 
						|
                test.maxscales->wait_for_monitor(2);
 | 
						|
                for (int i = 0; i < N; i++)
 | 
						|
                {
 | 
						|
                    string server_name = "server" + std::to_string(i + 1);
 | 
						|
                    auto srv_namez = server_name.c_str();
 | 
						|
                    auto status = test.maxscales->get_server_status(srv_namez);
 | 
						|
                    bool status_ok = status.count("Running") == 1;
 | 
						|
                    if (status_ok)
 | 
						|
                    {
 | 
						|
                        string status_str;
 | 
						|
                        for (auto s : status)
 | 
						|
                        {
 | 
						|
                            status_str += s + ",";
 | 
						|
                        }
 | 
						|
                        test.tprintf("%s status is: %s", srv_namez, status_str.c_str());
 | 
						|
                    }
 | 
						|
                    test.expect(status.count("Running") == 1, "Server '%s' is not running or monitor could "
 | 
						|
                                                              "not connect to it.", srv_namez);
 | 
						|
                    // Also, MaxScale should have used the extra port to connect to nodes 0 & 1.
 | 
						|
                    if (i < N_extra_port)
 | 
						|
                    {
 | 
						|
                        string pat = "Could not connect with normal port to server '" + server_name
 | 
						|
                            + "', using extra_port";
 | 
						|
                        test.log_includes(0, pat.c_str());
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if (test.ok())
 | 
						|
                {
 | 
						|
                    // Creating sessions should not work since normal connections cannot be created to
 | 
						|
                    // the master node.
 | 
						|
                    auto conn = test.maxscales->open_rwsplit_connection();
 | 
						|
                    if (!conn)
 | 
						|
                    {
 | 
						|
                        test.tprintf("Session creation failed, as expected.");
 | 
						|
                    }
 | 
						|
                    else if (execute_query_silent(conn, "SELECT 1;") == 1)
 | 
						|
                    {
 | 
						|
                        test.tprintf("Query failed, as expected.");
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        test.expect(false, "Routing sessions should not work.");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Make sure the old connections still work and close them.
 | 
						|
            for (auto conn : connections)
 | 
						|
            {
 | 
						|
                test.try_query(conn, "SELECT 2");
 | 
						|
                mysql_close(conn);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Remove extra_port
 | 
						|
    for (int i = 0; i < N_extra_port; i++)
 | 
						|
    {
 | 
						|
        test.tprintf("Removing extra port from node %i.", i);
 | 
						|
        test.repl->ssh_node_f(i, true, "%s", iptables_remove_cmd.c_str());
 | 
						|
 | 
						|
        test.repl->restore_server_settings(i);
 | 
						|
        test.repl->ssh_node_f(i, true, "systemctl restart mariadb || service mariadb restart");
 | 
						|
    }
 | 
						|
    return test.global_result;
 | 
						|
}
 |