##// END OF EJS Templates
General work on the kernel config.
Brian Granger -
Show More
@@ -1,60 +1,67 b''
1 from IPython.config.loader import Config
1 from IPython.config.loader import Config
2
2
3 c = get_config()
3 c = get_config()
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Global configuration
6 # Global configuration
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 c.Global.logfile = ''
9 c.Global.log_to_file = False
10 c.Global.import_statement = ''
10 c.Global.import_statements = []
11 c.Global.reuse_furls = False
11 c.Global.reuse_furls = False
12
12
13 # You shouldn't have to edit these
14 c.Global.log_dir_name = 'log'
15 c.Global.security_dir_name = 'security'
16
13
17
14 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
15 # Configure the client services
19 # Configure the client services
16 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
17
21
18 c.FCClientServiceFactory.ip = ''
22 c.FCClientServiceFactory.ip = ''
19 c.FCClientServiceFactory.port = 0
23 c.FCClientServiceFactory.port = 0
20 c.FCClientServiceFactory.location = ''
24 c.FCClientServiceFactory.location = ''
21 c.FCClientServiceFactory.secure = True
25 c.FCClientServiceFactory.secure = True
26 c.FCClientServiceFactory.reuse_furls = False
22 c.FCClientServiceFactory.cert_file = 'ipcontroller-client.pem'
27 c.FCClientServiceFactory.cert_file = 'ipcontroller-client.pem'
23
28
24 c.FCClientServiceFactory.Interfaces.Task.interface_chain = [
29 c.FCClientServiceFactory.Interfaces.Task.interface_chain = [
25 'IPython.kernel.task.ITaskController',
30 'IPython.kernel.task.ITaskController',
26 'IPython.kernel.taskfc.IFCTaskController'
31 'IPython.kernel.taskfc.IFCTaskController'
27 ]
32 ]
33 # This is just the filename of the furl file. The path is always the
34 # security dir of the cluster directory.
28 c.FCClientServiceFactory.Interfaces.Task.furl_file = 'ipcontroller-tc.furl'
35 c.FCClientServiceFactory.Interfaces.Task.furl_file = 'ipcontroller-tc.furl'
29
36
30 c.FCClientServiceFactory.Interfaces.MultiEngine.interface_chain = [
37 c.FCClientServiceFactory.Interfaces.MultiEngine.interface_chain = [
31 'IPython.kernel.multiengine.IMultiEngine',
38 'IPython.kernel.multiengine.IMultiEngine',
32 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
39 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
33 ]
40 ]
41 # This is just the filename of the furl file. The path is always the
42 # security dir of the cluster directory.
34 c.FCClientServiceFactory.Interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
43 c.FCClientServiceFactory.Interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
35
44
36
45
37 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
38 # Configure the engine services
47 # Configure the engine services
39 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
40
49
41 c.FCEngineServiceFactory.ip = ''
50 c.FCEngineServiceFactory.ip = ''
42 c.FCEngineServiceFactory.port = 0
51 c.FCEngineServiceFactory.port = 0
43 c.FCEngineServiceFactory.location = ''
52 c.FCEngineServiceFactory.location = ''
44 c.FCEngineServiceFactory.secure = True
53 c.FCEngineServiceFactory.secure = True
54 c.FCEngineServiceFactory.reuse_furls = False
45 c.FCEngineServiceFactory.cert_file = 'ipcontroller-engine.pem'
55 c.FCEngineServiceFactory.cert_file = 'ipcontroller-engine.pem'
46
56
47 engine_config = Config()
57 c.FCEngineServiceFactory.Intefaces.Default.interface_chain = [
48 engine_config.furl_file =
58 'IPython.kernel.enginefc.IFCControllerBase'
49 c.Global.engine_furl_file = 'ipcontroller-engine.furl'
59 ]
50 c.Global.engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase'
51
52
60
61 # This is just the filename of the furl file. The path is always the
62 # security dir of the cluster directory.
63 c.FCEngineServiceFactory.Intefaces.Default.furl_file = 'ipcontroller-engine.furl'
53
64
54
65
55
66
56 CLIENT_INTERFACES = dict(
57 TASK = dict(FURL_FILE = 'ipcontroller-tc.furl'),
58 MULTIENGINE = dict(FURLFILE='ipcontroller-mec.furl')
59 )
60
67
@@ -1,304 +1,334 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 An application for IPython
4 An application for IPython
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10
10
11 Notes
11 Notes
12 -----
12 -----
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2009 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 import logging
26 import logging
27 import os
27 import os
28 import sys
28 import sys
29 import traceback
29 import traceback
30 from copy import deepcopy
30 from copy import deepcopy
31
31
32 from IPython.utils.genutils import get_ipython_dir, filefind
32 from IPython.utils.genutils import get_ipython_dir, filefind
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 PyFileConfigLoader,
34 PyFileConfigLoader,
35 ArgParseConfigLoader,
35 ArgParseConfigLoader,
36 Config,
36 Config,
37 NoConfigDefault
37 NoConfigDefault
38 )
38 )
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Classes and functions
41 # Classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44
44
45 class IPythonArgParseConfigLoader(ArgParseConfigLoader):
45 class IPythonArgParseConfigLoader(ArgParseConfigLoader):
46 """Default command line options for IPython based applications."""
46 """Default command line options for IPython based applications."""
47
47
48 def _add_other_arguments(self):
48 def _add_other_arguments(self):
49 self.parser.add_argument('-ipythondir', '--ipythondir',
49 self.parser.add_argument('-ipythondir', '--ipython-dir',
50 dest='Global.ipythondir',type=str,
50 dest='Global.ipythondir',type=str,
51 help='Set to override default location of Global.ipythondir.',
51 help='Set to override default location of Global.ipythondir.',
52 default=NoConfigDefault,
52 default=NoConfigDefault,
53 metavar='Global.ipythondir')
53 metavar='Global.ipythondir')
54 self.parser.add_argument('-p','-profile', '--profile',
54 self.parser.add_argument('-p','-profile', '--profile',
55 dest='Global.profile',type=str,
55 dest='Global.profile',type=str,
56 help='The string name of the ipython profile to be used.',
56 help='The string name of the ipython profile to be used.',
57 default=NoConfigDefault,
57 default=NoConfigDefault,
58 metavar='Global.profile')
58 metavar='Global.profile')
59 self.parser.add_argument('-log_level', '--log-level',
59 self.parser.add_argument('-log_level', '--log-level',
60 dest="Global.log_level",type=int,
60 dest="Global.log_level",type=int,
61 help='Set the log level (0,10,20,30,40,50). Default is 30.',
61 help='Set the log level (0,10,20,30,40,50). Default is 30.',
62 default=NoConfigDefault)
62 default=NoConfigDefault)
63 self.parser.add_argument('-config_file', '--config-file',
63 self.parser.add_argument('-config_file', '--config-file',
64 dest='Global.config_file',type=str,
64 dest='Global.config_file',type=str,
65 help='Set the config file name to override default.',
65 help='Set the config file name to override default.',
66 default=NoConfigDefault,
66 default=NoConfigDefault,
67 metavar='Global.config_file')
67 metavar='Global.config_file')
68
68
69
69
70 class ApplicationError(Exception):
70 class ApplicationError(Exception):
71 pass
71 pass
72
72
73
73
74 class Application(object):
74 class Application(object):
75 """Load a config, construct an app and run it.
75 """Load a config, construct an app and run it.
76 """
76 """
77
77
78 config_file_name = 'ipython_config.py'
78 config_file_name = 'ipython_config.py'
79 name = 'ipython'
79 name = 'ipython'
80 default_log_level = logging.WARN
81
80
82
81 def __init__(self):
83 def __init__(self):
82 self.init_logger()
84 self.init_logger()
83 self.default_config_file_name = self.config_file_name
85 self.default_config_file_name = self.config_file_name
84
86
85 def init_logger(self):
87 def init_logger(self):
86 self.log = logging.getLogger(self.__class__.__name__)
88 self.log = logging.getLogger(self.__class__.__name__)
87 # This is used as the default until the command line arguments are read.
89 # This is used as the default until the command line arguments are read.
88 self.log.setLevel(logging.WARN)
90 self.log.setLevel(self.default_log_level)
89 self._log_handler = logging.StreamHandler()
91 self._log_handler = logging.StreamHandler()
90 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
92 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
91 self._log_handler.setFormatter(self._log_formatter)
93 self._log_handler.setFormatter(self._log_formatter)
92 self.log.addHandler(self._log_handler)
94 self.log.addHandler(self._log_handler)
93
95
94 def _set_log_level(self, level):
96 def _set_log_level(self, level):
95 self.log.setLevel(level)
97 self.log.setLevel(level)
96
98
97 def _get_log_level(self):
99 def _get_log_level(self):
98 return self.log.level
100 return self.log.level
99
101
100 log_level = property(_get_log_level, _set_log_level)
102 log_level = property(_get_log_level, _set_log_level)
101
103
102 def start(self):
104 def start(self):
103 """Start the application."""
105 """Start the application."""
104 self.attempt(self.create_default_config)
106 self.attempt(self.create_default_config)
107 self.log_default_config()
108 self.set_default_config_log_level()
105 self.attempt(self.pre_load_command_line_config)
109 self.attempt(self.pre_load_command_line_config)
106 self.attempt(self.load_command_line_config, action='abort')
110 self.attempt(self.load_command_line_config, action='abort')
111 self.set_command_line_config_log_level()
107 self.attempt(self.post_load_command_line_config)
112 self.attempt(self.post_load_command_line_config)
113 self.log_command_line_config()
108 self.attempt(self.find_ipythondir)
114 self.attempt(self.find_ipythondir)
109 self.attempt(self.find_config_file_name)
115 self.attempt(self.find_config_file_name)
110 self.attempt(self.find_config_file_paths)
116 self.attempt(self.find_config_file_paths)
111 self.attempt(self.pre_load_file_config)
117 self.attempt(self.pre_load_file_config)
112 self.attempt(self.load_file_config)
118 self.attempt(self.load_file_config)
119 self.set_file_config_log_level()
113 self.attempt(self.post_load_file_config)
120 self.attempt(self.post_load_file_config)
121 self.log_file_config()
114 self.attempt(self.merge_configs)
122 self.attempt(self.merge_configs)
123 self.log_master_config()
115 self.attempt(self.pre_construct)
124 self.attempt(self.pre_construct)
116 self.attempt(self.construct)
125 self.attempt(self.construct)
117 self.attempt(self.post_construct)
126 self.attempt(self.post_construct)
118 self.attempt(self.start_app)
127 self.attempt(self.start_app)
119
128
120 #-------------------------------------------------------------------------
129 #-------------------------------------------------------------------------
121 # Various stages of Application creation
130 # Various stages of Application creation
122 #-------------------------------------------------------------------------
131 #-------------------------------------------------------------------------
123
132
124 def create_default_config(self):
133 def create_default_config(self):
125 """Create defaults that can't be set elsewhere.
134 """Create defaults that can't be set elsewhere.
126
135
127 For the most part, we try to set default in the class attributes
136 For the most part, we try to set default in the class attributes
128 of Components. But, defaults the top-level Application (which is
137 of Components. But, defaults the top-level Application (which is
129 not a HasTraitlets or Component) are not set in this way. Instead
138 not a HasTraitlets or Component) are not set in this way. Instead
130 we set them here. The Global section is for variables like this that
139 we set them here. The Global section is for variables like this that
131 don't belong to a particular component.
140 don't belong to a particular component.
132 """
141 """
133 self.default_config = Config()
142 self.default_config = Config()
134 self.default_config.Global.ipythondir = get_ipython_dir()
143 self.default_config.Global.ipythondir = get_ipython_dir()
144
145 def log_default_config(self):
135 self.log.debug('Default config loaded:')
146 self.log.debug('Default config loaded:')
136 self.log.debug(repr(self.default_config))
147 self.log.debug(repr(self.default_config))
137
148
149 def set_default_config_log_level(self):
150 try:
151 self.log_level = self.default_config.Global.log_level
152 except AttributeError:
153 # Fallback to the default_log_level class attribute
154 pass
155
138 def create_command_line_config(self):
156 def create_command_line_config(self):
139 """Create and return a command line config loader."""
157 """Create and return a command line config loader."""
140 return IPythonArgParseConfigLoader(description=self.name)
158 return IPythonArgParseConfigLoader(description=self.name)
141
159
142 def pre_load_command_line_config(self):
160 def pre_load_command_line_config(self):
143 """Do actions just before loading the command line config."""
161 """Do actions just before loading the command line config."""
144 pass
162 pass
145
163
146 def load_command_line_config(self):
164 def load_command_line_config(self):
147 """Load the command line config.
165 """Load the command line config."""
148
149 This method also sets ``self.debug``.
150 """
151
152 loader = self.create_command_line_config()
166 loader = self.create_command_line_config()
153 self.command_line_config = loader.load_config()
167 self.command_line_config = loader.load_config()
154 self.extra_args = loader.get_extra_args()
168 self.extra_args = loader.get_extra_args()
155
169
170 def set_command_line_config_log_level(self):
156 try:
171 try:
157 self.log_level = self.command_line_config.Global.log_level
172 self.log_level = self.command_line_config.Global.log_level
158 except AttributeError:
173 except AttributeError:
159 pass # Use existing value which is set in Application.init_logger.
174 pass
160 self.log.debug("Command line config loaded:")
161 self.log.debug(repr(self.command_line_config))
162
175
163 def post_load_command_line_config(self):
176 def post_load_command_line_config(self):
164 """Do actions just after loading the command line config."""
177 """Do actions just after loading the command line config."""
165 pass
178 pass
166
179
180 def log_command_line_config(self):
181 self.log.debug("Command line config loaded:")
182 self.log.debug(repr(self.command_line_config))
183
167 def find_ipythondir(self):
184 def find_ipythondir(self):
168 """Set the IPython directory.
185 """Set the IPython directory.
169
186
170 This sets ``self.ipythondir``, but the actual value that is passed
187 This sets ``self.ipythondir``, but the actual value that is passed
171 to the application is kept in either ``self.default_config`` or
188 to the application is kept in either ``self.default_config`` or
172 ``self.command_line_config``. This also added ``self.ipythondir`` to
189 ``self.command_line_config``. This also added ``self.ipythondir`` to
173 ``sys.path`` so config files there can be references by other config
190 ``sys.path`` so config files there can be references by other config
174 files.
191 files.
175 """
192 """
176
193
177 try:
194 try:
178 self.ipythondir = self.command_line_config.Global.ipythondir
195 self.ipythondir = self.command_line_config.Global.ipythondir
179 except AttributeError:
196 except AttributeError:
180 self.ipythondir = self.default_config.Global.ipythondir
197 self.ipythondir = self.default_config.Global.ipythondir
181 sys.path.append(os.path.abspath(self.ipythondir))
198 sys.path.append(os.path.abspath(self.ipythondir))
182 if not os.path.isdir(self.ipythondir):
199 if not os.path.isdir(self.ipythondir):
183 os.makedirs(self.ipythondir, mode = 0777)
200 os.makedirs(self.ipythondir, mode=0777)
184 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
201 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
185
202
186 def find_config_file_name(self):
203 def find_config_file_name(self):
187 """Find the config file name for this application.
204 """Find the config file name for this application.
188
205
206 This must set ``self.config_file_name`` to the filename of the
207 config file to use (just the filename). The search paths for the
208 config file are set in :meth:`find_config_file_paths` and then passed
209 to the config file loader where they are resolved to an absolute path.
210
189 If a profile has been set at the command line, this will resolve
211 If a profile has been set at the command line, this will resolve
190 it. The search paths for the config file are set in
212 it.
191 :meth:`find_config_file_paths` and then passed to the config file
192 loader where they are resolved to an absolute path.
193 """
213 """
194
214
195 try:
215 try:
196 self.config_file_name = self.command_line_config.Global.config_file
216 self.config_file_name = self.command_line_config.Global.config_file
197 except AttributeError:
217 except AttributeError:
198 pass
218 pass
199
219
200 try:
220 try:
201 self.profile_name = self.command_line_config.Global.profile
221 self.profile_name = self.command_line_config.Global.profile
202 name_parts = self.config_file_name.split('.')
222 name_parts = self.config_file_name.split('.')
203 name_parts.insert(1, '_' + self.profile_name + '.')
223 name_parts.insert(1, '_' + self.profile_name + '.')
204 self.config_file_name = ''.join(name_parts)
224 self.config_file_name = ''.join(name_parts)
205 except AttributeError:
225 except AttributeError:
206 pass
226 pass
207
227
208 def find_config_file_paths(self):
228 def find_config_file_paths(self):
209 """Set the search paths for resolving the config file."""
229 """Set the search paths for resolving the config file.
230
231 This must set ``self.config_file_paths`` to a sequence of search
232 paths to pass to the config file loader.
233 """
210 self.config_file_paths = (os.getcwd(), self.ipythondir)
234 self.config_file_paths = (os.getcwd(), self.ipythondir)
211
235
212 def pre_load_file_config(self):
236 def pre_load_file_config(self):
213 """Do actions before the config file is loaded."""
237 """Do actions before the config file is loaded."""
214 pass
238 pass
215
239
216 def load_file_config(self):
240 def load_file_config(self):
217 """Load the config file.
241 """Load the config file.
218
242
219 This tries to load the config file from disk. If successful, the
243 This tries to load the config file from disk. If successful, the
220 ``CONFIG_FILE`` config variable is set to the resolved config file
244 ``CONFIG_FILE`` config variable is set to the resolved config file
221 location. If not successful, an empty config is used.
245 location. If not successful, an empty config is used.
222 """
246 """
223 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)
247 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)
224 loader = PyFileConfigLoader(self.config_file_name,
248 loader = PyFileConfigLoader(self.config_file_name,
225 path=self.config_file_paths)
249 path=self.config_file_paths)
226 try:
250 try:
227 self.file_config = loader.load_config()
251 self.file_config = loader.load_config()
228 self.file_config.Global.config_file = loader.full_filename
252 self.file_config.Global.config_file = loader.full_filename
229 except IOError:
253 except IOError:
230 # Only warn if the default config file was NOT being used.
254 # Only warn if the default config file was NOT being used.
231 if not self.config_file_name==self.default_config_file_name:
255 if not self.config_file_name==self.default_config_file_name:
232 self.log.warn("Config file not found, skipping: <%s>" % \
256 self.log.warn("Config file not found, skipping: <%s>" % \
233 self.config_file_name, exc_info=True)
257 self.config_file_name, exc_info=True)
234 self.file_config = Config()
258 self.file_config = Config()
235 except:
259 except:
236 self.log.warn("Error loading config file: <%s>" % \
260 self.log.warn("Error loading config file: <%s>" % \
237 self.config_file_name, exc_info=True)
261 self.config_file_name, exc_info=True)
238 self.file_config = Config()
262 self.file_config = Config()
239 else:
263
240 self.log.debug("Config file loaded: <%s>" % loader.full_filename)
264 def set_file_config_log_level(self):
241 self.log.debug(repr(self.file_config))
242 # We need to keeep self.log_level updated. But we only use the value
265 # We need to keeep self.log_level updated. But we only use the value
243 # of the file_config if a value was not specified at the command
266 # of the file_config if a value was not specified at the command
244 # line.
267 # line, because the command line overrides everything.
245 if not hasattr(self.command_line_config.Global, 'log_level'):
268 if not hasattr(self.command_line_config.Global, 'log_level'):
246 try:
269 try:
247 self.log_level = self.file_config.Global.log_level
270 self.log_level = self.file_config.Global.log_level
248 except AttributeError:
271 except AttributeError:
249 pass # Use existing value
272 pass # Use existing value
250
273
251 def post_load_file_config(self):
274 def post_load_file_config(self):
252 """Do actions after the config file is loaded."""
275 """Do actions after the config file is loaded."""
253 pass
276 pass
254
277
278 def log_file_config(self):
279 if hasattr(self.file_config.Global, 'config_file'):
280 self.log.debug("Config file loaded: <%s>" % self.file_config.Global.config_file)
281 self.log.debug(repr(self.file_config))
282
255 def merge_configs(self):
283 def merge_configs(self):
256 """Merge the default, command line and file config objects."""
284 """Merge the default, command line and file config objects."""
257 config = Config()
285 config = Config()
258 config._merge(self.default_config)
286 config._merge(self.default_config)
259 config._merge(self.file_config)
287 config._merge(self.file_config)
260 config._merge(self.command_line_config)
288 config._merge(self.command_line_config)
261 self.master_config = config
289 self.master_config = config
290
291 def log_master_config(self):
262 self.log.debug("Master config created:")
292 self.log.debug("Master config created:")
263 self.log.debug(repr(self.master_config))
293 self.log.debug(repr(self.master_config))
264
294
265 def pre_construct(self):
295 def pre_construct(self):
266 """Do actions after the config has been built, but before construct."""
296 """Do actions after the config has been built, but before construct."""
267 pass
297 pass
268
298
269 def construct(self):
299 def construct(self):
270 """Construct the main components that make up this app."""
300 """Construct the main components that make up this app."""
271 self.log.debug("Constructing components for application")
301 self.log.debug("Constructing components for application")
272
302
273 def post_construct(self):
303 def post_construct(self):
274 """Do actions after construct, but before starting the app."""
304 """Do actions after construct, but before starting the app."""
275 pass
305 pass
276
306
277 def start_app(self):
307 def start_app(self):
278 """Actually start the app."""
308 """Actually start the app."""
279 self.log.debug("Starting application")
309 self.log.debug("Starting application")
280
310
281 #-------------------------------------------------------------------------
311 #-------------------------------------------------------------------------
282 # Utility methods
312 # Utility methods
283 #-------------------------------------------------------------------------
313 #-------------------------------------------------------------------------
284
314
285 def abort(self):
315 def abort(self):
286 """Abort the starting of the application."""
316 """Abort the starting of the application."""
287 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
317 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
288 sys.exit(1)
318 sys.exit(1)
289
319
290 def exit(self):
320 def exit(self):
291 self.log.critical("Aborting application: %s" % self.name)
321 self.log.critical("Aborting application: %s" % self.name)
292 sys.exit(1)
322 sys.exit(1)
293
323
294 def attempt(self, func, action='abort'):
324 def attempt(self, func, action='abort'):
295 try:
325 try:
296 func()
326 func()
297 except SystemExit:
327 except SystemExit:
298 self.exit()
328 self.exit()
299 except:
329 except:
300 if action == 'abort':
330 if action == 'abort':
301 self.abort()
331 self.abort()
302 elif action == 'exit':
332 elif action == 'exit':
303 self.exit()
333 self.exit()
304 No newline at end of file
334
@@ -1,96 +1,96 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """This module contains blocking clients for the controller interfaces.
3 """This module contains blocking clients for the controller interfaces.
4
4
5 Unlike the clients in `asyncclient.py`, the clients in this module are fully
5 Unlike the clients in `asyncclient.py`, the clients in this module are fully
6 blocking. This means that methods on the clients return the actual results
6 blocking. This means that methods on the clients return the actual results
7 rather than a deferred to the result. Also, we manage the Twisted reactor
7 rather than a deferred to the result. Also, we manage the Twisted reactor
8 for you. This is done by running the reactor in a thread.
8 for you. This is done by running the reactor in a thread.
9
9
10 The main classes in this module are:
10 The main classes in this module are:
11
11
12 * MultiEngineClient
12 * MultiEngineClient
13 * TaskClient
13 * TaskClient
14 * Task
14 * Task
15 * CompositeError
15 * CompositeError
16 """
16 """
17
17
18 __docformat__ = "restructuredtext en"
18 __docformat__ = "restructuredtext en"
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Copyright (C) 2008 The IPython Development Team
21 # Copyright (C) 2008 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-------------------------------------------------------------------------------
25 #-------------------------------------------------------------------------------
26
26
27 #-------------------------------------------------------------------------------
27 #-------------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-------------------------------------------------------------------------------
29 #-------------------------------------------------------------------------------
30
30
31 import sys
31 import sys
32
32
33 # from IPython.utils import growl
33 # from IPython.utils import growl
34 # growl.start("IPython1 Client")
34 # growl.start("IPython1 Client")
35
35
36
36
37 from twisted.internet import reactor
37 from twisted.internet import reactor
38 from IPython.kernel.clientconnector import ClientConnector
38 from IPython.kernel.clientconnector import ClientConnector
39 from IPython.kernel.twistedutil import ReactorInThread
39 from IPython.kernel.twistedutil import ReactorInThread
40 from IPython.kernel.twistedutil import blockingCallFromThread
40 from IPython.kernel.twistedutil import blockingCallFromThread
41
41
42 # These enable various things
42 # These enable various things
43 from IPython.kernel import codeutil
43 from IPython.kernel import codeutil
44 import IPython.kernel.magic
44 # import IPython.kernel.magic
45
45
46 # Other things that the user will need
46 # Other things that the user will need
47 from IPython.kernel.task import MapTask, StringTask
47 from IPython.kernel.task import MapTask, StringTask
48 from IPython.kernel.error import CompositeError
48 from IPython.kernel.error import CompositeError
49
49
50 #-------------------------------------------------------------------------------
50 #-------------------------------------------------------------------------------
51 # Code
51 # Code
52 #-------------------------------------------------------------------------------
52 #-------------------------------------------------------------------------------
53
53
54 _client_tub = ClientConnector()
54 _client_tub = ClientConnector()
55
55
56
56
57 def get_multiengine_client(furl_or_file=''):
57 def get_multiengine_client(furl_or_file=''):
58 """Get the blocking MultiEngine client.
58 """Get the blocking MultiEngine client.
59
59
60 :Parameters:
60 :Parameters:
61 furl_or_file : str
61 furl_or_file : str
62 A furl or a filename containing a furl. If empty, the
62 A furl or a filename containing a furl. If empty, the
63 default furl_file will be used
63 default furl_file will be used
64
64
65 :Returns:
65 :Returns:
66 The connected MultiEngineClient instance
66 The connected MultiEngineClient instance
67 """
67 """
68 client = blockingCallFromThread(_client_tub.get_multiengine_client,
68 client = blockingCallFromThread(_client_tub.get_multiengine_client,
69 furl_or_file)
69 furl_or_file)
70 return client.adapt_to_blocking_client()
70 return client.adapt_to_blocking_client()
71
71
72 def get_task_client(furl_or_file=''):
72 def get_task_client(furl_or_file=''):
73 """Get the blocking Task client.
73 """Get the blocking Task client.
74
74
75 :Parameters:
75 :Parameters:
76 furl_or_file : str
76 furl_or_file : str
77 A furl or a filename containing a furl. If empty, the
77 A furl or a filename containing a furl. If empty, the
78 default furl_file will be used
78 default furl_file will be used
79
79
80 :Returns:
80 :Returns:
81 The connected TaskClient instance
81 The connected TaskClient instance
82 """
82 """
83 client = blockingCallFromThread(_client_tub.get_task_client,
83 client = blockingCallFromThread(_client_tub.get_task_client,
84 furl_or_file)
84 furl_or_file)
85 return client.adapt_to_blocking_client()
85 return client.adapt_to_blocking_client()
86
86
87
87
88 MultiEngineClient = get_multiengine_client
88 MultiEngineClient = get_multiengine_client
89 TaskClient = get_task_client
89 TaskClient = get_task_client
90
90
91
91
92
92
93 # Now we start the reactor in a thread
93 # Now we start the reactor in a thread
94 rit = ReactorInThread()
94 rit = ReactorInThread()
95 rit.setDaemon(True)
95 rit.setDaemon(True)
96 rit.start() No newline at end of file
96 rit.start()
@@ -1,209 +1,228 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Foolscap related utilities.
4 Foolscap related utilities.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import tempfile
19 import tempfile
20
20
21 from twisted.internet import reactor, defer
21 from twisted.internet import reactor, defer
22 from twisted.python import log
22 from twisted.python import log
23
23
24 from foolscap import Tub, UnauthenticatedTub
24 from foolscap import Tub, UnauthenticatedTub
25
25
26 from IPython.config.loader import Config
26 from IPython.config.loader import Config
27
27
28 from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
28 from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
29
29
30 from IPython.kernel.error import SecurityError
30 from IPython.kernel.error import SecurityError
31
31
32 from IPython.utils.traitlets import Int, Str, Bool, Instance
32 from IPython.utils.traitlets import Int, Str, Bool, Instance
33 from IPython.utils.importstring import import_item
33 from IPython.utils.importstring import import_item
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Code
36 # Code
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39
39
40 # We do this so if a user doesn't have OpenSSL installed, it will try to use
40 # We do this so if a user doesn't have OpenSSL installed, it will try to use
41 # an UnauthenticatedTub. But, they will still run into problems if they
41 # an UnauthenticatedTub. But, they will still run into problems if they
42 # try to use encrypted furls.
42 # try to use encrypted furls.
43 try:
43 try:
44 import OpenSSL
44 import OpenSSL
45 except:
45 except:
46 Tub = UnauthenticatedTub
46 Tub = UnauthenticatedTub
47 have_crypto = False
47 have_crypto = False
48 else:
48 else:
49 have_crypto = True
49 have_crypto = True
50
50
51
51
52 def check_furl_file_security(furl_file, secure):
52 def check_furl_file_security(furl_file, secure):
53 """Remove the old furl_file if changing security modes."""
53 """Remove the old furl_file if changing security modes."""
54 if os.path.isfile(furl_file):
54 if os.path.isfile(furl_file):
55 f = open(furl_file, 'r')
55 f = open(furl_file, 'r')
56 oldfurl = f.read().strip()
56 oldfurl = f.read().strip()
57 f.close()
57 f.close()
58 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
58 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
59 os.remove(furl_file)
59 os.remove(furl_file)
60
60
61
61
62 def is_secure(furl):
62 def is_secure(furl):
63 """Is the given FURL secure or not."""
63 """Is the given FURL secure or not."""
64 if is_valid(furl):
64 if is_valid(furl):
65 if furl.startswith("pb://"):
65 if furl.startswith("pb://"):
66 return True
66 return True
67 elif furl.startswith("pbu://"):
67 elif furl.startswith("pbu://"):
68 return False
68 return False
69 else:
69 else:
70 raise ValueError("invalid furl: %s" % furl)
70 raise ValueError("invalid furl: %s" % furl)
71
71
72
72
73 def is_valid(furl):
73 def is_valid(furl):
74 """Is the str a valid furl or not."""
74 """Is the str a valid furl or not."""
75 if isinstance(furl, str):
75 if isinstance(furl, str):
76 if furl.startswith("pb://") or furl.startswith("pbu://"):
76 if furl.startswith("pb://") or furl.startswith("pbu://"):
77 return True
77 return True
78 else:
78 else:
79 return False
79 return False
80
80
81
81
82 def find_furl(furl_or_file):
82 def find_furl(furl_or_file):
83 """Find, validate and return a FURL in a string or file."""
83 """Find, validate and return a FURL in a string or file."""
84 if isinstance(furl_or_file, str):
84 if isinstance(furl_or_file, str):
85 if is_valid(furl_or_file):
85 if is_valid(furl_or_file):
86 return furl_or_file
86 return furl_or_file
87 if os.path.isfile(furl_or_file):
87 if os.path.isfile(furl_or_file):
88 furl = open(furl_or_file, 'r').read().strip()
88 furl = open(furl_or_file, 'r').read().strip()
89 if is_valid(furl):
89 if is_valid(furl):
90 return furl
90 return furl
91 raise ValueError("not a furl or a file containing a furl: %s" % furl_or_file)
91 raise ValueError("not a furl or a file containing a furl: %s" % furl_or_file)
92
92
93
93
94 def get_temp_furlfile(filename):
94 def get_temp_furlfile(filename):
95 """Return a temporary furl file."""
95 """Return a temporary furl file."""
96 return tempfile.mktemp(dir=os.path.dirname(filename),
96 return tempfile.mktemp(dir=os.path.dirname(filename),
97 prefix=os.path.basename(filename))
97 prefix=os.path.basename(filename))
98
98
99
99
100 def make_tub(ip, port, secure, cert_file):
100 def make_tub(ip, port, secure, cert_file):
101 """Create a listening tub given an ip, port, and cert_file location.
101 """Create a listening tub given an ip, port, and cert_file location.
102
102
103 Parameters
103 Parameters
104 ----------
104 ----------
105 ip : str
105 ip : str
106 The ip address or hostname that the tub should listen on.
106 The ip address or hostname that the tub should listen on.
107 Empty means all interfaces.
107 Empty means all interfaces.
108 port : int
108 port : int
109 The port that the tub should listen on. A value of 0 means
109 The port that the tub should listen on. A value of 0 means
110 pick a random port
110 pick a random port
111 secure: bool
111 secure: bool
112 Will the connection be secure (in the Foolscap sense).
112 Will the connection be secure (in the Foolscap sense).
113 cert_file: str
113 cert_file: str
114 A filename of a file to be used for theSSL certificate.
114 A filename of a file to be used for theSSL certificate.
115
115
116 Returns
116 Returns
117 -------
117 -------
118 A tub, listener tuple.
118 A tub, listener tuple.
119 """
119 """
120 if secure:
120 if secure:
121 if have_crypto:
121 if have_crypto:
122 tub = Tub(certFile=cert_file)
122 tub = Tub(certFile=cert_file)
123 else:
123 else:
124 raise SecurityError("OpenSSL/pyOpenSSL is not available, so we "
124 raise SecurityError("OpenSSL/pyOpenSSL is not available, so we "
125 "can't run in secure mode. Try running without "
125 "can't run in secure mode. Try running without "
126 "security using 'ipcontroller -xy'.")
126 "security using 'ipcontroller -xy'.")
127 else:
127 else:
128 tub = UnauthenticatedTub()
128 tub = UnauthenticatedTub()
129
129
130 # Set the strport based on the ip and port and start listening
130 # Set the strport based on the ip and port and start listening
131 if ip == '':
131 if ip == '':
132 strport = "tcp:%i" % port
132 strport = "tcp:%i" % port
133 else:
133 else:
134 strport = "tcp:%i:interface=%s" % (port, ip)
134 strport = "tcp:%i:interface=%s" % (port, ip)
135 listener = tub.listenOn(strport)
135 listener = tub.listenOn(strport)
136
136
137 return tub, listener
137 return tub, listener
138
138
139
139
140 class FCServiceFactory(AdaptedConfiguredObjectFactory):
140 class FCServiceFactory(AdaptedConfiguredObjectFactory):
141 """This class creates a tub with various services running in it.
141 """This class creates a tub with various services running in it.
142
142
143 The basic idea is that :meth:`create` returns a running :class:`Tub`
143 The basic idea is that :meth:`create` returns a running :class:`Tub`
144 instance that has a number of Foolscap references registered in it.
144 instance that has a number of Foolscap references registered in it.
145 This class is a subclass of :class:`IPython.core.component.Component`
145 This class is a subclass of :class:`IPython.core.component.Component`
146 so the IPython configuration and component system are used.
146 so the IPython configuration and component system are used.
147
147
148 Attributes
148 Attributes
149 ----------
149 ----------
150 Interfaces : Config
150 Interfaces : Config
151 A Config instance whose values are sub-Config objects having two
151 A Config instance whose values are sub-Config objects having two
152 keys: furl_file and interface_chain.
152 keys: furl_file and interface_chain.
153
153
154 The other attributes are the standard ones for Foolscap.
154 The other attributes are the standard ones for Foolscap.
155 """
155 """
156
156
157 ip = Str('', config=True)
157 ip = Str('', config=True)
158 port = Int(0, config=True)
158 port = Int(0, config=True)
159 secure = Bool(True, config=True)
159 secure = Bool(True, config=True)
160 cert_file = Str('', config=True)
160 cert_file = Str('', config=True)
161 location = Str('', config=True)
161 location = Str('', config=True)
162 reuse_furls = Bool(False, config=True)
162 Interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
163 Interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
163
164
165 def __init__(self, config, adaptee):
166 super(FCServiceFactory, self).__init__(config, adaptee)
167 self._check_reuse_furls()
168
164 def _ip_changed(self, name, old, new):
169 def _ip_changed(self, name, old, new):
165 if new == 'localhost' or new == '127.0.0.1':
170 if new == 'localhost' or new == '127.0.0.1':
166 self.location = '127.0.0.1'
171 self.location = '127.0.0.1'
167
172
173 def _check_reuse_furls(self):
174 if not self.reuse_furls:
175 furl_files = [i.furl_file for i in self.Interfaces.values()]
176 for ff in furl_files:
177 fullfile = self._get_security_file(ff)
178 if os.path.isfile(fullfile):
179 os.remove(fullfile)
180
181 def _get_security_file(self, filename):
182 return os.path.join(self.config.Global.security_dir, filename)
183
168 def create(self):
184 def create(self):
169 """Create and return the Foolscap tub with everything running."""
185 """Create and return the Foolscap tub with everything running."""
170
186
171 self.tub, self.listener = make_tub(
187 self.tub, self.listener = make_tub(
172 self.ip, self.port, self.secure, self.cert_file)
188 self.ip, self.port, self.secure, self._get_security_file(self.cert_file))
189 log.msg("Created a tub and listener [%r]: %r, %r" % (self.__class__, self.tub, self.listener))
190 log.msg("Interfaces to register [%r]: %r" % (self.__class__, self.Interfaces))
173 if not self.secure:
191 if not self.secure:
174 log.msg("WARNING: running with no security: %s" % self.__class__.__name__)
192 log.msg("WARNING: running with no security: %s" % self.__class__.__name__)
175 reactor.callWhenRunning(self.set_location_and_register)
193 reactor.callWhenRunning(self.set_location_and_register)
176 return self.tub
194 return self.tub
177
195
178 def set_location_and_register(self):
196 def set_location_and_register(self):
179 """Set the location for the tub and return a deferred."""
197 """Set the location for the tub and return a deferred."""
180
198
181 if self.location == '':
199 if self.location == '':
182 d = self.tub.setLocationAutomatically()
200 d = self.tub.setLocationAutomatically()
183 else:
201 else:
184 d = defer.maybeDeferred(self.tub.setLocation,
202 d = defer.maybeDeferred(self.tub.setLocation,
185 "%s:%i" % (self.location, self.listener.getPortnum()))
203 "%s:%i" % (self.location, self.listener.getPortnum()))
186 self.adapt_to_interfaces(d)
204 self.adapt_to_interfaces(d)
187
205
188 def adapt_to_interfaces(self, d):
206 def adapt_to_interfaces(self, d):
189 """Run through the interfaces, adapt and register."""
207 """Run through the interfaces, adapt and register."""
190
208
191 for ifname, ifconfig in self.Interfaces.iteritems():
209 for ifname, ifconfig in self.Interfaces.iteritems():
210 ff = self._get_security_file(ifconfig.furl_file)
192 log.msg("Adapting %r to interface: %s" % (self.adaptee, ifname))
211 log.msg("Adapting %r to interface: %s" % (self.adaptee, ifname))
193 log.msg("Saving furl for interface [%s] to file: %s" % (ifname, ifconfig.furl_file))
212 log.msg("Saving furl for interface [%s] to file: %s" % (ifname, ff))
194 check_furl_file_security(ifconfig.furl_file, self.secure)
213 check_furl_file_security(ff, self.secure)
195 adaptee = self.adaptee
214 adaptee = self.adaptee
196 for i in ifconfig.interface_chain:
215 for i in ifconfig.interface_chain:
197 adaptee = import_item(i)(adaptee)
216 adaptee = import_item(i)(adaptee)
198 d.addCallback(self.register, adaptee, furl_file=ifconfig.furl_file)
217 d.addCallback(self.register, adaptee, furl_file=ff)
199
218
200 def register(self, empty, ref, furl_file):
219 def register(self, empty, ref, furl_file):
201 """Register the reference with the FURL file.
220 """Register the reference with the FURL file.
202
221
203 The FURL file is created and then moved to make sure that when the
222 The FURL file is created and then moved to make sure that when the
204 file appears, the buffer has been flushed and the file closed.
223 file appears, the buffer has been flushed and the file closed.
205 """
224 """
206 temp_furl_file = get_temp_furlfile(furl_file)
225 temp_furl_file = get_temp_furlfile(furl_file)
207 self.tub.registerReference(ref, furlFile=temp_furl_file)
226 self.tub.registerReference(ref, furlFile=temp_furl_file)
208 os.rename(temp_furl_file, furl_file)
227 os.rename(temp_furl_file, furl_file)
209
228
@@ -1,266 +1,310 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython controller application
4 The IPython controller application
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import copy
18 import copy
19 import logging
19 import os
20 import os
20 import sys
21 import sys
21
22
22 from twisted.application import service
23 from twisted.application import service
23 from twisted.internet import reactor, defer
24 from twisted.internet import reactor, defer
24 from twisted.python import log
25 from twisted.python import log
25
26
26 from IPython.config.loader import Config, NoConfigDefault
27 from IPython.config.loader import Config, NoConfigDefault
27
28
28 from IPython.core.application import Application, IPythonArgParseConfigLoader
29 from IPython.core.application import Application, IPythonArgParseConfigLoader
29 from IPython.core import release
30 from IPython.core import release
30
31
31 from IPython.utils.traitlets import Int, Str, Bool, Instance
32 from IPython.utils.traitlets import Int, Str, Bool, Instance
32 from IPython.utils.importstring import import_item
33 from IPython.utils.importstring import import_item
33
34
34 from IPython.kernel import controllerservice
35 from IPython.kernel import controllerservice
35 from IPython.kernel.configobjfactory import (
36 from IPython.kernel.configobjfactory import (
36 ConfiguredObjectFactory,
37 ConfiguredObjectFactory,
37 AdaptedConfiguredObjectFactory
38 AdaptedConfiguredObjectFactory
38 )
39 )
39
40
40 from IPython.kernel.fcutil import FCServiceFactory
41 from IPython.kernel.fcutil import FCServiceFactory
41
42
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43 # Components for creating services
44 # Default interfaces
44 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
45
46
46
47
47 # The default client interfaces for FCClientServiceFactory.Interfaces
48 # The default client interfaces for FCClientServiceFactory.Interfaces
48 default_client_interfaces = Config()
49 default_client_interfaces = Config()
49 default_client_interfaces.Task.interface_chain = [
50 default_client_interfaces.Task.interface_chain = [
50 'IPython.kernel.task.ITaskController',
51 'IPython.kernel.task.ITaskController',
51 'IPython.kernel.taskfc.IFCTaskController'
52 'IPython.kernel.taskfc.IFCTaskController'
52 ]
53 ]
54
53 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
55 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
54 default_client_interfaces.MultiEngine.interface_chain = [
56 default_client_interfaces.MultiEngine.interface_chain = [
55 'IPython.kernel.multiengine.IMultiEngine',
57 'IPython.kernel.multiengine.IMultiEngine',
56 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
58 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
57 ]
59 ]
60
58 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
61 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
59
62
60 # Make this a dict we can pass to Config.__init__ for the default
63 # Make this a dict we can pass to Config.__init__ for the default
61 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
64 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
62
65
63
66
64
67
65 # The default engine interfaces for FCEngineServiceFactory.Interfaces
68 # The default engine interfaces for FCEngineServiceFactory.Interfaces
66 default_engine_interfaces = Config()
69 default_engine_interfaces = Config()
67 default_engine_interfaces.Default.interface_chain = [
70 default_engine_interfaces.Default.interface_chain = [
68 'IPython.kernel.enginefc.IFCControllerBase'
71 'IPython.kernel.enginefc.IFCControllerBase'
69 ]
72 ]
73
70 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
74 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
71
75
72 # Make this a dict we can pass to Config.__init__ for the default
76 # Make this a dict we can pass to Config.__init__ for the default
73 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
77 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
74
78
75
79
80 #-----------------------------------------------------------------------------
81 # Service factories
82 #-----------------------------------------------------------------------------
83
76
84
77 class FCClientServiceFactory(FCServiceFactory):
85 class FCClientServiceFactory(FCServiceFactory):
78 """A Foolscap implementation of the client services."""
86 """A Foolscap implementation of the client services."""
79
87
80 cert_file = Str('ipcontroller-client.pem', config=True)
88 cert_file = Str('ipcontroller-client.pem', config=True)
81 Interfaces = Instance(klass=Config, kw=default_client_interfaces,
89 Interfaces = Instance(klass=Config, kw=default_client_interfaces,
82 allow_none=False, config=True)
90 allow_none=False, config=True)
83
91
84
92
85 class FCEngineServiceFactory(FCServiceFactory):
93 class FCEngineServiceFactory(FCServiceFactory):
86 """A Foolscap implementation of the engine services."""
94 """A Foolscap implementation of the engine services."""
87
95
88 cert_file = Str('ipcontroller-engine.pem', config=True)
96 cert_file = Str('ipcontroller-engine.pem', config=True)
89 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
97 Interfaces = Instance(klass=dict, kw=default_engine_interfaces,
90 allow_none=False, config=True)
98 allow_none=False, config=True)
91
99
92
100
93 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
94 # The main application
102 # The main application
95 #-----------------------------------------------------------------------------
103 #-----------------------------------------------------------------------------
96
104
97
105
98 cl_args = (
106 cl_args = (
99 # Client config
107 # Client config
100 (('--client-ip',), dict(
108 (('--client-ip',), dict(
101 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
109 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
102 help='The IP address or hostname the controller will listen on for client connections.',
110 help='The IP address or hostname the controller will listen on for client connections.',
103 metavar='FCClientServiceFactory.ip')
111 metavar='FCClientServiceFactory.ip')
104 ),
112 ),
105 (('--client-port',), dict(
113 (('--client-port',), dict(
106 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
114 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
107 help='The port the controller will listen on for client connections.',
115 help='The port the controller will listen on for client connections.',
108 metavar='FCClientServiceFactory.port')
116 metavar='FCClientServiceFactory.port')
109 ),
117 ),
110 (('--client-location',), dict(
118 (('--client-location',), dict(
111 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
119 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
112 help='The hostname or ip that clients should connect to.',
120 help='The hostname or ip that clients should connect to.',
113 metavar='FCClientServiceFactory.location')
121 metavar='FCClientServiceFactory.location')
114 ),
122 ),
115 (('-x',), dict(
123 (('-x',), dict(
116 action='store_false', dest='FCClientServiceFactory.secure', default=NoConfigDefault,
124 action='store_false', dest='FCClientServiceFactory.secure', default=NoConfigDefault,
117 help='Turn off all client security.')
125 help='Turn off all client security.')
118 ),
126 ),
119 (('--client-cert-file',), dict(
120 type=str, dest='FCClientServiceFactory.cert_file', default=NoConfigDefault,
121 help='File to store the client SSL certificate in.',
122 metavar='FCClientServiceFactory.cert_file')
123 ),
124 (('--task-furl-file',), dict(
125 type=str, dest='FCClientServiceFactory.Interfaces.Task.furl_file', default=NoConfigDefault,
126 help='File to store the FURL in for task clients to connect with.',
127 metavar='FCClientServiceFactory.Interfaces.Task.furl_file')
128 ),
129 (('--multiengine-furl-file',), dict(
130 type=str, dest='FCClientServiceFactory.Interfaces.MultiEngine.furl_file', default=NoConfigDefault,
131 help='File to store the FURL in for multiengine clients to connect with.',
132 metavar='FCClientServiceFactory.Interfaces.MultiEngine.furl_file')
133 ),
134 # Engine config
127 # Engine config
135 (('--engine-ip',), dict(
128 (('--engine-ip',), dict(
136 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
129 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
137 help='The IP address or hostname the controller will listen on for engine connections.',
130 help='The IP address or hostname the controller will listen on for engine connections.',
138 metavar='FCEngineServiceFactory.ip')
131 metavar='FCEngineServiceFactory.ip')
139 ),
132 ),
140 (('--engine-port',), dict(
133 (('--engine-port',), dict(
141 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
134 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
142 help='The port the controller will listen on for engine connections.',
135 help='The port the controller will listen on for engine connections.',
143 metavar='FCEngineServiceFactory.port')
136 metavar='FCEngineServiceFactory.port')
144 ),
137 ),
145 (('--engine-location',), dict(
138 (('--engine-location',), dict(
146 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
139 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
147 help='The hostname or ip that engines should connect to.',
140 help='The hostname or ip that engines should connect to.',
148 metavar='FCEngineServiceFactory.location')
141 metavar='FCEngineServiceFactory.location')
149 ),
142 ),
150 (('-y',), dict(
143 (('-y',), dict(
151 action='store_false', dest='FCEngineServiceFactory.secure', default=NoConfigDefault,
144 action='store_false', dest='FCEngineServiceFactory.secure', default=NoConfigDefault,
152 help='Turn off all engine security.')
145 help='Turn off all engine security.')
153 ),
146 ),
154 (('--engine-cert-file',), dict(
155 type=str, dest='FCEngineServiceFactory.cert_file', default=NoConfigDefault,
156 help='File to store the client SSL certificate in.',
157 metavar='FCEngineServiceFactory.cert_file')
158 ),
159 (('--engine-furl-file',), dict(
160 type=str, dest='FCEngineServiceFactory.Interfaces.Default.furl_file', default=NoConfigDefault,
161 help='File to store the FURL in for engines to connect with.',
162 metavar='FCEngineServiceFactory.Interfaces.Default.furl_file')
163 ),
164 # Global config
147 # Global config
165 (('-l','--logfile'), dict(
148 (('--log-to-file',), dict(
166 type=str, dest='Global.logfile', default=NoConfigDefault,
149 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
167 help='Log file name (default is stdout)',
150 help='Log to a file in the log directory (default is stdout)')
168 metavar='Global.logfile')
169 ),
151 ),
170 (('-r',), dict(
152 (('-r','--reuse-furls'), dict(
171 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
153 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
172 help='Try to reuse all FURL files.')
154 help='Try to reuse all FURL files.')
173 )
155 ),
156 (('-cluster_dir', '--cluster-dir',), dict(
157 type=str, dest='Global.cluster_dir', default=NoConfigDefault,
158 help='Absolute or relative path to the cluster directory.',
159 metavar='Global.cluster_dir')
160 ),
174 )
161 )
175
162
176
163
177 class IPControllerAppCLConfigLoader(IPythonArgParseConfigLoader):
164 class IPControllerAppCLConfigLoader(IPythonArgParseConfigLoader):
178
165
179 arguments = cl_args
166 arguments = cl_args
180
167
181
168
182 _default_config_file_name = 'ipcontroller_config.py'
169 _default_config_file_name = 'ipcontroller_config.py'
183
170
184 class IPControllerApp(Application):
171 class IPControllerApp(Application):
185
172
186 name = 'ipcontroller'
173 name = 'ipcontroller'
187 config_file_name = _default_config_file_name
174 config_file_name = _default_config_file_name
175 default_log_level = logging.DEBUG
188
176
189 def create_default_config(self):
177 def create_default_config(self):
190 super(IPControllerApp, self).create_default_config()
178 super(IPControllerApp, self).create_default_config()
191 self.default_config.Global.logfile = ''
192 self.default_config.Global.reuse_furls = False
179 self.default_config.Global.reuse_furls = False
193 self.default_config.Global.import_statements = []
180 self.default_config.Global.import_statements = []
181 self.default_config.Global.profile = 'default'
182 self.default_config.Global.log_dir_name = 'log'
183 self.default_config.Global.security_dir_name = 'security'
184 self.default_config.Global.log_to_file = False
185 # Resolve the default cluster_dir using the default profile
186 self.default_config.Global.cluster_dir = ''
194
187
195 def create_command_line_config(self):
188 def create_command_line_config(self):
196 """Create and return a command line config loader."""
189 """Create and return a command line config loader."""
197
190
198 return IPControllerAppCLConfigLoader(
191 return IPControllerAppCLConfigLoader(
199 description="Start an IPython controller",
192 description="Start an IPython controller",
200 version=release.version)
193 version=release.version)
201
194
195 def find_config_file_name(self):
196 """Find the config file name for this application."""
197 self.find_cluster_dir()
198 self.create_cluster_dir()
199
200 def find_cluster_dir(self):
201 """This resolves into full paths, the various cluster directories.
202
203 This method must set ``self.cluster_dir`` to the full paths of
204 the directory.
205 """
206 # Ignore self.command_line_config.Global.config_file
207 # Instead, first look for an explicit cluster_dir
208 try:
209 self.cluster_dir = self.command_line_config.Global.cluster_dir
210 except AttributeError:
211 self.cluster_dir = self.default_config.Global.cluster_dir
212 self.cluster_dir = os.path.expandvars(os.path.expanduser(self.cluster_dir))
213 if not self.cluster_dir:
214 # Then look for a profile
215 try:
216 self.profile = self.command_line_config.Global.profile
217 except AttributeError:
218 self.profile = self.default_config.Global.profile
219 cluster_dir_name = 'cluster_' + self.profile
220 try_this = os.path.join(os.getcwd(), cluster_dir_name)
221 if os.path.isdir(try_this):
222 self.cluster_dir = try_this
223 else:
224 self.cluster_dir = os.path.join(self.ipythondir, cluster_dir_name)
225 # These have to be set because they could be different from the one
226 # that we just computed. Because command line has the highest
227 # priority, this will always end up in the master_config.
228 self.default_config.Global.cluster_dir = self.cluster_dir
229 self.command_line_config.Global.cluster_dir = self.cluster_dir
230
231 def create_cluster_dir(self):
232 """Make sure that the cluster, security and log dirs exist."""
233 if not os.path.isdir(self.cluster_dir):
234 os.makedirs(self.cluster_dir, mode=0777)
235
236 def find_config_file_paths(self):
237 """Set the search paths for resolving the config file."""
238 self.config_file_paths = (self.cluster_dir,)
239
240 def pre_construct(self):
241 # Now set the security_dir and log_dir and create them. We use
242 # the names an construct the absolute paths.
243 security_dir = os.path.join(self.master_config.Global.cluster_dir,
244 self.master_config.Global.security_dir_name)
245 log_dir = os.path.join(self.master_config.Global.cluster_dir,
246 self.master_config.Global.log_dir_name)
247 if not os.path.isdir(security_dir):
248 os.mkdir(security_dir, 0700)
249 else:
250 os.chmod(security_dir, 0700)
251 if not os.path.isdir(log_dir):
252 os.mkdir(log_dir, 0777)
253
254 self.security_dir = self.master_config.Global.security_dir = security_dir
255 self.log_dir = self.master_config.Global.log_dir = log_dir
256
257 # Now setup reuse_furls
258 if hasattr(self.master_config.Global.reuse_furls):
259 self.master_config.FCClientServiceFactory.reuse_furls = \
260 self.master_config.Global.reuse_furls
261 self.master_config.FCEngineServiceFactory.reuse_furls = \
262 self.master_config.Global.reuse_furls
263
202 def construct(self):
264 def construct(self):
203 # I am a little hesitant to put these into InteractiveShell itself.
265 # I am a little hesitant to put these into InteractiveShell itself.
204 # But that might be the place for them
266 # But that might be the place for them
205 sys.path.insert(0, '')
267 sys.path.insert(0, '')
206
268
207 self.start_logging()
269 self.start_logging()
208 self.import_statements()
270 self.import_statements()
209 self.reuse_furls()
210
271
211 # Create the service hierarchy
272 # Create the service hierarchy
212 self.main_service = service.MultiService()
273 self.main_service = service.MultiService()
213 # The controller service
274 # The controller service
214 controller_service = controllerservice.ControllerService()
275 controller_service = controllerservice.ControllerService()
215 controller_service.setServiceParent(self.main_service)
276 controller_service.setServiceParent(self.main_service)
216 # The client tub and all its refereceables
277 # The client tub and all its refereceables
217 csfactory = FCClientServiceFactory(self.master_config, controller_service)
278 csfactory = FCClientServiceFactory(self.master_config, controller_service)
218 client_service = csfactory.create()
279 client_service = csfactory.create()
219 client_service.setServiceParent(self.main_service)
280 client_service.setServiceParent(self.main_service)
220 # The engine tub
281 # The engine tub
221 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
282 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
222 engine_service = esfactory.create()
283 engine_service = esfactory.create()
223 engine_service.setServiceParent(self.main_service)
284 engine_service.setServiceParent(self.main_service)
224
285
225 def start_logging(self):
286 def start_logging(self):
226 logfile = self.master_config.Global.logfile
287 if self.master_config.Global.log_to_file:
227 if logfile:
288 log_filename = self.name + '-' + str(os.getpid()) + '.log'
228 logfile = logfile + str(os.getpid()) + '.log'
289 logfile = os.path.join(self.log_dir, log_filename)
229 try:
290 open_log_file = open(logfile, 'w')
230 openLogFile = open(logfile, 'w')
231 except:
232 openLogFile = sys.stdout
233 else:
291 else:
234 openLogFile = sys.stdout
292 open_log_file = sys.stdout
235 log.startLogging(openLogFile)
293 log.startLogging(open_log_file)
236
294
237 def import_statements(self):
295 def import_statements(self):
238 statements = self.master_config.Global.import_statements
296 statements = self.master_config.Global.import_statements
239 for s in statements:
297 for s in statements:
240 try:
298 try:
241 exec s in globals(), locals()
299 exec s in globals(), locals()
242 except:
300 except:
243 log.msg("Error running import statement: %s" % s)
301 log.msg("Error running import statement: %s" % s)
244
302
245 def reuse_furls(self):
246 # This logic might need to be moved into the components
247 # Delete old furl files unless the reuse_furls is set
248 reuse = self.master_config.Global.reuse_furls
249 # if not reuse:
250 # paths = (
251 # self.master_config.FCEngineServiceFactory.Interfaces.Default.furl_file,
252 # self.master_config.FCClientServiceFactory.Interfaces.Task.furl_file,
253 # self.master_config.FCClientServiceFactory.Interfaces.MultiEngine.furl_file
254 # )
255 # for p in paths:
256 # if os.path.isfile(p):
257 # os.remove(p)
258
259 def start_app(self):
303 def start_app(self):
260 # Start the controller service and set things running
304 # Start the controller service and set things running
261 self.main_service.startService()
305 self.main_service.startService()
262 reactor.run()
306 reactor.run()
263
307
264 if __name__ == '__main__':
308 if __name__ == '__main__':
265 app = IPControllerApp()
309 app = IPControllerApp()
266 app.start()
310 app.start()
General Comments 0
You need to be logged in to leave comments. Login now