[pgpool-hackers: 4216] Re: Proposal: Add trusted_server_command parameter

Takuma Hoshiai hoshiai.takuma at nttcom.co.jp
Fri Oct 28 15:28:43 JST 2022


Hi,

On 2022/10/27 16:38, Takuma Hoshiai wrote:
> Hi Ishii-san,
> 
> On 2022/10/27 16:20, Tatsuo Ishii wrote:
>> Hoshiai-san,
>>
>>>> Hi all,
>>>>
>>>> I create a patch about trusted_servers for v4.4.
>>>> Add new parameter 'trusted_server_command'.
>>>>
>>>> Currently, only 'ping' command is used by trusted_servers for checking
>>>> up stream
>>>> connection, and number of sending packets is hard coded. In some
>>>> cases, user maybe
>>>> want to use other command.
>>>>
>>>> The trusted_server_command allow users to any specify command. 
>>>> Default is
>>>> 'ping -q -c %h' which means same as before. Pgpool-II replaces the
>>>> special
>>>> characters(%h) with the host name in trusted_servers.
>>>
>>> I have tested your patch and encountered an issue. Can you please
>>> help?
>>>
>>> I ran watchdog_setup to create a 3-pgpool-node cluster. And added
>>> following two lined to each pgpool.conf then ran ./startall.
>>>
>>> trusted_servers = 'localhost'
>>> trusted_server_command = 'ping -q -c3 %h'
>>>
>>> However the cluster did not start. I found following in the
>>> pgpool.log.
>>>
>>> ping: write error: Bad file descriptor
>>> 2022-10-27 13:35:29.855: watchdog_utility pid 326297: FATAL:  
>>> watchdog failed to ping host"localhost"
>>> 2022-10-27 13:35:29.855: watchdog_utility pid 326297: DETAIL:  
>>> system(ping -q -c3 localhost) failed. reason: Success
>>> 2022-10-27 13:35:29.856: life_check pid 326157: WARNING:  watchdog 
>>> lifecheck, failed to connect to any trusted servers
>>> 2022-10-27 13:35:29.856: life_check pid 326157: LOG:  informing the 
>>> node status change to watchdog
>>> 2022-10-27 13:35:29.856: life_check pid 326157: DETAIL:  node id :0 
>>> status = "NODE DEAD" message:"trusted server is unreachable"
>>>
>>> If I ran "ping -q -c3 localhost" manually, it works fine.
>>>
>>> $ ping -q -c3 localhost
>>> PING localhost (127.0.0.1) 56(84) bytes of data.
>>>
>>> --- localhost ping statistics ---
>>> 3 packets transmitted, 3 received, 0% packet loss, time 2034ms
>>> rtt min/avg/max/mdev = 0.082/0.087/0.095/0.005 ms
>>
>> I think wd_trusted_server_command() needs to assign appropreate fd
>> (/dev/null) to stdin, stdout and stderr. Attached is the revised
>> patch. Can you please check?

I think it's good!
But pgpool log messeges are suppressed, I fix debug and error messages
to your patch.
In addition, I add a regression test for trusted_server.


> Thank you for your suggestion. I will check it.
> 
>> Best reagards,
>> -- 
>> Tatsuo Ishii
>> SRA OSS LLC
>> English: http://www.sraoss.co.jp/index_en/
>> Japanese:http://www.sraoss.co.jp
>>
> 
> Best Regards,
> 

Best Regards,

-- 
Takuma Hoshiai <hoshiai.takuma at nttcom.co.jp>
-------------- next part --------------
 src/config/pool_config_variables.c                 | 10 +++
 src/include/pool_config.h                          |  1 +
 src/include/watchdog/wd_utils.h                    |  3 +-
 src/sample/pgpool.conf.sample-stream               |  6 ++
 .../regression/tests/036.trusted_servers/test.sh   | 75 +++++++++++++++++
 src/utils/pool_process_reporting.c                 |  5 ++
 src/watchdog/wd_lifecheck.c                        | 16 ++--
 src/watchdog/wd_ping.c                             | 95 +++++++++++++++++++++-
 8 files changed, 202 insertions(+), 9 deletions(-)

