10637.3.1
by Guilherme Salgado
Use the default python version instead of a hard-coded version |
1 |
#!/usr/bin/python
|
8452.3.3
by Karl Fogel
* utilities/: Add copyright header block to source files that were |
2 |
#
|
8687.15.2
by Karl Fogel
In files modified by r8688, change "<YEARS>" to "2009", as per |
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
8687.15.3
by Karl Fogel
Shorten the copyright header block to two lines. |
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
8452.3.3
by Karl Fogel
* utilities/: Add copyright header block to source files that were |
5 |
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
6 |
"""
|
7 |
Restore a full database dump. This script should become unnecessary
|
|
8 |
when we are running PostgreSQL 8 as it will correctly order its dumps.
|
|
9 |
"""
|
|
10 |
||
11 |
from optparse import OptionParser |
|
14612.2.6
by William Grant
utilities |
12 |
import os |
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
13 |
from signal import SIGTERM |
14612.2.6
by William Grant
utilities |
14 |
from subprocess import ( |
15 |
PIPE, |
|
16 |
Popen, |
|
17 |
)
|
|
18 |
import sys |
|
19 |
import tempfile |
|
20 |
||
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
21 |
|
22 |
class DumpFile(object): |
|
23 |
"""File-like object wrapping a normal or compressed file on disk"""
|
|
24 |
process = None |
|
25 |
||
26 |
def __init__(self, dumpname): |
|
27 |
||
28 |
if dumpname.endswith('.bz2'): |
|
29 |
self.process = Popen( |
|
30 |
["bunzip2", "-c", dumpname], stdin=PIPE, stdout=PIPE |
|
31 |
)
|
|
32 |
elif dumpname.endswith('.gz'): |
|
33 |
self.process = Popen( |
|
34 |
["gunzip", "-c", dumpname], stdin=PIPE, stdout=PIPE |
|
35 |
)
|
|
36 |
else: |
|
37 |
self.out = open(dumpname, 'r') |
|
38 |
||
39 |
if self.process is not None: |
|
40 |
self.process.stdin.close() |
|
41 |
self.out = self.process.stdout |
|
42 |
||
43 |
def read(self, bytes=None): |
|
44 |
return self.out.read(bytes) |
|
45 |
||
46 |
def close(self): |
|
47 |
if self.process is None: |
|
48 |
return self.out.close() |
|
49 |
||
50 |
if self.process.poll() is not None: |
|
51 |
if self.process.returncode != 0: |
|
52 |
print >> sys.stderr, "ERROR: Uncompressor returned %d" % ( |
|
53 |
self.process.returncode |
|
54 |
)
|
|
55 |
return
|
|
56 |
||
57 |
os.kill(self.process.pid, SIGTERM) |
|
58 |
||
59 |
def fileno(self): |
|
60 |
return self.out.fileno() |
|
61 |
||
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
62 |
|
63 |
def generate_order(dumpname): |
|
64 |
"""Generate a correctly order dump listing"""
|
|
65 |
||
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
66 |
dump_input = DumpFile(dumpname) |
67 |
cmd = Popen('pg_restore -l', shell=True, stdout=PIPE, stdin=dump_input) |
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
68 |
(stdout, stderr) = cmd.communicate() |
69 |
if cmd.returncode != 0: |
|
70 |
raise RuntimeError('pg_restore returned %d' % rv) |
|
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
71 |
dump_input.close() |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
72 |
|
73 |
full_listing = [l for l in stdout.split('\n') if l.strip()] |
|
74 |
||
75 |
full_listing.sort(listing_cmp) |
|
76 |
||
77 |
return '\n'.join(full_listing) |
|
78 |
||
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
79 |
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
80 |
def listing_cmp(a, b): |
2936.1.1
by Stuart Bishop
Update pgrestore.py to resture PostgreSQL 7.4 dumps under PostgreSQL 8.0 |
81 |
if POSTGRESQL7: |
82 |
idx = 2 |
|
83 |
else: |
|
84 |
idx = 3 |
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
85 |
if a.startswith(';'): |
86 |
atype = ';' |
|
87 |
else: |
|
2936.1.1
by Stuart Bishop
Update pgrestore.py to resture PostgreSQL 7.4 dumps under PostgreSQL 8.0 |
88 |
atype = a.split()[idx] |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
89 |
|
90 |
if b.startswith(';'): |
|
91 |
btype = ';' |
|
92 |
else: |
|
2936.1.1
by Stuart Bishop
Update pgrestore.py to resture PostgreSQL 7.4 dumps under PostgreSQL 8.0 |
93 |
btype = b.split()[idx] |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
94 |
|
2936.1.3
by Stuart Bishop
pgrestore helper should create INDEXes earlier so they can be used by contraints checks |
95 |
# Build indexes in same parse as tables, so that tables with constraints
|
96 |
# that need to reference other tables (eg. CHECK is_person() columns)
|
|
97 |
# load in a reasonable time. This is more fragile, but should last
|
|
98 |
# until postgresql 8 migration makes this script irrelevant.
|
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
99 |
scores = { |
100 |
';': 0, |
|
101 |
'SCHEMA': 1, |
|
102 |
'TYPE': 10, |
|
103 |
'FUNC': 10, |
|
104 |
'PROCEDURAL': 10, |
|
105 |
'FUNCTION': 10, |
|
106 |
'OPERATOR': 20, |
|
107 |
'TABLE': 30, |
|
108 |
'SEQUENCE': 35, |
|
109 |
'BLOBS': 38, |
|
110 |
'VIEW': 40, |
|
111 |
'TRIGGER': 90, |
|
112 |
'FK': 95, |
|
113 |
'CONSTRAINT': 95, |
|
2936.1.3
by Stuart Bishop
pgrestore helper should create INDEXes earlier so they can be used by contraints checks |
114 |
'INDEX': 30, |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
115 |
'COMMENT': 200, |
116 |
'ACL': 1000, |
|
117 |
}
|
|
118 |
||
119 |
# Will fail if we get an unknown type in the listing, which is by design
|
|
120 |
# at the moment. Might want a default value though instead?
|
|
121 |
return cmp(scores[atype], scores[btype]) |
|
122 |
||
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
123 |
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
124 |
def createdb(options): |
125 |
args = ['createdb', '--encoding=UNICODE'] |
|
126 |
||
127 |
if options.user: |
|
128 |
args.append('--username=%s' % options.user) |
|
129 |
||
130 |
if options.host: |
|
131 |
args.append('--host=%s' % options.host) |
|
132 |
||
133 |
args.append(options.dbname) |
|
134 |
||
135 |
if options.verbose: |
|
136 |
cmd = ' '.join(args) |
|
137 |
print >> sys.stderr, 'Running %s' % cmd |
|
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
138 |
createdb = Popen(args) |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
139 |
else: |
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
140 |
createdb = Popen(args, stdout=PIPE, stderr=PIPE) |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
141 |
|
142 |
(out, err) = createdb.communicate() |
|
143 |
||
144 |
if createdb.returncode != 0: |
|
145 |
print >> sys.stderr, err |
|
146 |
print >> sys.stderr, out |
|
147 |
print >> sys.stderr, 'ERROR: %d' % createdb.returncode |
|
148 |
sys.exit(createdb.returncode) |
|
149 |
||
150 |
||
151 |
if __name__ == "__main__": |
|
152 |
||
153 |
parser = OptionParser("usage: %prog [options] [DUMPFILE | -]") |
|
154 |
parser.add_option( |
|
155 |
"-d", "--dbname", dest="dbname", |
|
156 |
help="Create the database DBNAME and restore the dump into it", |
|
157 |
metavar="DBNAME" |
|
158 |
)
|
|
159 |
parser.add_option( |
|
160 |
"-H", "--host", dest="host", default=None, |
|
161 |
help="Connect to PostgreSQL running on HOST", |
|
162 |
metavar="HOST" |
|
163 |
)
|
|
164 |
parser.add_option( |
|
165 |
"--no-acl", dest="perms", action="store_false", |
|
166 |
default=True, help="Do not restore ownership or permissions", |
|
167 |
)
|
|
168 |
parser.add_option( |
|
169 |
"-U", "--user", dest="user", |
|
170 |
help="Connect as superuser USER", metavar="USER", default=None |
|
171 |
)
|
|
172 |
parser.add_option( |
|
173 |
"-v", "--verbose", dest="verbose", |
|
174 |
action="store_true", default=False |
|
175 |
)
|
|
2936.1.1
by Stuart Bishop
Update pgrestore.py to resture PostgreSQL 7.4 dumps under PostgreSQL 8.0 |
176 |
parser.add_option( |
177 |
"-7", dest="postgres7", |
|
178 |
action="store_true", default=False, |
|
179 |
help="Restore into a PostgreSQL 7.4 database" |
|
180 |
)
|
|
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
181 |
|
182 |
(options, args) = parser.parse_args() |
|
183 |
||
2936.1.1
by Stuart Bishop
Update pgrestore.py to resture PostgreSQL 7.4 dumps under PostgreSQL 8.0 |
184 |
if options.postgres7: |
185 |
POSTGRESQL7 = True |
|
186 |
else: |
|
187 |
POSTGRESQL7 = False |
|
188 |
||
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
189 |
if len(args) > 1: |
190 |
parser.error("Too many arguments") |
|
191 |
||
192 |
if len(args) == 0: |
|
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
193 |
parser.error("Must specify dump file name.") |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
194 |
|
195 |
dumpname = args[0] |
|
196 |
||
197 |
if not os.path.exists(dumpname): |
|
198 |
parser.error("%s does not exist" % dumpname) |
|
199 |
||
200 |
handle, listingfilename = tempfile.mkstemp() |
|
201 |
try: |
|
202 |
os.close(handle) |
|
203 |
listingfile = open(listingfilename, 'w') |
|
204 |
listingfile.write(generate_order(dumpname)) |
|
205 |
listingfile.close() |
|
206 |
||
207 |
pg_restore_args = ["pg_restore", "--use-list=%s" % listingfilename] |
|
208 |
||
209 |
if options.dbname: |
|
210 |
createdb(options) |
|
211 |
pg_restore_args.append("--dbname=%s" % options.dbname) |
|
212 |
||
213 |
if not options.perms: |
|
214 |
pg_restore_args.append("--no-owner") |
|
215 |
pg_restore_args.append("--no-acl") |
|
216 |
||
217 |
if options.user: |
|
218 |
pg_restore_args.append("--user=%s" % options.user) |
|
219 |
||
220 |
if options.host: |
|
221 |
pg_restore_args.append("--host=%s" % options.host) |
|
222 |
||
223 |
if options.verbose: |
|
224 |
pg_restore_args.append("--verbose") |
|
225 |
||
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
226 |
dump_input = DumpFile(dumpname) |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
227 |
|
228 |
if options.verbose: |
|
229 |
cmd = ' '.join(pg_restore_args) |
|
230 |
print >> sys.stderr, "Running %s" % cmd |
|
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
231 |
rest = Popen(pg_restore_args, stdin=dump_input) |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
232 |
else: |
1876
by Canonical.com Patch Queue Manager
[r=jamesh] database dump script |
233 |
rest = Popen(pg_restore_args, stderr=PIPE, stdin=dump_input) |
1745
by Canonical.com Patch Queue Manager
[r=jamesh] Simple database restoration script and sampledata fixes |
234 |
|
235 |
(out,err) = rest.communicate() |
|
236 |
if rest.returncode != 0: |
|
237 |
print >> sys.stderr, err |
|
238 |
print >> sys.stderr, 'ERROR: %d' % rest.returncode |
|
239 |
sys.exit(rest.returncode) |
|
240 |
||
241 |
finally: |
|
242 |
os.unlink(listingfilename) |
|
243 |
||
244 |