1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
#
# This makefile is used for two task:
#
# - Build a replicated development environment
# - Build and replicate the staging database
#
# To build a replicated development environment:
#
# $ make -C database/replication devsetup
# $ make run
#
# To test the staging rebuild script:
#
# $ cd database/replication
# $ pg_dump --format=c launchpad_dev > launchpad.dump
# $ make stagingsetup STAGING_CONFIG=dev-staging STAGING_DUMP=launchpad.dump
# $ make stagingswitch STAGING_CONFIG=dev-staging
#
# To restore a dogfood database:
#
# $ cd database/replication
# $ make dogfood DOGFOOD_DBNAME=launchpad_dogfood DOGFOOD_DUMP=launchpad.dump
#
# This used to be 10 seconds, so we always ran staging lagged to detect
# replication glitches more easily. However, this does not play well
# with DBLoopTuner, as it correctly blocks when it detects lag.
# We should put this back when DBLoopTuner is more intelligent, perhaps
# pulling the allowable lag setting from a config file.
LAG=0 seconds
DEV_CONFIG=replicated-development
NEW_STAGING_CONFIG=staging-setup # For building the db with a different name.
STAGING_CONFIG=staging # For swapping fresh db into place.
STAGING_DUMP=launchpad.dump # Dumpfile to build new staging from.
STAGING_TABLESPACE=pg_default # 'pg_default' for default
DOGFOOD_DBNAME=launchpad_dogfood
DOGFOOD_DUMP=launchpad.dump
_CONFIG=overridden-on-command-line
_SLAVE_TABLESPACE=pg_default
PGMASSACRE=../../utilities/pgmassacre.py
CREATEDB_83=createdb --encoding=UTF8
CREATEDB_84=createdb --encoding=UTF8 --locale=C --template=template0
CREATEDB=${CREATEDB_83}
# Turn off output silencing so we can see details of staging deployments.
# Without the timestamps, we are unable to estimate production deployment
# times.
#SHHH=../../utilities/shhh.py
SHHH=
default:
echo Usage: make [start|stop|restart]
start:
./slon_ctl.py --lag="${LAG}" start
stop:
./slon_ctl.py stop
restart: stop start
devsetup:
make _prelim LPCONFIG=${DEV_CONFIG} \
_MASTER=launchpad_dev _SLAVE=launchpad_dev_slave LAG="0 seconds"
# Build the master database
LPCONFIG=${DEV_CONFIG} make -C ../schema
# Replicate it
make _replicate LPCONFIG=${DEV_CONFIG} \
_MASTER=launchpad_dev _SLAVE=launchpad_dev_slave LAG="0 seconds"
# Replicate it again, so we can test with multiple slaves.
-${PGMASSACRE} launchpad_dev_slave2
${CREATEDB} launchpad_dev_slave2
LPCONFIG=${DEV_CONFIG} ./slon_ctl.py start \
node3_node 'dbname=launchpad_dev_slave2 user=slony'
LPCONFIG=${DEV_CONFIG} ./new-slave.py 3 launchpad_dev_slave2
LPCONFIG=${DEV_CONFIG} ../schema/security.py -d launchpad_dev_slave2
# Regenerate the preamble for manual slonik(1) usage.
LPCONFIG=${DEV_CONFIG} ./preamble.py > preamble.sk
# Restart slon daemons with default lag setting.
LPCONFIG=${DEV_CONFIG} ./slon_ctl.py stop
LPCONFIG=${DEV_CONFIG} ./slon_ctl.py --lag="${LAG}" start
# Build _new staging databases from a production dump.
stagingsetup:
make _prelim LPCONFIG=${NEW_STAGING_CONFIG} \
_MASTER=lpmain_staging_new _SLAVE=lpmain_staging_slave_new \
LAG="0 seconds"
# Create the DB with the desired default tablespace.
${CREATEDB} --tablespace ${STAGING_TABLESPACE} lpmain_staging_new
# Restore the database. We need to restore permissions, despite
# later running security.py, to pull in permissions granted on
# production to users not maintained by security.py.
pg_restore --dbname=lpmain_staging_new \
--no-owner --exit-on-error ${STAGING_DUMP}
# Uninstall Slony-I if it is installed - a pg_dump of a DB with
# Slony-I installed isn't usable without this step.
LPCONFIG=${NEW_STAGING_CONFIG} ./repair-restored-db.py
# Setup replication
make _replicate LPCONFIG=${NEW_STAGING_CONFIG} LAG="0 seconds" \
_MASTER=lpmain_staging_new _SLAVE=lpmain_staging_slave_new \
_SLAVE_TABLESPACE=${STAGING_TABLESPACE}
# Switch the _new staging databases into place.
stagingswitch:
# Stop Slony-I daemons - don't confuse the poor darlings.
-LPCONFIG=${NEW_STAGING_CONFIG} ./slon_ctl.py stop
-LPCONFIG=${STAGING_CONFIG} ./slon_ctl.py stop
# Kill the existing staging database if it exists.
-${PGMASSACRE} lpmain_staging
-${PGMASSACRE} lpmain_staging_slave
# Rename the newly build staging databases.
psql -d template1 -c \
"ALTER DATABASE lpmain_staging_new RENAME TO lpmain_staging;"
psql -d template1 -c "\
ALTER DATABASE lpmain_staging_slave_new \
RENAME TO lpmain_staging_slave;"
# Fix the paths to match.
psql -d lpmain_staging -U slony -c \
"UPDATE _sl.sl_path SET pa_conninfo=replace(pa_conninfo, '_new', '')"
psql -d lpmain_staging_slave -U slony -c \
"UPDATE _sl.sl_path SET pa_conninfo=replace(pa_conninfo, '_new', '')"
# Start the slon daemons, with requested lag.
LPCONFIG=${STAGING_CONFIG} ./slon_ctl.py --lag="${LAG}" start
dogfood:
${CREATEDB} ${DOGFOOD_DBNAME}
pg_restore --dbname=${DOGFOOD_DBNAME} --no-acl --no-owner \
--exit-on-error ${DOGFOOD_DUMP}
./repair-restored-db.py -d ${DOGFOOD_DBNAME}
../schema/upgrade.py -d ${DOGFOOD_DBNAME}
../schema/fti.py -d ${DOGFOOD_DBNAME}
../schema/security.py -d ${DOGFOOD_DBNAME}
_prelim:
@echo LPCONFIG currently ${LPCONFIG}
# Create the slony PostgreSQL superuser if necessary.
-createuser --superuser slony
# Stop the slon daemons and wait a bit for connections to drop.
-./slon_ctl.py stop
sleep 5
# Drop any existing databases if they exist
${PGMASSACRE} ${_MASTER}
${PGMASSACRE} ${_SLAVE}
_replicate:
@echo LPCONFIG currently ${LPCONFIG}
# Start the slon daemon for the master.
./slon_ctl.py --lag="0 seconds" start \
node1_node "dbname=${_MASTER} user=slony"
# Initialize the cluster and create replication sets.
./initialize.py
# Create the soon-to-be-slave database, empty at this point.
${CREATEDB} --tablespace=${_SLAVE_TABLESPACE} ${_SLAVE}
# Start the slon daemon for the slave
./slon_ctl.py --lag="0 seconds" start \
node2_node "dbname=${_SLAVE} user=slony"
# Setup the slave
./new-slave.py 2 "dbname=${_SLAVE}"
# Upgrade all databases in the cluster and reset security.
@echo Running upgrade.py `date`
${SHHH} ../schema/upgrade.py
@echo Running fti.py `date`
${SHHH} ../schema/fti.py
@echo Running security.py `date`
./slon_ctl.py stop # security.py can deadlock with slony
${SHHH} ../schema/security.py --cluster -U slony
# Restart slon daemons with default lag setting.
./slon_ctl.py --lag="${LAG}" start
# Generate a preamble for manual slonik(1) usage.
./preamble.py > preamble.sk
|