Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(920)

Side by Side Diff: scripts/tools/migrate_psql_to_sqlite.py

Issue 2096593002: Add a script to quickly migrate a master from postgresql to sqlite. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Lint Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """This script will change a master from using postgresql to sqlite.
7
8 It:
9 1) Creates .stop_master_lifecycle to stop master manager.
10 2) Stops the master.
11 3) Dumps the postgres database and imports it into sqlite.
12 4) Removes the .dbconfig file indicating buildbot should now use sqlite.
13 5) Starts the master.
14 6) Removes .stop_master_lifecycle.
15
16 If this script fails in the middle you will have to restore it to a known state
17 manually.
18
19 Run this script in the master's directory. Some third_party libraries need to
20 be on the PYTHONPATH, so use runit.py:
21 export TOOLS_DIR=~/buildbot/build/scripts/tools
22 ${TOOLS_DIR}/runit.py ${TOOLS_DIR}/migrate_psql_to_sqlite.py
23
24 Without any arguments this will run in a dry-run mode and create a
25 'dry-run-psql-conversion.sqlite' file for you to inspect manually. Use
26 --no-dry-run to actually stop and restart the master and update the config.
27 """
28
29 import argparse
30 import logging
31 import os
32 import sqlite3
33 import subprocess
34 import sys
35
36 from buildbot import cache
37 from buildbot.db import connector
38 from twisted.internet import defer, reactor
39
40
41 class FakeBuildMaster(object):
42 def __init__(self):
43 self.caches = cache.CacheManager()
44
45
46 @defer.inlineCallbacks
47 def Run(args):
48 if args.no_dry_run:
49 sqlite_filename = 'state.sqlite'
50 else:
51 sqlite_filename = 'dry-run-psql-conversion.sqlite'
52
53 # Read the dbconfig. This will fail if the config doesn't exist and the
54 # master doesn't use postgresql.
55 dbconfig = {}
56 execfile('.dbconfig', dbconfig)
57
58 if args.no_dry_run:
59 # Stop master manager from touching this master while we play with it.
60 if os.path.exists('.stop_master_lifecycle'):
61 raise Exception('A .stop_master_lifecycle file already exists')
62 logging.info('Creating .stop_master_lifecycle file')
63 with open('.stop_master_lifecycle', 'w') as fh:
64 fh.write('migrate_psql_to_sqlite.py')
65
66 # Stop the master.
67 logging.info('Stopping master')
68 subprocess.check_call(['make', 'stop'])
69 subprocess.check_call(['make', 'wait'])
70
71 # Dump the postgres database.
72 logging.info('Dumping postgres database %s', dbconfig['dbname'])
73 env = os.environ.copy()
74 env['PGPASSWORD'] = dbconfig['password']
75 sql = subprocess.check_output(['pg_dump',
76 '-d', dbconfig['dbname'],
77 '-U', dbconfig['username'],
78 '-h', 'localhost',
79 '--data-only',
80 '--inserts'], env=env)
81
82 # Strip out postgres-specific things.
83 sql = '\n'.join(
84 line for line in sql.splitlines()
85 if not line.startswith('SET') and
86 not line.startswith('INSERT INTO migrate_version') and
87 not 'pg_catalog.setval' in line)
88
89 # Delete any existing sqlite database.
90 if os.path.exists(sqlite_filename):
91 os.unlink(sqlite_filename)
92
93 # Create the new sqlite database.
94 logging.info('Creating empty sqlite database in %s', sqlite_filename)
95 db = connector.DBConnector(
96 FakeBuildMaster(), 'sqlite:///%s' % sqlite_filename, '.')
97 yield db.model.upgrade()
98
99 # Import the data into the sqlite database.
100 logging.info('Filling sqlite database %s', sqlite_filename)
101 conn = sqlite3.connect(sqlite_filename)
102 cursor = conn.cursor()
103 cursor.execute('pragma synchronous = off')
104 cursor.execute('pragma journal_mode = memory')
105 cursor.executescript(sql)
106 conn.commit()
107 conn.close()
108
109 if args.no_dry_run:
110 # Remove the .dbconfig to make it use the sqlite database.
111 logging.info('Moving .dbconfig file to dbconfig.bak')
112 os.rename('.dbconfig', 'dbconfig.bak')
113
114 # Start the master.
115 logging.info('Starting master')
116 subprocess.check_call(['make', 'start'])
117
118 # Let master manager take over again.
119 logging.info('Removing .stop_master_lifecycle file')
120 os.unlink('.stop_master_lifecycle')
121
122 logging.info('Done!')
123 else:
124 logging.info('Dry-run done!')
125
126
127 def main():
128 parser = argparse.ArgumentParser()
129 parser.add_argument('--no-dry-run', action='store_true')
130 args = parser.parse_args()
131
132 def HandleError(err):
133 err.printTraceback()
134 reactor.stop()
135
136 def Start():
137 d = Run(args)
138 d.addCallback(lambda _: reactor.stop())
139 d.addErrback(HandleError)
140
141 logging.basicConfig(level=logging.INFO,
142 format='\033[94m%(asctime)s %(message)s\033[0m')
143 reactor.callWhenRunning(Start)
144 reactor.run()
145
146
147 if __name__ == '__main__':
148 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698