From 3172ad97cf9d724d3e3c35090d7ec937bf9d72e0 Mon Sep 17 00:00:00 2001 From: Greg Smith Date: Mon, 8 Nov 2010 15:29:53 -0500 Subject: [PATCH] Add rsync remote user name option. Expand docs to include command line help examples. --- README.rst | 147 ++++++++++++++++++++++++++++++++++++++--------------- repmgr.c | 93 ++++++++++++++++++++------------- 2 files changed, 164 insertions(+), 76 deletions(-) diff --git a/README.rst b/README.rst index 3f8d80d0..566c3525 100644 --- a/README.rst +++ b/README.rst @@ -32,7 +32,7 @@ To install and use repmgr and repmgrd follow these steps: 3. Check your primary server is correctly configured -4. Write a suitable repmgr.conf for the node +4. Write a suitable ``repmgr.conf`` for the node 5. Setup repmgrd to aid in failover transitions @@ -132,9 +132,9 @@ You may need to include the full path of the binary instead, such as this RHEL example:: /usr/pgsql-9.0/bin/repmgr --version - /usr/pgsql-9.0/bin/repmgr --version + /usr/pgsql-9.0/bin/repmgrd --version -Below this base binary installation directory is referred to as PGDIR. +Below this binary installation base directory is referred to as PGDIR. Set up trusted copy between postgres accounts --------------------------------------------- @@ -172,7 +172,39 @@ user's account:: Now test that ssh in both directions works. You may have to accept some new known hosts in the process. -CONFIGURATION FILE +Primary server configuration +============================ + +PostgreSQL should have been previously built and installed on the system. Here +is a sample of changes to the ``postgresql.conf`` file:: + + listen_addresses='*' + wal_level = 'hot_standby' + archive_mode = on + archive_command = 'cd .' # we can also use exit 0, anything that + # just does nothing + max_wal_senders = 10 + wal_keep_segments = 5000 # 80 GB required on pg_xlog + hot_standby = on + +Also you need to add the machines that will participate in the cluster in +``pg_hba.conf`` file. One possibility is to trust all connections from the +replication users from all internal addresses, such as:: + + host all all 192.168.1.0/24 trust + host replication all 192.168.1.0/24 trust + +A more secure setup adds a repmgr user and database, just giving +access to that user:: + + host repmgr repmgr 192.168.1.0/24 trust + host replication all 192.168.1.0/24 trust + +If you give a password to the user, you need to create a ``.pgpass`` file for +them as well to allow automatic login. In this case you might use the +``md5`` authentication method instead of ``trust`` for the repmgr user. + +Configuration File ================== ``repmgr.conf`` is looked for in the directory repmgrd or repmgr exists. @@ -186,11 +218,52 @@ It should have these three parameters: 3. conninfo: A string (single quoted) specifying how we can connect to this node's PostgreSQL service +Command line syntax +=================== + +The current supported syntax for the program can be seen using:: + + repmgr --help + +The output from this program looks like this:: + + repmgr: Replicator manager + Usage: + repmgr [OPTIONS] master {register} + repmgr [OPTIONS] standby {register|clone|promote|follow} + + General options: + --help show this help, then exit + --version output version information, then exit + --verbose output verbose activity information + + Connection options: + -d, --dbname=DBNAME database to connect to + -h, --host=HOSTNAME database server host or socket directory + -p, --port=PORT database server port + -U, --username=USERNAME database user name to connect as + + Configuration options: + -D, --data-dir=DIR local directory where the files will be copied to + -f, --config_file=PATH path to the configuration file + -R, --remote-user=USERNAME database server username for rsync + + repmgr performs some tasks like clone a node, promote it or making follow another node and then exits. + COMMANDS: + master register - registers the master in a cluster + standby register - registers a standby in a cluster + standby clone [node] - allows creation of a new standby + standby promote - allows manual promotion of a specific standby into a new master in the event of a failover + standby follow - allows the standby to re-point itself to a new master + +The ``--verbose`` option can be useful in troubleshooting issues with +the program. + Commands ======== -None of this commands need the ``repmgr.conf`` file but they need to be able to -connect to the remote and local database. +Not all of these commands need the ``repmgr.conf`` file, but they need to be able to +connect to the remote and local databases. You can teach it which is the remote database by using the -h parameter or as a last parameter in standby clone and standby follow. If you need to specify @@ -212,7 +285,7 @@ its port if is different from the default one. * Backup via rsync the data directory of the primary. And creates the recovery file we need to start a new hot standby server. - It doesn't need the repmgr.conf so it can be executed anywhere in the new node. + It doesn't need the ``repmgr.conf`` so it can be executed anywhere in the new node. So, you can step where you want your new data directory and execute:: ./repmgr standby clone 10.68.1.161 @@ -245,38 +318,6 @@ its port if is different from the default one. ./repmgr standby follow -Primary server configuration -============================ - -PostgreSQL should have been previously built and installed on the system. Here -is a sample of changes to the postgresql.conf file:: - - listen_addresses='*' - wal_level = 'hot_standby' - archive_mode = on - archive_command = 'cd .' # we can also use exit 0, anything that - # just does nothing - max_wal_senders = 10 - wal_keep_segments = 5000 # 80 GB required on pg_xlog - hot_standby = on - -Also you need to add the machines that will participate in the cluster in -``pg_hba.conf`` file. One possibility is to trust all connections from the -replication users from all internal addresses, such as:: - - host all all 192.168.1.0/24 trust - host replication all 192.168.1.0/24 trust - -A more secure setup adds a repmgr user and database, just giving -access to that user:: - - host repmgr repmgr 192.168.1.0/24 trust - host replication all 192.168.1.0/24 trust - -If you give a password to the user, you need to create a ``.pgpass`` file for -them as well to allow automatic login. In this case you might use the -``md5`` authentication method instead of ``trust`` for the repmgr user. - Examples ======== @@ -302,14 +343,38 @@ and run:: repmgr -D /var/lib/postgresql/9.0 standby clone node2 -NOTE: you need to have PGDIR/bin in your path, if you don't want that as a -permanent setting you can do it this way:: +NOTE: you need to have PGDIR/bin in your path. If you don't want that as a +permanent setting, you can do it this way:: PATH=$PGDIR/bin:$PATH repmgr standby promote repmgr Daemon ============= +Command line syntax +------------------- + +The current supported syntax for the program can be seen using:: + + repmgrd --help + +The output from this program looks like this:: + + repmgrd: Replicator manager daemon + Usage: + repmgrd [OPTIONS] + + Options: + --help show this help, then exit + --version output version information, then exit + --verbose output verbose activity information + -f, --config_file=PATH database to connect to + + repmgrd monitors a cluster of servers. + +The ``--verbose`` option can be useful in troubleshooting issues with +the program. + Setup ----- diff --git a/repmgr.c b/repmgr.c index 23435ee1..04379498 100644 --- a/repmgr.c +++ b/repmgr.c @@ -30,9 +30,11 @@ #define STANDBY_PROMOTE 4 #define STANDBY_FOLLOW 5 +#define QUERY_STR_LEN 8192 + static void help(const char *progname); static bool create_recovery_file(const char *data_dir); -static int copy_remote_files(char *host, char *remote_path, char *local_path, bool is_directory); +static int copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory); static bool check_parameters_for_action(const int action); static void do_master_register(void); @@ -51,6 +53,7 @@ char *host = NULL; char *username = NULL; char *dest_dir = NULL; char *config_file = NULL; +char *remote_user = NULL; bool verbose = false; bool force = false; @@ -71,6 +74,7 @@ main(int argc, char **argv) {"username", required_argument, NULL, 'U'}, {"dest-dir", required_argument, NULL, 'D'}, {"config-file", required_argument, NULL, 'f'}, + {"remote-user", required_argument, NULL, 'R'}, {"force", no_argument, NULL, 'F'}, {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} @@ -97,7 +101,7 @@ main(int argc, char **argv) } - while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:F:v", long_options, &optindex)) != -1) + while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:F:v", long_options, &optindex)) != -1) { switch (c) { @@ -119,6 +123,9 @@ main(int argc, char **argv) case 'f': config_file = optarg; break; + case 'R': + remote_user = optarg; + break; case 'F': force = true; break; @@ -262,7 +269,7 @@ do_master_register(void) { PGconn *conn; PGresult *res; - char sqlquery[8192]; + char sqlquery[QUERY_STR_LEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -440,7 +447,7 @@ do_standby_register(void) int master_id; PGresult *res; - char sqlquery[8192]; + char sqlquery[QUERY_STR_LEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -566,7 +573,7 @@ do_standby_clone(void) { PGconn *conn; PGresult *res; - char sqlquery[8192]; + char sqlquery[QUERY_STR_LEN]; int r = 0; int i; @@ -842,11 +849,11 @@ do_standby_clone(void) goto stop_backup; } - r = copy_remote_files(host, master_control_file, local_control_file, false); + r = copy_remote_files(host, remote_user, master_control_file, local_control_file, false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, master_data_directory, dest_dir, true); + r = copy_remote_files(host, remote_user, master_data_directory, dest_dir, true); if (r != 0) goto stop_backup; @@ -864,20 +871,20 @@ do_standby_clone(void) } for (i = 0; i < PQntuples(res); i++) { - r = copy_remote_files(host, PQgetvalue(res, i, 0), PQgetvalue(res, i, 0), true); + r = copy_remote_files(host, remote_user, PQgetvalue(res, i, 0), PQgetvalue(res, i, 0), true); if (r != 0) goto stop_backup; } - r = copy_remote_files(host, master_config_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_config_file, dest_dir, false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, master_hba_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_hba_file, dest_dir, false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, master_ident_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_ident_file, dest_dir, false); if (r != 0) goto stop_backup; @@ -911,14 +918,14 @@ stop_backup: return; if (verbose) - printf(_("%s requires primary to keep WAL files %s until at least %s"), + printf(_("%s requires primary to keep WAL files %s until at least %s\n"), progname, first_wal_segment, last_wal_segment); /* we need to create the pg_xlog sub directory too, i'm reusing a variable here */ sprintf(local_control_file, "%s/pg_xlog", dest_dir); if (!create_directory(local_control_file)) { - fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually... "), + fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"), progname, dest_dir); } @@ -935,8 +942,8 @@ do_standby_promote(void) { PGconn *conn; PGresult *res; - char sqlquery[8192]; - char script[8192]; + char sqlquery[QUERY_STR_LEN]; + char script[QUERY_STR_LEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -1043,8 +1050,8 @@ do_standby_follow(void) { PGconn *conn; PGresult *res; - char sqlquery[8192]; - char script[8192]; + char sqlquery[QUERY_STR_LEN]; + char script[QUERY_STR_LEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -1180,18 +1187,21 @@ help(const char *progname) printf(_("Usage:\n")); printf(_(" %s [OPTIONS] master {register}\n"), progname); printf(_(" %s [OPTIONS] standby {register|clone|promote|follow}\n"), progname); - printf(_("\nOptions:\n")); - printf(_(" --help show this help, then exit\n")); - printf(_(" --version output version information, then exit\n")); - printf(_(" --verbose output verbose activity information\n")); + printf(_("\nGeneral options:\n")); + printf(_(" --help show this help, then exit\n")); + printf(_(" --version output version information, then exit\n")); + printf(_(" --verbose output verbose activity information\n")); printf(_("\nConnection options:\n")); - printf(_(" -d, --dbname=DBNAME database to connect to\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); - printf(_(" -p, --port=PORT database server port\n")); - printf(_(" -U, --username=USERNAME user name to connect as\n")); - printf(_(" -D, --data-dir=DIR directory where the files will be copied to\n")); - printf(_(" -f, --config_file=PATH path to the configuration file\n")); - printf(_("\n%s performs some tasks like clone a node, promote it "), progname); + printf(_(" -d, --dbname=DBNAME database to connect to\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); + printf(_(" -p, --port=PORT database server port\n")); + printf(_(" -U, --username=USERNAME database user name to connect as\n")); + printf(_("\nConfiguration options:\n")); + printf(_(" -D, --data-dir=DIR local directory where the files will be copied to\n")); + printf(_(" -f, --config_file=PATH path to the configuration file\n")); + printf(_(" -R, --remote-user=USERNAME database server username for rsync\n")); + + printf(_("\n%s performs some tasks like clone a node, promote it "), progname); printf(_("or making follow another node and then exits.\n")); printf(_("COMMANDS:\n")); printf(_(" master register - registers the master in a cluster\n")); @@ -1243,33 +1253,46 @@ create_recovery_file(const char *data_dir) static int -copy_remote_files(char *host, char *remote_path, char *local_path, bool is_directory) +copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory) { - char script[8192]; - char options[8192]; + char script[QUERY_STR_LEN]; + char options[QUERY_STR_LEN]; + char host_string[QUERY_STR_LEN]; int r; sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); if (force) strcat(options, " --delete"); + if (remote_user == NULL) + { + sprintf(host_string,"%s",host); + } + else + { + sprintf(host_string,"%s@%s",remote_user,host); + } + if (is_directory) { strcat(options, " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); sprintf(script, "rsync %s %s:%s/* %s", - options, host, remote_path, local_path); + options, host_string, remote_path, local_path); } else { sprintf(script, "rsync %s %s:%s %s/.", - options, host, remote_path, local_path); + options, host_string, remote_path, local_path); } + if (verbose) + printf("rsync command line: '%s'\n",script); + r = system(script); - + if (r != 0) fprintf(stderr, _("Can't rsync from remote file or directory (%s:%s)\n"), - host, remote_path); + host_string, remote_path); return r; }