Merge lp:~therp-nl/openupgrade-server/openupgrade-server_migrate-script into lp:openupgrade-server/6.1

Proposed by Holger Brunn (Therp)
Status: Superseded
Proposed branch: lp:~therp-nl/openupgrade-server/openupgrade-server_migrate-script
Merge into: lp:openupgrade-server/6.1
Diff against target: 212 lines (+207/-0)
1 file modified
scripts/migrate.py (+207/-0)
To merge this branch: bzr merge lp:~therp-nl/openupgrade-server/openupgrade-server_migrate-script
Reviewer Review Type Date Requested Status
Stefan Rijnhart (Opener) Needs Fixing
Review via email: mp+117287@code.launchpad.net

This proposal has been superseded by a proposal from 2012-11-16.

Description of the change

Usage: migrate.py [options]

Migrate script for the impatient or lazy. Makes a copy of your database,
downloads the files necessary to migrate it as requested and runs the
migration on the copy (so your original database will not be touched). While
the migration is running only errors are shown, for a detailed log see
${branch-dir}/migration.log

Options:
  -h, --help show this help message and exit
  -C CONFIG, --config=CONFIG
                        current openerp config (required)
  -D DATABASE, --database=DATABASE
                        current openerp database (required if not given in
                        config)
  -B BRANCH_DIR, --branch-dir=BRANCH_DIR
                        the directory to download openupgrade-server code to
                        [/var/tmp/openupgrade]
  -R MIGRATIONS, --run-migrations=MIGRATIONS
                        comma separated list of migrations to run 6.0,6.1
                        (required)

To post a comment you must log in.
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi Holger,

Thank you, I can see this being useful. However, it seems a bit tailor made for Therp as it has the Banking Addons hardcoded in the script. Worse is that it does not allow for an arbitrary collection of addons branches.

Could you make it a little more generic so that an arbitrary number of branches may be downloaded and incorporated in the addons path? Such a construction may very well feature the Banking Addons as an example.

One more thing is the location of the script (the root path of the repository) which together with its name make it a little too prominent. It seems to imply that the script is tantamount to migrating any database. Please move it to the openupgrade directory, and change it to something like 'batch-migrate.py'.

Cheers,
Stefan.

review: Needs Fixing
3992. By Holger Brunn (Therp)

[IMP] enable injecting own upgrade modules
[IMP] enable inplace upgrade

3993. By Holger Brunn (Therp)

[IMP] refactor branch/pull process

3994. By Holger Brunn (Therp)

[FIX] set without_demo=True for migration

3995. By Holger Brunn (Therp)

[IMP] remove unused db_host in config file

3996. By Holger Brunn (Therp)

