Skip to content

Commit 8be3d7c

Browse files
authored
Implement pg_autoctl create postgres --pg-hba-lan option. (#561)
* Implement pg_autoctl create postgres --pg-hba-lan option. With this option pg_autoctl edits the pg_hba.conf for Postgres to grant connection privileges on the detected LAN for the --dbname database and for the --username user. The LAN detection is done the same way as with the monitor. * Implement a retry loop when trying to figure local IP address. We connect to the monitor to figure out the local hostname and IP address, and the monitor might not be running yet. In that case, we might want to persist with some retries before failing back to the user. * Install HBA on the monitor early. This avoids some retry attemps from the other nodes at first startup. * When we WARN about hostname, use IP address in HBA. Rather than adding an hostname that we know faulty in the HBA file, we add one of the IP addresses of the hostname instead. We might want to revisit this (add all IP addresses maybe? or find the one we want to add by connecting, like we do for the monitor?), but it allows the docker-compose demo to just work with a minimum of trouble. * Add a docker-compose.yml setup. This allows to run a demo where the monitor and the Postgres nodes are each running in their own container and connecting through the docker provided TCP/IP network.
1 parent a817326 commit 8be3d7c

25 files changed

+478
-124
lines changed

docker-compose.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
version: "3.9" # optional since v1.27.0
2+
services:
3+
monitor:
4+
image: citusdata/pg_auto_failover:demo
5+
environment:
6+
PGDATA: /tmp/pgaf
7+
PG_AUTOCTL_DEBUG: 1
8+
command: pg_autoctl create monitor --ssl-self-signed --auth trust --run
9+
expose:
10+
- 5432
11+
node1:
12+
image: citusdata/pg_auto_failover:demo
13+
environment:
14+
PGDATA: /tmp/pgaf
15+
PG_AUTOCTL_DEBUG: 1
16+
command: [
17+
"pg_autoctl", "create", "postgres",
18+
"--ssl-self-signed",
19+
"--auth", "trust",
20+
"--pg-hba-lan",
21+
"--username", "ad",
22+
"--dbname", "analytics",
23+
"--monitor", "postgresql://autoctl_node@monitor/pg_auto_failover",
24+
"--run"]
25+
expose:
26+
- 5432
27+
node2:
28+
image: citusdata/pg_auto_failover:demo
29+
expose:
30+
- 5432
31+
environment:
32+
PGDATA: /tmp/pgaf
33+
PG_AUTOCTL_DEBUG: 1
34+
command: [
35+
"pg_autoctl", "create", "postgres",
36+
"--ssl-self-signed",
37+
"--auth", "trust",
38+
"--pg-hba-lan",
39+
"--username", "ad",
40+
"--dbname", "analytics",
41+
"--monitor", "postgresql://autoctl_node@monitor/pg_auto_failover",
42+
"--run"]
43+
expose:
44+
- 5432
45+
node3:
46+
image: citusdata/pg_auto_failover:demo
47+
environment:
48+
PGDATA: /tmp/pgaf
49+
PG_AUTOCTL_DEBUG: 1
50+
command: [
51+
"pg_autoctl", "create", "postgres",
52+
"--ssl-self-signed",
53+
"--auth", "trust",
54+
"--pg-hba-lan",
55+
"--username", "ad",
56+
"--dbname", "analytics",
57+
"--monitor", "postgresql://autoctl_node@monitor/pg_auto_failover",
58+
"--run"]
59+
expose:
60+
- 5432

docs/ref/reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ The other commands accept the same set of options.
424424
--monitor pg_auto_failover Monitor Postgres URL
425425
--auth authentication method for connections from monitor
426426
--skip-pg-hba skip editing pg_hba.conf rules
427+
--pg-hba-lan edit pg_hba.conf rules for --dbname in detected LAN
427428
--candidate-priority priority of the node to be promoted to become primary
428429
--replication-quorum true if node participates in write quorum
429430
--ssl-self-signed setup network encryption using self signed certificates (does NOT protect against MITM)

src/bin/pg_autoctl/cli_common.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
KeeperConfig keeperOptions;
3636
bool createAndRun = false;
3737
bool outputJSON = false;
38+
bool openAppHBAonLAN = false;
3839
int ssl_flag = 0;
3940

4041
/* stores --node-id, only used with --disable-monitor */
@@ -57,7 +58,8 @@ static void stop_postgres_and_remove_pgdata_and_config(ConfigFilePaths *pathname
5758
* { "proxyport", required_argument, NULL, 'y' },
5859
* { "username", required_argument, NULL, 'U' },
5960
* { "auth", required_argument, NULL, 'A' },
60-
* { "skip-pg-hba", required_argument, NULL, 'S' },
61+
* { "skip-pg-hba", no_argument, NULL, 'S' },
62+
* { "pg-hba-lan", no_argument, NULL, 'L' },
6163
* { "dbname", required_argument, NULL, 'd' },
6264
* { "name", required_argument, NULL, 'a' },
6365
* { "hostname", required_argument, NULL, 'n' },
@@ -211,13 +213,41 @@ cli_common_keeper_getopts(int argc, char **argv,
211213
log_error("Please use either --auth or --skip-pg-hba");
212214
}
213215

216+
/* force default authentication method then */
214217
strlcpy(LocalOptionConfig.pgSetup.authMethod,
215-
SKIP_HBA_AUTH_METHOD,
218+
DEFAULT_AUTH_METHOD,
216219
NAMEDATALEN);
220+
221+
strlcpy(LocalOptionConfig.pgSetup.hbaLevelStr,
222+
pgsetup_hba_level_to_string(HBA_EDIT_SKIP),
223+
sizeof(LocalOptionConfig.pgSetup.hbaLevelStr));
224+
225+
LocalOptionConfig.pgSetup.hbaLevel = HBA_EDIT_SKIP;
226+
217227
log_trace("--skip-pg-hba");
218228
break;
219229
}
220230

231+
case 'L':
232+
{
233+
/* { "pg-hba-lan", required_argument, NULL, 'L' }, */
234+
if (LocalOptionConfig.pgSetup.hbaLevel != HBA_EDIT_UNKNOWN &&
235+
LocalOptionConfig.pgSetup.hbaLevel != HBA_EDIT_LAN)
236+
{
237+
errors++;
238+
log_error("Please use either --skip-pg-hba or --pg-hba-lan");
239+
}
240+
241+
strlcpy(LocalOptionConfig.pgSetup.hbaLevelStr,
242+
pgsetup_hba_level_to_string(HBA_EDIT_LAN),
243+
sizeof(LocalOptionConfig.pgSetup.hbaLevelStr));
244+
245+
LocalOptionConfig.pgSetup.hbaLevel = HBA_EDIT_LAN;
246+
247+
log_trace("--pg-hba-lan");
248+
break;
249+
}
250+
221251
case 'd':
222252
{
223253
/* { "dbname", required_argument, NULL, 'd' } */
@@ -478,6 +508,12 @@ cli_common_keeper_getopts(int argc, char **argv,
478508
exit(EXIT_CODE_BAD_ARGS);
479509
}
480510

511+
/* the default HBA editing level is MINIMAL, time to install it */
512+
if (LocalOptionConfig.pgSetup.hbaLevel == HBA_EDIT_UNKNOWN)
513+
{
514+
LocalOptionConfig.pgSetup.hbaLevel = HBA_EDIT_MINIMAL;
515+
}
516+
481517
/*
482518
* Now, all commands need PGDATA validation.
483519
*/
@@ -513,7 +549,8 @@ cli_common_keeper_getopts(int argc, char **argv,
513549
* { "proxyport", required_argument, NULL, 'y' },
514550
* { "username", required_argument, NULL, 'U' },
515551
* { "auth", required_argument, NULL, 'A' },
516-
* { "skip-pg-hba", required_argument, NULL, 'S' },
552+
* { "skip-pg-hba", no_argument, NULL, 'S' },
553+
* { "pg-hba-lan", no_argument, NULL, 'L' },
517554
* { "dbname", required_argument, NULL, 'd' },
518555
* { "hostname", required_argument, NULL, 'n' },
519556
* { "formation", required_argument, NULL, 'f' },

src/bin/pg_autoctl/cli_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern MonitorConfig monitorOptions;
2222
extern KeeperConfig keeperOptions;
2323
extern bool createAndRun;
2424
extern bool outputJSON;
25+
extern bool openAppHBAonLAN;
2526

2627
#define SSL_CA_FILE_FLAG 1 /* root public certificate */
2728
#define SSL_CRL_FILE_FLAG 2 /* certificates revocation list */

src/bin/pg_autoctl/cli_create_drop_node.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ CommandLine create_postgres_command =
9797
" --monitor pg_auto_failover Monitor Postgres URL\n"
9898
" --auth authentication method for connections from monitor\n"
9999
" --skip-pg-hba skip editing pg_hba.conf rules\n"
100+
" --pg-hba-lan edit pg_hba.conf rules for --dbname in detected LAN\n"
101+
KEEPER_CLI_SSL_OPTIONS
100102
" --candidate-priority priority of the node to be promoted to become primary\n"
101-
" --replication-quorum true if node participates in write quorum\n"
102-
KEEPER_CLI_SSL_OPTIONS,
103+
" --replication-quorum true if node participates in write quorum\n",
103104
cli_create_postgres_getopts,
104105
cli_create_postgres);
105106

@@ -284,6 +285,7 @@ cli_create_postgres_getopts(int argc, char **argv)
284285
{ "username", required_argument, NULL, 'U' },
285286
{ "auth", required_argument, NULL, 'A' },
286287
{ "skip-pg-hba", no_argument, NULL, 'S' },
288+
{ "pg-hba-lan", no_argument, NULL, 'L' },
287289
{ "dbname", required_argument, NULL, 'd' },
288290
{ "name", required_argument, NULL, 'a' },
289291
{ "hostname", required_argument, NULL, 'n' },
@@ -311,7 +313,7 @@ cli_create_postgres_getopts(int argc, char **argv)
311313

312314
int optind =
313315
cli_create_node_getopts(argc, argv, long_options,
314-
"C:D:H:p:l:U:A:Sd:a:n:f:m:MI:RVvqhP:r:xsN",
316+
"C:D:H:p:l:U:A:SLd:a:n:f:m:MI:RVvqhP:r:xsN",
315317
&options);
316318

317319
/* publish our option parsing in the global variable */
@@ -470,9 +472,13 @@ cli_create_monitor_getopts(int argc, char **argv)
470472
log_error("Please use either --auth or --skip-pg-hba");
471473
}
472474

475+
/* force default authentication method then */
473476
strlcpy(options.pgSetup.authMethod,
474-
SKIP_HBA_AUTH_METHOD,
477+
DEFAULT_AUTH_METHOD,
475478
NAMEDATALEN);
479+
480+
options.pgSetup.hbaLevel = HBA_EDIT_SKIP;
481+
476482
log_trace("--skip-pg-hba");
477483
break;
478484
}
@@ -1291,12 +1297,40 @@ discover_hostname(char *hostname, int size,
12911297
char localIpAddr[BUFSIZE];
12921298
char hostnameCandidate[_POSIX_HOST_NAME_MAX];
12931299

1294-
/* fetch our local address among the network interfaces */
1295-
if (!fetchLocalIPAddress(ipAddr, BUFSIZE, monitorHostname, monitorPort))
1300+
ConnectionRetryPolicy retryPolicy = { 0 };
1301+
1302+
/* retry connecting to the monitor when it's not available */
1303+
(void) pgsql_set_monitor_interactive_retry_policy(&retryPolicy);
1304+
1305+
while (!pgsql_retry_policy_expired(&retryPolicy))
12961306
{
1297-
log_fatal("Failed to find a local IP address, "
1298-
"please provide --hostname.");
1299-
return false;
1307+
bool mayRetry = false;
1308+
1309+
/* fetch our local address among the network interfaces */
1310+
if (fetchLocalIPAddress(ipAddr, BUFSIZE, monitorHostname, monitorPort,
1311+
LOG_DEBUG, &mayRetry))
1312+
{
1313+
/* success: break out of the retry loop */
1314+
break;
1315+
}
1316+
1317+
if (!mayRetry)
1318+
{
1319+
log_fatal("Failed to find a local IP address, "
1320+
"please provide --hostname.");
1321+
return false;
1322+
}
1323+
1324+
int sleepTimeMs =
1325+
pgsql_compute_connection_retry_sleep_time(&retryPolicy);
1326+
1327+
log_warn("Failed to connect to \"%s\" on port %d "
1328+
"to discover this machine hostname, "
1329+
"retrying in %d ms.",
1330+
monitorHostname, monitorPort, sleepTimeMs);
1331+
1332+
/* we have milliseconds, pg_usleep() wants microseconds */
1333+
(void) pg_usleep(sleepTimeMs * 1000);
13001334
}
13011335

13021336
/* from there on we can take the ipAddr as the default --hostname */
@@ -1364,6 +1398,7 @@ check_hostname(const char *hostname)
13641398
else
13651399
{
13661400
char cidr[BUFSIZE];
1401+
char ipaddr[BUFSIZE];
13671402

13681403
if (!fetchLocalCIDR(hostname, cidr, BUFSIZE))
13691404
{
@@ -1373,6 +1408,6 @@ check_hostname(const char *hostname)
13731408
}
13741409

13751410
/* use pghba_check_hostname for log diagnostics */
1376-
(void) pghba_check_hostname(hostname);
1411+
(void) pghba_check_hostname(hostname, ipaddr, sizeof(ipaddr));
13771412
}
13781413
}

