2018-03-14 11:27:27 +08:00
|
|
|
/* $%BEGINLICENSE%$
|
|
|
|
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; version 2 of the
|
|
|
|
License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
|
02110-1301 USA
|
|
|
|
|
|
|
|
$%ENDLICENSE%$ */
|
2018-03-21 14:50:34 +08:00
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE
|
2018-03-15 09:49:40 +08:00
|
|
|
#define _GNU_SOURCE
|
2018-03-21 14:50:34 +08:00
|
|
|
#endif
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <malloc.h>
|
2018-05-16 17:30:56 +08:00
|
|
|
#include <sys/stat.h>
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
#include "cetus-users.h"
|
|
|
|
#include "cetus-util.h"
|
|
|
|
#include "cetus-variable.h"
|
|
|
|
#include "character-set.h"
|
|
|
|
#include "chassis-event.h"
|
|
|
|
#include "chassis-options.h"
|
|
|
|
#include "cetus-monitor.h"
|
|
|
|
#include "glib-ext.h"
|
|
|
|
#include "network-mysqld-packet.h"
|
|
|
|
#include "network-mysqld-proto.h"
|
|
|
|
#include "network-mysqld.h"
|
|
|
|
#include "server-session.h"
|
|
|
|
#include "sys-pedantic.h"
|
2018-05-03 16:31:41 +08:00
|
|
|
#include "network-ssl.h"
|
2018-05-02 09:17:08 +08:00
|
|
|
#include "chassis-options-utils.h"
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
#ifndef PLUGIN_VERSION
|
|
|
|
#ifdef CHASSIS_BUILD_TAG
|
|
|
|
#define PLUGIN_VERSION CHASSIS_BUILD_TAG
|
|
|
|
#else
|
|
|
|
#define PLUGIN_VERSION PACKAGE_VERSION
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct chassis_plugin_config {
|
|
|
|
gchar *address; /**< listening address of the admin interface */
|
|
|
|
|
|
|
|
gchar *admin_username; /**< login username */
|
|
|
|
gchar *admin_password; /**< login password */
|
|
|
|
|
|
|
|
gchar *allow_ip; /**< allow ip addr list */
|
|
|
|
GHashTable *allow_ip_table;
|
|
|
|
|
|
|
|
gchar *deny_ip; /**< deny ip addr list */
|
|
|
|
GHashTable *deny_ip_table;
|
|
|
|
|
|
|
|
gboolean has_shard_plugin; /**< another plugin name is shard or proxy, TRUE is shard, FALSE is proxy */
|
|
|
|
|
|
|
|
network_mysqld_con *listen_con;
|
|
|
|
};
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static struct event *g_sampling_timer = NULL;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* tokenize input, alloc and return nth token
|
|
|
|
* n -> [0,..)
|
|
|
|
*/
|
2018-03-20 14:19:44 +08:00
|
|
|
static char *
|
|
|
|
str_nth_token(const char *input, int n)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *t = NULL;
|
|
|
|
char **tokens = g_strsplit(input, " ", -1);
|
|
|
|
if (g_strv_length(tokens) > n) {
|
|
|
|
t = g_strdup(tokens[n]);
|
|
|
|
}
|
|
|
|
g_strfreev(tokens);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get config->has_shard_plugin */
|
2018-03-20 14:19:44 +08:00
|
|
|
static gboolean
|
|
|
|
has_shard_plugin(GPtrArray *modules)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, "shard") == 0) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-05-16 15:42:49 +08:00
|
|
|
/* judge if client_ip is in allowed or denied ip range*/
|
|
|
|
static gboolean
|
|
|
|
ip_range_lookup(GHashTable *ip_table, char *client_ip)
|
|
|
|
{
|
|
|
|
char ip_range[128] = { 0 };
|
|
|
|
char wildcard[128] = { 0 };
|
|
|
|
GList *ip_range_table = g_hash_table_get_keys(ip_table);
|
|
|
|
GList *l;
|
|
|
|
for (l = ip_range_table; l; l = l->next) {
|
|
|
|
sscanf(l->data, "%64[0-9.].%s", ip_range, wildcard);
|
|
|
|
gchar *pos = NULL;
|
|
|
|
if ((pos = strcasestr(client_ip, ip_range))) {
|
|
|
|
if(pos == client_ip) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
NETWORK_MYSQLD_PLUGIN_PROTO(server_con_init)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
network_mysqld_auth_challenge *challenge;
|
|
|
|
GString *packet;
|
|
|
|
|
|
|
|
challenge = network_mysqld_auth_challenge_new();
|
2018-05-25 09:25:15 +08:00
|
|
|
challenge->server_version_str = g_strdup_printf("5.7 admin");
|
|
|
|
challenge->server_version = 50700;
|
|
|
|
challenge->charset = charset_get_number("utf8");
|
2018-05-16 17:11:23 +08:00
|
|
|
challenge->capabilities = CETUS_DEFAULT_FLAGS & (~CLIENT_TRANSACTIONS);
|
2018-05-03 16:31:41 +08:00
|
|
|
#ifdef HAVE_OPENSSL
|
2018-05-11 15:11:38 +08:00
|
|
|
if (chas->ssl) {
|
|
|
|
challenge->capabilities |= CLIENT_SSL;
|
|
|
|
}
|
2018-05-03 16:31:41 +08:00
|
|
|
#endif
|
2018-03-20 14:19:44 +08:00
|
|
|
challenge->server_status = SERVER_STATUS_AUTOCOMMIT;
|
|
|
|
challenge->thread_id = 1;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* generate a random challenge */
|
|
|
|
network_mysqld_auth_challenge_set_challenge(challenge);
|
|
|
|
|
|
|
|
packet = g_string_new(NULL);
|
|
|
|
network_mysqld_proto_append_auth_challenge(packet, challenge);
|
|
|
|
con->client->challenge = challenge;
|
|
|
|
|
|
|
|
network_mysqld_queue_append(con->client, con->client->send_queue, S(packet));
|
|
|
|
|
|
|
|
g_string_free(packet, TRUE);
|
|
|
|
|
|
|
|
con->state = ST_SEND_HANDSHAKE;
|
|
|
|
|
|
|
|
g_assert(con->plugin_con_state == NULL);
|
|
|
|
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
NETWORK_MYSQLD_PLUGIN_PROTO(server_read_auth)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
network_packet packet;
|
|
|
|
network_socket *recv_sock, *send_sock;
|
|
|
|
network_mysqld_auth_response *auth;
|
|
|
|
GString *excepted_response;
|
|
|
|
GString *hashed_pwd;
|
|
|
|
|
|
|
|
recv_sock = con->client;
|
|
|
|
send_sock = con->client;
|
|
|
|
|
|
|
|
packet.data = g_queue_peek_head(recv_sock->recv_queue->chunks);
|
|
|
|
packet.offset = 0;
|
|
|
|
|
|
|
|
/* decode the packet */
|
|
|
|
network_mysqld_proto_skip_network_header(&packet);
|
|
|
|
|
2018-05-16 17:57:23 +08:00
|
|
|
if (con->client->response == NULL) {
|
|
|
|
auth = network_mysqld_auth_response_new(con->client->challenge->capabilities);
|
|
|
|
if (network_mysqld_proto_get_auth_response(&packet, auth)) {
|
|
|
|
network_mysqld_auth_response_free(auth);
|
|
|
|
return NETWORK_SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
if (!(auth->client_capabilities & CLIENT_PROTOCOL_41)) {
|
|
|
|
/* should use packet-id 0 */
|
|
|
|
network_mysqld_queue_append(con->client, con->client->send_queue,
|
|
|
|
C("\xff\xd7\x07" "4.0 protocol is not supported"));
|
|
|
|
network_mysqld_auth_response_free(auth);
|
|
|
|
return NETWORK_SOCKET_ERROR;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-05-03 16:31:41 +08:00
|
|
|
#ifdef HAVE_OPENSSL
|
2018-05-16 17:57:23 +08:00
|
|
|
if (auth->ssl_request) {
|
|
|
|
network_ssl_create_connection(con->client, NETWORK_SSL_SERVER);
|
|
|
|
g_string_free(g_queue_pop_tail(con->client->recv_queue->chunks), TRUE);
|
|
|
|
con->state = ST_FRONT_SSL_HANDSHAKE;
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
2018-05-03 16:31:41 +08:00
|
|
|
#endif
|
2018-05-16 17:57:23 +08:00
|
|
|
con->client->response = auth;
|
|
|
|
|
2018-05-17 14:24:42 +08:00
|
|
|
if ((auth->client_capabilities & CLIENT_PLUGIN_AUTH)
|
|
|
|
&& (g_strcmp0(auth->auth_plugin_name->str, "mysql_native_password") != 0))
|
|
|
|
{
|
2018-05-16 17:57:23 +08:00
|
|
|
GString *packet = g_string_new(0);
|
|
|
|
network_mysqld_proto_append_auth_switch(packet, "mysql_native_password",
|
|
|
|
con->client->challenge->auth_plugin_data);
|
|
|
|
network_mysqld_queue_append(con->client, con->client->send_queue, S(packet));
|
|
|
|
con->state = ST_SEND_AUTH_RESULT;
|
|
|
|
con->auth_result_state = AUTH_SWITCH;
|
|
|
|
g_string_free(packet, TRUE);
|
|
|
|
g_string_free(g_queue_pop_tail(recv_sock->recv_queue->chunks), TRUE);
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* auth switch response */
|
|
|
|
gsize auth_data_len = packet.data->len - 4;
|
|
|
|
GString *auth_data = g_string_sized_new(auth_data_len);
|
|
|
|
network_mysqld_proto_get_gstr_len(&packet, auth_data_len, auth_data);
|
|
|
|
g_string_append_len(con->client->response->auth_plugin_data, S(auth_data));
|
|
|
|
g_string_free(auth_data, TRUE);
|
|
|
|
auth = con->client->response;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
/* Check client addr in admin-allow-ip and admin-deny-ip */
|
|
|
|
gboolean check_ip;
|
|
|
|
char *ip_err_msg = NULL;
|
|
|
|
if (con->config->allow_ip_table || con->config->deny_ip_table) {
|
|
|
|
char *client_addr = con->client->src->name->str;
|
|
|
|
char **client_addr_arr = g_strsplit(client_addr, ":", -1);
|
|
|
|
char *client_ip = client_addr_arr[0];
|
|
|
|
if (g_hash_table_size(con->config->allow_ip_table) != 0 &&
|
2018-05-25 10:47:58 +08:00
|
|
|
(g_hash_table_lookup(con->config->allow_ip_table, "*")
|
|
|
|
|| ip_range_lookup(con->config->allow_ip_table, client_ip)
|
|
|
|
|| g_hash_table_lookup(con->config->allow_ip_table, client_ip))) {
|
2018-03-06 14:00:39 +08:00
|
|
|
check_ip = FALSE;
|
|
|
|
} else if (g_hash_table_size(con->config->deny_ip_table) != 0 &&
|
2018-05-25 10:47:58 +08:00
|
|
|
(g_hash_table_lookup(con->config->deny_ip_table, "*")
|
|
|
|
|| ip_range_lookup(con->config->deny_ip_table, client_ip)
|
|
|
|
|| g_hash_table_lookup(con->config->deny_ip_table, client_ip))) {
|
2018-03-06 14:00:39 +08:00
|
|
|
check_ip = TRUE;
|
2018-03-20 14:19:44 +08:00
|
|
|
ip_err_msg = g_strdup_printf("Access denied for user '%s'@'%s'", con->config->admin_username, client_ip);
|
2018-03-06 14:00:39 +08:00
|
|
|
} else {
|
|
|
|
check_ip = FALSE;
|
|
|
|
}
|
|
|
|
g_strfreev(client_addr_arr);
|
|
|
|
} else {
|
|
|
|
check_ip = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_ip) {
|
|
|
|
network_mysqld_con_send_error_full(send_sock, L(ip_err_msg), 1045, "28000");
|
|
|
|
g_free(ip_err_msg);
|
|
|
|
con->state = ST_SEND_ERROR;
|
|
|
|
} else {
|
|
|
|
/* check if the password matches */
|
|
|
|
excepted_response = g_string_new(NULL);
|
|
|
|
hashed_pwd = g_string_new(NULL);
|
|
|
|
|
|
|
|
if (!strleq(S(con->client->response->username),
|
2018-03-20 14:19:44 +08:00
|
|
|
con->config->admin_username, strlen(con->config->admin_username))) {
|
|
|
|
network_mysqld_con_send_error_full(send_sock, C("unknown user"), 1045, "28000");
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* close the connection after we have sent this packet */
|
|
|
|
con->state = ST_SEND_ERROR;
|
|
|
|
} else if (network_mysqld_proto_password_hash(hashed_pwd,
|
2018-03-20 14:19:44 +08:00
|
|
|
con->config->admin_password,
|
|
|
|
strlen(con->config->admin_password))) {
|
2018-03-06 14:00:39 +08:00
|
|
|
} else if (network_mysqld_proto_password_scramble(excepted_response,
|
2018-03-20 14:19:44 +08:00
|
|
|
S(recv_sock->challenge->auth_plugin_data), S(hashed_pwd))) {
|
|
|
|
network_mysqld_con_send_error_full(send_sock, C("scrambling failed"), 1045, "28000");
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* close the connection after we have sent this packet */
|
|
|
|
con->state = ST_SEND_ERROR;
|
|
|
|
} else if (!g_string_equal(excepted_response, auth->auth_plugin_data)) {
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_error_full(send_sock, C("password doesn't match"), 1045, "28000");
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* close the connection after we have sent this packet */
|
|
|
|
con->state = ST_SEND_ERROR;
|
|
|
|
} else {
|
|
|
|
network_mysqld_con_send_ok(send_sock);
|
|
|
|
|
|
|
|
con->state = ST_SEND_AUTH_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_free(hashed_pwd, TRUE);
|
|
|
|
g_string_free(excepted_response, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_free(g_queue_pop_tail(recv_sock->recv_queue->chunks), TRUE);
|
|
|
|
|
|
|
|
if (recv_sock->recv_queue->chunks->length > 0) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_warning("%s: client-recv-queue-len = %d", G_STRLOC, recv_sock->recv_queue->chunks->length);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static const char *
|
|
|
|
get_conn_xa_state_name(network_mysqld_con_dist_tran_state_t state)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
switch (state) {
|
2018-03-20 14:19:44 +08:00
|
|
|
case NEXT_ST_XA_START:
|
|
|
|
return "XS";
|
|
|
|
case NEXT_ST_XA_QUERY:
|
|
|
|
return "XQ";
|
|
|
|
case NEXT_ST_XA_END:
|
|
|
|
return "XE";
|
|
|
|
case NEXT_ST_XA_PREPARE:
|
|
|
|
return "XP";
|
|
|
|
case NEXT_ST_XA_COMMIT:
|
|
|
|
return "XC";
|
|
|
|
case NEXT_ST_XA_ROLLBACK:
|
|
|
|
return "XR";
|
|
|
|
case NEXT_ST_XA_CANDIDATE_OVER:
|
|
|
|
return "XCO";
|
|
|
|
case NEXT_ST_XA_OVER:
|
|
|
|
return "XO";
|
2018-03-06 14:00:39 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "NX";
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *states[] = {
|
|
|
|
"unknown",
|
|
|
|
"up",
|
|
|
|
"down",
|
|
|
|
"maintaining",
|
|
|
|
"deleted",
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *types[] = {
|
|
|
|
"unknown",
|
|
|
|
"rw",
|
|
|
|
"ro",
|
|
|
|
};
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_backends_info(network_mysqld_con *admin_con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
chassis *chas = admin_con->srv;
|
|
|
|
chassis_private *priv = chas->priv;
|
|
|
|
|
|
|
|
chassis_plugin_config *config = admin_con->config;
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *fields = g_ptr_array_new_with_free_func((GDestroyNotify) network_mysqld_proto_fielddef_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
MYSQL_FIELD *field;
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("backend_ndx");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("address");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("state");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("type");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("slave delay");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("uuid");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("idle_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("used_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("total_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
if (config->has_shard_plugin) {
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("group");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((GDestroyNotify) network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
network_backends_t *bs = priv->backends;
|
|
|
|
int len = bs->backends->len;
|
|
|
|
int i;
|
|
|
|
char buffer[32];
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
network_backend_t *backend = bs->backends->pdata[i];
|
|
|
|
GPtrArray *row = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", i + 1);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
|
|
|
g_ptr_array_add(row, g_strdup(backend->addr->name->str));
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup(states[(int)(backend->state)]));
|
|
|
|
g_ptr_array_add(row, g_strdup(types[(int)(backend->type)]));
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", backend->slave_delay_msec);
|
|
|
|
g_ptr_array_add(row, backend->type == BACKEND_TYPE_RO ? g_strdup(buffer) : NULL);
|
|
|
|
|
|
|
|
g_ptr_array_add(row, backend->uuid->len ? g_strdup(backend->uuid->str) : NULL);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", backend->pool->cur_idle_connections);
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", backend->connected_clients);
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", backend->pool->cur_idle_connections + backend->connected_clients);
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, backend->server_group->len ? g_strdup(backend->server_group->str) : NULL);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(admin_con->client, fields, rows);
|
|
|
|
|
|
|
|
/* Free data */
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_ptr_array_free(fields, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
g_table_free_all(gpointer q)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
GHashTable *table = q;
|
|
|
|
g_hash_table_destroy(table);
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:59:07 +08:00
|
|
|
struct used_conns_t {
|
2018-03-06 14:00:39 +08:00
|
|
|
int num;
|
2018-03-19 15:59:07 +08:00
|
|
|
};
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_backend_detail_info(network_mysqld_con *admin_con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
chassis *chas = admin_con->srv;
|
|
|
|
chassis_private *priv = chas->priv;
|
|
|
|
|
|
|
|
int i, j, len;
|
|
|
|
|
|
|
|
char buffer[32];
|
|
|
|
GPtrArray *fields;
|
|
|
|
GPtrArray *rows;
|
|
|
|
GPtrArray *row;
|
|
|
|
MYSQL_FIELD *field;
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GHashTable *back_user_conn_hash_table = g_hash_table_new_full(g_str_hash,
|
|
|
|
g_str_equal, g_free, g_table_free_all);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
network_backends_t *bs = priv->backends;
|
|
|
|
len = bs->backends->len;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
network_backend_t *backend = bs->backends->pdata[i];
|
|
|
|
GHashTable *table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
g_hash_table_insert(back_user_conn_hash_table, g_strdup(backend->addr->name->str), table);
|
|
|
|
}
|
2018-03-20 14:19:44 +08:00
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
len = priv->cons->len;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
network_mysqld_con *con = priv->cons->pdata[i];
|
|
|
|
|
|
|
|
if (!con->client || !con->client->response) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-12 15:52:54 +08:00
|
|
|
#ifndef SIMPLE_PARSER
|
|
|
|
if (con->servers == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < con->servers->len; j++) {
|
2018-03-22 11:36:38 +08:00
|
|
|
server_session_t *ss = g_ptr_array_index(con->servers, j);
|
2018-03-12 15:52:54 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GHashTable *table = g_hash_table_lookup(back_user_conn_hash_table,
|
2018-03-22 11:36:38 +08:00
|
|
|
ss->backend->addr->name->str);
|
2018-03-12 15:52:54 +08:00
|
|
|
if (table == NULL) {
|
2018-03-22 11:36:38 +08:00
|
|
|
g_warning("%s: table is null for backend:%s", G_STRLOC, ss->backend->addr->name->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:59:07 +08:00
|
|
|
struct used_conns_t *total_used = g_hash_table_lookup(table,
|
2018-03-20 14:19:44 +08:00
|
|
|
con->client->response->username->str);
|
2018-03-12 15:52:54 +08:00
|
|
|
if (total_used == NULL) {
|
2018-03-19 15:59:07 +08:00
|
|
|
total_used = g_new0(struct used_conns_t, 1);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(table, g_strdup(con->client->response->username->str), total_used);
|
2018-03-12 15:52:54 +08:00
|
|
|
}
|
|
|
|
total_used->num++;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-12 15:52:54 +08:00
|
|
|
#else
|
|
|
|
if (con->servers != NULL) {
|
|
|
|
for (j = 0; j < con->servers->len; j++) {
|
|
|
|
network_socket *sock = g_ptr_array_index(con->servers, j);
|
2018-03-20 14:19:44 +08:00
|
|
|
GHashTable *table = g_hash_table_lookup(back_user_conn_hash_table,
|
|
|
|
sock->dst->name->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
if (table == NULL) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_warning("%s: table is null for backend:%s", G_STRLOC, sock->dst->name->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:59:07 +08:00
|
|
|
struct used_conns_t *total_used = g_hash_table_lookup(table,
|
2018-03-20 14:19:44 +08:00
|
|
|
con->client->response->username->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
if (total_used == NULL) {
|
2018-03-19 15:59:07 +08:00
|
|
|
total_used = g_new0(struct used_conns_t, 1);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(table, g_strdup(con->client->response->username->str), total_used);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
total_used->num++;
|
|
|
|
}
|
|
|
|
} else {
|
2018-03-12 15:52:54 +08:00
|
|
|
if (con->server == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GHashTable *table = g_hash_table_lookup(back_user_conn_hash_table,
|
|
|
|
con->server->dst->name->str);
|
2018-03-12 15:52:54 +08:00
|
|
|
if (table == NULL) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_warning("%s: table is null for backend:%s", G_STRLOC, con->server->dst->name->str);
|
2018-03-12 15:52:54 +08:00
|
|
|
continue;
|
|
|
|
}
|
2018-03-19 15:59:07 +08:00
|
|
|
struct used_conns_t *total_used = g_hash_table_lookup(table,
|
2018-03-20 14:19:44 +08:00
|
|
|
con->client->response->username->str);
|
2018-03-12 15:52:54 +08:00
|
|
|
if (total_used == NULL) {
|
2018-03-19 15:59:07 +08:00
|
|
|
total_used = g_new0(struct used_conns_t, 1);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(table, g_strdup(con->client->response->username->str), total_used);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
2018-03-12 15:52:54 +08:00
|
|
|
|
|
|
|
total_used->num++;
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
2018-03-12 15:52:54 +08:00
|
|
|
#endif
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
fields = g_ptr_array_new_with_free_func((void *)network_mysqld_proto_fielddef_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("backend_ndx");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("username");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("idle_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("used_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("total_conns");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
len = bs->backends->len;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
network_backend_t *backend = bs->backends->pdata[i];
|
2018-03-20 14:19:44 +08:00
|
|
|
|
|
|
|
GHashTable *table = g_hash_table_lookup(back_user_conn_hash_table,
|
|
|
|
backend->addr->name->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
if (table == NULL) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_warning("%s: table is null for backend:%s", G_STRLOC, backend->addr->name->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
GHashTable *users = backend->pool->users;
|
|
|
|
if (users != NULL) {
|
|
|
|
GHashTableIter iter;
|
|
|
|
GString *key;
|
|
|
|
GQueue *queue;
|
|
|
|
g_hash_table_iter_init(&iter, users);
|
|
|
|
/* count all users' pooled connections */
|
|
|
|
while (g_hash_table_iter_next(&iter, (void **)&key, (void **)&queue)) {
|
|
|
|
row = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", i + 1);
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
g_ptr_array_add(row, g_strdup(key->str));
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", queue->length);
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
2018-03-19 15:59:07 +08:00
|
|
|
struct used_conns_t *total_used = g_hash_table_lookup(table, key->str);
|
2018-03-06 14:00:39 +08:00
|
|
|
if (total_used) {
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", total_used->num);
|
2018-03-06 14:00:39 +08:00
|
|
|
} else {
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "%d", 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
|
|
|
if (total_used) {
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", queue->length + total_used->num);
|
|
|
|
} else {
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", queue->length);
|
|
|
|
}
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(admin_con->client, fields, rows);
|
|
|
|
|
|
|
|
/* Free data */
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_ptr_array_free(fields, TRUE);
|
|
|
|
|
|
|
|
g_hash_table_destroy(back_user_conn_hash_table);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_show_connectionlist(network_mysqld_con *admin_con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *arg = str_nth_token(sql, 2);
|
|
|
|
int number = 65536;
|
|
|
|
if (arg) {
|
|
|
|
number = atoi(arg);
|
|
|
|
g_free(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
chassis *chas = admin_con->srv;
|
|
|
|
chassis_private *priv = chas->priv;
|
2018-03-20 14:19:44 +08:00
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis_plugin_config *config = admin_con->config;
|
|
|
|
|
|
|
|
int i, len;
|
|
|
|
char buffer[32];
|
|
|
|
GPtrArray *fields;
|
|
|
|
GPtrArray *rows;
|
|
|
|
GPtrArray *row;
|
|
|
|
MYSQL_FIELD *field;
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
fields = g_ptr_array_new_with_free_func((void *)network_mysqld_proto_fielddef_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("User");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Host");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("db");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Command");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Time");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Trans");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("PS");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("State");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
if (config->has_shard_plugin) {
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Xa");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Xid");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
}
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Server");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Info");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
struct timeval now;
|
|
|
|
gettimeofday(&(now), NULL);
|
|
|
|
|
|
|
|
len = priv->cons->len;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
network_mysqld_con *con = priv->cons->pdata[i];
|
|
|
|
|
|
|
|
if (!con->client) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count >= number) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
row = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
if (con->client->response != NULL) {
|
|
|
|
g_ptr_array_add(row, g_strdup(con->client->response->username->str));
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, NULL);
|
|
|
|
}
|
|
|
|
g_ptr_array_add(row, g_strdup(con->client->src->name->str));
|
|
|
|
|
|
|
|
g_ptr_array_add(row, g_strdup(con->client->default_db->str));
|
|
|
|
|
|
|
|
if (con->state <= ST_READ_QUERY) {
|
|
|
|
g_ptr_array_add(row, g_strdup("Sleep"));
|
|
|
|
g_ptr_array_add(row, g_strdup("0"));
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, g_strdup("Query"));
|
2018-03-19 11:08:40 +08:00
|
|
|
int diff = now.tv_sec - con->req_recv_time.tv_sec;
|
|
|
|
if (diff > 7200) {
|
|
|
|
g_critical("%s:too slow connection(%s) processing for con:%p",
|
2018-04-02 16:27:32 +08:00
|
|
|
G_STRLOC, con->client->src->name->str, con);
|
2018-03-19 11:08:40 +08:00
|
|
|
}
|
|
|
|
diff = diff * 1000;
|
2018-03-06 14:00:39 +08:00
|
|
|
diff += (now.tv_usec - con->req_recv_time.tv_usec) / 1000;
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", diff);
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
}
|
|
|
|
g_ptr_array_add(row, g_strdup(con->is_in_transaction ? "Y" : "N"));
|
|
|
|
g_ptr_array_add(row, g_strdup(con->is_prepared ? "Y" : "N"));
|
|
|
|
|
|
|
|
g_ptr_array_add(row, g_strdup(network_mysqld_con_st_name(con->state)));
|
|
|
|
|
|
|
|
if (config->has_shard_plugin) {
|
|
|
|
g_ptr_array_add(row, g_strdup(get_conn_xa_state_name(con->dist_tran_state)));
|
|
|
|
if (con->dist_tran) {
|
|
|
|
snprintf(buffer, sizeof(buffer), "%lld", con->xa_id);
|
|
|
|
g_ptr_array_add(row, g_strdup(buffer));
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (con->servers != NULL) {
|
|
|
|
int j;
|
|
|
|
GString *servers = g_string_new(NULL);
|
|
|
|
for (j = 0; j < con->servers->len; j++) {
|
2018-03-22 11:36:38 +08:00
|
|
|
server_session_t *ss = g_ptr_array_index(con->servers, j);
|
|
|
|
if (ss && ss->server) {
|
|
|
|
if (ss->server->src) {
|
|
|
|
g_string_append_len(servers, S(ss->server->src->name));
|
2018-03-06 14:00:39 +08:00
|
|
|
char *delim = "->";
|
|
|
|
g_string_append_len(servers, delim, strlen(delim));
|
2018-03-20 14:19:44 +08:00
|
|
|
}
|
2018-03-22 11:36:38 +08:00
|
|
|
g_string_append_len(servers, S(ss->server->dst->name));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_string_append_c(servers, ' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_ptr_array_add(row, g_strdup(servers->str));
|
|
|
|
g_string_free(servers, TRUE);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (con->server != NULL) {
|
|
|
|
GString *server = g_string_new(NULL);
|
|
|
|
if (con->server->src) {
|
|
|
|
g_string_append_len(server, S(con->server->src->name));
|
|
|
|
char *delim = "->";
|
|
|
|
g_string_append_len(server, delim, strlen(delim));
|
|
|
|
}
|
|
|
|
g_string_append_len(server, S(con->server->dst->name));
|
|
|
|
g_ptr_array_add(row, g_strdup(server->str));
|
|
|
|
g_string_free(server, TRUE);
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (con->orig_sql->len) {
|
|
|
|
if (con->state == ST_READ_QUERY) {
|
|
|
|
g_ptr_array_add(row, NULL);
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, g_strdup(con->orig_sql->str));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(admin_con->client, fields, rows);
|
|
|
|
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_ptr_array_free(fields, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static GList *
|
|
|
|
network_mysqld_admin_plugin_allow_ip_get(chassis_plugin_config *config)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
if (config && config->allow_ip_table) {
|
|
|
|
return g_hash_table_get_keys(config->allow_ip_table);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static GList *
|
|
|
|
network_mysqld_admin_plugin_deny_ip_get(chassis_plugin_config *config)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
if (config && config->deny_ip_table) {
|
|
|
|
return g_hash_table_get_keys(config->deny_ip_table);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static gboolean
|
2018-03-06 14:00:39 +08:00
|
|
|
network_mysqld_admin_plugin_allow_ip_add(chassis_plugin_config *config, char *addr)
|
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
if (!config || !addr)
|
|
|
|
return FALSE;
|
2018-03-06 14:00:39 +08:00
|
|
|
if (!config->allow_ip_table) {
|
|
|
|
config->allow_ip_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
}
|
|
|
|
gboolean success = FALSE;
|
|
|
|
if (!g_hash_table_lookup(config->allow_ip_table, addr)) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(config->allow_ip_table, g_strdup(addr), (void *)TRUE);
|
2018-03-06 14:00:39 +08:00
|
|
|
success = TRUE;
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
network_mysqld_admin_plugin_deny_ip_add(chassis_plugin_config *config, char *addr)
|
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
if (!config || !addr)
|
|
|
|
return FALSE;
|
2018-03-06 14:00:39 +08:00
|
|
|
if (!config->deny_ip_table) {
|
|
|
|
config->deny_ip_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
}
|
|
|
|
gboolean success = FALSE;
|
|
|
|
if (!g_hash_table_lookup(config->deny_ip_table, addr)) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(config->deny_ip_table, g_strdup(addr), (void *)TRUE);
|
2018-03-06 14:00:39 +08:00
|
|
|
success = TRUE;
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static gboolean
|
2018-03-06 14:00:39 +08:00
|
|
|
network_mysqld_admin_plugin_allow_ip_del(chassis_plugin_config *config, char *addr)
|
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
if (!config || !addr || !config->allow_ip_table)
|
|
|
|
return FALSE;
|
2018-03-06 14:00:39 +08:00
|
|
|
return g_hash_table_remove(config->allow_ip_table, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
network_mysqld_admin_plugin_deny_ip_del(chassis_plugin_config *config, char *addr)
|
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
if (!config || !addr || !config->deny_ip_table)
|
|
|
|
return FALSE;
|
2018-03-06 14:00:39 +08:00
|
|
|
return g_hash_table_remove(config->deny_ip_table, addr);
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_show_allow_ip(network_mysqld_con *con, const char *sql)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name) {
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
|
|
|
chassis *chas = con->srv;
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *fields = g_ptr_array_new_with_free_func((void *)network_mysqld_proto_fielddef_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
MYSQL_FIELD *field;
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
GPtrArray *row;
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Plugin");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Address");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
GList *allow_ip_list = plugin->allow_ip_get(plugin->config);
|
|
|
|
if (allow_ip_list) {
|
|
|
|
GList *cur_p = allow_ip_list;
|
|
|
|
while (cur_p) {
|
|
|
|
row = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
g_ptr_array_add(row, g_strdup(module_name));
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup((char *)cur_p->data));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
cur_p = cur_p->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
/* Free data */
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_ptr_array_free(fields, TRUE);
|
|
|
|
g_free(module_name);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_show_deny_ip(network_mysqld_con *con, const char *sql)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name) {
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
|
|
|
chassis *chas = con->srv;
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *fields = g_ptr_array_new_with_free_func((void *)network_mysqld_proto_fielddef_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
MYSQL_FIELD *field;
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
GPtrArray *row;
|
|
|
|
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Plugin");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("Address");
|
|
|
|
field->type = MYSQL_TYPE_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
GList *deny_ip_list = plugin->deny_ip_get(plugin->config);
|
|
|
|
if (deny_ip_list) {
|
|
|
|
GList *cur_p = deny_ip_list;
|
|
|
|
while (cur_p) {
|
|
|
|
row = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
g_ptr_array_add(row, g_strdup(module_name));
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup((char *)cur_p->data));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
cur_p = cur_p->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
/* Free data */
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_ptr_array_free(fields, TRUE);
|
|
|
|
g_free(module_name);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_add_allow_ip(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name)
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
char *addr = str_nth_token(sql, 3);
|
|
|
|
if (!addr)
|
|
|
|
return PROXY_NO_DECISION;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
chassis *chas = con->srv;
|
|
|
|
int i;
|
|
|
|
gboolean success = FALSE;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
success = plugin->allow_ip_add(plugin->config, addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_ok_full(con->client, success, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_add_deny_ip(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name)
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
char *addr = str_nth_token(sql, 3);
|
|
|
|
if (!addr)
|
|
|
|
return PROXY_NO_DECISION;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
chassis *chas = con->srv;
|
|
|
|
int i;
|
|
|
|
gboolean success = FALSE;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
success = plugin->deny_ip_add(plugin->config, addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_ok_full(con->client, success, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_delete_allow_ip(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name)
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
char *addr = str_nth_token(sql, 3);
|
|
|
|
if (!addr)
|
|
|
|
return PROXY_NO_DECISION;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
chassis *chas = con->srv;
|
|
|
|
int i;
|
|
|
|
gboolean success = FALSE;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
success = plugin->allow_ip_del(plugin->config, addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_ok_full(con->client, success, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_delete_deny_ip(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *module_name = str_nth_token(sql, 2);
|
|
|
|
if (!module_name)
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
char *addr = str_nth_token(sql, 3);
|
|
|
|
if (!addr)
|
|
|
|
return PROXY_NO_DECISION;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (strcmp(module_name, "admin") != 0 && strcmp(module_name, "proxy") != 0 && strcmp(module_name, "shard") != 0) {
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
chassis *chas = con->srv;
|
|
|
|
int i;
|
|
|
|
gboolean success = FALSE;
|
|
|
|
for (i = 0; i < chas->modules->len; i++) {
|
|
|
|
chassis_plugin *plugin = chas->modules->pdata[i];
|
|
|
|
if (strcmp(plugin->name, module_name) == 0) {
|
|
|
|
success = plugin->deny_ip_del(plugin->config, addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_ok_full(con->client, success, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
g_free(module_name);
|
|
|
|
g_free(addr);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAKE_FIELD_DEF_1_COL(fields, col_name) \
|
|
|
|
do {\
|
|
|
|
MYSQL_FIELD *field = network_mysqld_proto_fielddef_new();\
|
|
|
|
field->name = g_strdup((col_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
}while(0)
|
|
|
|
|
|
|
|
#define MAKE_FIELD_DEF_2_COL(fields, col1_name, col2_name) \
|
|
|
|
do {\
|
|
|
|
MYSQL_FIELD *field = network_mysqld_proto_fielddef_new();\
|
|
|
|
field->name = g_strdup((col1_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
field = network_mysqld_proto_fielddef_new(); \
|
|
|
|
field->name = g_strdup((col2_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
}while(0)
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
#define MAKE_FIELD_DEF_3_COL(fields, col1_name, col2_name, col3_name) \
|
|
|
|
do {\
|
|
|
|
MYSQL_FIELD *field = network_mysqld_proto_fielddef_new();\
|
|
|
|
field->name = g_strdup((col1_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
field = network_mysqld_proto_fielddef_new(); \
|
|
|
|
field->name = g_strdup((col2_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
field = network_mysqld_proto_fielddef_new(); \
|
|
|
|
field->name = g_strdup((col3_name)); \
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;\
|
|
|
|
g_ptr_array_add(fields, field); \
|
|
|
|
}while(0)
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
#define APPEND_ROW_1_COL(rows, row_data) \
|
|
|
|
do {\
|
|
|
|
GPtrArray *row = g_ptr_array_new();\
|
|
|
|
g_ptr_array_add(row, (row_data)); \
|
|
|
|
g_ptr_array_add(rows, row);\
|
|
|
|
}while(0)
|
|
|
|
|
|
|
|
#define APPEND_ROW_2_COL(rows, col1, col2) \
|
|
|
|
do {\
|
|
|
|
GPtrArray *row = g_ptr_array_new();\
|
|
|
|
g_ptr_array_add(row, (col1)); \
|
|
|
|
g_ptr_array_add(row, (col2)); \
|
|
|
|
g_ptr_array_add(rows, row);\
|
|
|
|
}while(0)
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
#define APPEND_ROW_3_COL(rows, col1, col2, col3) \
|
|
|
|
do {\
|
|
|
|
GPtrArray *row = g_ptr_array_new();\
|
|
|
|
g_ptr_array_add(row, (col1)); \
|
|
|
|
g_ptr_array_add(row, (col2)); \
|
|
|
|
g_ptr_array_add(row, (col3)); \
|
|
|
|
g_ptr_array_add(rows, row);\
|
|
|
|
}while(0)
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
strip_extra_spaces(char *str)
|
|
|
|
{
|
|
|
|
int i, x;
|
|
|
|
for (i = x = 0; str[i]; ++i)
|
|
|
|
if (!isspace(str[i]) || (i > 0 && !isspace(str[i - 1])))
|
|
|
|
str[x++] = str[i];
|
|
|
|
str[x] = '\0';
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
str_replace(char *p, const char *x, char y)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
int i, j;
|
|
|
|
for (i = j = 0; p[i]; ++i) {
|
|
|
|
if (p[i] == x[0] && p[i + 1] == x[1]) {
|
2018-03-06 14:00:39 +08:00
|
|
|
++i;
|
|
|
|
p[j++] = y;
|
|
|
|
} else {
|
|
|
|
p[j++] = p[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p[j] = '\0';
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
normalize_equal_sign(char *p)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
str_replace(p, "= ", '=');
|
|
|
|
str_replace(p, " =", '=');
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* tolower, but leave "quoted strings" unmodified
|
|
|
|
*/
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
lower_identifiers(char *str)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
gboolean in_string = FALSE;
|
|
|
|
int i;
|
|
|
|
for (i = 0; str[i]; ++i) {
|
|
|
|
if (in_string)
|
|
|
|
continue;
|
|
|
|
if (str[i] == '\'' || str[i] == '"')
|
|
|
|
in_string = !in_string;
|
|
|
|
if (isalpha(str[i]))
|
|
|
|
str[i] = tolower(str[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only match % wildcard, case insensitive */
|
2018-03-20 14:19:44 +08:00
|
|
|
static gboolean
|
|
|
|
sql_pattern_like(const char *pattern, const char *string)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
if (!pattern || pattern[0] == '\0')
|
|
|
|
return TRUE;
|
|
|
|
char *glob = g_strdup(pattern);
|
|
|
|
int i;
|
|
|
|
for (i = 0; glob[i]; ++i) {
|
2018-03-20 14:19:44 +08:00
|
|
|
if (glob[i] == '%')
|
|
|
|
glob[i] = '*';
|
2018-03-06 14:00:39 +08:00
|
|
|
glob[i] = tolower(glob[i]);
|
|
|
|
}
|
|
|
|
char *lower_str = g_ascii_strdown(string, -1);
|
|
|
|
gboolean rc = g_pattern_match_simple(glob, lower_str);
|
|
|
|
g_free(glob);
|
|
|
|
g_free(lower_str);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returned list must be freed */
|
2018-03-20 14:19:44 +08:00
|
|
|
static GList *
|
|
|
|
admin_get_all_options(chassis *chas)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
GList *options = g_list_copy(chas->options->options); /* shallow copy */
|
2018-03-06 14:00:39 +08:00
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_show_variables(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char **tokens = g_strsplit(sql, " ", -1);
|
|
|
|
int token_count = g_strv_length(tokens);
|
|
|
|
char *pattern = NULL;
|
|
|
|
if (token_count == 2) {
|
|
|
|
pattern = "%";
|
|
|
|
} else if (token_count == 4) {
|
|
|
|
pattern = tokens[3];
|
|
|
|
cetus_string_dequote(pattern);
|
|
|
|
} else {
|
|
|
|
network_mysqld_con_send_error(con->client, C("error syntax"));
|
|
|
|
g_strfreev(tokens);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
GList *options = admin_get_all_options(con->srv);
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
2018-05-02 09:17:08 +08:00
|
|
|
MAKE_FIELD_DEF_3_COL(fields, "Variable_name", "Value", "Property");
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
GList *freelist = NULL;
|
|
|
|
GList *l = NULL;
|
|
|
|
for (l = options; l; l = l->next) {
|
|
|
|
chassis_option_t *opt = l->data;
|
|
|
|
/* just support these for now */
|
|
|
|
if (sql_pattern_like(pattern, opt->long_name)) {
|
2018-05-02 09:17:08 +08:00
|
|
|
struct external_param param = {0};
|
|
|
|
param.chas = con->srv;
|
|
|
|
param.opt_type = opt->opt_property;
|
|
|
|
char *value = opt->show_hook != NULL? opt->show_hook(¶m) : NULL;
|
|
|
|
if(NULL == value) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
freelist = g_list_append(freelist, value);
|
2018-05-02 09:17:08 +08:00
|
|
|
APPEND_ROW_3_COL(rows, (char *)opt->long_name, value, (CAN_ASSIGN_OPTS_PROPERTY(opt->opt_property)? "Dynamic" : "Static"));
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_list_free_full(freelist, g_free);
|
|
|
|
g_list_free(options);
|
|
|
|
g_strfreev(tokens);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_show_status(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char **tokens = g_strsplit(sql, " ", -1);
|
|
|
|
int token_count = g_strv_length(tokens);
|
|
|
|
char *pattern = NULL;
|
|
|
|
if (token_count == 2) {
|
|
|
|
pattern = "%";
|
|
|
|
} else if (token_count == 4) {
|
|
|
|
pattern = tokens[3];
|
|
|
|
cetus_string_dequote(pattern);
|
|
|
|
} else {
|
|
|
|
network_mysqld_con_send_error(con->client, C("error syntax"));
|
|
|
|
g_strfreev(tokens);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
cetus_variable_t *variables = con->srv->priv->stats_variables;
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "Variable_name", "Value");
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
GList *freelist = NULL;
|
|
|
|
int i = 0;
|
|
|
|
for (i = 0; variables[i].name; ++i) {
|
|
|
|
if (sql_pattern_like(pattern, variables[i].name)) {
|
|
|
|
char *value = cetus_variable_get_value_str(&variables[i]);
|
|
|
|
freelist = g_list_append(freelist, value);
|
|
|
|
APPEND_ROW_2_COL(rows, variables[i].name, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_list_free_full(freelist, g_free);
|
|
|
|
g_strfreev(tokens);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_set_reduce_conns(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *mode = str_nth_token(sql, 2);
|
|
|
|
if (mode) {
|
|
|
|
if (strcasecmp(mode, "true") == 0) {
|
|
|
|
con->srv->is_reduce_conns = 1;
|
|
|
|
} else if (strcasecmp(mode, "false") == 0) {
|
|
|
|
con->srv->is_reduce_conns = 0;
|
|
|
|
}
|
|
|
|
g_free(mode);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_ok(con->client);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_reduce_memory(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
struct mallinfo m;
|
|
|
|
|
|
|
|
m = mallinfo();
|
|
|
|
|
|
|
|
g_message("%s:Total allocated space (bytes): %d", G_STRLOC, m.uordblks);
|
|
|
|
g_message("%s:Total free space (bytes): %d", G_STRLOC, m.fordblks);
|
|
|
|
g_message("%s:Top-most, releasable space (bytes): %d", G_STRLOC, m.keepcost);
|
|
|
|
|
|
|
|
if (m.fordblks > m.uordblks) {
|
|
|
|
malloc_trim(0);
|
|
|
|
m = mallinfo();
|
|
|
|
g_message("%s:After trim, total allocated space (bytes): %d", G_STRLOC, m.uordblks);
|
|
|
|
g_message("%s:After trim, total free space (bytes): %d", G_STRLOC, m.fordblks);
|
|
|
|
g_message("%s:After trim, top-most, releasable space (bytes): %d", G_STRLOC, m.keepcost);
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_ok_full(con->client, 1, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_set_maintain(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
gboolean error = FALSE;
|
2018-05-17 10:16:15 +08:00
|
|
|
gint effected_rows = 0;
|
2018-03-06 14:00:39 +08:00
|
|
|
char *mode = str_nth_token(sql, 2);
|
|
|
|
if (mode) {
|
|
|
|
if (strcasecmp(mode, "true") == 0) {
|
2018-05-17 10:16:15 +08:00
|
|
|
if(con->srv->maintain_close_mode != 1) {
|
|
|
|
con->srv->maintain_close_mode = 1;
|
|
|
|
effected_rows++;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
} else if (strcasecmp(mode, "false") == 0) {
|
2018-05-17 10:16:15 +08:00
|
|
|
if(con->srv->maintain_close_mode != 0) {
|
|
|
|
con->srv->maintain_close_mode = 0;
|
|
|
|
effected_rows++;
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
} else {
|
|
|
|
error = TRUE;
|
|
|
|
}
|
|
|
|
g_free(mode);
|
|
|
|
} else {
|
|
|
|
error = TRUE;
|
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
return PROXY_NO_DECISION;
|
2018-05-17 10:16:15 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, effected_rows, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-05-16 15:30:51 +08:00
|
|
|
static int
|
|
|
|
admin_show_maintain(network_mysqld_con *con, const char *sql)
|
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
|
|
|
MAKE_FIELD_DEF_1_COL(fields, "Cetus maintain status");
|
|
|
|
if(con->srv->maintain_close_mode == 1) {
|
|
|
|
APPEND_ROW_1_COL(rows, "true");
|
|
|
|
} else {
|
|
|
|
APPEND_ROW_1_COL(rows, "false");
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_reload_shard(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
network_mysqld_con_send_ok_full(con->client, 1, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_version(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
|
|
|
|
MAKE_FIELD_DEF_1_COL(fields, "cetus version");
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
APPEND_ROW_1_COL(rows, PLUGIN_VERSION);
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_connection_stat(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
int backend_ndx = -1;
|
2018-03-20 14:19:44 +08:00
|
|
|
char user[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(sql,
|
2018-03-20 14:19:44 +08:00
|
|
|
"select conn_num from backends where backend_ndx=%d and user=%*['\"]%64[^'\"]%*['\"]", &backend_ndx, user);
|
2018-03-06 14:00:39 +08:00
|
|
|
if (backend_ndx == -1 || user[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
|
|
|
|
MAKE_FIELD_DEF_1_COL(fields, "connection_num");
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
char *numstr = NULL;
|
|
|
|
chassis_private *g = con->srv->priv;
|
2018-03-20 14:19:44 +08:00
|
|
|
backend_ndx -= 1; /* index in sql start from 1, not 0 */
|
2018-03-06 14:00:39 +08:00
|
|
|
if (backend_ndx >= 0 && backend_ndx < network_backends_count(g->backends)) {
|
|
|
|
network_backend_t *backend = network_backends_get(g->backends, backend_ndx);
|
|
|
|
GString *user_name = g_string_new(user);
|
2018-05-16 13:48:26 +08:00
|
|
|
GQueue *conns = NULL;
|
|
|
|
|
|
|
|
if(backend && backend->pool && backend->pool->users && user_name) {
|
|
|
|
conns = g_hash_table_lookup(backend->pool->users, user_name);
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
if (conns) {
|
|
|
|
numstr = g_strdup_printf("%d", conns->length);
|
|
|
|
}
|
|
|
|
g_string_free(user_name, TRUE);
|
|
|
|
}
|
|
|
|
if (numstr) {
|
|
|
|
APPEND_ROW_1_COL(rows, numstr);
|
|
|
|
} else {
|
|
|
|
APPEND_ROW_1_COL(rows, "0");
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
if (numstr)
|
|
|
|
g_free(numstr);
|
|
|
|
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
bytes_to_hex_str(char *pin, int len, char *pout)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
const char *hex = "0123456789ABCDEF";
|
|
|
|
int i = 0;
|
2018-03-20 14:19:44 +08:00
|
|
|
for (; i < len; ++i) {
|
|
|
|
*pout++ = hex[(*pin >> 4) & 0xF];
|
|
|
|
*pout++ = hex[(*pin++) & 0xF];
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
*pout = 0;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_user_password(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
char from_table[128] = { 0 };
|
|
|
|
char user[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
char *where_start = strcasestr(sql, "where");
|
|
|
|
if (where_start) {
|
|
|
|
sscanf(sql, "select * from %s where user=%*['\"]%64[^'\"]%*['\"]", from_table, user);
|
|
|
|
if (from_table[0] == '\0' || user[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
} else {
|
|
|
|
sscanf(sql, "select * from %s", from_table);
|
|
|
|
if (from_table[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
enum cetus_pwd_type pwd_type;
|
|
|
|
if (strcmp(from_table, "user_pwd") == 0) {
|
|
|
|
pwd_type = CETUS_SERVER_PWD;
|
|
|
|
} else if (strcmp(from_table, "app_user_pwd") == 0) {
|
|
|
|
pwd_type = CETUS_CLIENT_PWD;
|
|
|
|
} else {
|
|
|
|
g_critical("error target db");
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
}
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "user", "password(sha1)");
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
if (user[0]) { /* one user */
|
2018-03-06 14:00:39 +08:00
|
|
|
GString *hashpwd = g_string_new(0);
|
|
|
|
cetus_users_get_hashed_pwd(g->users, user, pwd_type, hashpwd);
|
|
|
|
char *pwdhex = NULL;
|
|
|
|
if (hashpwd->len > 0) {
|
2018-03-20 14:19:44 +08:00
|
|
|
pwdhex = g_malloc0(hashpwd->len * 2 + 10);
|
2018-03-06 14:00:39 +08:00
|
|
|
bytes_to_hex_str(hashpwd->str, hashpwd->len, pwdhex);
|
|
|
|
APPEND_ROW_2_COL(rows, user, pwdhex);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_string_free(hashpwd, TRUE);
|
|
|
|
if (pwdhex)
|
|
|
|
g_free(pwdhex);
|
2018-03-20 14:19:44 +08:00
|
|
|
} else { /* all users */
|
2018-03-06 14:00:39 +08:00
|
|
|
GList *strings_to_free = NULL;
|
|
|
|
GHashTableIter iter;
|
|
|
|
char *username = NULL;
|
|
|
|
GString *hashpwd = g_string_new(0);
|
2018-03-20 14:19:44 +08:00
|
|
|
char *hack = NULL; /* don't use value directly */
|
2018-03-06 14:00:39 +08:00
|
|
|
g_hash_table_iter_init(&iter, g->users->records);
|
2018-03-20 14:19:44 +08:00
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) & username, (gpointer *) & hack)) {
|
2018-03-06 14:00:39 +08:00
|
|
|
cetus_users_get_hashed_pwd(g->users, username, pwd_type, hashpwd);
|
|
|
|
char *pwdhex = NULL;
|
|
|
|
if (hashpwd->len > 0) {
|
2018-03-20 14:19:44 +08:00
|
|
|
pwdhex = g_malloc0(hashpwd->len * 2 + 10);
|
2018-03-06 14:00:39 +08:00
|
|
|
bytes_to_hex_str(hashpwd->str, hashpwd->len, pwdhex);
|
|
|
|
strings_to_free = g_list_append(strings_to_free, pwdhex);
|
|
|
|
}
|
|
|
|
APPEND_ROW_2_COL(rows, username, pwdhex);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_string_free(hashpwd, TRUE);
|
|
|
|
if (strings_to_free)
|
|
|
|
g_list_free_full(strings_to_free, g_free);
|
|
|
|
}
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update or insert */
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_update_user_password(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
char from_table[128] = { 0 };
|
|
|
|
char user[128] = { 0 };
|
|
|
|
char new_pwd[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(sql, "update %64s set password=%*['\"]%64[^'\"]%*['\"] where user=%*['\"]%64[^'\"]%*['\"]",
|
|
|
|
from_table, new_pwd, user);
|
|
|
|
if (new_pwd[0] == '\0' || from_table[0] == '\0' || user[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
enum cetus_pwd_type pwd_type = CETUS_UNKNOWN_PWD;
|
|
|
|
if (strcmp(from_table, "user_pwd") == 0) {
|
|
|
|
pwd_type = CETUS_SERVER_PWD;
|
|
|
|
} else if (strcmp(from_table, "app_user_pwd") == 0) {
|
|
|
|
pwd_type = CETUS_CLIENT_PWD;
|
|
|
|
}
|
|
|
|
gboolean affected = cetus_users_update_record(g->users, user, new_pwd, pwd_type);
|
|
|
|
if (affected)
|
|
|
|
cetus_users_write_json(g->users);
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, affected ? 1 : 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_delete_user_password(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
char from_table[128] = { 0 };
|
|
|
|
char user[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(sql, "delete from %64s where user=%*['\"]%64[^'\"]%*['\"]", from_table, user);
|
|
|
|
if (from_table[0] == '\0' || user[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
gboolean affected = cetus_users_delete_record(g->users, user);
|
|
|
|
if (affected)
|
|
|
|
cetus_users_write_json(g->users);
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, affected ? 1 : 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static backend_type_t
|
|
|
|
backend_type(const char *str)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
backend_type_t type = BACKEND_TYPE_UNKNOWN;
|
|
|
|
if (strcasecmp(str, "ro") == 0)
|
|
|
|
type = BACKEND_TYPE_RO;
|
|
|
|
else if (strcasecmp(str, "rw") == 0)
|
|
|
|
type = BACKEND_TYPE_RW;
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static backend_state_t
|
|
|
|
backend_state(const char *str)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-06-01 18:01:35 +08:00
|
|
|
backend_state_t state = BACKEND_STATE_END;
|
2018-03-06 14:00:39 +08:00
|
|
|
if (strcasecmp(str, "up") == 0)
|
|
|
|
state = BACKEND_STATE_UP;
|
|
|
|
else if (strcasecmp(str, "down") == 0)
|
|
|
|
state = BACKEND_STATE_DOWN;
|
|
|
|
else if (strcasecmp(str, "maintaining") == 0)
|
|
|
|
state = BACKEND_STATE_MAINTAINING;
|
2018-06-01 18:01:35 +08:00
|
|
|
else if (strcasecmp(str, "unknown") == 0)
|
|
|
|
state = BACKEND_STATE_UNKNOWN;
|
2018-03-06 14:00:39 +08:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_insert_backend(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
/* TODO: to which group */
|
2018-03-20 14:19:44 +08:00
|
|
|
char address[128] = { 0 };
|
|
|
|
char type_str[64] = { 0 };
|
|
|
|
char state_str[64] = { 0 };
|
|
|
|
sscanf(sql,
|
|
|
|
"insert into backends values (%*['\"]%64[0-9:.@a-zA-Z]%*['\"], %*['\"]%32[rowRWO]%*['\"], %*['\"]%32[a-zA-Z]%*['\"])",
|
2018-03-06 14:00:39 +08:00
|
|
|
address, type_str, state_str);
|
|
|
|
if (address[0] == '\0' || type_str[0] == '\0' || state_str[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
2018-03-28 17:05:12 +08:00
|
|
|
backend_state_t state = backend_state(state_str);
|
|
|
|
if (state == BACKEND_STATE_DOWN) {
|
|
|
|
con->srv->is_manual_down = 1;
|
|
|
|
} else {
|
|
|
|
con->srv->is_manual_down = 0;
|
|
|
|
}
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
int affected = network_backends_add(g->backends, address,
|
|
|
|
backend_type(type_str),
|
2018-03-28 17:05:12 +08:00
|
|
|
state,
|
2018-03-06 14:00:39 +08:00
|
|
|
con->srv);
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, affected == 0 ? 1 : 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_add_backend(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
char address[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
backend_type_t type = BACKEND_TYPE_UNKNOWN;
|
|
|
|
if (strncasecmp(sql, "add master", 10) == 0) {
|
|
|
|
sscanf(sql, "add master %*['\"]%64[0-9:.@a-zA-Z]%*['\"]", address);
|
|
|
|
type = BACKEND_TYPE_RW;
|
|
|
|
} else if (strncasecmp(sql, "add slave", 9) == 0) {
|
|
|
|
sscanf(sql, "add slave %*['\"]%64[0-9:.@a-zA-Z]%*['\"]", address);
|
|
|
|
type = BACKEND_TYPE_RO;
|
|
|
|
}
|
|
|
|
if (address[0] == '\0' || type == BACKEND_TYPE_UNKNOWN)
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
int affected = network_backends_add(g->backends, address, type, BACKEND_STATE_UNKNOWN, con->srv);
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, affected == 0 ? 1 : 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_update_backend(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-05-15 17:38:16 +08:00
|
|
|
gint ret = 0;
|
2018-03-06 14:00:39 +08:00
|
|
|
char *set_start = strcasestr(sql, "set");
|
|
|
|
char *where_start = strcasestr(sql, "where");
|
|
|
|
|
|
|
|
char *set_cols_str = NULL;
|
|
|
|
if (where_start) {
|
2018-03-20 14:19:44 +08:00
|
|
|
set_cols_str = g_strndup(set_start + 4, where_start - set_start - 4);
|
2018-03-06 14:00:39 +08:00
|
|
|
} else {
|
2018-03-20 14:19:44 +08:00
|
|
|
set_cols_str = g_strdup(set_start + 4);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
char **set_cols_array = g_strsplit(set_cols_str, ",", -1);
|
|
|
|
int i = 0;
|
2018-03-20 14:19:44 +08:00
|
|
|
char type_str[64] = { 0 };
|
|
|
|
char state_str[64] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
char *col;
|
|
|
|
for (; (col = set_cols_array[i]) != NULL; ++i) {
|
|
|
|
g_strstrip(col);
|
|
|
|
if (strncasecmp(col, "type", 4) == 0) {
|
|
|
|
sscanf(col, "type=%*['\"]%32[a-zA-Z]%*['\"]", type_str);
|
|
|
|
} else if (strncasecmp(col, "state", 5) == 0) {
|
|
|
|
sscanf(col, "state=%*['\"]%32[a-zA-Z]%*['\"]", state_str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free(set_cols_str);
|
|
|
|
g_strfreev(set_cols_array);
|
|
|
|
|
|
|
|
if (type_str[0] == '\0' && state_str[0] == '\0')
|
|
|
|
return PROXY_NO_DECISION;
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
int affected_rows = 0;
|
|
|
|
if (where_start) {
|
|
|
|
int backend_ndx = -1;
|
|
|
|
sscanf(where_start, "where backend_ndx=%d", &backend_ndx);
|
2018-03-20 14:19:44 +08:00
|
|
|
backend_ndx -= 1; /* index in sql start from 1, not 0 */
|
2018-03-06 14:00:39 +08:00
|
|
|
if (backend_ndx < 0) {
|
2018-03-20 14:19:44 +08:00
|
|
|
char address[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(where_start, "where address=%*['\"]%64[0-9:.]%*['\"]", address);
|
|
|
|
backend_ndx = network_backends_find_address(g->backends, address);
|
|
|
|
}
|
|
|
|
network_backend_t *bk = network_backends_get(g->backends, backend_ndx);
|
|
|
|
if (!bk) {
|
|
|
|
network_mysqld_con_send_error(con->client, C("no such backend"));
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
int type = type_str[0] != '\0' ? backend_type(type_str) : bk->type;
|
|
|
|
int state = state_str[0] != '\0' ? backend_state(state_str) : bk->state;
|
2018-05-15 17:38:16 +08:00
|
|
|
ret = network_backends_modify(g->backends, backend_ndx, type, state, NO_PREVIOUS_STATE);
|
2018-03-06 14:00:39 +08:00
|
|
|
affected_rows = 1;
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < network_backends_count(g->backends); ++i) {
|
|
|
|
network_backend_t *bk = network_backends_get(g->backends, i);
|
|
|
|
if (bk) {
|
|
|
|
int type = type_str[0] != '\0' ? backend_type(type_str) : bk->type;
|
|
|
|
int state = state_str[0] != '\0' ? backend_state(state_str) : bk->state;
|
2018-05-15 17:38:16 +08:00
|
|
|
ret = network_backends_modify(g->backends, i, type, state, NO_PREVIOUS_STATE);
|
2018-03-06 14:00:39 +08:00
|
|
|
affected_rows += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-15 17:38:16 +08:00
|
|
|
if(ret == 0) {
|
|
|
|
network_mysqld_con_send_ok_full(con->client, affected_rows, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
} else {
|
2018-06-01 18:01:35 +08:00
|
|
|
network_mysqld_con_send_error_full(con->client, C("Command or parameter is incorrect."), 1045, "28000");
|
2018-05-15 17:38:16 +08:00
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_delete_backend(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
char *where_start = strcasestr(sql, "where");
|
|
|
|
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
int backend_ndx = -1;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (where_start) { /* delete from backends where xx=xx */
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(where_start, "where backend_ndx=%d", &backend_ndx);
|
2018-03-20 14:19:44 +08:00
|
|
|
backend_ndx -= 1; /* index in sql start from 1, not 0 */
|
2018-03-06 14:00:39 +08:00
|
|
|
if (backend_ndx < 0) {
|
2018-03-20 14:19:44 +08:00
|
|
|
char address[128] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(where_start, "where address=%*['\"]%64[0-9:.]%*['\"]", address);
|
|
|
|
backend_ndx = network_backends_find_address(g->backends, address);
|
|
|
|
}
|
2018-03-20 14:19:44 +08:00
|
|
|
} else { /* remove backend xxx */
|
2018-03-06 14:00:39 +08:00
|
|
|
sscanf(sql, "remove backend %d", &backend_ndx);
|
2018-03-20 14:19:44 +08:00
|
|
|
backend_ndx -= 1; /* index in sql start from 1, not 0 */
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
if (backend_ndx >= 0 && backend_ndx < network_backends_count(g->backends)) {
|
2018-05-15 17:38:16 +08:00
|
|
|
gint ret = network_backends_remove(g->backends, backend_ndx); /* TODO: just change state? */
|
|
|
|
if(ret == 0) {
|
|
|
|
network_mysqld_con_send_ok_full(con->client, 1, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
} else {
|
|
|
|
network_mysqld_con_send_error_full(con->client, C("delete failed."), 1045, "28000");
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
} else {
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_supported_stats(network_mysqld_con *con)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_1_COL(fields, "name");
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
APPEND_ROW_1_COL(rows, "client_query");
|
|
|
|
APPEND_ROW_1_COL(rows, "proxyed_query");
|
|
|
|
APPEND_ROW_1_COL(rows, "reset");
|
|
|
|
APPEND_ROW_1_COL(rows, "query_time_table");
|
|
|
|
APPEND_ROW_1_COL(rows, "server_query_details");
|
|
|
|
APPEND_ROW_1_COL(rows, "query_wait_table");
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_get_stats(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
const char *p = sql + 9;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (*p == '\0') { /* just "stats get", no argument */
|
2018-03-06 14:00:39 +08:00
|
|
|
return admin_supported_stats(con);
|
|
|
|
} else {
|
2018-03-20 14:19:44 +08:00
|
|
|
++p; /* stats get [xxx], point to xxx */
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "name", "value");
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis *chas = con->srv;
|
|
|
|
query_stats_t *stats = &(chas->query_stats);
|
2018-03-20 14:19:44 +08:00
|
|
|
char buf1[32] = { 0 };
|
|
|
|
char buf2[32] = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
int i;
|
|
|
|
if (strcasecmp(p, "client_query") == 0) {
|
|
|
|
snprintf(buf1, 32, "%lu", stats->client_query.ro);
|
|
|
|
snprintf(buf2, 32, "%lu", stats->client_query.rw);
|
|
|
|
APPEND_ROW_2_COL(rows, "client_query.ro", buf1);
|
|
|
|
APPEND_ROW_2_COL(rows, "client_query.rw", buf2);
|
|
|
|
} else if (strcasecmp(p, "proxyed_query") == 0) {
|
|
|
|
snprintf(buf1, 32, "%lu", stats->proxyed_query.ro);
|
|
|
|
snprintf(buf2, 32, "%lu", stats->proxyed_query.rw);
|
|
|
|
APPEND_ROW_2_COL(rows, "proxyed_query.ro", buf1);
|
|
|
|
APPEND_ROW_2_COL(rows, "proxyed_query.rw", buf2);
|
|
|
|
} else if (strcasecmp(p, "query_time_table") == 0) {
|
|
|
|
for (i = 0; i < MAX_QUERY_TIME && stats->query_time_table[i]; ++i) {
|
|
|
|
GPtrArray *row = g_ptr_array_new_with_free_func(g_free);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("query_time_table.%d", i + 1));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("%lu", stats->query_time_table[i]));
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
} else if (strcasecmp(p, "query_wait_table") == 0) {
|
|
|
|
for (i = 0; i < MAX_QUERY_TIME && stats->query_wait_table[i]; ++i) {
|
|
|
|
GPtrArray *row = g_ptr_array_new_with_free_func(g_free);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("query_wait_table.%d", i + 1));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("%lu", stats->query_wait_table[i]));
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
} else if (strcasecmp(p, "server_query_details") == 0) {
|
|
|
|
for (i = 0; i < MAX_SERVER_NUM && i < network_backends_count(chas->priv->backends); ++i) {
|
|
|
|
GPtrArray *row = g_ptr_array_new_with_free_func(g_free);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("server_query_details.%d.ro", i + 1));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("%lu", stats->server_query_details[i].ro));
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
row = g_ptr_array_new_with_free_func(g_free);
|
2018-03-20 14:19:44 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("server_query_details.%d.rw", i + 1));
|
2018-03-06 14:00:39 +08:00
|
|
|
g_ptr_array_add(row, g_strdup_printf("%lu", stats->server_query_details[i].rw));
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
} else if (strcasecmp(p, "reset") == 0) {
|
|
|
|
APPEND_ROW_2_COL(rows, "reset", "0");
|
|
|
|
} else {
|
|
|
|
APPEND_ROW_2_COL(rows, (char *)p, (char *)p);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_supported_config(network_mysqld_con *con)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_1_COL(fields, "name");
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
APPEND_ROW_1_COL(rows, "common");
|
|
|
|
APPEND_ROW_1_COL(rows, "pool");
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_get_config(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
const char *p = sql + 10;
|
2018-03-20 14:19:44 +08:00
|
|
|
if (*p == '\0') { /* just "config get", no argument */
|
2018-03-06 14:00:39 +08:00
|
|
|
return admin_supported_config(con);
|
|
|
|
} else {
|
2018-03-20 14:19:44 +08:00
|
|
|
++p; /* config get [xxx], point to xxx */
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "name", "value");
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis *chas = con->srv;
|
2018-03-20 14:19:44 +08:00
|
|
|
char buf1[32] = { 0 }, buf2[32] = {
|
|
|
|
0};
|
|
|
|
char buf3[32] = { 0 }, buf4[32] = {
|
|
|
|
0};
|
2018-03-06 14:00:39 +08:00
|
|
|
if (strcasecmp(p, "common") == 0) {
|
|
|
|
snprintf(buf1, 32, "%d", chas->check_slave_delay);
|
2018-05-02 09:17:08 +08:00
|
|
|
snprintf(buf2, 32, "%lf", chas->slave_delay_down_threshold_sec);
|
|
|
|
snprintf(buf3, 32, "%lf", chas->slave_delay_recover_threshold_sec);
|
2018-03-06 14:00:39 +08:00
|
|
|
snprintf(buf4, 32, "%d", chas->long_query_time);
|
|
|
|
APPEND_ROW_2_COL(rows, "common.check_slave_delay", buf1);
|
|
|
|
APPEND_ROW_2_COL(rows, "common.slave_delay_down_threshold_sec", buf2);
|
|
|
|
APPEND_ROW_2_COL(rows, "common.slave_delay_recover_threshold_sec", buf3);
|
|
|
|
APPEND_ROW_2_COL(rows, "common.long_query_time", buf4);
|
|
|
|
} else if (strcasecmp(p, "pool") == 0) {
|
|
|
|
snprintf(buf1, 32, "%d", chas->mid_idle_connections);
|
|
|
|
snprintf(buf2, 32, "%d", chas->max_idle_connections);
|
|
|
|
snprintf(buf3, 32, "%d", chas->max_resp_len);
|
|
|
|
snprintf(buf4, 32, "%d", chas->master_preferred);
|
|
|
|
APPEND_ROW_2_COL(rows, "pool.default_pool_size", buf1);
|
|
|
|
APPEND_ROW_2_COL(rows, "pool.max_pool_size", buf2);
|
|
|
|
APPEND_ROW_2_COL(rows, "pool.max_resp_len", buf3);
|
|
|
|
APPEND_ROW_2_COL(rows, "pool.master_preferred", buf4);
|
|
|
|
} else {
|
|
|
|
APPEND_ROW_2_COL(rows, (char *)p, (char *)p);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_set_config(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
char key[128] = { 0 };
|
2018-05-02 09:17:08 +08:00
|
|
|
char val[128] = { 0 };
|
|
|
|
sscanf(sql, "config set %64[a-zA-Z0-9_.-]=%64[a-zA-Z0-9_.-]", key, val);
|
|
|
|
if (key[0] == '\0') {
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, 0, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
2018-05-02 09:17:08 +08:00
|
|
|
|
2018-05-18 09:04:56 +08:00
|
|
|
if (val[0] == '\0') {
|
|
|
|
network_mysqld_con_send_error_full(con->client, C("Value can only contain [a-zA-Z0-9_.-], and don't have to surround with quotes. "), 1065, "28000");
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
int affected_rows = 0;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
GList *options = admin_get_all_options(con->srv);
|
|
|
|
|
|
|
|
GList *l = NULL;
|
|
|
|
for (l = options; l; l = l->next) {
|
|
|
|
chassis_option_t *opt = l->data;
|
|
|
|
if (strcasecmp(key, opt->long_name) == 0) {
|
|
|
|
struct external_param param = {0};
|
|
|
|
param.chas = con->srv;
|
|
|
|
param.opt_type = opt->opt_property;
|
|
|
|
ret = opt->assign_hook != NULL? opt->assign_hook(val, ¶m) : ASSIGN_NOT_SUPPORT;
|
|
|
|
affected_rows++;
|
|
|
|
break;
|
2018-03-28 17:05:12 +08:00
|
|
|
}
|
2018-05-02 09:17:08 +08:00
|
|
|
}
|
|
|
|
g_list_free(options);
|
|
|
|
|
|
|
|
if(0 == ret) {
|
|
|
|
network_mysqld_con_send_ok_full(con->client, affected_rows, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
|
|
|
} else if(ASSIGN_NOT_SUPPORT == ret){
|
|
|
|
network_mysqld_con_send_error_full(con->client, C("Variable cannot be set dynamically"), 1065, "28000");
|
|
|
|
} else if(ASSIGN_VALUE_INVALID == ret){
|
|
|
|
network_mysqld_con_send_error_full(con->client, C("Value is illegal"), 1065, "28000");
|
2018-03-06 14:00:39 +08:00
|
|
|
} else {
|
2018-05-02 09:17:08 +08:00
|
|
|
network_mysqld_con_send_error_full(con->client, C("You have an error in your SQL syntax"), 1065, "28000");
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_reset_stats(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
query_stats_t *stats = &con->srv->query_stats;
|
|
|
|
memset(stats, 0, sizeof(*stats));
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, 1, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_save_settings(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
2018-05-02 09:17:08 +08:00
|
|
|
chassis *srv = con->srv;
|
|
|
|
GKeyFile *keyfile = g_key_file_new();
|
|
|
|
g_key_file_set_list_separator(keyfile, ',');
|
2018-05-17 18:01:41 +08:00
|
|
|
gint ret = ASSIGN_OK;
|
2018-05-02 09:17:08 +08:00
|
|
|
gint effected_rows = 0;
|
|
|
|
GString *free_path = g_string_new(NULL);
|
2018-05-17 18:01:41 +08:00
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
if(srv->default_file == NULL) {
|
|
|
|
free_path = g_string_append(free_path, get_current_dir_name());
|
|
|
|
free_path = g_string_append(free_path, "/default.conf");
|
|
|
|
srv->default_file = g_strdup(free_path->str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!g_path_is_absolute(srv->default_file)) {
|
|
|
|
free_path = g_string_append(free_path, get_current_dir_name());
|
|
|
|
free_path = g_string_append(free_path, "/");
|
|
|
|
free_path = g_string_append(free_path, srv->default_file);
|
|
|
|
if(srv->default_file) {
|
|
|
|
g_free(srv->default_file);
|
|
|
|
}
|
|
|
|
srv->default_file = g_strdup(free_path->str);
|
|
|
|
}
|
|
|
|
if(free_path) {
|
|
|
|
g_string_free(free_path, TRUE);
|
|
|
|
}
|
2018-05-17 18:01:41 +08:00
|
|
|
/* rename config file */
|
2018-05-02 09:17:08 +08:00
|
|
|
if(srv->default_file) {
|
|
|
|
GString *new_file = g_string_new(NULL);
|
|
|
|
new_file = g_string_append(new_file, srv->default_file);
|
|
|
|
new_file = g_string_append(new_file, ".old");
|
2018-05-17 18:01:41 +08:00
|
|
|
|
|
|
|
if (remove(new_file->str)) {
|
|
|
|
g_debug("remove operate, filename:%s, errno:%d",
|
|
|
|
new_file->str == NULL? "":new_file->str, errno);
|
|
|
|
}
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
if(rename(srv->default_file, new_file->str)) {
|
2018-05-17 18:01:41 +08:00
|
|
|
g_debug("rename operate failed, filename:%s, filename:%s, errno:%d",
|
|
|
|
(srv->default_file == NULL ? "":srv->default_file),
|
2018-05-11 10:23:01 +08:00
|
|
|
(new_file->str == NULL ? "":new_file->str), errno);
|
2018-05-02 09:17:08 +08:00
|
|
|
ret = RENAME_ERROR;
|
|
|
|
}
|
|
|
|
g_string_free(new_file, TRUE);
|
|
|
|
}
|
|
|
|
|
2018-05-17 18:01:41 +08:00
|
|
|
if(ret == ASSIGN_OK) {
|
|
|
|
/* save new config */
|
2018-05-02 09:17:08 +08:00
|
|
|
effected_rows = chassis_options_save(keyfile, srv->options, srv);
|
|
|
|
gsize file_size = 0;
|
|
|
|
gchar *file_buf = g_key_file_to_data(keyfile, &file_size, NULL);
|
2018-05-17 18:01:41 +08:00
|
|
|
GError *gerr = NULL;
|
2018-05-02 09:17:08 +08:00
|
|
|
if (FALSE == g_file_set_contents(srv->default_file, file_buf, file_size, &gerr)) {
|
|
|
|
ret = SAVE_ERROR;
|
|
|
|
} else {
|
|
|
|
if((ret = chmod(srv->default_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))) {
|
2018-05-17 18:01:41 +08:00
|
|
|
g_debug("remove operate failed, filename:%s, errno:%d",
|
|
|
|
(srv->default_file == NULL? "":srv->default_file), errno);
|
2018-05-02 09:17:08 +08:00
|
|
|
ret = CHMOD_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-17 18:01:41 +08:00
|
|
|
if(ret == ASSIGN_OK) {
|
2018-05-02 09:17:08 +08:00
|
|
|
network_mysqld_con_send_ok_full(con->client, effected_rows, 0, SERVER_STATUS_AUTOCOMMIT, 0);
|
2018-05-17 18:01:41 +08:00
|
|
|
} else if(ret == RENAME_ERROR) {
|
2018-05-02 09:17:08 +08:00
|
|
|
network_mysqld_con_send_error_full(con->client, C("rename file failed"), 1066, "28000");
|
2018-05-17 18:01:41 +08:00
|
|
|
} else if(ret == SAVE_ERROR) {
|
2018-05-02 09:17:08 +08:00
|
|
|
network_mysqld_con_send_error_full(con->client, C("save file failed"), 1066, "28000");
|
2018-05-17 18:01:41 +08:00
|
|
|
} else if(ret == CHMOD_ERROR) {
|
2018-05-02 09:17:08 +08:00
|
|
|
network_mysqld_con_send_error_full(con->client, C("chmod file failed"), 1066, "28000");
|
|
|
|
}
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void calc_qps_average(char *buf, int len);
|
|
|
|
static void calc_tps_average(char *buf, int len);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
get_module_names(chassis *chas, GString *plugin_names)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < chas->modules->len; ++i) {
|
|
|
|
chassis_plugin *p = g_ptr_array_index(chas->modules, i);
|
|
|
|
g_string_append(plugin_names, p->name);
|
|
|
|
g_string_append_c(plugin_names, ' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_status(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
chassis_private *g = con->srv->priv;
|
|
|
|
chassis_plugin_config *config = con->config;
|
|
|
|
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "Status", "Value");
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
APPEND_ROW_2_COL(rows, "Cetus version", PLUGIN_VERSION);
|
|
|
|
char start_time[32];
|
|
|
|
chassis_epoch_to_string(&con->srv->startup_time, C(start_time));
|
|
|
|
APPEND_ROW_2_COL(rows, "Startup time", start_time);
|
|
|
|
GString *plugin_names = g_string_new(0);
|
|
|
|
get_module_names(con->srv, plugin_names);
|
|
|
|
APPEND_ROW_2_COL(rows, "Loaded modules", plugin_names->str);
|
|
|
|
const int bsize = 32;
|
|
|
|
static char buf1[32], buf2[32], buf3[32];
|
|
|
|
snprintf(buf1, bsize, "%d", network_backends_idle_conns(g->backends));
|
|
|
|
APPEND_ROW_2_COL(rows, "Idle backend connections", buf1);
|
|
|
|
snprintf(buf2, bsize, "%d", network_backends_used_conns(g->backends));
|
|
|
|
APPEND_ROW_2_COL(rows, "Used backend connections", buf2);
|
|
|
|
snprintf(buf3, bsize, "%d", g->cons->len);
|
|
|
|
APPEND_ROW_2_COL(rows, "Client connections", buf3);
|
|
|
|
|
|
|
|
query_stats_t *stats = &(con->srv->query_stats);
|
|
|
|
char qcount[32];
|
2018-03-20 14:19:44 +08:00
|
|
|
snprintf(qcount, 32, "%ld", stats->client_query.ro + stats->client_query.rw);
|
2018-03-06 14:00:39 +08:00
|
|
|
APPEND_ROW_2_COL(rows, "Query count", qcount);
|
2018-03-20 14:19:44 +08:00
|
|
|
|
|
|
|
if (config->has_shard_plugin) {
|
2018-03-06 14:00:39 +08:00
|
|
|
char xacount[32];
|
|
|
|
snprintf(xacount, 32, "%ld", stats->xa_count);
|
|
|
|
APPEND_ROW_2_COL(rows, "XA count", xacount);
|
|
|
|
}
|
|
|
|
|
|
|
|
char qps[64];
|
|
|
|
calc_qps_average(C(qps));
|
|
|
|
APPEND_ROW_2_COL(rows, "QPS (1min, 5min, 15min)", qps);
|
|
|
|
char tps[64];
|
|
|
|
calc_tps_average(C(tps));
|
|
|
|
APPEND_ROW_2_COL(rows, "TPS (1min, 5min, 15min)", tps);
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_string_free(plugin_names, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_send_group_info(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
|
|
|
|
MYSQL_FIELD *field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup("group");
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup(("master"));
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
field = network_mysqld_proto_fielddef_new();
|
|
|
|
field->name = g_strdup(("slaves"));
|
|
|
|
field->type = FIELD_TYPE_VAR_STRING;
|
|
|
|
g_ptr_array_add(fields, field);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
GList *free_list = NULL;
|
|
|
|
network_backends_t *bs = con->srv->priv->backends;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < bs->groups->len; ++i) {
|
|
|
|
network_group_t *gp = g_ptr_array_index(bs->groups, i);
|
|
|
|
GPtrArray *row = g_ptr_array_new();
|
|
|
|
g_ptr_array_add(row, gp->name->str);
|
|
|
|
if (gp->master) {
|
|
|
|
g_ptr_array_add(row, gp->master->addr->name->str);
|
|
|
|
} else {
|
|
|
|
g_ptr_array_add(row, "");
|
|
|
|
}
|
|
|
|
GString *slaves = g_string_new(0);
|
|
|
|
network_group_get_slave_names(gp, slaves);
|
|
|
|
g_ptr_array_add(row, slaves->str);
|
|
|
|
free_list = g_list_append(free_list, slaves);
|
|
|
|
g_ptr_array_add(rows, row);
|
|
|
|
}
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
g_list_free_full(free_list, g_string_true_free);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int admin_help(network_mysqld_con *con, const char *sql);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
typedef int (*sql_handler_func) (network_mysqld_con *, const char *);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
struct sql_handler_entry_t {
|
|
|
|
const char *prefix;
|
|
|
|
sql_handler_func func;
|
|
|
|
const char *pattern;
|
|
|
|
const char *desc;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct sql_handler_entry_t sql_handler_shard_map[] = {
|
|
|
|
{"select conn_details from backend", admin_send_backend_detail_info,
|
|
|
|
"select conn_details from backend", "display the idle conns"},
|
|
|
|
{"select * from backends", admin_send_backends_info,
|
|
|
|
"select * from backends", "list the backends and their state"},
|
|
|
|
{"select * from groups", admin_send_group_info,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select * from groups","list the backends and their groups"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show connectionlist", admin_show_connectionlist,
|
|
|
|
"show connectionlist [<num>]", "show <num> connections"},
|
|
|
|
{"show allow_ip ", admin_show_allow_ip,
|
2018-05-25 20:55:36 +08:00
|
|
|
"show allow_ip <module>", "show allow_ip rules of module, currently admin|shard"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show deny_ip ", admin_show_deny_ip,
|
2018-05-25 20:55:36 +08:00
|
|
|
"show deny_ip <module>", "show deny_ip rules of module, currently admin|shard"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"add allow_ip ", admin_add_allow_ip,
|
|
|
|
"add allow_ip <module> <address>", "add address to white list of module"},
|
|
|
|
{"add deny_ip ", admin_add_deny_ip,
|
2018-03-30 18:20:15 +08:00
|
|
|
"add deny_ip <module> <address>", "add address to black list of module"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete allow_ip ", admin_delete_allow_ip,
|
|
|
|
"delete allow_ip <module> <address>", "delete address from white list of module"},
|
|
|
|
{"delete deny_ip ", admin_delete_deny_ip,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete deny_ip <module> <address>", "delete address from black list of module"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"set reduce_conns ", admin_set_reduce_conns,
|
|
|
|
"set reduce_conns (true|false)", "reduce idle connections if set to true"},
|
|
|
|
{"reduce memory", admin_reduce_memory,
|
|
|
|
"reduce memory", "reduce memory occupied by system"},
|
|
|
|
{"set maintain ", admin_set_maintain,
|
|
|
|
"set maintain (true|false)", "close all client connections if set to true"},
|
2018-05-16 15:30:51 +08:00
|
|
|
{"show maintain status", admin_show_maintain,
|
|
|
|
"show maintain status", "query whether cetus' status is maintain"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"reload shard", admin_reload_shard,
|
|
|
|
"reload shard", "reload sharding config from remote db"},
|
|
|
|
{"show status", admin_show_status,
|
2018-03-30 18:20:15 +08:00
|
|
|
"show status [like '%<pattern>%']", "show select/update/insert/delete statistics"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show variables", admin_show_variables,
|
2018-03-30 18:20:15 +08:00
|
|
|
"show variables [like '%<pattern>%']","show configuration variables"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select version", admin_send_version,
|
|
|
|
"select version", "cetus version"},
|
|
|
|
{"select conn_num from backends where", admin_send_connection_stat,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select conn_num from backends where backend_ndx=<index> and user='<name>')",
|
|
|
|
"display selected backend and its connection number"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from user_pwd", admin_send_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select * from user_pwd [where user='<name>']","display server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from app_user_pwd", admin_send_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select * from app_user_pwd [where user='<name>']","display client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"update user_pwd set password", admin_update_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update user_pwd set password='xx' where user='<name>'","update server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"update app_user_pwd set password", admin_update_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update app_user_pwd set password='xx' where user='<name>'","update client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete from user_pwd where", admin_delete_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from user_pwd where user='<name>'","delete server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete from app_user_pwd where", admin_delete_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from app_user_pwd where user='<name>'","delete client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"insert into backends values", admin_insert_backend,
|
|
|
|
"insert into backends values ('<ip:port@group>', '(ro|rw)', '<state>')",
|
|
|
|
"add mysql instance to backends list"},
|
|
|
|
{"update backends set", admin_update_backend,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update backends set (type|state)='<value>' where (backend_ndx=<index>|address='<ip:port>')",
|
2018-03-06 14:00:39 +08:00
|
|
|
"update mysql instance type or state"},
|
|
|
|
{"delete from backends", admin_delete_backend,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from backends where (backend_ndx=<index>|address='<ip:port>')",
|
|
|
|
"set state of mysql instance to deleted"},
|
2018-03-20 14:19:44 +08:00
|
|
|
{"remove backend ", admin_delete_backend, /* TODO: unify */
|
2018-03-30 18:20:15 +08:00
|
|
|
"remove backend where (backend_ndx=<index>|address='<ip:port>')",
|
|
|
|
"set state of mysql instance to deleted"},
|
|
|
|
{"add master", admin_add_backend, "add master '<ip:port@group>'","add master"},
|
|
|
|
{"add slave", admin_add_backend, "add slave '<ip:port@group>'","add slave"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"stats get", admin_get_stats, "stats get [<item>]", "show query statistics"},
|
|
|
|
{"config get", admin_get_config, "config get [<item>]", "show config"},
|
2018-03-30 18:20:15 +08:00
|
|
|
{"config set ", admin_set_config, "config set <key>=<value>","set config"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"stats reset", admin_reset_stats, "stats reset", "reset query statistics"},
|
2018-05-11 10:23:01 +08:00
|
|
|
{"save settings", admin_save_settings, "save settings", "save config file"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from help", admin_help, "select * from help", "show this help"},
|
|
|
|
{"select help", admin_help, "select help", "show this help"},
|
2018-03-30 18:20:15 +08:00
|
|
|
{"cetus", admin_send_status, "cetus", "show overall status of Cetus"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{NULL, NULL, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct sql_handler_entry_t sql_handler_rw_map[] = {
|
|
|
|
{"select conn_details from backend", admin_send_backend_detail_info,
|
|
|
|
"select conn_details from backend", "display the idle conns"},
|
|
|
|
{"select * from backends", admin_send_backends_info,
|
|
|
|
"select * from backends", "list the backends and their state"},
|
|
|
|
{"show connectionlist", admin_show_connectionlist,
|
|
|
|
"show connectionlist [<num>]", "show <num> connections"},
|
|
|
|
{"show allow_ip ", admin_show_allow_ip,
|
2018-05-25 20:55:36 +08:00
|
|
|
"show allow_ip <module>", "show allow_ip rules of module, currently admin|proxy"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show deny_ip ", admin_show_deny_ip,
|
2018-05-25 20:55:36 +08:00
|
|
|
"show deny_ip <module>", "show deny_ip rules of module, currently admin|proxy"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"add allow_ip ", admin_add_allow_ip,
|
|
|
|
"add allow_ip <module> <address>", "add address to white list of module"},
|
|
|
|
{"add deny_ip ", admin_add_deny_ip,
|
2018-03-30 18:20:15 +08:00
|
|
|
"add deny_ip <module> <address>", "add address to black list of module"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete allow_ip ", admin_delete_allow_ip,
|
|
|
|
"delete allow_ip <module> <address>", "delete address from white list of module"},
|
|
|
|
{"delete deny_ip ", admin_delete_deny_ip,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete deny_ip <module> <address>", "delete address from black list of module"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"set reduce_conns ", admin_set_reduce_conns,
|
|
|
|
"set reduce_conns (true|false)", "reduce idle connections if set to true"},
|
|
|
|
{"reduce memory", admin_reduce_memory,
|
|
|
|
"reduce memory", "reduce memory occupied by system"},
|
|
|
|
{"set maintain ", admin_set_maintain,
|
|
|
|
"set maintain (true|false)", "close all client connections if set to true"},
|
2018-05-16 15:30:51 +08:00
|
|
|
{"show maintain status", admin_show_maintain,
|
|
|
|
"show maintain status", "query whether cetus' status is maintain"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show status", admin_show_status,
|
2018-03-30 18:20:15 +08:00
|
|
|
"show status [like '%<pattern>%']", "show select/update/insert/delete statistics"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"show variables", admin_show_variables,
|
2018-03-30 18:20:15 +08:00
|
|
|
"show variables [like '%<pattern>%']","show configuration variables"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select version", admin_send_version,
|
|
|
|
"select version", "cetus version"},
|
|
|
|
{"select conn_num from backends where", admin_send_connection_stat,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select conn_num from backends where backend_ndx=<index> and user='<name>')",
|
|
|
|
"display selected backend and its connection number"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from user_pwd", admin_send_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select * from user_pwd [where user='<name>']","display server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from app_user_pwd", admin_send_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"select * from app_user_pwd [where user='<name>']","display client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"update user_pwd set password", admin_update_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update user_pwd set password='xx' where user='<name>'","update server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"update app_user_pwd set password", admin_update_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update app_user_pwd set password='xx' where user='<name>'","update client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete from user_pwd where", admin_delete_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from user_pwd where user='<name>'","delete server username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"delete from app_user_pwd where", admin_delete_user_password,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from app_user_pwd where user='<name>'","delete client username and password"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"insert into backends values", admin_insert_backend,
|
|
|
|
"insert into backends values ('<ip:port>', '(ro|rw)', '<state>')",
|
|
|
|
"add mysql instance to backends list"},
|
|
|
|
{"update backends set", admin_update_backend,
|
2018-03-30 18:20:15 +08:00
|
|
|
"update backends set (type|state)='<value>' where (backend_ndx=<index>|address='<ip:port>')",
|
2018-03-06 14:00:39 +08:00
|
|
|
"update mysql instance type or state"},
|
|
|
|
{"delete from backends", admin_delete_backend,
|
2018-03-30 18:20:15 +08:00
|
|
|
"delete from backends where (backend_ndx=<index>|address='<ip:port>')",
|
|
|
|
"set state of mysql instance to deleted"},
|
2018-03-20 14:19:44 +08:00
|
|
|
{"remove backend ", admin_delete_backend, /* TODO: unify */
|
2018-03-30 18:20:15 +08:00
|
|
|
"remove backend where (backend_ndx=<index>|address='<ip:port>')",
|
|
|
|
"set state of mysql instance to deleted"},
|
|
|
|
{"add master", admin_add_backend, "add master '<ip:port>'","add master"},
|
|
|
|
{"add slave", admin_add_backend, "add slave '<ip:port>'","add slave"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"stats get", admin_get_stats, "stats get [<item>]", "show query statistics"},
|
|
|
|
{"config get", admin_get_config, "config get [<item>]", "show config"},
|
2018-03-30 18:20:15 +08:00
|
|
|
{"config set ", admin_set_config, "config set <key>=<value>","set config"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"stats reset", admin_reset_stats, "stats reset", "reset query statistics"},
|
2018-05-11 10:23:01 +08:00
|
|
|
{"save settings", admin_save_settings, "save settings", "save config file"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{"select * from help", admin_help, "select * from help", "show this help"},
|
|
|
|
{"select help", admin_help, "select help", "show this help"},
|
2018-03-30 18:20:15 +08:00
|
|
|
{"cetus", admin_send_status, "cetus", "show overall status of Cetus"},
|
2018-03-06 14:00:39 +08:00
|
|
|
{NULL, NULL, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
admin_help(network_mysqld_con *con, const char *sql)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
GPtrArray *fields = network_mysqld_proto_fielddefs_new();
|
|
|
|
MAKE_FIELD_DEF_2_COL(fields, "Command", "Description");
|
2018-03-20 14:19:44 +08:00
|
|
|
GPtrArray *rows = g_ptr_array_new_with_free_func((void *)network_mysqld_mysql_field_row_free);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
chassis_plugin_config *config = con->config;
|
2018-03-20 14:19:44 +08:00
|
|
|
struct sql_handler_entry_t *sql_handler_map = config->has_shard_plugin ? sql_handler_shard_map : sql_handler_rw_map;
|
2018-03-06 14:00:39 +08:00
|
|
|
int i;
|
|
|
|
for (i = 0; sql_handler_map[i].prefix; ++i) {
|
|
|
|
struct sql_handler_entry_t *e = &(sql_handler_map[i]);
|
|
|
|
char *pattern = e->pattern ? (char *)e->pattern : "";
|
|
|
|
char *desc = e->desc ? (char *)e->desc : "";
|
|
|
|
APPEND_ROW_2_COL(rows, pattern, desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_resultset(con->client, fields, rows);
|
|
|
|
network_mysqld_proto_fielddefs_free(fields);
|
|
|
|
g_ptr_array_free(rows, TRUE);
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static network_mysqld_stmt_ret
|
|
|
|
admin_process_query(network_mysqld_con *con)
|
|
|
|
{
|
|
|
|
char command = -1;
|
|
|
|
network_socket *recv_sock = con->client;
|
2018-03-20 14:19:44 +08:00
|
|
|
GList *chunk = recv_sock->recv_queue->chunks->head;
|
2018-03-06 14:00:39 +08:00
|
|
|
GString *packet = chunk->data;
|
|
|
|
|
|
|
|
if (packet->len < NET_HEADER_SIZE) {
|
|
|
|
/* packet too short */
|
|
|
|
return PROXY_SEND_QUERY;
|
|
|
|
}
|
|
|
|
|
|
|
|
command = packet->str[NET_HEADER_SIZE + 0];
|
|
|
|
|
|
|
|
if (COM_QUERY == command) {
|
|
|
|
/* we need some more data after the COM_QUERY */
|
2018-03-20 14:19:44 +08:00
|
|
|
if (packet->len < NET_HEADER_SIZE + 2)
|
|
|
|
return PROXY_SEND_QUERY;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* LOAD DATA INFILE is nasty */
|
|
|
|
if (packet->len - NET_HEADER_SIZE - 1 >= sizeof("LOAD ") - 1 &&
|
2018-03-20 14:19:44 +08:00
|
|
|
!g_ascii_strncasecmp(packet->str + NET_HEADER_SIZE + 1, C("LOAD "))) {
|
2018-03-06 14:00:39 +08:00
|
|
|
return PROXY_SEND_QUERY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
g_string_assign_len(con->orig_sql, packet->str + (NET_HEADER_SIZE + 1), packet->len - (NET_HEADER_SIZE + 1));
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
g_strstrip(con->orig_sql->str); /* strip leading and trailing spaces */
|
|
|
|
strip_extra_spaces(con->orig_sql->str); /* replace multiple spaces with one */
|
2018-03-20 14:19:44 +08:00
|
|
|
normalize_equal_sign(con->orig_sql->str); /* remove spaces on the side of = */
|
2018-03-06 14:00:39 +08:00
|
|
|
lower_identifiers(con->orig_sql->str);
|
|
|
|
con->orig_sql->len = strlen(con->orig_sql->str);
|
|
|
|
|
|
|
|
const char *sql = con->orig_sql->str;
|
|
|
|
|
|
|
|
chassis_plugin_config *config = con->config;
|
2018-03-20 14:19:44 +08:00
|
|
|
struct sql_handler_entry_t *sql_handler_map = config->has_shard_plugin ? sql_handler_shard_map : sql_handler_rw_map;
|
2018-03-06 14:00:39 +08:00
|
|
|
int i;
|
|
|
|
for (i = 0; sql_handler_map[i].prefix; ++i) {
|
2018-05-15 19:37:02 +08:00
|
|
|
gchar *pos = NULL;
|
|
|
|
if ((pos = strcasestr(sql, sql_handler_map[i].prefix))) {
|
|
|
|
if(pos == sql) {
|
|
|
|
return sql_handler_map[i].func(con, sql);
|
|
|
|
}
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
network_mysqld_con_send_error(con->client, C("request error, \"select * from help\" for usage"));
|
|
|
|
return PROXY_SEND_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gets called after a query has been read
|
|
|
|
*/
|
2018-03-20 14:19:44 +08:00
|
|
|
NETWORK_MYSQLD_PLUGIN_PROTO(server_read_query)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
network_socket *recv_sock;
|
|
|
|
network_mysqld_stmt_ret ret;
|
|
|
|
|
|
|
|
gettimeofday(&(con->req_recv_time), NULL);
|
|
|
|
|
|
|
|
recv_sock = con->client;
|
|
|
|
|
|
|
|
if (recv_sock->recv_queue->chunks->length != 1) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_message("%s: client-recv-queue-len = %d", G_STRLOC, recv_sock->recv_queue->chunks->length);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = admin_process_query(con);
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case PROXY_NO_DECISION:
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_error(con->client, C("request error, \"select * from help\" for usage"));
|
2018-03-06 14:00:39 +08:00
|
|
|
con->state = ST_SEND_QUERY_RESULT;
|
|
|
|
break;
|
|
|
|
case PROXY_SEND_RESULT:
|
|
|
|
con->state = ST_SEND_QUERY_RESULT;
|
|
|
|
break;
|
|
|
|
default:
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_con_send_error(con->client, C("need a resultset + proxy.PROXY_SEND_RESULT, got something else"));
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
con->state = ST_SEND_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_free(g_queue_pop_tail(recv_sock->recv_queue->chunks), TRUE);
|
|
|
|
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-06-01 17:06:50 +08:00
|
|
|
NETWORK_MYSQLD_PLUGIN_PROTO(proxy_timeout)
|
|
|
|
{
|
2018-06-04 09:37:52 +08:00
|
|
|
con->prev_state = con->state;
|
|
|
|
con->state = ST_SEND_ERROR;
|
2018-06-01 17:06:50 +08:00
|
|
|
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
/**
|
|
|
|
* cleanup the admin specific data on the current connection
|
|
|
|
*
|
|
|
|
* @return NETWORK_SOCKET_SUCCESS
|
|
|
|
*/
|
2018-03-20 14:19:44 +08:00
|
|
|
NETWORK_MYSQLD_PLUGIN_PROTO(admin_disconnect_client)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
/* private state is not used in admin-plugin */
|
|
|
|
con->plugin_con_state = NULL;
|
|
|
|
|
|
|
|
return NETWORK_SOCKET_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static int
|
|
|
|
network_mysqld_server_connection_init(network_mysqld_con *con)
|
|
|
|
{
|
|
|
|
con->plugins.con_init = server_con_init;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
con->plugins.con_read_auth = server_read_auth;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
con->plugins.con_read_query = server_read_query;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-06-01 17:06:50 +08:00
|
|
|
con->plugins.con_timeout = proxy_timeout;
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
con->plugins.con_cleanup = admin_disconnect_client;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
chassis_plugin_config *config;
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static chassis_plugin_config *
|
|
|
|
network_mysqld_admin_plugin_new(void)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
config = g_new0(chassis_plugin_config, 1);
|
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
network_mysqld_admin_plugin_free(chassis *chas, chassis_plugin_config *config)
|
|
|
|
{
|
2018-03-06 14:00:39 +08:00
|
|
|
if (config->listen_con) {
|
|
|
|
/* the socket will be freed by network_mysqld_free() */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config->address) {
|
|
|
|
chassis_config_unregister_service(chas->config_manager, config->address);
|
|
|
|
g_free(config->address);
|
|
|
|
}
|
|
|
|
if (g_sampling_timer) {
|
|
|
|
evtimer_del(g_sampling_timer);
|
|
|
|
g_free(g_sampling_timer);
|
|
|
|
g_sampling_timer = NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
if (config->admin_username)
|
|
|
|
g_free(config->admin_username);
|
|
|
|
if (config->admin_password)
|
|
|
|
g_free(config->admin_password);
|
|
|
|
if (config->allow_ip)
|
|
|
|
g_free(config->allow_ip);
|
|
|
|
if (config->allow_ip_table)
|
|
|
|
g_hash_table_destroy(config->allow_ip_table);
|
|
|
|
if (config->deny_ip)
|
|
|
|
g_free(config->deny_ip);
|
|
|
|
if (config->deny_ip_table)
|
|
|
|
g_hash_table_destroy(config->deny_ip_table);
|
2018-03-06 14:00:39 +08:00
|
|
|
g_free(config);
|
|
|
|
}
|
|
|
|
|
2018-05-02 09:17:08 +08:00
|
|
|
gchar*
|
|
|
|
show_admin_address(gpointer param) {
|
|
|
|
struct external_param *opt_param = (struct external_param *)param;
|
|
|
|
gint opt_type = opt_param->opt_type;
|
|
|
|
if(CAN_SHOW_OPTS_PROPERTY(opt_type)) {
|
|
|
|
return g_strdup_printf("%s", config->address != NULL ? config->address: "NULL");
|
|
|
|
}
|
|
|
|
if(CAN_SAVE_OPTS_PROPERTY(opt_type)) {
|
|
|
|
if(config->address != NULL) {
|
|
|
|
return g_strdup_printf("%s", config->address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar*
|
|
|
|
show_admin_username(gpointer param) {
|
|
|
|
struct external_param *opt_param = (struct external_param *)param;
|
|
|
|
gint opt_type = opt_param->opt_type;
|
|
|
|
if(CAN_SHOW_OPTS_PROPERTY(opt_type)) {
|
|
|
|
return g_strdup_printf("%s", config->admin_username != NULL ? config->admin_username: "NULL");
|
|
|
|
}
|
|
|
|
if(CAN_SAVE_OPTS_PROPERTY(opt_type)) {
|
|
|
|
if(config->admin_username != NULL) {
|
|
|
|
return g_strdup_printf("%s", config->admin_username);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar*
|
|
|
|
show_admin_password(gpointer param) {
|
|
|
|
struct external_param *opt_param = (struct external_param *)param;
|
|
|
|
gint opt_type = opt_param->opt_type;
|
|
|
|
if(CAN_SHOW_OPTS_PROPERTY(opt_type)) {
|
|
|
|
return g_strdup_printf("%s", config->admin_password != NULL ? config->admin_password: "NULL");
|
|
|
|
}
|
|
|
|
if(CAN_SAVE_OPTS_PROPERTY(opt_type)) {
|
|
|
|
if(config->admin_password != NULL) {
|
|
|
|
return g_strdup_printf("%s", config->admin_password);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar*
|
|
|
|
show_admin_allow_ip(gpointer param) {
|
|
|
|
struct external_param *opt_param = (struct external_param *)param;
|
|
|
|
gchar *ret = NULL;
|
|
|
|
gint opt_type = opt_param->opt_type;
|
|
|
|
if(CAN_SAVE_OPTS_PROPERTY(opt_type)) {
|
|
|
|
GString *free_str = g_string_new(NULL);
|
|
|
|
GList *free_list = NULL;
|
|
|
|
if(config && config->allow_ip_table && g_hash_table_size(config->allow_ip_table)) {
|
|
|
|
free_list = g_hash_table_get_keys(config->allow_ip_table);
|
|
|
|
GList *it = NULL;
|
|
|
|
for(it = free_list; it; it=it->next) {
|
|
|
|
free_str = g_string_append(free_str, it->data);
|
|
|
|
free_str = g_string_append(free_str, ",");
|
|
|
|
}
|
|
|
|
if(free_str->len) {
|
|
|
|
free_str->str[free_str->len - 1] = '\0';
|
|
|
|
ret = g_strdup(free_str->str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(free_str) {
|
|
|
|
g_string_free(free_str, TRUE);
|
|
|
|
}
|
|
|
|
if(free_list) {
|
|
|
|
g_list_free(free_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar*
|
|
|
|
show_admin_deny_ip(gpointer param) {
|
|
|
|
struct external_param *opt_param = (struct external_param *)param;
|
|
|
|
gchar *ret = NULL;
|
|
|
|
gint opt_type = opt_param->opt_type;
|
|
|
|
if(CAN_SAVE_OPTS_PROPERTY(opt_type)) {
|
|
|
|
GString *free_str = g_string_new(NULL);
|
|
|
|
GList *free_list = NULL;
|
|
|
|
if(config && config->deny_ip_table && g_hash_table_size(config->deny_ip_table)) {
|
|
|
|
free_list = g_hash_table_get_keys(config->deny_ip_table);
|
|
|
|
GList *it = NULL;
|
|
|
|
for(it = free_list; it; it=it->next) {
|
|
|
|
free_str = g_string_append(free_str, it->data);
|
|
|
|
free_str = g_string_append(free_str, ",");
|
|
|
|
}
|
|
|
|
if(free_str->len) {
|
|
|
|
free_str->str[free_str->len - 1] = '\0';
|
|
|
|
ret = g_strdup(free_str->str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(free_str) {
|
|
|
|
g_string_free(free_str, TRUE);
|
|
|
|
}
|
|
|
|
if(free_list) {
|
|
|
|
g_list_free(free_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
/**
|
|
|
|
* add the proxy specific options to the cmdline interface
|
|
|
|
*/
|
|
|
|
static GList *
|
|
|
|
network_mysqld_admin_plugin_get_options(chassis_plugin_config *config)
|
|
|
|
{
|
2018-03-20 14:19:44 +08:00
|
|
|
chassis_options_t opts = { 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
chassis_options_add(&opts, "admin-address",
|
2018-03-20 14:19:44 +08:00
|
|
|
0, 0, OPTION_ARG_STRING, &(config->address),
|
2018-05-02 09:17:08 +08:00
|
|
|
"listening address:port of the admin-server (default: :4041)", "<host:port>",
|
|
|
|
NULL, show_admin_address, SHOW_OPTS_PROPERTY|SAVE_OPTS_PROPERTY);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
chassis_options_add(&opts, "admin-username",
|
2018-05-02 09:17:08 +08:00
|
|
|
0, 0, OPTION_ARG_STRING, &(config->admin_username), "username to allow to log in", "<string>",
|
|
|
|
NULL, show_admin_username, SHOW_OPTS_PROPERTY|SAVE_OPTS_PROPERTY);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
chassis_options_add(&opts, "admin-password",
|
2018-05-02 09:17:08 +08:00
|
|
|
0, 0, OPTION_ARG_STRING, &(config->admin_password), "password to allow to log in", "<string>",
|
|
|
|
NULL, show_admin_password, SHOW_OPTS_PROPERTY|SAVE_OPTS_PROPERTY);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
chassis_options_add(&opts, "admin-allow-ip",
|
2018-03-20 14:19:44 +08:00
|
|
|
0, 0, OPTION_ARG_STRING, &(config->allow_ip),
|
2018-05-02 09:17:08 +08:00
|
|
|
"ip address allowed to connect to admin", "<string>",
|
|
|
|
NULL, show_admin_allow_ip, SAVE_OPTS_PROPERTY);
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis_options_add(&opts, "admin-deny-ip",
|
2018-03-20 14:19:44 +08:00
|
|
|
0, 0, OPTION_ARG_STRING, &(config->deny_ip),
|
2018-05-02 09:17:08 +08:00
|
|
|
"ip address denyed to connect to admin", "<string>",
|
|
|
|
NULL, show_admin_deny_ip, SAVE_OPTS_PROPERTY);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
return opts.options;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ring buffer from: https://github.com/AndersKaloer/Ring-Buffer */
|
2018-03-20 14:19:44 +08:00
|
|
|
#define RING_BUFFER_SIZE 128 /* must be power of 2, !! index [0, 126] !! */
|
2018-03-06 14:00:39 +08:00
|
|
|
#define RING_BUFFER_MASK (RING_BUFFER_SIZE-1)
|
2018-03-19 15:59:07 +08:00
|
|
|
struct ring_buffer_t {
|
2018-03-06 14:00:39 +08:00
|
|
|
int head;
|
|
|
|
int tail;
|
|
|
|
guint64 buffer[RING_BUFFER_SIZE];
|
2018-03-19 15:59:07 +08:00
|
|
|
};
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
ring_buffer_add(struct ring_buffer_t *buffer, guint64 data)
|
|
|
|
{
|
|
|
|
if (((buffer->head - buffer->tail) & RING_BUFFER_MASK) == RING_BUFFER_MASK)
|
|
|
|
buffer->tail = ((buffer->tail + 1) & RING_BUFFER_MASK);
|
|
|
|
buffer->buffer[buffer->head] = data;
|
|
|
|
buffer->head = ((buffer->head + 1) & RING_BUFFER_MASK);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static guint64
|
|
|
|
ring_buffer_get(struct ring_buffer_t *buffer, int index)
|
|
|
|
{
|
|
|
|
if (index >= ((buffer->head - buffer->tail) & RING_BUFFER_MASK))
|
|
|
|
return 0;
|
|
|
|
int data_index = ((buffer->tail + index) & RING_BUFFER_MASK);
|
|
|
|
return buffer->buffer[data_index];
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static struct ring_buffer_t g_sql_count = { 126, 0 };
|
|
|
|
static struct ring_buffer_t g_trx_count = { 126, 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
calc_qps_average(char *buf, int len)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
const int MOST_RECENT = 126;
|
|
|
|
guint64 c_now = ring_buffer_get(&g_sql_count, MOST_RECENT);
|
|
|
|
guint64 c_1min = ring_buffer_get(&g_sql_count, MOST_RECENT - 6);
|
2018-03-20 14:19:44 +08:00
|
|
|
guint64 c_5min = ring_buffer_get(&g_sql_count, MOST_RECENT - 6 * 5);
|
|
|
|
guint64 c_15min = ring_buffer_get(&g_sql_count, MOST_RECENT - 6 * 15);
|
2018-03-06 14:00:39 +08:00
|
|
|
snprintf(buf, len, "%.2f, %.2f, %.2f",
|
2018-03-20 14:19:44 +08:00
|
|
|
(c_now - c_1min) / 60.0, (c_now - c_5min) / 300.0, (c_now - c_15min) / 900.0);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
calc_tps_average(char *buf, int len)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
const int MOST_RECENT = 126;
|
|
|
|
guint64 c_now = ring_buffer_get(&g_trx_count, MOST_RECENT);
|
|
|
|
guint64 c_1min = ring_buffer_get(&g_trx_count, MOST_RECENT - 6);
|
2018-03-20 14:19:44 +08:00
|
|
|
guint64 c_5min = ring_buffer_get(&g_trx_count, MOST_RECENT - 6 * 5);
|
|
|
|
guint64 c_15min = ring_buffer_get(&g_trx_count, MOST_RECENT - 6 * 15);
|
2018-03-06 14:00:39 +08:00
|
|
|
snprintf(buf, len, "%.2f, %.2f, %.2f",
|
2018-03-20 14:19:44 +08:00
|
|
|
(c_now - c_1min) / 60.0, (c_now - c_5min) / 300.0, (c_now - c_15min) / 900.0);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct _timer_func_arg_t {
|
|
|
|
chassis *chas;
|
|
|
|
struct event *ev;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* sample interval is 10-sec, 127 samples takes about 21-min */
|
2018-03-20 14:19:44 +08:00
|
|
|
static void
|
|
|
|
sql_stats_sampling_func(int fd, short what, void *arg)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
chassis *chas = arg;
|
|
|
|
|
|
|
|
query_stats_t *stats = &(chas->query_stats);
|
|
|
|
ring_buffer_add(&g_sql_count, stats->client_query.ro + stats->client_query.rw);
|
|
|
|
ring_buffer_add(&g_trx_count, stats->xa_count);
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
static struct timeval ten_sec = { 10, 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
/* EV_PERSIST not work for libevent1.4, re-activate timer each time */
|
|
|
|
chassis_event_add_with_timeout(chas, g_sampling_timer, &ten_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* init the plugin with the parsed config
|
|
|
|
*/
|
|
|
|
static int
|
2018-03-20 14:19:44 +08:00
|
|
|
network_mysqld_admin_plugin_apply_config(chassis *chas, chassis_plugin_config *config)
|
2018-03-06 14:00:39 +08:00
|
|
|
{
|
|
|
|
network_mysqld_con *con;
|
|
|
|
network_socket *listen_sock;
|
|
|
|
|
|
|
|
if (!config->address) {
|
|
|
|
config->address = g_strdup(":4041");
|
|
|
|
} else {
|
|
|
|
chas->proxy_address = config->address;
|
|
|
|
g_message("set proxy address for chassis:%s", config->address);
|
|
|
|
}
|
2018-03-20 14:19:44 +08:00
|
|
|
|
2018-03-06 14:00:39 +08:00
|
|
|
if (!config->admin_username) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_critical("%s: --admin-username needs to be set", G_STRLOC);
|
2018-03-06 14:00:39 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!config->admin_password) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_critical("%s: --admin-password needs to be set", G_STRLOC);
|
2018-03-06 14:00:39 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!g_strcmp0(config->admin_password, "")) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_critical("%s: --admin-password cannot be empty", G_STRLOC);
|
2018-03-06 14:00:39 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_message("%s:admin-server listening on port", G_STRLOC);
|
|
|
|
GHashTable *allow_ip_table = NULL;
|
|
|
|
if (config->allow_ip) {
|
|
|
|
allow_ip_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
char **ip_arr = g_strsplit(config->allow_ip, ",", -1);
|
|
|
|
int i;
|
|
|
|
for (i = 0; ip_arr[i]; i++) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(allow_ip_table, g_strdup(ip_arr[i]), (void *)TRUE);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
g_strfreev(ip_arr);
|
|
|
|
}
|
|
|
|
config->allow_ip_table = allow_ip_table;
|
|
|
|
|
|
|
|
GHashTable *deny_ip_table = NULL;
|
|
|
|
if (config->deny_ip) {
|
|
|
|
deny_ip_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
char **ip_arr = g_strsplit(config->deny_ip, ",", -1);
|
|
|
|
int i;
|
|
|
|
for (i = 0; ip_arr[i]; i++) {
|
2018-03-20 14:19:44 +08:00
|
|
|
g_hash_table_insert(deny_ip_table, g_strdup(ip_arr[i]), (void *)TRUE);
|
2018-03-06 14:00:39 +08:00
|
|
|
}
|
|
|
|
g_strfreev(ip_arr);
|
|
|
|
}
|
|
|
|
config->deny_ip_table = deny_ip_table;
|
|
|
|
|
|
|
|
g_message("%s:admin-server listening on port", G_STRLOC);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create a connection handle for the listen socket
|
|
|
|
*/
|
|
|
|
con = network_mysqld_con_new();
|
|
|
|
network_mysqld_add_connection(chas, con, TRUE);
|
|
|
|
con->config = config;
|
|
|
|
|
|
|
|
config->listen_con = con;
|
|
|
|
|
|
|
|
listen_sock = network_socket_new();
|
|
|
|
con->server = listen_sock;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set the plugin hooks as we want to apply them to the new
|
|
|
|
* connections too later
|
|
|
|
*/
|
|
|
|
network_mysqld_server_connection_init(con);
|
|
|
|
|
|
|
|
g_message("%s:admin-server listening on port:%s", G_STRLOC, config->address);
|
|
|
|
/* FIXME: network_socket_set_address() */
|
2018-03-20 14:19:44 +08:00
|
|
|
if (0 != network_address_set_address(listen_sock->dst, config->address)) {
|
2018-03-06 14:00:39 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_message("%s:admin-server listening on port", G_STRLOC);
|
|
|
|
/* FIXME: network_socket_bind() */
|
|
|
|
if (0 != network_socket_bind(listen_sock)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
g_message("admin-server listening on port %s", config->address);
|
|
|
|
|
|
|
|
/* set config->has_shard_plugin */
|
|
|
|
config->has_shard_plugin = has_shard_plugin(chas->modules);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* call network_mysqld_con_accept() with this connection when we are done
|
|
|
|
*/
|
2018-03-20 14:19:44 +08:00
|
|
|
event_set(&(listen_sock->event), listen_sock->fd, EV_READ | EV_PERSIST, network_mysqld_con_accept, con);
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis_event_add(chas, &(listen_sock->event));
|
|
|
|
|
|
|
|
chassis_config_register_service(chas->config_manager, config->address, "admin");
|
|
|
|
|
|
|
|
/* EV_PERSIST not work for libevent 1.4 */
|
|
|
|
g_sampling_timer = g_new0(struct event, 1);
|
|
|
|
evtimer_set(g_sampling_timer, sql_stats_sampling_func, chas);
|
2018-03-20 14:19:44 +08:00
|
|
|
struct timeval ten_sec = { 10, 0 };
|
2018-03-06 14:00:39 +08:00
|
|
|
chassis_event_add_with_timeout(chas, g_sampling_timer, &ten_sec);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
G_MODULE_EXPORT int
|
|
|
|
plugin_init(chassis_plugin *p)
|
|
|
|
{
|
|
|
|
p->magic = CHASSIS_PLUGIN_MAGIC;
|
|
|
|
p->name = g_strdup("admin");
|
|
|
|
p->version = g_strdup(PLUGIN_VERSION);
|
2018-03-06 14:00:39 +08:00
|
|
|
|
2018-03-20 14:19:44 +08:00
|
|
|
p->init = network_mysqld_admin_plugin_new;
|
|
|
|
p->get_options = network_mysqld_admin_plugin_get_options;
|
2018-03-06 14:00:39 +08:00
|
|
|
p->apply_config = network_mysqld_admin_plugin_apply_config;
|
2018-03-20 14:19:44 +08:00
|
|
|
p->destroy = network_mysqld_admin_plugin_free;
|
2018-03-06 14:00:39 +08:00
|
|
|
|
|
|
|
/* For allow_ip configs */
|
|
|
|
p->allow_ip_get = network_mysqld_admin_plugin_allow_ip_get;
|
|
|
|
p->allow_ip_add = network_mysqld_admin_plugin_allow_ip_add;
|
|
|
|
p->allow_ip_del = network_mysqld_admin_plugin_allow_ip_del;
|
|
|
|
|
|
|
|
/* For deny_ip configs */
|
|
|
|
p->deny_ip_get = network_mysqld_admin_plugin_deny_ip_get;
|
|
|
|
p->deny_ip_add = network_mysqld_admin_plugin_deny_ip_add;
|
|
|
|
p->deny_ip_del = network_mysqld_admin_plugin_deny_ip_del;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|