4
The IPython controller application.
7
#-----------------------------------------------------------------------------
8
# Copyright (C) 2008-2009 The IPython Development Team
10
# Distributed under the terms of the BSD License. The full license is in
11
# the file COPYING, distributed as part of this software.
12
#-----------------------------------------------------------------------------
14
#-----------------------------------------------------------------------------
16
#-----------------------------------------------------------------------------
18
from __future__ import with_statement
23
from twisted.application import service
24
from twisted.internet import reactor
25
from twisted.python import log
27
from IPython.config.loader import Config
28
from IPython.kernel import controllerservice
29
from IPython.kernel.clusterdir import (
30
ApplicationWithClusterDir,
31
ClusterDirConfigLoader
33
from IPython.kernel.fcutil import FCServiceFactory, FURLError
34
from IPython.utils.traitlets import Instance, Unicode
37
#-----------------------------------------------------------------------------
38
# Module level variables
39
#-----------------------------------------------------------------------------
42
#: The default config file name for this application
43
default_config_file_name = u'ipcontroller_config.py'
46
_description = """Start the IPython controller for parallel computing.
48
The IPython controller provides a gateway between the IPython engines and
49
clients. The controller needs to be started before the engines and can be
50
configured using command line options or using a cluster directory. Cluster
51
directories contain config, log and security files and are usually located in
52
your .ipython directory and named as "cluster_<profile>". See the --profile
53
and --cluster-dir options for details.
56
#-----------------------------------------------------------------------------
58
#-----------------------------------------------------------------------------
60
# The default client interfaces for FCClientServiceFactory.interfaces
61
default_client_interfaces = Config()
62
default_client_interfaces.Task.interface_chain = [
63
'IPython.kernel.task.ITaskController',
64
'IPython.kernel.taskfc.IFCTaskController'
67
default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
69
default_client_interfaces.MultiEngine.interface_chain = [
70
'IPython.kernel.multiengine.IMultiEngine',
71
'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
74
default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl'
76
# Make this a dict we can pass to Config.__init__ for the default
77
default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
81
# The default engine interfaces for FCEngineServiceFactory.interfaces
82
default_engine_interfaces = Config()
83
default_engine_interfaces.Default.interface_chain = [
84
'IPython.kernel.enginefc.IFCControllerBase'
87
default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl'
89
# Make this a dict we can pass to Config.__init__ for the default
90
default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
93
#-----------------------------------------------------------------------------
95
#-----------------------------------------------------------------------------
98
class FCClientServiceFactory(FCServiceFactory):
99
"""A Foolscap implementation of the client services."""
101
cert_file = Unicode(u'ipcontroller-client.pem', config=True)
102
interfaces = Instance(klass=Config, kw=default_client_interfaces,
103
allow_none=False, config=True)
106
class FCEngineServiceFactory(FCServiceFactory):
107
"""A Foolscap implementation of the engine services."""
109
cert_file = Unicode(u'ipcontroller-engine.pem', config=True)
110
interfaces = Instance(klass=dict, kw=default_engine_interfaces,
111
allow_none=False, config=True)
114
#-----------------------------------------------------------------------------
115
# Command line options
116
#-----------------------------------------------------------------------------
119
class IPControllerAppConfigLoader(ClusterDirConfigLoader):
121
def _add_arguments(self):
122
super(IPControllerAppConfigLoader, self)._add_arguments()
123
paa = self.parser.add_argument
126
type=str, dest='FCClientServiceFactory.ip',
127
help='The IP address or hostname the controller will listen on for '
128
'client connections.',
129
metavar='FCClientServiceFactory.ip')
131
type=int, dest='FCClientServiceFactory.port',
132
help='The port the controller will listen on for client connections. '
133
'The default is to use 0, which will autoselect an open port.',
134
metavar='FCClientServiceFactory.port')
135
paa('--client-location',), dict(
136
type=str, dest='FCClientServiceFactory.location',
137
help='The hostname or IP that clients should connect to. This does '
138
'not control which interface the controller listens on. Instead, this '
139
'determines the hostname/IP that is listed in the FURL, which is how '
140
'clients know where to connect. Useful if the controller is listening '
141
'on multiple interfaces.',
142
metavar='FCClientServiceFactory.location')
145
type=str, dest='FCEngineServiceFactory.ip',
146
help='The IP address or hostname the controller will listen on for '
147
'engine connections.',
148
metavar='FCEngineServiceFactory.ip')
150
type=int, dest='FCEngineServiceFactory.port',
151
help='The port the controller will listen on for engine connections. '
152
'The default is to use 0, which will autoselect an open port.',
153
metavar='FCEngineServiceFactory.port')
154
paa('--engine-location',
155
type=str, dest='FCEngineServiceFactory.location',
156
help='The hostname or IP that engines should connect to. This does '
157
'not control which interface the controller listens on. Instead, this '
158
'determines the hostname/IP that is listed in the FURL, which is how '
159
'engines know where to connect. Useful if the controller is listening '
160
'on multiple interfaces.',
161
metavar='FCEngineServiceFactory.location')
164
action='store_true', dest='Global.log_to_file',
165
help='Log to a file in the log directory (default is stdout)')
166
paa('-r','--reuse-furls',
167
action='store_true', dest='Global.reuse_furls',
168
help='Try to reuse all FURL files. If this is not set all FURL files '
169
'are deleted before the controller starts. This must be set if '
170
'specific ports are specified by --engine-port or --client-port.')
172
action='store_false', dest='Global.secure',
173
help='Turn off SSL encryption for all connections.')
175
action='store_true', dest='Global.secure',
176
help='Turn off SSL encryption for all connections.')
179
#-----------------------------------------------------------------------------
180
# The main application
181
#-----------------------------------------------------------------------------
184
class IPControllerApp(ApplicationWithClusterDir):
186
name = u'ipcontroller'
187
description = _description
188
command_line_loader = IPControllerAppConfigLoader
189
default_config_file_name = default_config_file_name
190
auto_create_cluster_dir = True
192
def create_default_config(self):
193
super(IPControllerApp, self).create_default_config()
194
# Don't set defaults for Global.secure or Global.reuse_furls
195
# as those are set in a component.
196
self.default_config.Global.import_statements = []
197
self.default_config.Global.clean_logs = True
199
def pre_construct(self):
200
super(IPControllerApp, self).pre_construct()
201
c = self.master_config
202
# The defaults for these are set in FCClientServiceFactory and
203
# FCEngineServiceFactory, so we only set them here if the global
204
# options have be set to override the class level defaults.
205
if hasattr(c.Global, 'reuse_furls'):
206
c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls
207
c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls
208
del c.Global.reuse_furls
209
if hasattr(c.Global, 'secure'):
210
c.FCClientServiceFactory.secure = c.Global.secure
211
c.FCEngineServiceFactory.secure = c.Global.secure
215
# This is the working dir by now.
216
sys.path.insert(0, '')
219
self.import_statements()
221
# Create the service hierarchy
222
self.main_service = service.MultiService()
223
# The controller service
224
controller_service = controllerservice.ControllerService()
225
controller_service.setServiceParent(self.main_service)
226
# The client tub and all its refereceables
228
csfactory = FCClientServiceFactory(self.master_config, controller_service)
232
client_service = csfactory.create()
233
client_service.setServiceParent(self.main_service)
236
esfactory = FCEngineServiceFactory(self.master_config, controller_service)
240
engine_service = esfactory.create()
241
engine_service.setServiceParent(self.main_service)
243
def import_statements(self):
244
statements = self.master_config.Global.import_statements
247
log.msg("Executing statement: '%s'" % s)
248
exec s in globals(), locals()
250
log.msg("Error running statement: %s" % s)
253
# Start the controller service.
254
self.main_service.startService()
255
# Write the .pid file overwriting old ones. This allow multiple
256
# controllers to clober each other. But Windows is not cleaning
258
self.write_pid_file(overwrite=True)
259
# Add a trigger to delete the .pid file upon shutting down.
260
reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
264
def launch_new_instance():
265
"""Create and run the IPython controller"""
266
app = IPControllerApp()
270
if __name__ == '__main__':
271
launch_new_instance()