diff --git a/src/config/pool_config_variables.c b/src/config/pool_config_variables.c
index fe1bfd7..c804ee1 100644
--- a/src/config/pool_config_variables.c
+++ b/src/config/pool_config_variables.c
@@ -1042,6 +1042,16 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"trusted_server_command", CFGCXT_RELOAD, WATCHDOG_CONFIG,
+			"Command to excute when communicate trusted server.",
+			CONFIG_VAR_TYPE_STRING, false, 0
+		},
+		&g_pool_config.trusted_server_command,
+		"ping -q -c3 %h",
+		NULL, NULL, NULL, NULL
+	},
+
+	{
 		{"delegate_IP", CFGCXT_INIT, WATCHDOG_CONFIG,
 			"Old config parameter for delegate_ip.",
 			CONFIG_VAR_TYPE_STRING, false, VAR_HIDDEN_IN_SHOW_ALL
diff --git a/src/include/pool_config.h b/src/include/pool_config.h
index b6967cf..142c6fa 100644
--- a/src/include/pool_config.h
+++ b/src/include/pool_config.h
@@ -579,6 +579,7 @@ typedef struct
 	int			pgpool_node_id;	/* pgpool (watchdog) node id */
 	WdNodesConfig wd_nodes;		/* watchdog lists */
 	char	   *trusted_servers;	/* icmp reachable server list (A,B,C) */
+	char	   *trusted_server_command;	/* Executes this command when upper servers are observed */
 	char	   *delegate_ip;	/* delegate IP address */
 	int			wd_interval;	/* lifecheck interval (sec) */
 	char	   *wd_authkey;		/* Authentication key for watchdog
diff --git a/src/include/watchdog/wd_utils.h b/src/include/watchdog/wd_utils.h
index cdf829c..414376a 100644
--- a/src/include/watchdog/wd_utils.h
+++ b/src/include/watchdog/wd_utils.h
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2018	PgPool Global Development Group
+ * Copyright (c) 2003-2022	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -52,6 +52,7 @@ extern int	wd_is_upper_ok(char *server_list);
 extern bool wd_is_ip_exists(char *ip);
 extern bool wd_get_ping_result(char *hostname, int exit_status, int outfd);
 extern pid_t wd_issue_ping_command(char *hostname, int *outfd);
+extern pid_t wd_trusted_server_command(char *hostname);
 
 /* wd_if.c */
 extern List *get_all_local_ips(void);
diff --git a/src/sample/pgpool.conf.sample-stream b/src/sample/pgpool.conf.sample-stream
index 87678c7..fd34eb8 100644
--- a/src/sample/pgpool.conf.sample-stream
+++ b/src/sample/pgpool.conf.sample-stream
@@ -654,6 +654,12 @@ backend_clustering_mode = 'streaming_replication'
                                     # to confirm network connection
                                     # (hostA,hostB,hostC,...)
                                     # (change requires restart)
+
+#trusted_server_command = 'ping -q -c3 %h'
+                                    # Command to excute when communicate trusted server.
+                                    # Special values:
+                                    #   %h = host name specified by trusted_servers
+
 #ping_path = '/bin'
                                     # ping command path
                                     # (change requires restart)
diff --git a/src/test/regression/tests/036.trusted_servers/test.sh b/src/test/regression/tests/036.trusted_servers/test.sh
new file mode 100755
index 0000000..b3a9515
--- /dev/null
+++ b/src/test/regression/tests/036.trusted_servers/test.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# test script for trusted_server_command
+#
+source $TESTLIBS
+TESTDIR=testdir
+PSQL=$PGBIN/psql
+
+# set trusted_servers and trusted_server_command
+function set_param
+{
+    n=0
+    while [ $n -lt 2 ]
+    do
+	echo "trusted_servers = 'localhost'" >> pgpool$n/etc/pgpool.conf
+	echo "trusted_server_command = 'ping -q -c3 %h'" >> pgpool$n/etc/pgpool.conf
+	n=`expr $n + 1`
+    done
+}
+
+# wait for watchdog starting up by looking for "lifecheck started" in
+# the pgpool.log.  argument: $log: absolute path to the pgpool.log.
+function wait_for_watchdog_startup
+{
+    while :
+    do
+	grep "lifecheck started" $log >/dev/null
+	if [ $? = 0 ];then
+	    break;
+	fi
+	sleep 1
+    done
+}
+
+
+#-------------------------------------------------------------------
+dir=`pwd`
+
+failed=false
+export PCPPASSFILE=$dir/$TESTDIR/pgpool0/pcppass
+
+cd $dir
+rm -fr $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR
+
+$WATCHDOG_SETUP -wn 2 || exit 1
+
+set_param
+
+./startall
+
+cd pgpool0
+source ./bashrc.ports
+export PGPORT=$PGPOOL_PORT
+cd ..
+
+echo -n "waiting for watchdog node 0 starting up... "
+log=$dir/$TESTDIR/pgpool0/log/pgpool.log
+wait_for_watchdog_startup $log
+echo "done."
+
+sleep 10
+
+grep "watchdog failed to ping host" $log >/dev/null
+if [ $? -eq 0 ];then
+	failed=true
+fi
+
+./shutdownall
+
+if [ $failed = "true" ];then
+    exit 1
+fi
+exit 0
diff --git a/src/utils/pool_process_reporting.c b/src/utils/pool_process_reporting.c
index 268c174..acb32c7 100644
--- a/src/utils/pool_process_reporting.c
+++ b/src/utils/pool_process_reporting.c
@@ -820,6 +820,11 @@ get_config(int *nrows)
 	StrNCpy(status[i].desc, "upper server list to observe connection", POOLCONFIG_MAXDESCLEN);
 	i++;
 
+	StrNCpy(status[i].name, "trusted_server_command", POOLCONFIG_MAXNAMELEN);
+	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->trusted_server_command);
+	StrNCpy(status[i].desc, "command executed when upper servers are observed", POOLCONFIG_MAXDESCLEN);
+	i++;
+
 	StrNCpy(status[i].name, "delegate_ip", POOLCONFIG_MAXNAMELEN);
 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->delegate_ip);
 	StrNCpy(status[i].desc, "delegate IP address of leader pgpool", POOLCONFIG_MAXDESCLEN);