src/bin/pg_autoctl/cli_do_misc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ keeper_cli_create_monitor_user(int argc, char **argv)
188188
PG_AUTOCTL_HEALTH_PASSWORD,
189189
monitorHostname,
190190
"trust",
191+
HBA_EDIT_MINIMAL,
191192
connlimit))
192193
{
193194
log_fatal("Failed to create the database user that the pg_auto_failover "

src/bin/pg_autoctl/cli_do_root.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ keeper_cli_keeper_setup_getopts(int argc, char **argv)
572572

573573
int optind = cli_common_keeper_getopts(argc, argv,
574574
long_options,
575-
"C:D:H:p:l:U:A:Sd:n:f:m:MRVvqhP:r:xsN",
575+
"C:D:H:p:l:U:A:SLd:n:f:m:MRVvqhP:r:xsN",
576576
&options,
577577
&sslCommandLineOptions);
578578

src/bin/pg_autoctl/cli_do_show.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ static void
8888
cli_show_ipaddr(int argc, char **argv)
8989
{
9090
char ipAddr[BUFSIZE];
91+
bool mayRetry = false;
9192

9293
if (!fetchLocalIPAddress(ipAddr, BUFSIZE,
9394
DEFAULT_INTERFACE_LOOKUP_SERVICE_NAME,
94-
DEFAULT_INTERFACE_LOOKUP_SERVICE_PORT))
95+
DEFAULT_INTERFACE_LOOKUP_SERVICE_PORT,
96+
LOG_WARN, &mayRetry))
9597
{
9698
log_warn("Failed to determine network configuration.");
9799
exit(EXIT_CODE_INTERNAL_ERROR);
@@ -111,10 +113,12 @@ cli_show_cidr(int argc, char **argv)
111113
{
112114
char ipAddr[BUFSIZE];
113115
char cidr[BUFSIZE];
116+
bool mayRetry = false;
114117

115118
if (!fetchLocalIPAddress(ipAddr, BUFSIZE,
116119
DEFAULT_INTERFACE_LOOKUP_SERVICE_NAME,
117-
DEFAULT_INTERFACE_LOOKUP_SERVICE_PORT))
120+
DEFAULT_INTERFACE_LOOKUP_SERVICE_PORT,
121+
LOG_WARN, &mayRetry))
118122
{
119123
log_warn("Failed to determine network configuration.");
120124
exit(EXIT_CODE_INTERNAL_ERROR);
@@ -207,6 +211,8 @@ cli_show_hostname(int argc, char **argv)
207211
char monitorHostname[_POSIX_HOST_NAME_MAX];
208212
int monitorPort = pgsetup_get_pgport();
209213

214+
bool mayRetry = false;
215+
210216
/*
211217
* When no argument is used, use hostname(3) and 5432, as we would for a
212218
* monitor (pg_autoctl create monitor).
@@ -256,7 +262,9 @@ cli_show_hostname(int argc, char **argv)
256262
}
257263

258264
/* fetch the default local address used when connecting remotely */
259-
if (!fetchLocalIPAddress(ipAddr, BUFSIZE, monitorHostname, monitorPort))
265+
if (!fetchLocalIPAddress(ipAddr, BUFSIZE,
266+
monitorHostname, monitorPort,
267+
LOG_WARN, &mayRetry))
260268
{
261269
log_warn("Failed to determine network configuration.");
262270
exit(EXIT_CODE_INTERNAL_ERROR);
@@ -321,6 +329,7 @@ cli_show_reverse(int argc, char **argv)
321329
log_fatal("Failed to find an IP address for hostname \"%s\" that "
322330
"matches hostname again in a reverse-DNS lookup.",
323331
hostname);
332+
log_info("Continuing with IP address \"%s\"", ipaddr);
324333
exit(EXIT_CODE_INTERNAL_ERROR);
325334
}
326335

src/bin/pg_autoctl/cli_do_tmux.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,10 @@ tmux_pg_autoctl_create_postgres(PQExpBuffer script,
646646

647647
tmux_add_send_keys_command(script,
648648
"%s create postgres %s "
649-
"--monitor %s --name %s "
649+
"--monitor %s "
650+
"--name %s "
651+
"--dbname demo "
652+
"--pg-hba-lan "
650653
"--replication-quorum %s "
651654
"--candidate-priority %d "
652655
"--run",

src/bin/pg_autoctl/defaults.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#define DEFAULT_DATABASE_NAME "postgres"
3333
#define DEFAULT_USERNAME "postgres"
3434
#define DEFAULT_AUTH_METHOD "trust"
35-
#define SKIP_HBA_AUTH_METHOD "skip"
3635
#define REPLICATION_SLOT_NAME_DEFAULT "pgautofailover_standby"
3736
#define REPLICATION_SLOT_NAME_PATTERN "^pgautofailover_standby_"
3837
#define REPLICATION_PASSWORD_DEFAULT NULL

0 commit comments

Comments
 (0)