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