diff --git a/src/watchdog/wd_lifecheck.c b/src/watchdog/wd_lifecheck.c
index e62ca01..b697d84 100644
--- a/src/watchdog/wd_lifecheck.c
+++ b/src/watchdog/wd_lifecheck.c
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020	PgPool Global Development Group
+ * Copyright (c) 2003-2022	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -72,7 +72,6 @@ typedef struct WdUpstreamConnectionData
 	char	   *hostname;		/* host name of server */
 	pid_t		pid;			/* pid of ping process */
 	bool		reachable;		/* true if last ping was successful */
-	int			outputfd;		/* pipe fd linked to output of ping process */
 }			WdUpstreamConnectionData;
 
 
@@ -168,9 +167,8 @@ reaper(void)
 
 		if (server)
 		{
-			server->reachable = wd_get_ping_result(server->hostname, status, server->outputfd);
+			server->reachable = (status == 0);
 			server->pid = 0;
-			close(server->outputfd);
 		}
 		else
 			wd_reaper_lifecheck(pid, status);
@@ -1118,7 +1116,7 @@ wd_ping_all_server(void)
 		WdUpstreamConnectionData *server = (WdUpstreamConnectionData *) lfirst(lc);
 
 		if (server->pid <= 0)
-			server->pid = wd_issue_ping_command(server->hostname, &server->outputfd);
+			server->pid = wd_trusted_server_command(server->hostname);
 
 		if (server->pid > 0)
 			ping_process++;
