diff options
Diffstat (limited to '')
-rwxr-xr-x | pg_renamecluster | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/pg_renamecluster b/pg_renamecluster new file mode 100755 index 0000000..b9bbf7e --- /dev/null +++ b/pg_renamecluster @@ -0,0 +1,175 @@ +#!/usr/bin/perl -wT + +# Rename a PostgreSQL cluster +# +# (C) 2014-2019 Christoph Berg <myon@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +use strict; +use warnings; +use PgCommon; +use Getopt::Long; +use POSIX; + +# untaint environment +$ENV{'PATH'} = '/bin:/usr/bin'; +delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + +if (@ARGV != 3) { + print "Usage: $0 [OPTIONS] <version> <old cluster name> <new cluster name>\n"; + exit 1; +} + +my ($version) = $ARGV[0] =~ /^(\d+\.?\d+)$/; +my ($oldcluster) = $ARGV[1] =~ /^([-.\w]+)$/; +my ($newcluster) = $ARGV[2] =~ /^([-.\w]+)$/; +if ($newcluster =~ /-/ and -t 1) { + print "Warning: cluster names containing dashes (-) will cause problems when running from systemd. Continuing anyway\n"; +} + +error "Old and new name must be different" + if ($oldcluster eq $newcluster); +error "specified cluster $version $oldcluster does not exist" + unless (cluster_exists $version, $oldcluster); +error "target cluster $version $newcluster already exists" + if (cluster_exists $version, $newcluster); +my %info = cluster_info ($version, $oldcluster); + +# stopping old cluster, so that we notice early when there are still +# connections +if ($info{'running'}) { + print "Stopping cluster $version $oldcluster ...\n"; + my @argv = ('pg_ctlcluster', $version, $oldcluster, 'stop'); + error "Could not stop cluster" if system @argv; +} + +# Arguments: <string>, <from>, <to> +sub strrepl { + my ($s, $f, $t) = @_; + $s =~ s/\b\Q$f\E\b/$t/g; + return $s; +} + +# rename config directory +my $olddir = "$PgCommon::confroot/$version/$oldcluster"; +my $newdir = "$PgCommon::confroot/$version/$newcluster"; +rename $olddir, $newdir or error "Could not rename config directory $olddir: $!"; + +# adapt paths to configuration files +my %c = read_cluster_conf_file $version, $newcluster, 'postgresql.conf'; +if ($c{hba_file}) { + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', 'hba_file', + strrepl($c{hba_file}, $oldcluster, $newcluster); +} +if ($c{ident_file}) { + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', 'ident_file', + strrepl($c{ident_file}, $oldcluster, $newcluster); +} +if ($c{external_pid_file}) { + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', 'external_pid_file', + strrepl($c{external_pid_file}, $oldcluster, $newcluster); +} + +# update cluster_name +if ($c{cluster_name}) { + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', 'cluster_name', + strrepl ($c{cluster_name}, $oldcluster, $newcluster); +} + + +# rename data directory +if ($info{pgdata}) { + my $newpgdata = strrepl ($info{pgdata}, $oldcluster, $newcluster); + if ($info{pgdata} ne $newpgdata) { + rename $info{pgdata}, $newpgdata or + error "Could not rename data directory $info{pgdata}: $!"; + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', + 'data_directory', $newpgdata; + } +} + +# rename stats_temp_directory +my $statstempdir = $info{config}->{stats_temp_directory}; +if ($statstempdir) { + my $newstatstempdir = strrepl ($statstempdir, $oldcluster, $newcluster); + if ($statstempdir ne $newstatstempdir) { + PgCommon::set_conf_value $version, $newcluster, 'postgresql.conf', + 'stats_temp_directory', $newstatstempdir; + if (-d $statstempdir) { + rename $statstempdir, $newstatstempdir or + error "Could not rename stats temp directory $statstempdir}: $!"; + } + } +} + +# rename old log files +my $logdir = "/var/log/postgresql"; +if (opendir LOG, $logdir) { + while (my $logfile = readdir LOG) { + next unless $logfile =~ /^(\Qpostgresql-$version-$oldcluster.log\E.*)/; + $logfile = $1; # untaint + my $f = strrepl ($logfile, $oldcluster, $newcluster); + rename "$logdir/$logfile", "$logdir/$f" or error "rename $logdir/$logfile: $!"; + } + closedir LOG; +} + +# notify systemd about the new cluster +if (not exists $ENV{'PG_CLUSTER_CONF_ROOT'} and -d '/run/systemd/system') { + if ($> == 0) { + system 'systemctl daemon-reload'; + } elsif (-t 1) { + print "Warning: systemd does not know about the new cluster yet. Operations like \"service postgresql start\" will not handle it. To fix, run:\n"; + print " sudo systemctl daemon-reload\n"; + } +} + +# start cluster if it was running before +if ($info{'running'}) { + print "Starting cluster $version $newcluster ...\n"; + my @argv = ('pg_ctlcluster', $version, $newcluster, 'start'); + error "Could not start cluster" if system @argv; +} + +__END__ + +=head1 NAME + +pg_renamecluster - rename a PostgreSQL cluster + +=head1 SYNOPSIS + +B<pg_renamecluster> I<version> I<oldname> I<newname> + +=head1 DESCRIPTION + +B<pg_renamecluster> changes the name of a PostgreSQL cluster, i. e. the name of +the config directory in /etc/postgresql/I<version>/ along with the data +directory in /var/lib/postgresql/I<version>/. Existing log files in +/var/log/postgresql/ are also renamed. The cluster is stopped and started for +the operation. + +The following B<postgresql.conf> config options are updated to refer to the +changed path names: B<data_directory>, B<hba_file>, B<ident_file>, +B<external_pid_file>, B<stats_temp_directory>, B<cluster_name>. + +=head1 OPTIONS + +None. + +=head1 SEE ALSO + +L<pg_createcluster(8)>, L<pg_dropcluster(8)>, L<pg_lsclusters(1)>, L<pg_wrapper(1)> + +=head1 AUTHOR + +Christoph Berg L<E<lt>myon@debian.orgE<gt>> |