store the multi-user state in a database

via SQLAlchemy ORM
This commit is contained in:
MinRK
2014-08-18 15:20:43 -07:00
parent a2d1481cd5
commit ec52f67cea
7 changed files with 671 additions and 275 deletions

View File

@@ -9,10 +9,12 @@ import tornado.options
from tornado import web
from IPython.utils.traitlets import (
Unicode, Integer, Dict, TraitError, List,
Unicode, Integer, Dict, TraitError, List, Instance, Bool, Bytes, Any,
DottedObjectName,
)
from IPython.config import Application
from IPython.html import utils
from IPython.html.utils import url_path_join
from IPython.utils.importstring import import_item
here = os.path.dirname(__file__)
@@ -24,35 +26,79 @@ from .handlers import (
UserHandler,
)
from .user import UserManager
from . import db
class MultiUserAuthenticationApp(Application):
# from .user import UserManager
class MultiUserApp(Application):
ip = Unicode('localhost', config=True,
help="The public facing ip of the proxy"
)
port = Integer(8000, config=True,
help="The public facing port of the proxy"
)
base_url = Unicode('/', config=True,
help="The base URL of the entire application"
)
proxy_auth_token = Unicode(config=True,
help="The Proxy Auth token"
)
def _proxy_auth_token_default(self):
return db.new_token()
proxy_api_ip = Unicode('localhost', config=True,
help="The ip for the proxy API handlers"
)
proxy_api_port = Integer(config=True,
help="The port for the proxy API handlers"
)
def _proxy_api_port_default(self):
return self.port + 1
multiuser_port = Integer(8081, config=True,
hub_port = Integer(8081, config=True,
help="The port for this process"
)
multiuser_prefix = Unicode('/multiuser/', config=True,
help="The prefix for the multi-user server. Must not be '/'"
hub_ip = Unicode('localhost', config=True,
help="The ip for this process"
)
def _multiuser_prefix_changed(self, name, old, new):
hub_prefix = Unicode('/hub/', config=True,
help="The prefix for the hub server. Must not be '/'"
)
def _hub_prefix_default(self):
return url_path_join(self.base_url, '/hub/')
def _hub_prefix_changed(self, name, old, new):
if new == '/':
raise TraitError("'/' is not a valid multi-user prefix")
raise TraitError("'/' is not a valid hub prefix")
newnew = new
if not new.startswith('/'):
newnew = '/' + new
if not newnew.endswith('/'):
newnew = newnew + '/'
if not newnew.startswith(self.base_url):
newnew = url_path_join(self.base_url, newnew)
if newnew != new:
self.multiuser_prefix = newnew
self.hub_prefix = newnew
cookie_secret = Bytes(config=True)
def _cookie_secret_default(self):
return b'secret!'
# spawning subprocesses
spawner_class = DottedObjectName("multiuser.spawner.ProcessSpawner")
def _spawner_class_changed(self, name, old, new):
self.spawner = import_item(new)
spawner = Any()
def _spawner_default(self):
return import_item(self.spawner_class)
db_url = Unicode('sqlite:///:memory:', config=True)
debug_db = Bool(False)
db = Any()
tornado_settings = Dict(config=True)
@@ -62,7 +108,7 @@ class MultiUserAuthenticationApp(Application):
"""add a url prefix to handlers"""
for i, tup in enumerate(handlers):
lis = list(tup)
lis[0] = utils.url_path_join(prefix, tup[0])
lis[0] = url_path_join(prefix, tup[0])
handlers[i] = tuple(lis)
return handlers
@@ -73,38 +119,62 @@ class MultiUserAuthenticationApp(Application):
(r"/logout", LogoutHandler),
(r"/api/authorizations/([^/]+)", AuthorizationsHandler),
]
self.handlers = self.add_url_prefix(self.multiuser_prefix, handlers)
self.handlers = self.add_url_prefix(self.hub_prefix, handlers)
self.handlers.extend([
(r"/user/([^/]+)/?.*", UserHandler),
(r"/", web.RedirectHandler, {"url" : self.multiuser_prefix}),
(r"/", web.RedirectHandler, {"url" : self.hub_prefix}),
])
def init_user_manager(self):
self.user_manager = UserManager(proxy_port=self.proxy_api_port)
def init_db(self):
# TODO: load state from db for resume
self.db = db.new_session(self.db_url, echo=self.debug_db)
def init_hub(self):
self.hub = db.Hub(
server=db.Server(
ip=self.hub_ip,
port=self.hub_port,
base_url=self.hub_prefix,
cookie_secret=self.cookie_secret,
cookie_name='jupyter-hub-token',
)
)
self.db.add(self.hub)
self.db.commit()
def init_proxy(self):
self.proxy = db.Proxy(
public_server=db.Server(
ip=self.ip,
port=self.port,
),
api_server=db.Server(
ip=self.proxy_api_ip,
port=self.proxy_api_port,
base_url='/api/routes/'
),
auth_token = db.new_token(),
)
self.db.add(self.proxy)
self.db.commit()
def start_proxy(self):
env = os.environ.copy()
env['CONFIGPROXY_AUTH_TOKEN'] = self.user_manager.proxy_auth_token
env['CONFIGPROXY_AUTH_TOKEN'] = self.proxy.auth_token
self.proxy = Popen(["node", os.path.join(here, 'js', 'main.js'),
'--port', str(self.port),
'--api-port', str(self.proxy_api_port),
'--upstream-port', str(self.multiuser_port),
'--port', str(self.proxy.public_server.port),
'--api-port', str(self.proxy.api_server.port),
'--upstream-port', str(self.hub.server.port),
], env=env)
def init_tornado_settings(self):
base_url = self.multiuser_prefix
base_url = self.base_url
self.tornado_settings.update(
db=self.db,
hub=self.hub,
base_url=base_url,
user_manager=self.user_manager,
cookie_secret='super secret',
cookie_name='multiusertest',
multiuser_prefix=base_url,
multiuser_api_url=utils.url_path_join(
'http://localhost:%i' % self.multiuser_port,
base_url,
'api',
),
login_url=utils.url_path_join(base_url, 'login'),
cookie_secret=self.cookie_secret,
login_url=url_path_join(self.hub.server.base_url, 'login'),
template_path=os.path.join(here, 'templates'),
)
@@ -112,25 +182,28 @@ class MultiUserAuthenticationApp(Application):
self.tornado_application = web.Application(self.handlers, **self.tornado_settings)
def initialize(self, *args, **kwargs):
super(MultiUserAuthenticationApp, self).initialize(*args, **kwargs)
self.init_user_manager()
super(MultiUserApp, self).initialize(*args, **kwargs)
self.init_db()
self.init_hub()
self.init_proxy()
self.init_handlers()
self.init_tornado_settings()
self.init_tornado_application()
def start(self):
self.start_proxy()
http_server = tornado.httpserver.HTTPServer(self.tornado_application)
http_server.listen(self.multiuser_port)
http_server.listen(self.hub_port)
try:
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
print("\nInterrupted")
finally:
self.proxy.terminate()
self.user_manager.cleanup()
pass
# self.proxy.terminate()
# self.user_manager.cleanup()
main = MultiUserAuthenticationApp.launch_instance
main = MultiUserApp.launch_instance
if __name__ == "__main__":
main()