@@ -1135,15 +1133,19 @@ wd_ping_all_server(void)
 			if (server)
 			{
 				ping_process--;
-				server->reachable = wd_get_ping_result(server->hostname, status, server->outputfd);
+				server->reachable = (status == 0);
 				server->pid = 0;
-				close(server->outputfd);
 				if (server->reachable)
 				{
 					/* one reachable server is all we need */
 					POOL_SETMASK(&UnBlockSig);
 					return true;
 				}
+				if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
+				{
+					ereport(WARNING,
+							(errmsg("watchdog failed to ping host\"%s\"", server->hostname)));
+				}
 			}
 			else
 			{
diff --git a/src/watchdog/wd_ping.c b/src/watchdog/wd_ping.c
index 6e758c4..89bbe0b 100644
--- a/src/watchdog/wd_ping.c
+++ b/src/watchdog/wd_ping.c
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020	PgPool Global Development Group
+ * Copyright (c) 2003-2022	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -30,6 +30,8 @@
 #include <netdb.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 #include "pool.h"
 #include "utils/elog.h"
 #include "pool_config.h"
@@ -155,6 +157,97 @@ wd_issue_ping_command(char *hostname, int *outfd)
 }
 
 /*
+ * execute specified command for trusted servers and return the
+ * pid of the process.
+ */
+pid_t
+wd_trusted_server_command(char *hostname)
+{
+	int			status;
+	int			pid;
+	StringInfoData		exec_cmd_data;
+	StringInfo				exec_cmd = &exec_cmd_data;
+	char *command_line = pstrdup(pool_config->trusted_server_command);
+
+	initStringInfo(exec_cmd);
+
+	while (*command_line)
+	{
+		if (*command_line == '%')
+		{
+			if (*(command_line + 1))
+			{
+				char		val = *(command_line + 1);
+
+				switch (val)
+				{
+					case 'h':	/* trusted server host name */
+						appendStringInfoString(exec_cmd, hostname);
+						break;
+
+					case '%':	/* escape */
+						appendStringInfoString(exec_cmd, "%");
+						break;
+
+					default:	/* ignore */
+						break;
+				}
+				command_line++;
+			}
+		}
+		else
+			appendStringInfoChar(exec_cmd, *command_line);
+
+		command_line++;
+	}
+
+	pid = fork();
+	if (pid == -1)
+	{
+		ereport(WARNING,
+				(errmsg("watchdog failed to ping host\"%s\"", hostname),
+				 errdetail("fork() failed. reason: %m")));
+		return -1;
+	}
+	if (pid == 0)
+	{
+		/* CHILD */
+		int	fd;
+
+		on_exit_reset();
+		SetProcessGlobalVariables(PT_WATCHDOG_UTILITY);
+		if (strlen(exec_cmd->data) != 0)
+			elog(DEBUG1, "trusted_server_command: %s", exec_cmd->data);
+
+		fd = open("/dev/null", O_RDWR);
+		if (fd < 0)
+		{
+			ereport(ERROR,
+					(errmsg("failed to open \"/dev/null\""),
+					 errdetail("%m")));
+		}
+		dup2(fd, 0);
+		dup2(fd, 1);
+		dup2(fd, 2);
+		close(fd);
+
+		if (strlen(exec_cmd->data) != 0)
+		{
+			status = system(exec_cmd->data);
+		}
+		pfree(exec_cmd->data);
+
+		if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0)
+		{
+			exit(EXIT_FAILURE);
+		}
+		exit(0);
+	}
+
+	return pid;
+}
+
+/*
  * The function is helper function and can be used with the
  * wd_issue_ping_command() function to identify if the ping command
  * was successful */


More information about the pgpool-hackers mailing list