ipcontrollerapp.py
271 lines
| 10.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 sys | ||||
from twisted.application import service | ||||
Brian Granger
|
r2301 | from twisted.internet import reactor | ||
Brian Granger
|
r2288 | from twisted.python import log | ||
Brian Granger
|
r2498 | from IPython.config.loader import Config | ||
Brian Granger
|
r2288 | from IPython.kernel import controllerservice | ||
Brian Granger
|
r2501 | from IPython.kernel.clusterdir import ( | ||
ApplicationWithClusterDir, | ||||
ClusterDirConfigLoader | ||||
) | ||||
Brian Granger
|
r2511 | from IPython.kernel.fcutil import FCServiceFactory, FURLError | ||
Brian Granger
|
r2498 | from IPython.utils.traitlets import Instance, Unicode | ||
Brian Granger
|
r2288 | |||
Brian Granger
|
r2501 | |||
#----------------------------------------------------------------------------- | ||||
# Module level variables | ||||
#----------------------------------------------------------------------------- | ||||
#: The default config file name for this application | ||||
default_config_file_name = u'ipcontroller_config.py' | ||||
_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
|
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) | ||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2501 | # Command line options | ||
Brian Granger
|
r2288 | #----------------------------------------------------------------------------- | ||
Brian Granger
|
r2501 | class IPControllerAppConfigLoader(ClusterDirConfigLoader): | ||
def _add_arguments(self): | ||||
super(IPControllerAppConfigLoader, self)._add_arguments() | ||||
paa = self.parser.add_argument | ||||
# Client config | ||||
paa('--client-ip', | ||||
type=str, dest='FCClientServiceFactory.ip', | ||||
help='The IP address or hostname the controller will listen on for ' | ||||
'client connections.', | ||||
metavar='FCClientServiceFactory.ip') | ||||
paa('--client-port', | ||||
type=int, dest='FCClientServiceFactory.port', | ||||
help='The port the controller will listen on for client connections. ' | ||||
'The default is to use 0, which will autoselect an open port.', | ||||
metavar='FCClientServiceFactory.port') | ||||
paa('--client-location',), dict( | ||||
type=str, dest='FCClientServiceFactory.location', | ||||
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.', | ||||
metavar='FCClientServiceFactory.location') | ||||
# Engine config | ||||
paa('--engine-ip', | ||||
type=str, dest='FCEngineServiceFactory.ip', | ||||
help='The IP address or hostname the controller will listen on for ' | ||||
'engine connections.', | ||||
metavar='FCEngineServiceFactory.ip') | ||||
paa('--engine-port', | ||||
type=int, dest='FCEngineServiceFactory.port', | ||||
help='The port the controller will listen on for engine connections. ' | ||||
'The default is to use 0, which will autoselect an open port.', | ||||
metavar='FCEngineServiceFactory.port') | ||||
paa('--engine-location', | ||||
type=str, dest='FCEngineServiceFactory.location', | ||||
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.', | ||||
metavar='FCEngineServiceFactory.location') | ||||
# Global config | ||||
paa('--log-to-file', | ||||
action='store_true', dest='Global.log_to_file', | ||||
help='Log to a file in the log directory (default is stdout)') | ||||
paa('-r','--reuse-furls', | ||||
action='store_true', dest='Global.reuse_furls', | ||||
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.') | ||||
paa('--no-secure', | ||||
action='store_false', dest='Global.secure', | ||||
help='Turn off SSL encryption for all connections.') | ||||
paa('--secure', | ||||
action='store_true', dest='Global.secure', | ||||
help='Turn off SSL encryption for all connections.') | ||||
Brian Granger
|
r2288 | |||
Brian Granger
|
r2501 | #----------------------------------------------------------------------------- | ||
# The main application | ||||
#----------------------------------------------------------------------------- | ||||
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
|
r2501 | command_line_loader = IPControllerAppConfigLoader | ||
Brian Granger
|
r2511 | default_config_file_name = default_config_file_name | ||
Brian Granger
|
r2303 | auto_create_cluster_dir = True | ||
Brian Granger
|
r2288 | |||
def create_default_config(self): | ||||
super(IPControllerApp, self).create_default_config() | ||||
Brian Granger
|
r2511 | # Don't set defaults for Global.secure or Global.reuse_furls | ||
# as those are set in a component. | ||||
Brian Granger
|
r2288 | self.default_config.Global.import_statements = [] | ||
Brian Granger
|
r2306 | self.default_config.Global.clean_logs = True | ||
Brian Granger
|
r2294 | |||
Brian Granger
|
r2511 | def pre_construct(self): | ||
super(IPControllerApp, self).pre_construct() | ||||
c = self.master_config | ||||
# The defaults for these are set in FCClientServiceFactory and | ||||
# FCEngineServiceFactory, so we only set them here if the global | ||||
# options have be set to override the class level defaults. | ||||
Brian Granger
|
r2301 | 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 | ||||
Brian Granger
|
r2511 | try: | ||
csfactory = FCClientServiceFactory(self.master_config, controller_service) | ||||
except FURLError, e: | ||||
log.err(e) | ||||
self.exit(0) | ||||
Brian Granger
|
r2288 | client_service = csfactory.create() | ||
client_service.setServiceParent(self.main_service) | ||||
# The engine tub | ||||
Brian Granger
|
r2511 | try: | ||
esfactory = FCEngineServiceFactory(self.master_config, controller_service) | ||||
except FURLError, e: | ||||
log.err(e) | ||||
self.exit(0) | ||||
Brian Granger
|
r2288 | 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() | ||||