4 from sqlalchemy import MetaData, Table
5 from sqlalchemy.exc import NoSuchTableError
7 from migrate.versioning.api import version, db_version, version_control, upgrade
9 from sfa.util.sfalogging import logger
10 from sfa.storage.model import init_tables
12 ### this script will upgrade from a pre-2.1 db
13 # * 1.0 and up to 1.1-4: ('very old')
14 # was piggybacking the planetlab5 database
15 # this is kind of out of our scope here, we don't have the credentials
16 # to connect to planetlab5, but this is documented in
17 # https://svn.planet-lab.org/wiki/SFATutorialConfigureSFA#Upgradingnotes
18 # and essentially this is seamless to users
19 # * from 1.1-5 up to 2.0-x: ('old')
20 # uses the 'sfa' db and essentially the 'records' table,
21 # as well as record_types
22 # together with an 'sfa_db_version' table (version, subversion)
24 # we have an 'records' table, plus 'users' and the like
25 # and once migrate has kicked in there is a table named
26 # migrate_db_version (repository_id, repository_path, version)
28 # An initial attempt to run this as a 001_*.py migrate script
29 # did not quite work out (essentially we need to set the current version
30 # number out of the migrations logic)
31 # also this approach has less stuff in the initscript, which seems just right
35 header="Upgrading to 2.1 or higher"
38 from sfa.storage.alchemy import alchemy
40 self.engine=alchemy.engine
41 self.repository="/usr/share/sfa/migrations"
42 self.meta=MetaData (bind=self.engine)
44 def current_version (self):
46 return db_version (self.url, self.repository)
50 def table_exists (self, tablename):
52 table=Table (tablename, self.meta, autoload=True)
54 except NoSuchTableError:
57 def drop_table (self, tablename):
58 if self.table_exists (tablename):
59 print >>sys.stderr, "%s: Dropping table %s"%(DBSchema.header,tablename)
60 self.engine.execute ("drop table %s cascade"%tablename)
62 print >>sys.stderr, "%s: no need to drop table %s"%(DBSchema.header,tablename)
64 def handle_old_releases (self):
66 # try to find out which old version this can be
67 if not self.table_exists ('records'):
68 # this likely means we've just created the db, so it's either a fresh install
69 # or we come from a 'very old' depl.
70 # in either case, an import is required but there's nothing to clean up
71 print >> sys.stderr,"%s: make sure to run import"%(DBSchema.header,)
72 elif self.table_exists ('sfa_db_version'):
73 # we come from an 'old' version
74 self.drop_table ('records')
75 self.drop_table ('record_types')
76 self.drop_table ('sfa_db_version')
78 # we should be good here
81 print >> sys.stderr, "%s: unknown exception"%(DBSchema.header,)
82 traceback.print_exc ()
84 # after this call the db schema and the version as known by migrate should
85 # reflect the current data model and the latest known version
86 def init_or_upgrade (self):
87 # check if under version control, and initialize it otherwise
88 if self.current_version() is None:
90 # can be either a very old version, or a fresh install
91 # for very old versions:
92 self.handle_old_releases()
93 # in any case, initialize db from current code and reflect in migrate
94 init_tables(self.engine)
95 code_version = version (self.repository)
96 version_control (self.url, self.repository, code_version)
98 # use migrate in the usual way
99 before="%s"%self.current_version()
100 upgrade (self.url, self.repository)
101 after="%s"%self.current_version()
103 logger.info("DBSchema : upgraded from %s to %s"%(before,after))
105 # this call will trash the db altogether
107 drop_tables(self.engine)
109 if __name__ == '__main__':
110 DBSchema().init_or_upgrade()