Skip to content

Commit e82e3e1

Browse files
committed
Implement on_primary hooks.
This allows users of pg_auto_failover to setup their own scripts/actions to complement a failover. The hooks are run in a process that is separate from the main FSM, so as to prevent the system from making progress. As a result, it's not possible for the hooks to change how things are implemented in pg_auto_failover itself. The hook system also allows running a user-defined "service", which is a long running process or a deamon that belongs to pg_autoctl process tree. - [x] Implement a new internal service for running user-defined hooks - [ ] Implement pg_autoctl enable|disable run-hooks - [ ] Implement pg_autoctl create listener - [ ] Implement support for running script/commands (man system) - [ ] Add unit testing support for user-defined hooks - [ ] Document the new hook system, including tutorial - [ ] Add documentation examples covering pgbouncer as a hooked system
1 parent 11bd982 commit e82e3e1

File tree

8 files changed

+625
-0
lines changed

8 files changed

+625
-0
lines changed

src/bin/pg_autoctl/cli_do_service.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "service_keeper.h"
2828
#include "service_monitor.h"
2929
#include "service_postgres_ctl.h"
30+
#include "service_run_hooks.h"
3031
#include "signals.h"
3132
#include "supervisor.h"
3233

@@ -39,14 +40,17 @@ static void cli_do_service_getpid(const char *serviceName);
3940
static void cli_do_service_getpid_postgres(int argc, char **argv);
4041
static void cli_do_service_getpid_listener(int argc, char **argv);
4142
static void cli_do_service_getpid_node_active(int argc, char **argv);
43+
static void cli_do_service_getpid_run_hooks(int argc, char **argv);
4244

4345
static void cli_do_service_restart(const char *serviceName);
4446
static void cli_do_service_restart_postgres(int argc, char **argv);
4547
static void cli_do_service_restart_listener(int argc, char **argv);
4648
static void cli_do_service_restart_node_active(int argc, char **argv);
49+
static void cli_do_service_restart_run_hooks(int argc, char **argv);
4750

4851
static void cli_do_service_monitor_listener(int argc, char **argv);
4952
static void cli_do_service_node_active(int argc, char **argv);
53+
static void cli_do_service_run_hooks(int argc, char **argv);
5054

5155
CommandLine service_pgcontroller =
5256
make_command("pgcontroller",
@@ -80,6 +84,14 @@ CommandLine service_node_active =
8084
cli_getopt_pgdata,
8185
cli_do_service_node_active);
8286

87+
CommandLine service_run_hooks =
88+
make_command("run-hooks",
89+
"pg_autoctl service that run hooks (scripts)",
90+
CLI_PGDATA_USAGE,
91+
CLI_PGDATA_OPTION,
92+
cli_getopt_pgdata,
93+
cli_do_service_run_hooks);
94+
8395
CommandLine service_getpid_postgres =
8496
make_command("postgres",
8597
"Get the pid of the pg_autoctl postgres controller service",
@@ -104,10 +116,19 @@ CommandLine service_getpid_node_active =
104116
cli_getopt_pgdata,
105117
cli_do_service_getpid_node_active);
106118

119+
CommandLine service_getpid_run_hooks =
120+
make_command("run-hooks",
121+
"Get the pid of the pg_autoctl run-hooks service",
122+
CLI_PGDATA_USAGE,
123+
CLI_PGDATA_OPTION,
124+
cli_getopt_pgdata,
125+
cli_do_service_getpid_run_hooks);
126+
107127
static CommandLine *service_getpid[] = {
108128
&service_getpid_postgres,
109129
&service_getpid_listener,
110130
&service_getpid_node_active,
131+
&service_getpid_run_hooks,
111132
NULL
112133
};
113134

@@ -141,10 +162,19 @@ CommandLine service_restart_node_active =
141162
cli_getopt_pgdata,
142163
cli_do_service_restart_node_active);
143164

165+
CommandLine service_restart_run_hooks =
166+
make_command("run-hooks",
167+
"Restart the pg_autoctl run-hooks service",
168+
CLI_PGDATA_USAGE,
169+
CLI_PGDATA_OPTION,
170+
cli_getopt_pgdata,
171+
cli_do_service_restart_run_hooks);
172+
144173
static CommandLine *service_restart[] = {
145174
&service_restart_postgres,
146175
&service_restart_listener,
147176
&service_restart_node_active,
177+
&service_restart_run_hooks,
148178
NULL
149179
};
150180

@@ -160,6 +190,7 @@ static CommandLine *service[] = {
160190
&service_postgres,
161191
&service_monitor_listener,
162192
&service_node_active,
193+
&service_run_hooks,
163194
NULL
164195
};
165196

@@ -255,6 +286,16 @@ cli_do_service_getpid_node_active(int argc, char **argv)
255286
}
256287

257288