[IMP] add possibility to just link some addon paths

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'scripts'
2=== added file 'scripts/migrate.py'
3--- scripts/migrate.py 1970-01-01 00:00:00 +0000
4+++ scripts/migrate.py 2012-11-16 10:05:24 +0000
5@@ -0,0 +1,207 @@
6+#!/usr/bin/python
7+
8+import os
9+import sys
10+import StringIO
11+import psycopg2
12+import psycopg2.extensions
13+from optparse import OptionParser
14+from ConfigParser import SafeConfigParser
15+from bzrlib.branch import Branch
16+from bzrlib.repository import Repository
17+from bzrlib.workingtree import WorkingTree
18+import bzrlib.plugin
19+import bzrlib.builtins
20+import bzrlib.info
21+
22+migrations={
23+ '6.1': {
24+ 'addons': {
25+ 'addons': 'lp:openupgrade-addons',
26+ 'banking': 'lp:banking-addons',
27+ 'web': {'url': 'lp:openerp-web/6.1', 'addons_dir': 'addons'},
28+ },
29+ 'server': {
30+ 'url': 'lp:openupgrade-server',
31+ 'addons_dir': os.path.join('openerp','addons'),
32+ 'root_dir': os.path.join(''),
33+ 'cmd': 'openerp-server --update=all --database=%(db)s '+
34+ '--config=%(config)s --stop-after-init --no-xmlrpc --no-netrpc',
35+ },
36+ },
37+ '6.0': {
38+ 'addons': {
39+ 'addons': 'lp:openupgrade-addons/6.0',
40+ 'banking': 'lp:banking-addons/6.0',
41+ },
42+ 'server': {
43+ 'url': 'lp:openupgrade-server/6.0',
44+ 'addons_dir': os.path.join('bin','addons'),
45+ 'root_dir': os.path.join('bin'),
46+ 'cmd': 'bin/openerp-server.py --update=all --database=%(db)s '+
47+ '--config=%(config)s --stop-after-init --no-xmlrpc --no-netrpc',
48+ },
49+ },
50+}
51+config = SafeConfigParser({'db_host': 'localhost'})
52+parser = OptionParser(description="""Migrate script for the impatient or lazy.
53+Makes a copy of your database, downloads the files necessary to migrate
54+it as requested and runs the migration on the copy (so your original
55+database will not be touched). While the migration is running only errors are
56+shown, for a detailed log see ${branch-dir}/migration.log
57+""")
58+parser.add_option("-C", "--config", action="store", type="string",
59+ dest="config",
60+ help="current openerp config (required)")
61+parser.add_option("-D", "--database", action="store", type="string",
62+ dest="database",
63+ help="current openerp database (required if not given in config)")
64+parser.add_option("-B", "--branch-dir", action="store", type="string",
65+ dest="branch_dir",
66+ help="the directory to download openupgrade-server code to [%default]",
67+ default='/var/tmp/openupgrade')
68+parser.add_option("-R", "--run-migrations", action="store", type="string",
69+ dest="migrations",
70+ help="comma separated list of migrations to run\n\n"+
71+ ','.join(sorted([a for a in migrations]))+
72+ "\n(required)")
73+parser.add_option("-A", "--add", action="store", type="string", dest="add",
74+ help="load a python module that declares on dict 'migrations' which is"+
75+ " merged with the one of this script (see the source for details)")
76+parser.add_option("-I", "--inplace", action="store_true", dest="inplace",
77+ help="don't copy database before attempting upgrade (dangerous)")
78+(options, args) = parser.parse_args()
79+
80+if (not options.config or not options.migrations
81+ or not reduce(lambda a,b: a and (b in migrations),
82+ options.migrations.split(','), True)):
83+ parser.print_help()
84+ sys.exit()
85+
86+config.read(options.config)
87+
88+db_user=config.get('options', 'db_user')
89+db_name=options.database or config.get('options', 'db_name')
90+
91+if not db_name or db_name=='' or db_name.isspace() or db_name.lower()=='false':
92+ parser.print_help()
93+ sys.exit()
94+
95+if options.inplace:
96+ db=db_name
97+else:
98+ db=db_name+'_migrated'
99+
100+if options.add:
101+ merge_migrations={}
102+ if os.path.isfile(options.add):
103+ import imp
104+ merge_migrations_mod=imp.load_source('merge_migrations_mod',
105+ options.add)
106+ merge_migrations=merge_migrations_mod.migrations
107+ else:
108+ merge_migrations=eval(options.add)
109+
110+ def deep_update(dict1, dict2):
111+ result={}
112+ for (name,value) in dict1.iteritems():
113+ if dict2.has_key(name):
114+ if isinstance(dict1[name], dict) and isinstance(dict2[name],
115+ dict):
116+ result[name]=deep_update(dict1[name], dict2[name])
117+ else:
118+ result[name]=dict2[name]
119+ else:
120+ result[name]=dict1[name]
121+ for (name,value) in dict2.iteritems():
122+ if name not in dict1:
123+ result[name]=value
124+ return result
125+
126+ migrations=deep_update(migrations, merge_migrations)
127+
128+for version in options.migrations.split(','):
129+ if version not in migrations:
130+ print '%s is not a valid version! (valid verions are %s)' % (version,
131+ ','.join(sorted([a for a in migrations])))
132+
133+bzrlib.plugin.load_plugins()
134+bzrlib.trace.enable_default_logging()
135+logfile=os.path.join(options.branch_dir,'migration.log')
136+
137+if not os.path.exists(options.branch_dir):
138+ os.mkdir(options.branch_dir)
139+
140+for version in options.migrations.split(','):
141+ if not os.path.exists(os.path.join(options.branch_dir,version)):
142+ os.mkdir(os.path.join(options.branch_dir,version))
143+ for (name,url) in dict(migrations[version]['addons'],
144+ server=migrations[version]['server']['url']).iteritems():
145+ url=url['url'] if isinstance(url, dict) else url
146+ if os.path.exists(os.path.join(options.branch_dir,version,name)):
147+ cmd_revno=bzrlib.builtins.cmd_revno()
148+ cmd_revno.outf=StringIO.StringIO()
149+ cmd_revno.run(location=os.path.join(options.branch_dir,version,
150+ name))
151+ print 'updating %s rev%s' %(os.path.join(version,name),
152+ cmd_revno.outf.getvalue().strip())
153+ cmd_pull=bzrlib.builtins.cmd_pull()
154+ cmd_pull.outf=StringIO.StringIO()
155+ cmd_pull.outf.encoding='utf8'
156+ cmd_pull.run(directory=os.path.join(options.branch_dir,version,
157+ name), overwrite=True)
158+ if hasattr(cmd_pull, '_operation'):
159+ cmd_pull.cleanup_now()
160+ print 'now at rev'+cmd_revno.outf.getvalue().strip()
161+ else:
162+ print 'getting '+url
163+ cmd_branch=bzrlib.builtins.cmd_branch()
164+ cmd_branch.outf=StringIO.StringIO()
165+ cmd_branch.run(url, os.path.join(options.branch_dir,version,name))
166+
167+if not options.inplace:
168+ print('copying database %(db_name)s to %(db)s...' % {'db_name': db_name,
169+ 'db': db})
170+ conn=psycopg2.connect(database=db_name, user=db_user)
171+ conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
172+ cur=conn.cursor()
173+ cur.execute('drop database if exists %(db)s' % {'db': db})
174+ cur.execute('create database %(db)s' % {'db': db})
175+ cur.close()
176+ os.system(('pg_dump --format=custom --user=%(user)s %(db_name)s | pg_restore '+
177+ '--dbname=%(db)s') % {
178+ 'user': db_user,
179+ 'db_name': db_name,
180+ 'db': db,
181+ })
182+
183+for version in options.migrations.split(','):
184+ print 'running migration for '+version
185+ config.set('options', 'logfile', logfile)
186+ config.set('options', 'port', 'False')
187+ config.set('options', 'netport', 'False')
188+ config.set('options', 'xmlrpc_port', 'False')
189+ config.set('options', 'netrpc_port', 'False')
190+ config.set('options', 'addons_path',
191+ ','.join([os.path.join(options.branch_dir,
192+ version,'server',migrations[version]['server']['addons_dir'])] +
193+ [
194+ os.path.join(options.branch_dir,version,name,
195+ url['addons_dir'] if isinstance(url, dict) else '')
196+ for (name,url) in migrations[version]['addons'].iteritems()
197+ ]
198+ )
199+ )
200+ config.set('options', 'root_path', os.path.join(options.branch_dir,version,
201+ 'server', migrations[version]['server']['root_dir']))
202+ config.write(open(
203+ os.path.join(options.branch_dir,version,'server.cfg'), 'w+'))
204+ os.system(
205+ os.path.join(options.branch_dir,version,'server',
206+ migrations[version]['server']['cmd'] % {
207+ 'db': db,
208+ 'config': os.path.join(options.branch_dir,version,
209+ 'server.cfg')
210+ }
211+ )
212+ )

Subscribers

People subscribed via source and target branches

to status/vote changes: