From 811477e176b07dbcd9c5126fbeaf01fb93c89824 Mon Sep 17 00:00:00 2001 From: jesperpedersen Date: Thu, 17 Sep 2020 10:16:13 -0400 Subject: [PATCH] [#108] switch-to support --- doc/GETTING_STARTED.md | 1 + doc/man/pgagroal-cli.1.rst | 3 +++ src/cli.c | 26 +++++++++++++++++++++++++ src/include/management.h | 11 +++++++++++ src/include/server.h | 9 +++++++++ src/libpgagroal/management.c | 30 +++++++++++++++++++++++++++++ src/libpgagroal/remote.c | 1 + src/libpgagroal/server.c | 37 ++++++++++++++++++++++++++++++++++++ src/main.c | 11 +++++++++++ 9 files changed, 129 insertions(+) diff --git a/doc/GETTING_STARTED.md b/doc/GETTING_STARTED.md index 40c7a99a..18e50756 100644 --- a/doc/GETTING_STARTED.md +++ b/doc/GETTING_STARTED.md @@ -149,6 +149,7 @@ Commands: cancel-shutdown Cancel the graceful shutdown status Status of pgagroal details Detailed status of pgagroal + switch-to Switch to another primary reset Reset the Prometheus statistics reset-server Reset the state of a server ``` diff --git a/doc/man/pgagroal-cli.1.rst b/doc/man/pgagroal-cli.1.rst index d8e74778..8186bf1a 100644 --- a/doc/man/pgagroal-cli.1.rst +++ b/doc/man/pgagroal-cli.1.rst @@ -83,6 +83,9 @@ status details Detailed status of pgagroal +switch-to + Switch to another primary + reset Reset the Prometheus statistics diff --git a/src/cli.c b/src/cli.c index ed0d0cac..48792789 100644 --- a/src/cli.c +++ b/src/cli.c @@ -63,6 +63,7 @@ #define ACTION_DISABLEDB 9 #define ACTION_RESET 10 #define ACTION_RESET_SERVER 11 +#define ACTION_SWITCH_TO 12 static int flush(SSL* ssl, int socket, int32_t mode); static int enabledb(SSL* ssl, int socket, char* database); @@ -75,6 +76,7 @@ static int details(SSL* ssl, int socket); static int isalive(SSL* ssl, int socket); static int reset(SSL* ssl, int socket); static int reset_server(SSL* ssl, int socket, char* server); +static int switch_to(SSL* ssl, int socket, char* server); static void @@ -116,6 +118,7 @@ usage() printf(" cancel-shutdown Cancel the graceful shutdown\n"); printf(" status Status of pgagroal\n"); printf(" details Detailed status of pgagroal\n"); + printf(" switch-to Switch to another primary\n"); printf(" reset Reset the Prometheus statistics\n"); printf(" reset-server Reset the state of a server\n"); printf("\n"); @@ -322,6 +325,14 @@ main(int argc, char **argv) server = argv[argc - 1]; } } + else if (!strcmp("switch-to", argv[argc - 1]) || !strcmp("switch-to", argv[argc - 2])) + { + if (!strcmp("switch-to", argv[argc - 2])) + { + action = ACTION_SWITCH_TO; + server = argv[argc - 1]; + } + } if (action != ACTION_UNKNOWN) { @@ -440,6 +451,10 @@ main(int argc, char **argv) { exit_code = reset_server(s_ssl, socket, server); } + else if (action == ACTION_SWITCH_TO) + { + exit_code = switch_to(s_ssl, socket, server); + } } done: @@ -639,3 +654,14 @@ reset_server(SSL* ssl, int socket, char* server) return 0; } + +static int +switch_to(SSL* ssl, int socket, char* server) +{ + if (pgagroal_management_switch_to(ssl, socket, server)) + { + return 1; + } + + return 0; +} diff --git a/src/include/management.h b/src/include/management.h index 49d71585..0dedcb87 100644 --- a/src/include/management.h +++ b/src/include/management.h @@ -56,6 +56,7 @@ extern "C" { #define MANAGEMENT_RESET_SERVER 14 #define MANAGEMENT_CLIENT_DONE 15 #define MANAGEMENT_CLIENT_FD 16 +#define MANAGEMENT_SWITCH_TO 17 /** * Read the management header @@ -282,6 +283,16 @@ pgagroal_management_client_done(void* shmem, pid_t pid); int pgagroal_management_client_fd(void* shmem, int32_t slot, pid_t pid); +/** + * Management operation: Switch to + * @param ssl The SSL connection + * @param socket The socket + * @param server The server + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_management_switch_to(SSL* ssl, int socket, char* server); + #ifdef __cplusplus } #endif diff --git a/src/include/server.h b/src/include/server.h index 18ab11e0..1c73b04f 100644 --- a/src/include/server.h +++ b/src/include/server.h @@ -91,6 +91,15 @@ pgagroal_server_force_failover(void* shmem, int server); int pgagroal_server_reset(void* shmem, char* server); +/** + * Switch server + * @param shmem The shared memory segment + * @param server The server + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_server_switch(void* shmem, char* server); + #ifdef __cplusplus } #endif diff --git a/src/libpgagroal/management.c b/src/libpgagroal/management.c index c379e3a7..1e88633c 100644 --- a/src/libpgagroal/management.c +++ b/src/libpgagroal/management.c @@ -182,6 +182,7 @@ pgagroal_management_read_payload(int socket, signed char id, int* payload_i, cha *payload_s = s; break; case MANAGEMENT_RESET_SERVER: + case MANAGEMENT_SWITCH_TO: s = malloc(MISC_LENGTH); memset(s, 0, MISC_LENGTH); if (read_complete(NULL, socket, s, MISC_LENGTH)) @@ -1119,6 +1120,35 @@ pgagroal_management_client_fd(void* shmem, int32_t slot, pid_t pid) return 1; } +int +pgagroal_management_switch_to(SSL* ssl, int fd, char* server) +{ + char name[MISC_LENGTH]; + + if (write_header(ssl, fd, MANAGEMENT_SWITCH_TO, -1)) + { + ZF_LOGW("pgagroal_management_switch_to: write: %d", fd); + errno = 0; + goto error; + } + + memset(&name[0], 0, MISC_LENGTH); + memcpy(&name[0], server, strlen(server)); + + if (write_complete(ssl, fd, &name[0], sizeof(name))) + { + ZF_LOGW("pgagroal_management_switch_to: write: %d %s", fd, strerror(errno)); + errno = 0; + goto error; + } + + return 0; + +error: + + return 1; +} + static int read_complete(SSL* ssl, int socket, void* buf, size_t size) { diff --git a/src/libpgagroal/remote.c b/src/libpgagroal/remote.c index 2cea0429..255dc01f 100644 --- a/src/libpgagroal/remote.c +++ b/src/libpgagroal/remote.c @@ -113,6 +113,7 @@ pgagroal_remote_management(int client_fd, char* address, void* shmem, void* pipe break; case MANAGEMENT_FLUSH: case MANAGEMENT_RESET_SERVER: + case MANAGEMENT_SWITCH_TO: status = pgagroal_read_timeout_message(client_ssl, client_fd, config->authentication_timeout, &msg); if (status != MESSAGE_STATUS_OK) { diff --git a/src/libpgagroal/server.c b/src/libpgagroal/server.c index ac5e4131..aaa6eec7 100644 --- a/src/libpgagroal/server.c +++ b/src/libpgagroal/server.c @@ -289,6 +289,43 @@ pgagroal_server_reset(void* shmem, char* server) return 1; } +int +pgagroal_server_switch(void* shmem, char* server) +{ + int old_primary; + int new_primary; + signed char state; + struct configuration* config = NULL; + + config = (struct configuration*)shmem; + + old_primary = -1; + new_primary = -1; + + for (int i = 0; i < config->number_of_servers; i++) + { + state = atomic_load(&config->servers[i].state); + + if (state == SERVER_PRIMARY) + { + old_primary = i; + } + else if (!strcmp(config->servers[i].name, server)) + { + new_primary = i; + } + } + + if (old_primary != -1 && new_primary != -1) + { + atomic_store(&config->servers[old_primary].state, SERVER_FAILED); + atomic_store(&config->servers[new_primary].state, SERVER_PRIMARY); + return 0; + } + + return 1; +} + static int failover(void* shmem, int old_primary) { diff --git a/src/main.c b/src/main.c index 2871441d..deba8d6c 100644 --- a/src/main.c +++ b/src/main.c @@ -1217,6 +1217,17 @@ accept_mgt_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) remove_client(p); } break; + case MANAGEMENT_SWITCH_TO: + ZF_LOGD("pgagroal: Management switch to"); + if (!pgagroal_server_switch(ai->shmem, payload_s)) + { + if (!fork()) + { + pgagroal_flush(ai->shmem, FLUSH_GRACEFULLY); + } + pgagroal_prometheus_failed_servers(ai->shmem); + } + break; default: ZF_LOGD("pgagroal: Unknown management id: %d", id); break;