First version of cluster web service.

This exposes ipcluster's over the web. The current implementation
uses IPClusterLauncher to run ipcluster in a separate process.
Here is the URL scheme we are using:

GET /clusters => list available clusters
GET /cluster/profile => list info for cluster with profile
POST /cluster/profile/start => start a cluster
POST /cluster/profile/stop => stop a cluster
Brian Granger 14 years ago
parent 6b5a5f0b36
commit f19a63759b

@ -0,0 +1,90 @@
"""Manage IPython.parallel clusters in the notebook.
Authors:
* Brian Granger
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import datetime
import os
import uuid
import glob
from tornado import web
from zmq.eventloop import ioloop
from IPython.config.configurable import LoggingConfigurable
from IPython.utils.traitlets import Unicode, List, Dict, Bool
from IPython.parallel.apps.launcher import IPClusterLauncher
from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
class ClusterManager(LoggingConfigurable):
profiles = Dict()
def list_profile_names(self):
"""List all profiles in the ipython_dir and cwd.
"""
profiles = list_profiles_in(get_ipython_dir())
profiles += list_profiles_in(os.getcwdu())
return profiles
def list_profiles(self):
profiles = self.list_profile_names()
result = [self.profile_info(p) for p in profiles]
return result
def profile_info(self, profile):
if profile not in self.list_profile_names():
raise web.HTTPError(404, u'profile not found')
result = dict(profile=profile)
data = self.profiles.get(profile)
if data is None:
result['status'] = 'stopped'
else:
result['status'] = 'running'
result['n'] = data['n']
return result
def start_cluster(self, profile, n=4):
"""Start a cluster for a given profile."""
if profile not in self.list_profile_names():
raise web.HTTPError(404, u'profile not found')
if profile in self.profiles:
raise web.HTTPError(409, u'cluster already running')
launcher = IPClusterLauncher(ipcluster_profile=profile, ipcluster_n=n)
launcher.start()
self.profiles[profile] = {
'launcher': launcher,
'n': n
}
def stop_cluster(self, profile):
"""Stop a cluster for a given profile."""
if profile not in self.profiles:
raise web.HTTPError(409, u'cluster not running')
launcher = self.profiles.pop(profile)['launcher']
launcher.stop()
def stop_all_clusters(self):
for p in self.profiles.values():
p['launcher'].stop()

@ -587,7 +587,6 @@ class NotebookRootHandler(AuthenticatedHandler):
@authenticate_unless_readonly
def get(self):
nbm = self.application.notebook_manager
files = nbm.list_notebooks()
self.finish(jsonapi.dumps(files))
@ -661,6 +660,41 @@ class NotebookCopyHandler(AuthenticatedHandler):
mathjax_url=self.application.ipython_app.mathjax_url,
)
#-----------------------------------------------------------------------------
# Cluster handlers
#-----------------------------------------------------------------------------
class MainClusterHandler(AuthenticatedHandler):
@web.authenticated
def get(self):
cm = self.application.cluster_manager
self.finish(jsonapi.dumps(cm.list_profiles()))
class ClusterProfileHandler(AuthenticatedHandler):
@web.authenticated
def get(self, profile):
cm = self.application.cluster_manager
self.finish(jsonapi.dumps(cm.profile_info(profile)))
class ClusterActionHandler(AuthenticatedHandler):
@web.authenticated
def post(self, profile, action):
cm = self.application.cluster_manager
if action == 'start':
n = int(self.get_argument('n', default=4))
cm.start_cluster(profile, n)
if action == 'stop':
cm.stop_cluster(profile)
self.finish()
#-----------------------------------------------------------------------------
# RST web service handlers
#-----------------------------------------------------------------------------

@ -49,9 +49,11 @@ from .handlers import (LoginHandler, LogoutHandler,
ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler
RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
MainClusterHandler, ClusterProfileHandler, ClusterActionHandler
)
from .notebookmanager import NotebookManager
from .clustermanager import ClusterManager
from IPython.config.application import catch_config_error, boolean_flag
from IPython.core.application import BaseIPythonApplication
@ -74,6 +76,9 @@ from IPython.utils import py3compat
_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
_kernel_action_regex = r"(?P<action>restart|interrupt)"
_notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
_profile_regex = r"(?P<profile>[a-zA-Z0-9]+)"
_cluster_action_regex = r"(?P<action>start|stop)"
LOCALHOST = '127.0.0.1'
@ -101,7 +106,8 @@ def url_path_join(a,b):
class NotebookWebApplication(web.Application):
def __init__(self, ipython_app, kernel_manager, notebook_manager, log,
def __init__(self, ipython_app, kernel_manager, notebook_manager,
cluster_manager, log,
base_project_url, settings_overrides):
handlers = [
(r"/", ProjectDashboardHandler),
@ -120,6 +126,9 @@ class NotebookWebApplication(web.Application):
(r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
(r"/rstservice/render", RSTHandler),
(r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
(r"/clusters", MainClusterHandler),
(r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
(r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
@ -151,10 +160,11 @@ class NotebookWebApplication(web.Application):
super(NotebookWebApplication, self).__init__(new_handlers, **settings)
self.kernel_manager = kernel_manager
self.log = log
self.notebook_manager = notebook_manager
self.cluster_manager = cluster_manager
self.ipython_app = ipython_app
self.read_only = self.ipython_app.read_only
self.log = log
#-----------------------------------------------------------------------------
@ -395,6 +405,7 @@ class NotebookApp(BaseIPythonApplication):
)
self.notebook_manager = NotebookManager(config=self.config, log=self.log)
self.notebook_manager.list_notebooks()
self.cluster_manager = ClusterManager(config=self.config, log=self.log)
def init_logging(self):
super(NotebookApp, self).init_logging()
@ -406,7 +417,8 @@ class NotebookApp(BaseIPythonApplication):
def init_webapp(self):
"""initialize tornado webapp and httpserver"""
self.web_app = NotebookWebApplication(
self, self.kernel_manager, self.notebook_manager, self.log,
self, self.kernel_manager, self.notebook_manager,
self.cluster_manager, self.log,
self.base_project_url, self.webapp_settings
)
if self.certfile:

Loading…
Cancel
Save