289+
/*
290+
* cli_do_service_getpid_node_active gets the postgres service pid.
291+
*/
292+
static void
293+
cli_do_service_getpid_run_hooks(int argc, char **argv)
294+
{
295+
(void) cli_do_service_getpid(SERVICE_NAME_RUN_HOOKS);
296+
}
297+
298+
258299
/*
259300
* cli_do_service_restart sends the TERM signal to the given serviceName, which
260301
* is known to have the restart policy RP_PERMANENT (that's hard-coded). As a
@@ -352,6 +393,18 @@ cli_do_service_restart_node_active(int argc, char **argv)
352393
}
353394

354395

396+
/*
397+
* cli_do_service_restart_run_hooks sends the TERM signal to the run-hooks,
398+
* which is known to have the restart policy RP_PERMANENT (that's hard-coded).
399+
* As a consequence the supervisor will restart the service.
400+
*/
401+
static void
402+
cli_do_service_restart_run_hooks(int argc, char **argv)
403+
{
404+
(void) cli_do_service_restart(SERVICE_NAME_RUN_HOOKS);
405+
}
406+
407+
355408
/*
356409
* cli_do_pgcontroller starts the process controller service within a supervision
357410
* tree. It is used for debug purposes only. When using this entry point we
@@ -588,3 +641,44 @@ cli_do_service_node_active(int argc, char **argv)
588641
/* Start the node_active() protocol client */
589642
(void) keeper_node_active_loop(&keeper, ppid);
590643
}
644+
645+
646+
/*
647+
* cli_do_service_run_hooks starts the run-hooks service.
648+
*/
649+
static void
650+
cli_do_service_run_hooks(int argc, char **argv)
651+
{
652+
Keeper keeper = { 0 };
653+
654+
pid_t ppid = getppid();
655+
656+
bool exitOnQuit = true;
657+
658+
keeper.config = keeperOptions;
659+
660+
/* Establish a handler for signals. */
661+
(void) set_signal_handlers(exitOnQuit);
662+
663+
/* display a user-friendly process name */
664+
(void) set_ps_title("pg_autoctl: run-hooks");
665+
666+
/* Prepare our Keeper and KeeperConfig from the CLI options */
667+
if (!service_run_hooks_init(&keeper))
668+
{
669+
log_fatal("Failed to initialize the run-hooks service, "
670+
"see above for details");
671+
exit(EXIT_CODE_INTERNAL_ERROR);
672+
}
673+
674+
/* create the service pidfile */
675+
if (!create_service_pidfile(keeper.config.pathnames.pid,
676+
SERVICE_NAME_RUN_HOOKS))
677+
{
678+
/* errors have already been logged */
679+
exit(EXIT_CODE_INTERNAL_ERROR);
680+
}
681+
682+
/* Start the node_active() protocol client */
683+
(void) service_run_hooks_loop(&keeper, ppid);
684+
}

src/bin/pg_autoctl/keeper_config.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@
143143
make_strbuf_option("replication", "backup_directory", NULL, \
144144
false, MAXPGPATH, config->backupDirectory)
145145

146+
#define OPTION_HOOKS_ACTIVE(config) \
147+
make_int_option_default("hooks", "active", NULL, \
148+
false, &(config->enableHooks), 0)
149+
150+
#define OPTION_HOOKS_ON_PRIMARY_CMD(config) \
151+
make_strbuf_option("hooks", "on_primary", NULL, \
152+
false, BUFSIZE, config->onPrimaryCmd)
153+
154+
#define OPTION_HOOKS_SERVICE_START_CMD(config) \
155+
make_strbuf_option("hooks", "service", NULL, \
156+
false, BUFSIZE, config->serviceStartCmd)
157+
146158
#define OPTION_TIMEOUT_NETWORK_PARTITION(config) \
147159
make_int_option_default("timeout", "network_partition_timeout", \
148160
NULL, false, \
@@ -241,6 +253,9 @@
241253
OPTION_REPLICATION_MAXIMUM_BACKUP_RATE(config), \
242254
OPTION_REPLICATION_BACKUP_DIR(config), \
243255
OPTION_REPLICATION_PASSWORD(config), \
256+
OPTION_HOOKS_ACTIVE(config), \
257+
OPTION_HOOKS_ON_PRIMARY_CMD(config), \
258+
OPTION_HOOKS_SERVICE_START_CMD(config), \
244259
OPTION_TIMEOUT_NETWORK_PARTITION(config), \
245260
OPTION_TIMEOUT_PREPARE_PROMOTION_CATCHUP(config), \
246261
OPTION_TIMEOUT_PREPARE_PROMOTION_WALRECEIVER(config), \

src/bin/pg_autoctl/keeper_config.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ typedef struct KeeperConfig
5656
char maximum_backup_rate[MAXIMUM_BACKUP_RATE_LEN];
5757
char backupDirectory[MAXPGPATH];
5858

59+
/* Hooks settings (JSON strings) */
60+
int enableHooks; /* hooks.active */
61+
char onPrimaryCmd[BUFSIZE];
62+
char serviceStartCmd[BUFSIZE];
63+
5964
/* Citus specific options and settings */
6065
char citusRoleStr[NAMEDATALEN];
6166
CitusRole citusRole;

src/bin/pg_autoctl/service_keeper.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "pidfile.h"
2828
#include "service_keeper.h"
2929
#include "service_postgres_ctl.h"
30+
#include "service_run_hooks.h"
3031
#include "signals.h"
3132
#include "state.h"
3233
#include "string_utils.h"
@@ -85,6 +86,13 @@ start_keeper(Keeper *keeper)
8586
-1,
8687
&service_keeper_start,
8788
(void *) keeper
89+
},
90+
{
91+
SERVICE_NAME_RUN_HOOKS,
92+
RP_PERMANENT,
93+
-1,
94+
&service_run_hooks_start,
95+
(void *) keeper
8896
}
8997
};
9098

src/bin/pg_autoctl/service_keeper_init.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "service_keeper.h"
2929
#include "service_keeper_init.h"
3030
#include "service_postgres_ctl.h"
31+
#include "service_run_hooks.h"
3132
#include "signals.h"
3233
#include "string_utils.h"
3334
#include "supervisor.h"
@@ -57,6 +58,13 @@ service_keeper_init(Keeper *keeper)
5758
-1,
5859
&service_keeper_init_start,
5960
(void *) keeper
61+
},
62+
{
63+
SERVICE_NAME_RUN_HOOKS,
64+
RP_PERMANENT,
65+
-1,
66+
&service_run_hooks_start,
67+
(void *) keeper
6068
}
6169
};
6270

0 commit comments

Comments
 (0)