~ellisonbg/ipython/trunk-dev

« back to all changes in this revision

Viewing changes to IPython/kernel/ipcontrollerapp.py

  • Committer: Brian Granger
  • Date: 2010-01-31 23:57:46 UTC
  • mfrom: (1109.1.113 ipython)
  • Revision ID: ellisonbg@gmail.com-20100131235746-rj81qa8klooepq2m
Merging from upstream trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# encoding: utf-8
 
3
"""
 
4
The IPython controller application.
 
5
"""
 
6
 
 
7
#-----------------------------------------------------------------------------
 
8
#  Copyright (C) 2008-2009  The IPython Development Team
 
9
#
 
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
#-----------------------------------------------------------------------------
 
13
 
 
14
#-----------------------------------------------------------------------------
 
15
# Imports
 
16
#-----------------------------------------------------------------------------
 
17
 
 
18
from __future__ import with_statement
 
19
 
 
20
import copy
 
21
import sys
 
22
 
 
23
from twisted.application import service
 
24
from twisted.internet import reactor
 
25
from twisted.python import log
 
26
 
 
27
from IPython.config.loader import Config
 
28
from IPython.kernel import controllerservice
 
29
from IPython.kernel.clusterdir import (
 
30
    ApplicationWithClusterDir,
 
31
    ClusterDirConfigLoader
 
32
)
 
33
from IPython.kernel.fcutil import FCServiceFactory, FURLError
 
34
from IPython.utils.traitlets import Instance, Unicode
 
35
 
 
36
 
 
37
#-----------------------------------------------------------------------------
 
38
# Module level variables
 
39
#-----------------------------------------------------------------------------
 
40
 
 
41
 
 
42
#: The default config file name for this application
 
43
default_config_file_name = u'ipcontroller_config.py'
 
44
 
 
45
 
 
46
_description = """Start the IPython controller for parallel computing.
 
47
 
 
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.
 
54
"""
 
55
 
 
56
#-----------------------------------------------------------------------------
 
57
# Default interfaces
 
58
#-----------------------------------------------------------------------------
 
59
 
 
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'
 
65
]
 
66
 
 
67
default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
 
68
 
 
69
default_client_interfaces.MultiEngine.interface_chain = [
 
70
    'IPython.kernel.multiengine.IMultiEngine',
 
71
    'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
 
72
]
 
73
 
 
74
default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl'
 
75
 
 
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()))
 
78
 
 
79
 
 
80
 
 
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'
 
85
]
 
86
 
 
87
default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl'
 
88
 
 
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()))
 
91
 
 
92
 
 
93
#-----------------------------------------------------------------------------
 
94
# Service factories
 
95
#-----------------------------------------------------------------------------
 
96
 
 
97
 
 
98
class FCClientServiceFactory(FCServiceFactory):
 
99
    """A Foolscap implementation of the client services."""
 
100
 
 
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)
 
104
 
 
105
 
 
106
class FCEngineServiceFactory(FCServiceFactory):
 
107
    """A Foolscap implementation of the engine services."""
 
108
 
 
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)
 
112
 
 
113
 
 
114
#-----------------------------------------------------------------------------
 
115
# Command line options
 
116
#-----------------------------------------------------------------------------
 
117
 
 
118
 
 
119
class IPControllerAppConfigLoader(ClusterDirConfigLoader):
 
120
 
 
121
    def _add_arguments(self):
 
122
        super(IPControllerAppConfigLoader, self)._add_arguments()
 
123
        paa = self.parser.add_argument
 
124
        # Client config
 
125
        paa('--client-ip',
 
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')
 
130
        paa('--client-port',
 
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')
 
143
        # Engine config
 
144
        paa('--engine-ip',
 
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')
 
149
        paa('--engine-port',
 
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')
 
162
        # Global config
 
163
        paa('--log-to-file',
 
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.')
 
171
        paa('--no-secure',
 
172
            action='store_false', dest='Global.secure',
 
173
            help='Turn off SSL encryption for all connections.')
 
174
        paa('--secure',
 
175
            action='store_true', dest='Global.secure',
 
176
            help='Turn off SSL encryption for all connections.')
 
177
 
 
178
 
 
179
#-----------------------------------------------------------------------------
 
180
# The main application
 
181
#-----------------------------------------------------------------------------
 
182
 
 
183
 
 
184
class IPControllerApp(ApplicationWithClusterDir):
 
185
 
 
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
 
191
 
 
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
 
198
 
 
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
 
212
            del c.Global.secure
 
213
 
 
214
    def construct(self):
 
215
        # This is the working dir by now.
 
216
        sys.path.insert(0, '')
 
217
 
 
218
        self.start_logging()
 
219
        self.import_statements()
 
220
 
 
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
 
227
        try:
 
228
            csfactory = FCClientServiceFactory(self.master_config, controller_service)
 
229
        except FURLError, e:
 
230
            log.err(e)
 
231
            self.exit(0)
 
232
        client_service = csfactory.create()
 
233
        client_service.setServiceParent(self.main_service)
 
234
        # The engine tub
 
235
        try:
 
236
            esfactory = FCEngineServiceFactory(self.master_config, controller_service)
 
237
        except FURLError, e:
 
238
            log.err(e)
 
239
            self.exit(0)
 
240
        engine_service = esfactory.create()
 
241
        engine_service.setServiceParent(self.main_service)
 
242
 
 
243
    def import_statements(self):
 
244
        statements = self.master_config.Global.import_statements
 
245
        for s in statements:
 
246
            try:
 
247
                log.msg("Executing statement: '%s'" % s)
 
248
                exec s in globals(), locals()
 
249
            except:
 
250
                log.msg("Error running statement: %s" % s)
 
251
 
 
252
    def start_app(self):
 
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
 
257
        # these up properly.
 
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)
 
261
        reactor.run()
 
262
 
 
263
 
 
264
def launch_new_instance():
 
265
    """Create and run the IPython controller"""
 
266
    app = IPControllerApp()
 
267
    app.start()
 
268
 
 
269
 
 
270
if __name__ == '__main__':
 
271
    launch_new_instance()