Also create plugin UserStore data tables
[cascardo/ipsilon.git] / ipsilon / tools / dbupgrade.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2015 Ipsilon project Contributors, for license see COPYING
4
5 import cherrypy
6 import os
7 from jinja2 import Environment, FileSystemLoader
8 import ipsilon.util.sessions
9 from ipsilon.util.data import AdminStore, Store, UserStore, TranStore
10 from ipsilon.util.sessions import SqlSession
11 from ipsilon.root import Root
12
13 import logging
14
15 logger = logging.getLogger(__name__)
16
17
18 def _upgrade_database(datastore):
19     logger.debug('Considering datastore %s', datastore.__class__.__name__)
20     # pylint: disable=protected-access
21     current_version = datastore._get_schema_version()
22     # pylint: disable=protected-access
23     code_schema_version = datastore._code_schema_version()
24     upgrade_required = False
25     if current_version is None:
26         # Initialize schema
27         logger.debug('Initializing schema for %s',
28                      datastore.__class__.__name__)
29         upgrade_required = True
30     elif current_version != code_schema_version:
31         logger.debug('Upgrading schema for %s', datastore.__class__.__name__)
32         upgrade_required = True
33     else:
34         logger.debug('Schema for %s is up-to-date',
35                      datastore.__class__.__name__)
36     if upgrade_required:
37         if datastore.is_readonly:
38             logger.warning('Datastore is readonly. Please fix manually!')
39             return False
40         try:
41             datastore.upgrade_database()
42         except Exception as ex:  # pylint: disable=broad-except
43             # Error upgrading database
44             logger.error('Error upgrading datastore: %s', ex)
45             return False
46         else:
47             # Upgrade went OK
48             return True
49     else:
50         return True
51
52
53 def upgrade_failed():
54     logger.error('Upgrade failed. Please fix errors above and retry')
55     raise Exception('Upgrading failed')
56
57
58 def execute_upgrade(cfgfile):
59     cherrypy.lib.sessions.SqlSession = ipsilon.util.sessions.SqlSession
60     cherrypy.config.update(cfgfile)
61
62     # pylint: disable=protected-access
63     Store._is_upgrade = True
64
65     adminstore = AdminStore()
66     # First try to upgrade the config store before continuing
67     if not _upgrade_database(adminstore):
68         return upgrade_failed()
69
70     admin_config = adminstore.load_config()
71     for option in admin_config:
72         cherrypy.config[option] = admin_config[option]
73
74     # Initialize a minimal env
75     template_env = Environment(loader=FileSystemLoader(
76         os.path.join(cherrypy.config['base.dir'],
77                      'templates')))
78     root = Root('default', template_env)
79
80     # Handle the session store if that is Sql
81     logger.debug('Handling sessions datastore')
82     if cherrypy.config['tools.sessions.storage_type'] != 'sql':
83         logger.debug('Not SQL-based, skipping')
84     else:
85         dburi = cherrypy.config['tools.sessions.storage_dburi']
86         SqlSession.setup(storage_dburi=dburi)
87         if not _upgrade_database(SqlSession._store):
88             return upgrade_failed()
89
90     # Now handle the rest of the default datastores
91     for store in [UserStore, TranStore]:
92         store = store()
93         logger.debug('Handling default datastore %s',
94                      store.__class__.__name__)
95         if not _upgrade_database(store):
96             return upgrade_failed()
97
98     # And now datastores for any of the plugins
99     userstore = UserStore()
100     for facility in ['provider_config',
101                      'login_config',
102                      'info_config']:
103         for plugin in root._site[facility].enabled:
104             logger.debug('Handling plugin %s', plugin)
105             plugin = root._site[facility].available[plugin]
106             logger.debug('Creating plugin AdminStore table')
107             adminstore.create_plugin_data_table(plugin.name)
108             logger.debug('Creating plugin UserStore table')
109             userstore.create_plugin_data_table(plugin.name)
110             for store in plugin.used_datastores():
111                 logger.debug('Handling plugin datastore %s',
112                              store.__class__.__name__)
113                 if not _upgrade_database(store):
114                     return upgrade_failed()
115
116     # We are done with the init/upgrade
117     # pylint: disable=protected-access
118     Store._is_upgrade = False