ipcontrollerapp.py
255 lines
| 9.7 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2288 | #!/usr/bin/env python | ||
# encoding: utf-8 | ||||
""" | ||||
Brian Granger
|
r2301 | The IPython controller application. | ||
Brian Granger
|
r2288 | """ | ||
#----------------------------------------------------------------------------- | ||||
# Copyright (C) 2008-2009 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 | ||||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2313 | from __future__ import with_statement | ||
Brian Granger
|
r2288 | import copy | ||
import os | ||||
import sys | ||||
from twisted.application import service | ||||
Brian Granger
|
r2301 | from twisted.internet import reactor | ||
Brian Granger
|
r2288 | from twisted.python import log | ||
from IPython.config.loader import Config, NoConfigDefault | ||||
from IPython.core import release | ||||
Fernando Perez
|
r2429 | from IPython.core.application import Application | ||
Brian Granger
|
r2288 | from IPython.kernel import controllerservice | ||
Fernando Perez
|
r2429 | from IPython.kernel.clusterdir import ApplicationWithClusterDir | ||
Brian Granger
|
r2288 | from IPython.kernel.fcutil import FCServiceFactory | ||
Fernando Perez
|
r2429 | from IPython.utils.traitlets import Str, Instance, Unicode | ||
Brian Granger
|
r2288 | |||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2294 | # Default interfaces | ||
Brian Granger
|
r2288 | #----------------------------------------------------------------------------- | ||
Brian Granger
|
r2297 | # The default client interfaces for FCClientServiceFactory.interfaces | ||
Brian Granger
|
r2288 | default_client_interfaces = Config() | ||
default_client_interfaces.Task.interface_chain = [ | ||||
'IPython.kernel.task.ITaskController', | ||||
'IPython.kernel.taskfc.IFCTaskController' | ||||
] | ||||
Brian Granger
|
r2294 | |||
Brian Granger
|
r2288 | default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl' | ||
Brian Granger
|
r2297 | |||
Brian Granger
|
r2288 | default_client_interfaces.MultiEngine.interface_chain = [ | ||
'IPython.kernel.multiengine.IMultiEngine', | ||||
'IPython.kernel.multienginefc.IFCSynchronousMultiEngine' | ||||
] | ||||
Brian Granger
|
r2294 | |||
Brian Granger
|
r2328 | default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl' | ||
Brian Granger
|
r2288 | |||
# Make this a dict we can pass to Config.__init__ for the default | ||||
default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items())) | ||||
Brian Granger
|
r2297 | # The default engine interfaces for FCEngineServiceFactory.interfaces | ||
Brian Granger
|
r2288 | default_engine_interfaces = Config() | ||
default_engine_interfaces.Default.interface_chain = [ | ||||
'IPython.kernel.enginefc.IFCControllerBase' | ||||
] | ||||
Brian Granger
|
r2294 | |||
Brian Granger
|
r2328 | default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl' | ||
Brian Granger
|
r2288 | |||
# Make this a dict we can pass to Config.__init__ for the default | ||||
default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items())) | ||||
Brian Granger
|
r2294 | #----------------------------------------------------------------------------- | ||
# Service factories | ||||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2288 | |||
class FCClientServiceFactory(FCServiceFactory): | ||||
"""A Foolscap implementation of the client services.""" | ||||
Brian Granger
|
r2328 | cert_file = Unicode(u'ipcontroller-client.pem', config=True) | ||
Brian Granger
|
r2297 | interfaces = Instance(klass=Config, kw=default_client_interfaces, | ||
Brian Granger
|
r2288 | allow_none=False, config=True) | ||
class FCEngineServiceFactory(FCServiceFactory): | ||||
"""A Foolscap implementation of the engine services.""" | ||||
Brian Granger
|
r2328 | cert_file = Unicode(u'ipcontroller-engine.pem', config=True) | ||
Brian Granger
|
r2297 | interfaces = Instance(klass=dict, kw=default_engine_interfaces, | ||
Brian Granger
|
r2288 | allow_none=False, config=True) | ||
#----------------------------------------------------------------------------- | ||||
# The main application | ||||
#----------------------------------------------------------------------------- | ||||
cl_args = ( | ||||
# Client config | ||||
(('--client-ip',), dict( | ||||
Fernando Perez
|
r2429 | type=str, dest='FCClientServiceFactory.ip', | ||
Brian Granger
|
r2301 | help='The IP address or hostname the controller will listen on for ' | ||
'client connections.', | ||||
Brian Granger
|
r2288 | metavar='FCClientServiceFactory.ip') | ||
), | ||||
(('--client-port',), dict( | ||||
Fernando Perez
|
r2429 | type=int, dest='FCClientServiceFactory.port', | ||
Brian Granger
|
r2301 | help='The port the controller will listen on for client connections. ' | ||
'The default is to use 0, which will autoselect an open port.', | ||||
Brian Granger
|
r2288 | metavar='FCClientServiceFactory.port') | ||
), | ||||
(('--client-location',), dict( | ||||
Fernando Perez
|
r2429 | type=str, dest='FCClientServiceFactory.location', | ||
Brian Granger
|
r2301 | help='The hostname or IP that clients should connect to. This does ' | ||
'not control which interface the controller listens on. Instead, this ' | ||||
'determines the hostname/IP that is listed in the FURL, which is how ' | ||||
'clients know where to connect. Useful if the controller is listening ' | ||||
'on multiple interfaces.', | ||||
Brian Granger
|
r2288 | metavar='FCClientServiceFactory.location') | ||
), | ||||
# Engine config | ||||
(('--engine-ip',), dict( | ||||
Fernando Perez
|
r2429 | type=str, dest='FCEngineServiceFactory.ip', | ||
Brian Granger
|
r2301 | help='The IP address or hostname the controller will listen on for ' | ||
'engine connections.', | ||||
Brian Granger
|
r2288 | metavar='FCEngineServiceFactory.ip') | ||
), | ||||
(('--engine-port',), dict( | ||||
Fernando Perez
|
r2429 | type=int, dest='FCEngineServiceFactory.port', | ||
Brian Granger
|
r2301 | help='The port the controller will listen on for engine connections. ' | ||
'The default is to use 0, which will autoselect an open port.', | ||||
Brian Granger
|
r2288 | metavar='FCEngineServiceFactory.port') | ||
), | ||||
(('--engine-location',), dict( | ||||
Fernando Perez
|
r2429 | type=str, dest='FCEngineServiceFactory.location', | ||
Brian Granger
|
r2301 | help='The hostname or IP that engines should connect to. This does ' | ||
'not control which interface the controller listens on. Instead, this ' | ||||
'determines the hostname/IP that is listed in the FURL, which is how ' | ||||
'engines know where to connect. Useful if the controller is listening ' | ||||
'on multiple interfaces.', | ||||
Brian Granger
|
r2288 | metavar='FCEngineServiceFactory.location') | ||
), | ||||
# Global config | ||||
Brian Granger
|
r2294 | (('--log-to-file',), dict( | ||
Fernando Perez
|
r2429 | action='store_true', dest='Global.log_to_file', | ||
Brian Granger
|
r2294 | help='Log to a file in the log directory (default is stdout)') | ||
Brian Granger
|
r2288 | ), | ||
Brian Granger
|
r2294 | (('-r','--reuse-furls'), dict( | ||
Fernando Perez
|
r2429 | action='store_true', dest='Global.reuse_furls', | ||
Brian Granger
|
r2301 | help='Try to reuse all FURL files. If this is not set all FURL files ' | ||
'are deleted before the controller starts. This must be set if ' | ||||
'specific ports are specified by --engine-port or --client-port.') | ||||
Brian Granger
|
r2297 | ), | ||
Brian Granger
|
r2314 | (('--no-secure',), dict( | ||
Fernando Perez
|
r2429 | action='store_false', dest='Global.secure', | ||
Brian Granger
|
r2297 | help='Turn off SSL encryption for all connections.') | ||
Brian Granger
|
r2314 | ), | ||
(('--secure',), dict( | ||||
Fernando Perez
|
r2429 | action='store_true', dest='Global.secure', | ||
Brian Granger
|
r2314 | help='Turn off SSL encryption for all connections.') | ||
Brian Granger
|
r2296 | ) | ||
Brian Granger
|
r2288 | ) | ||
Brian Granger
|
r2343 | _description = """Start the IPython controller for parallel computing. | ||
The IPython controller provides a gateway between the IPython engines and | ||||
clients. The controller needs to be started before the engines and can be | ||||
configured using command line options or using a cluster directory. Cluster | ||||
directories contain config, log and security files and are usually located in | ||||
your .ipython directory and named as "cluster_<profile>". See the --profile | ||||
and --cluster-dir options for details. | ||||
""" | ||||
Brian Granger
|
r2328 | default_config_file_name = u'ipcontroller_config.py' | ||
Brian Granger
|
r2288 | |||
Brian Granger
|
r2296 | |||
Brian Granger
|
r2301 | class IPControllerApp(ApplicationWithClusterDir): | ||
Brian Granger
|
r2288 | |||
Brian Granger
|
r2328 | name = u'ipcontroller' | ||
Brian Granger
|
r2343 | description = _description | ||
Brian Granger
|
r2297 | config_file_name = default_config_file_name | ||
Brian Granger
|
r2303 | auto_create_cluster_dir = True | ||
Fernando Perez
|
r2429 | cl_arguments = Application.cl_arguments + cl_args | ||
Brian Granger
|
r2288 | |||
def create_default_config(self): | ||||
super(IPControllerApp, self).create_default_config() | ||||
self.default_config.Global.reuse_furls = False | ||||
Brian Granger
|
r2297 | self.default_config.Global.secure = True | ||
Brian Granger
|
r2288 | self.default_config.Global.import_statements = [] | ||
Brian Granger
|
r2306 | self.default_config.Global.clean_logs = True | ||
Brian Granger
|
r2294 | |||
Brian Granger
|
r2297 | def post_load_command_line_config(self): | ||
# Now setup reuse_furls | ||||
Brian Granger
|
r2301 | c = self.command_line_config | ||
if hasattr(c.Global, 'reuse_furls'): | ||||
c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls | ||||
c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls | ||||
del c.Global.reuse_furls | ||||
if hasattr(c.Global, 'secure'): | ||||
c.FCClientServiceFactory.secure = c.Global.secure | ||||
c.FCEngineServiceFactory.secure = c.Global.secure | ||||
del c.Global.secure | ||||
Brian Granger
|
r2297 | |||
Brian Granger
|
r2288 | def construct(self): | ||
Brian Granger
|
r2330 | # This is the working dir by now. | ||
Brian Granger
|
r2288 | sys.path.insert(0, '') | ||
self.start_logging() | ||||
self.import_statements() | ||||
Brian Granger
|
r2313 | |||
Brian Granger
|
r2288 | # Create the service hierarchy | ||
self.main_service = service.MultiService() | ||||
# The controller service | ||||
controller_service = controllerservice.ControllerService() | ||||
controller_service.setServiceParent(self.main_service) | ||||
# The client tub and all its refereceables | ||||
csfactory = FCClientServiceFactory(self.master_config, controller_service) | ||||
client_service = csfactory.create() | ||||
client_service.setServiceParent(self.main_service) | ||||
# The engine tub | ||||
esfactory = FCEngineServiceFactory(self.master_config, controller_service) | ||||
engine_service = esfactory.create() | ||||
engine_service.setServiceParent(self.main_service) | ||||
def import_statements(self): | ||||
statements = self.master_config.Global.import_statements | ||||
for s in statements: | ||||
try: | ||||
Brian Granger
|
r2297 | log.msg("Executing statement: '%s'" % s) | ||
Brian Granger
|
r2288 | exec s in globals(), locals() | ||
except: | ||||
Brian Granger
|
r2297 | log.msg("Error running statement: %s" % s) | ||
Brian Granger
|
r2288 | |||
def start_app(self): | ||||
Brian Granger
|
r2323 | # Start the controller service. | ||
Brian Granger
|
r2288 | self.main_service.startService() | ||
Brian Granger
|
r2323 | # Write the .pid file overwriting old ones. This allow multiple | ||
# controllers to clober each other. But Windows is not cleaning | ||||
# these up properly. | ||||
bgranger
|
r2318 | self.write_pid_file(overwrite=True) | ||
Brian Granger
|
r2323 | # Add a trigger to delete the .pid file upon shutting down. | ||
Brian Granger
|
r2313 | reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file) | ||
Brian Granger
|
r2288 | reactor.run() | ||
Brian Granger
|
r2296 | |||
def launch_new_instance(): | ||||
"""Create and run the IPython controller""" | ||||
Brian Granger
|
r2288 | app = IPControllerApp() | ||
app.start() | ||||
Brian Granger
|
r2302 | |||
if __name__ == '__main__': | ||||
launch_new_instance() | ||||