From: Simo Sorce Date: Mon, 10 Nov 2014 19:57:53 +0000 (-0500) Subject: Add simple SqlSession implementation X-Git-Tag: v0.3.0~29 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=5e0b9747121eab67c5a3ee3bb42a677e35da7fd6 Add simple SqlSession implementation This allows us to store session data in the DB. This way session data can be shared by multiple servers behind a balancer. Signed-off-by: Simo Sorce Reviewed-by: Patrick Uiterwijk --- diff --git a/ipsilon/install/ipsilon-server-install b/ipsilon/install/ipsilon-server-install index c6d656d..df2a965 100755 --- a/ipsilon/install/ipsilon-server-install +++ b/ipsilon/install/ipsilon-server-install @@ -112,6 +112,18 @@ def install(plugins, args): 'datadir': args['data_dir'], 'dbname': 'transactions'}, 'secure': "False" if args['secure'] == "no" else "True", 'debugging': "True" if args['server_debugging'] else "False"} + # Testing database sessions + if 'session_type' in args: + confopts['sesstype'] = args['session_type'] + else: + confopts['sesstype'] = 'file' + if 'session_dburi' in args: + confopts['sessopt'] = 'dburi' + confopts['sessval'] = args['session_dburi'] + else: + confopts['sessopt'] = 'path' + confopts['sessval'] = os.path.join(args['data_dir'], 'sessions') + # Whetehr to disable security (for testing) if args['secure'] == 'no': confopts['secure'] = "False" confopts['sslrequiressl'] = "" diff --git a/ipsilon/ipsilon b/ipsilon/ipsilon index 681600d..094a09d 100755 --- a/ipsilon/ipsilon +++ b/ipsilon/ipsilon @@ -27,6 +27,7 @@ from ipsilon.util.data import AdminStore from ipsilon.util import page from ipsilon.root import Root from jinja2 import Environment, FileSystemLoader +import ipsilon.util.sessions def nuke_session_locks(): @@ -51,6 +52,7 @@ elif os.path.isfile('/etc/ipsilon/ipsilon.conf'): else: raise IOError("Configuration file not found") +cherrypy.lib.sessions.SqlSession = ipsilon.util.sessions.SqlSession cherrypy.config.update(cfgfile) nuke_session_locks() diff --git a/ipsilon/util/sessions.py b/ipsilon/util/sessions.py new file mode 100755 index 0000000..b724471 --- /dev/null +++ b/ipsilon/util/sessions.py @@ -0,0 +1,74 @@ +#!/usr/bin/python +# +# Copyright (C) 2014 Ipsilon project Contributors, for licensee see COPYING + +import base64 +from cherrypy.lib.sessions import Session +from ipsilon.util.data import SqlStore, SqlQuery +import threading +try: + import cPickle as pickle +except ImportError: + import pickle + + +SESSION_COLUMNS = ['id', 'data', 'expiration_time'] + + +class SqlSession(Session): + + dburi = None + _db = None + _proto = 2 + locks = {} + + @classmethod + def setup(cls, **kwargs): + """Initialization from cherrypy""" + + for k, v in kwargs.items(): + if k == 'storage_dburi': + cls.dburi = v + + cls._db = SqlStore(cls.dburi) + + def _exists(self): + q = SqlQuery(self._db, 'sessions', SESSION_COLUMNS) + result = q.select({'id': self.id}) + return True if result.fetchone() else False + + def _load(self): + q = SqlQuery(self._db, 'sessions', SESSION_COLUMNS) + result = q.select({'id': self.id}) + r = result.fetchone() + if r: + data = str(base64.b64decode(r[1])) + return pickle.loads(data) + + def _save(self, expiration_time): + q = None + try: + q = SqlQuery(self._db, 'sessions', SESSION_COLUMNS, trans=True) + q.delete({'id': self.id}) + data = pickle.dumps((self._data, expiration_time), self._proto) + q.insert((self.id, base64.b64encode(data), expiration_time)) + q.commit() + except Exception: # pylint: disable=broad-except + if q: + q.rollback() + raise + + def _delete(self): + q = SqlQuery(self._db, 'sessions', SESSION_COLUMNS) + q.delete({'id': self.id}) + + # copy what RamSession does for now + def acquire_lock(self): + """Acquire an exclusive lock on the currently-loaded session data.""" + self.locked = True + self.locks.setdefault(self.id, threading.RLock()).acquire() + + def release_lock(self): + """Release the lock on the currently-loaded session data.""" + self.locks[self.id].release() + self.locked = False diff --git a/quickrun.py b/quickrun.py index 852f8b0..0546fcc 100755 --- a/quickrun.py +++ b/quickrun.py @@ -77,6 +77,9 @@ def config(workdir): 'admindb': admin_db, 'usersdb': users_db, 'transdb': trans_db, + 'sesstype': 'file', + 'sessopt': 'path', + 'sessval': os.path.join(workdir, 'sessions'), 'secure': 'False'}) conf = os.path.join(workdir, 'ipsilon.conf') with open(conf, 'w+') as f: diff --git a/templates/install/ipsilon.conf b/templates/install/ipsilon.conf index 2e402a3..4b170ca 100644 --- a/templates/install/ipsilon.conf +++ b/templates/install/ipsilon.conf @@ -11,8 +11,8 @@ transactions.db = "${transdb}" tools.sessions.on = True tools.sessions.name = "${instance}_ipsilon_session_id" -tools.sessions.storage_type = "file" -tools.sessions.storage_path = "${datadir}/sessions" +tools.sessions.storage_type = "${sesstype}" +tools.sessions.storage_${sessopt} = "${sessval}" tools.sessions.path = "/${instance}" tools.sessions.timeout = 60 tools.sessions.httponly = ${secure} diff --git a/tests/helpers/common.py b/tests/helpers/common.py index a0adfae..e316718 100755 --- a/tests/helpers/common.py +++ b/tests/helpers/common.py @@ -138,7 +138,7 @@ class IpsilonTestBase(object): env=env, preexec_fn=os.setsid) self.processes.append(p) p.wait() - for d in ['adminconfig', 'userprefs', 'transactions']: + for d in ['adminconfig', 'userprefs', 'transactions', 'sessions']: cmd = ['/usr/bin/createdb', '-h', addr, '-p', port, d] subprocess.check_call(cmd, env=env) diff --git a/tests/pgdb.py b/tests/pgdb.py index 12f1cf2..14ffd36 100755 --- a/tests/pgdb.py +++ b/tests/pgdb.py @@ -37,6 +37,8 @@ idp_g = {'TEMPLATES': '${TESTDIR}/templates/install', idp_a = {'hostname': '${ADDRESS}:${PORT}', 'database_url': 'postgresql://@127.0.0.10:45432/%(dbname)s', + 'session_type': 'sql', + 'session_dburi': 'postgresql://@127.0.0.10:45432/sessions', 'admin_user': '${TEST_USER}', 'system_user': '${TEST_USER}', 'instance': '${NAME}',