Update README.md
[pgpool-online-recovery] / streaming-replication.sh
1 #!/bin/bash
2
3 ##This is meanst to be run on the slave, with the masters ip as the passed variable. ($1)
4 sourcehost="$1"
5 datadir=/var/lib/postgresql/9.1/main
6 archivedir=/var/lib/postgresql/9.1/archive
7 archivedirdest=/var/lib/postgresql/9.1/archive
8
9 #Usage
10 if [ "$1" = "" ] || [ "$1" = "-h" ] || [ "$1" = "-help" ] || [ "$1" = "--help" ];
11 then
12         echo "Usage: $0 masters ip address"
13 exit 0
14 fi
15 #This script must be run as postgres user
16 Whoami () {
17     if [[ $(whoami) != "postgres" ]]
18     then
19         echo "[INFO] This script must be run as postgres user !"
20         exit 1
21     fi
22 }
23
24 #Check if postgres server is running on remote host
25 CheckIfPostgresIsRunningOnRemoteHost () {
26         isrunning="$(ssh postgres@"$1" 'if killall -0 postgres; then echo "postgres_running"; else echo "postgress_not_running"; fi;')"
27
28         if [[ "$isrunning" = "postgress_not_running" ]]
29         then
30                 echo "[ERROR] Postgres not running on the master. Exiting..";
31         exit 1
32
33         elif [[ "$isrunning" = "postgres_running" ]]
34         then
35                 echo "[OK] Postgres master running on remote host";
36
37         elif echo "[ERROR] Unexpected response. Exiting.."
38         then
39                 exit 1
40         fi
41 }
42
43 #Check if the supposed master is actually a master
44 CheckIfMasterIsActuallyAMaster () {
45     ismaster="$(ssh postgres@"$1" 'if [ -f /var/lib/postgresql/9.1/main/recovery.done ]; then echo "postgres_is_a_master_instance"; else echo "postgres_is_not_master"; fi;')"
46
47     if [[ "$ismaster" = "postgres_is_not_master" ]]
48     then
49         echo "[ERROR] Postgres is already running as a slave. Exiting..";
50         exit 1
51     elif [[ "$ismaster" = "postgres_is_a_master_instance" ]]
52     then
53         echo "[INFO] Postgres is running as master (probably)";
54     elif echo "[ERROR] Unexpected response. Exiting.."
55     then
56         exit 1
57     fi
58 }
59
60 #prepare local server to become the new slave server.
61 PrepareLocalServer () {
62
63     if [ -f '/tmp/trigger_file' ]
64     then
65             rm /tmp/trigger_file
66     fi
67     echo "[INFO] Stopping slave node.."
68     bash /etc/init.d/postgresql stop
69
70     if [[ -f "$datadir/recovery.done" ]];
71     then
72             mv "$datadir"/recovery.done "$datadir"/recovery.conf
73     fi 
74
75     #Remove old WAL logs
76     rm /var/lib/postgresql/9.1/archive/*
77 }
78
79
80 CheckForRecoveryConfig () {
81     if [[ -f "$datadir/recovery.conf" ]];
82     then
83         echo "[OK] Slave config file found, Continuing.."
84     else
85         echo "[ERROR] recovery.conf not found. Postgres is not a slave. Exiting.."
86         exit 1
87     fi
88 }
89
90
91 #Put master into backup mode
92 #Before doing PutMasterIntoBackupMode clean up archive logs (IE rm or mv /var/lib/postgresql/9.1/archive/*). They are not needed since we are effectivly createing a new base backup and then synching it.
93 PutMasterIntoBackupMode () {
94     echo "[INFO] Putting postgres master '$1' in backup mode."
95     ssh postgres@"$1" "rm /var/lib/postgresql/9.1/archive/*"
96     ssh postgres@"$1" "psql -c \"SELECT pg_start_backup('Streaming Replication', true)\" postgres"
97 }
98
99 #rsync master's data to local postgres dir
100 RsyncWhileLive () {
101     echo "[INFO] Transfering data from master '$1' ..."
102     rsync -C -av --delete --progress -e ssh --exclude server.key --exclude server.crt --exclude recovery.conf --exclude recovery.done --exclude postmaster.pid --exclude pg_xlog/ "$1":"$datadir"/ "$datadir"/ > /dev/null
103     if [ $? == 0 ]
104     then
105         echo "[OK] Transfert completed.";
106     else
107         echo "[ERROR] Error during transfer !";
108         exit 0;
109     fi
110 }
111
112
113 #This archives the WAL log (ends writing to it and moves it to the $archive dir
114 StopBackupModeAndArchiveIntoWallLog () {
115     echo "[INFO] Disable backup mode from master '$1'."
116     ssh postgres@"$1" "psql -c \"SELECT pg_stop_backup()\" postgres"
117     echo "[INFO] Synchronising master/slave archive directory..."
118     rsync -C -a --progress -e ssh "$1":"$archivedir"/ "$archivedirdest"/ > /dev/null
119     if [ $? == 0 ]
120     then
121         echo "[OK] Sync achieved.";
122     else
123         echo "[ERROR] Error during sync !";
124         exit 0;
125     fi
126 }
127
128 #stop postgres and copy transactions made during the last two rsync's
129 StopPostgreSqlAndFinishRsync () {
130     echo "[INFO] Stopping master node.."
131     ssh postgres@"$1" "/etc/init.d/postgresql stop"
132     echo "[INFO] Transfering xlog files from master... "
133     rsync -av --delete --progress -e ssh "$sourcehost":"$datadir"/pg_xlog/ "$datadir"/pg_xlog/ > /dev/null
134     if [ $? == 0 ]
135     then
136         echo "[OK] Transfert completed.";
137     else
138         echo "[ERROR] Error during transfer !";
139         exit 0;
140     fi
141 }
142
143 #Start both Master and Slave
144 StartLocalAndThenRemotePostGreSql () {
145     echo "[INFO] Starting slave node.."
146     /etc/init.d/postgresql start
147     if ! killall -0 postgres; then echo '[ERROR] Slave not running !'; else echo "[OK] Slave started."; fi;
148
149
150     echo "[INFO] Starting master node.."
151     ssh postgres@"$1" "/etc/init.d/postgresql start"
152     
153     status=$(ssh  postgres@$1 "if ! killall -0 postgres; then echo 'error'; else echo 'running'; fi;")
154     if [ $status == "error" ]
155     then
156         echo "[ERROR] Master not running !";
157         exit 0;
158     else
159         echo "[OK] Master started.";
160     fi
161 }
162
163 #Execute above operations
164 Whoami
165 CheckIfPostgresIsRunningOnRemoteHost "$1"
166 CheckIfMasterIsActuallyAMaster "$1"
167 PrepareLocalServer "$datadir"
168 CheckForRecoveryConfig "$datadir"
169 PutMasterIntoBackupMode "$1"
170 RsyncWhileLive "$1"
171 StopBackupModeAndArchiveIntoWallLog "$1" "$archivedir" "$archivedirdest"
172 StopPostgreSqlAndFinishRsync "$1"
173 StartLocalAndThenRemotePostGreSql "$1"