##// END OF EJS Templates
Finished refactoring ipcontroller to be a proper application....
Brian Granger -
Show More
@@ -6,62 +6,67 b' c = get_config()'
6 6 # Global configuration
7 7 #-----------------------------------------------------------------------------
8 8
9 c.Global.log_to_file = False
10 c.Global.import_statements = []
11 c.Global.reuse_furls = False
9 # Basic Global config attributes
10 # c.Global.log_to_file = False
11 # c.Global.import_statements = ['import math']
12 # c.Global.reuse_furls = True
13 # c.Global.secure = True
12 14
13 # You shouldn't have to edit these
14 c.Global.log_dir_name = 'log'
15 c.Global.security_dir_name = 'security'
15 # You shouldn't have to modify these
16 # c.Global.log_dir_name = 'log'
17 # c.Global.security_dir_name = 'security'
16 18
17 19
18 20 #-----------------------------------------------------------------------------
19 21 # Configure the client services
20 22 #-----------------------------------------------------------------------------
21 23
22 c.FCClientServiceFactory.ip = ''
23 c.FCClientServiceFactory.port = 0
24 c.FCClientServiceFactory.location = ''
25 c.FCClientServiceFactory.secure = True
26 c.FCClientServiceFactory.reuse_furls = False
27 c.FCClientServiceFactory.cert_file = 'ipcontroller-client.pem'
28
29 c.FCClientServiceFactory.Interfaces.Task.interface_chain = [
30 'IPython.kernel.task.ITaskController',
31 'IPython.kernel.taskfc.IFCTaskController'
32 ]
33 # This is just the filename of the furl file. The path is always the
34 # security dir of the cluster directory.
35 c.FCClientServiceFactory.Interfaces.Task.furl_file = 'ipcontroller-tc.furl'
36
37 c.FCClientServiceFactory.Interfaces.MultiEngine.interface_chain = [
38 'IPython.kernel.multiengine.IMultiEngine',
39 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
40 ]
41 # This is just the filename of the furl file. The path is always the
42 # security dir of the cluster directory.
43 c.FCClientServiceFactory.Interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
44
24 # Basic client service config attributes
25 # c.FCClientServiceFactory.ip = ''
26 # c.FCClientServiceFactory.port = 0
27 # c.FCClientServiceFactory.location = ''
28 # c.FCClientServiceFactory.secure = True
29 # c.FCClientServiceFactory.reuse_furls = False
30
31 # You shouldn't have to modify the rest of this section
32 # c.FCClientServiceFactory.cert_file = 'ipcontroller-client.pem'
33
34 # default_client_interfaces = Config()
35 # default_client_interfaces.Task.interface_chain = [
36 # 'IPython.kernel.task.ITaskController',
37 # 'IPython.kernel.taskfc.IFCTaskController'
38 # ]
39 #
40 # default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
41 #
42 # default_client_interfaces.MultiEngine.interface_chain = [
43 # 'IPython.kernel.multiengine.IMultiEngine',
44 # 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
45 # ]
46 #
47 # default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
48 #
49 # c.FCEngineServiceFactory.interfaces = default_client_interfaces
45 50
46 51 #-----------------------------------------------------------------------------
47 52 # Configure the engine services
48 53 #-----------------------------------------------------------------------------
49 54
50 c.FCEngineServiceFactory.ip = ''
51 c.FCEngineServiceFactory.port = 0
52 c.FCEngineServiceFactory.location = ''
53 c.FCEngineServiceFactory.secure = True
54 c.FCEngineServiceFactory.reuse_furls = False
55 c.FCEngineServiceFactory.cert_file = 'ipcontroller-engine.pem'
56
57 c.FCEngineServiceFactory.Intefaces.Default.interface_chain = [
58 'IPython.kernel.enginefc.IFCControllerBase'
59 ]
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'
64
65
66
67
55 # Basic config attributes for the engine services
56 # c.FCEngineServiceFactory.ip = ''
57 # c.FCEngineServiceFactory.port = 0
58 # c.FCEngineServiceFactory.location = ''
59 # c.FCEngineServiceFactory.secure = True
60 # c.FCEngineServiceFactory.reuse_furls = False
61
62 # You shouldn't have to modify the rest of this section
63 # c.FCEngineServiceFactory.cert_file = 'ipcontroller-engine.pem'
64
65 # default_engine_interfaces = Config()
66 # default_engine_interfaces.Default.interface_chain = [
67 # 'IPython.kernel.enginefc.IFCControllerBase'
68 # ]
69 #
70 # default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
71 #
72 # c.FCEngineServiceFactory.interfaces = default_engine_interfaces
@@ -77,9 +77,9 b' class Application(object):'
77 77 """Load a config, construct an app and run it.
78 78 """
79 79
80 config_file_name = 'ipython_config.py'
81 80 name = 'ipython'
82 81 description = 'IPython: an enhanced interactive Python shell.'
82 config_file_name = 'ipython_config.py'
83 83 default_log_level = logging.WARN
84 84
85 85
@@ -351,7 +351,11 b' class AppWithDirArgParseConfigLoader(ArgParseConfigLoader):'
351 351 metavar='Global.ipythondir')
352 352 self.parser.add_argument('-p','-profile', '--profile',
353 353 dest='Global.profile',type=str,
354 help='The string name of the ipython profile to be used.',
354 help='The string name of the profile to be used. This determines '
355 'the name of the application dir: basename_<profile>. The basename is '
356 'determined by the particular application. The default profile '
357 'is named "default". This convention is used if the -app_dir '
358 'option is not used.',
355 359 default=NoConfigDefault,
356 360 metavar='Global.profile')
357 361 self.parser.add_argument('-log_level', '--log-level',
@@ -360,22 +364,40 b' class AppWithDirArgParseConfigLoader(ArgParseConfigLoader):'
360 364 default=NoConfigDefault)
361 365 self.parser.add_argument('-app_dir', '--app-dir',
362 366 dest='Global.app_dir',type=str,
363 help='Set the application directory where everything for this '
364 'application will be found (including the config file).',
367 help='Set the application dir where everything for this '
368 'application will be found (including the config file). This '
369 'overrides the logic used by the profile option.',
365 370 default=NoConfigDefault,
366 371 metavar='Global.app_dir')
367 372
368 373
369 374 class ApplicationWithDir(Application):
375 """An application that puts everything into a application directory.
370 376
371 name = 'appname'
372 description = 'Application: foo and bar it.'
373 config_file_name = 'appname_config.py'
374 default_log_level = logging.WARN
377 Instead of looking for things in the ipythondir, this type of application
378 will use its own private directory called the "application directory"
379 for things like config files, log files, etc.
380
381 The application directory is resolved as follows:
382
383 * If the ``--app-dir`` option is given, it is used.
384 * If ``--app-dir`` is not given, the application directory is resolve using
385 ``app_dir_basename`` and ``profile`` as ``<app_dir_basename>_<profile>``.
386 The search path for this directory is then i) cwd if it is found there
387 and ii) in ipythondir otherwise.
388
389 The config file for the application is to be put in the application
390 dir and named the value of the ``config_file_name`` class attribute.
391 """
392
393 # The basename used for the application dir: <app_dir_basename>_<profile>
394 app_dir_basename = 'cluster'
375 395
376 396 def create_default_config(self):
377 397 super(ApplicationWithDir, self).create_default_config()
378 398 self.default_config.Global.profile = 'default'
399 # The application dir. This is empty initially so the default is to
400 # try to resolve this using the profile.
379 401 self.default_config.Global.app_dir = ''
380 402
381 403 def create_command_line_config(self):
@@ -391,10 +413,10 b' class ApplicationWithDir(Application):'
391 413 self.create_app_dir()
392 414
393 415 def find_app_dir(self):
394 """This resolves into full paths, the app directory.
416 """This resolves the app directory.
395 417
396 This method must set ``self.app_dir`` to the full path of
397 the directory.
418 This method must set ``self.app_dir`` to the location of the app
419 dir.
398 420 """
399 421 # Instead, first look for an explicit app_dir
400 422 try:
@@ -408,7 +430,7 b' class ApplicationWithDir(Application):'
408 430 self.profile = self.command_line_config.Global.profile
409 431 except AttributeError:
410 432 self.profile = self.default_config.Global.profile
411 app_dir_name = 'cluster_' + self.profile
433 app_dir_name = self.app_dir_basename + '_' + self.profile
412 434 try_this = os.path.join(os.getcwd(), app_dir_name)
413 435 if os.path.isdir(try_this):
414 436 self.app_dir = try_this
@@ -421,7 +443,7 b' class ApplicationWithDir(Application):'
421 443 self.command_line_config.Global.app_dir = self.app_dir
422 444
423 445 def create_app_dir(self):
424 """Make sure that the cluster, security and log dirs exist."""
446 """Make sure that the app dir exists."""
425 447 if not os.path.isdir(self.app_dir):
426 448 os.makedirs(self.app_dir, mode=0777)
427 449
@@ -296,7 +296,19 b' class Component(HasTraitlets):'
296 296 if new._has_section(sname):
297 297 my_config = new[sname]
298 298 for k, v in traitlets.items():
299 # Don't allow traitlets with config=True to start with
300 # uppercase. Otherwise, they are confused with Config
301 # subsections. But, developers shouldn't have uppercase
302 # attributes anyways! (PEP 6)
303 if k[0].upper()==k[0] and not k.startswith('_'):
304 raise ComponentError('Component traitlets with '
305 'config=True must start with a lowercase so they are '
306 'not confused with Config subsections: %s.%s' % \
307 (self.__class__.__name__, k))
299 308 try:
309 # Here we grab the value from the config
310 # If k has the naming convention of a config
311 # section, it will be auto created.
300 312 config_value = my_config[k]
301 313 except KeyError:
302 314 pass
@@ -294,13 +294,13 b' class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader):'
294 294 arguments = cl_args
295 295
296 296
297 _default_config_file_name = 'ipython_config.py'
297 default_config_file_name = 'ipython_config.py'
298 298
299 299
300 300 class IPythonApp(Application):
301 301 name = 'ipython'
302 302 description = 'IPython: an enhanced interactive Python shell.'
303 config_file_name = _default_config_file_name
303 config_file_name = default_config_file_name
304 304
305 305 def create_default_config(self):
306 306 super(IPythonApp, self).create_default_config()
@@ -533,7 +533,7 b' def load_default_config(ipythondir=None):'
533 533 """
534 534 if ipythondir is None:
535 535 ipythondir = get_ipython_dir()
536 cl = PyFileConfigLoader(_default_config_file_name, ipythondir)
536 cl = PyFileConfigLoader(default_config_file_name, ipythondir)
537 537 config = cl.load_config()
538 538 return config
539 539
@@ -68,7 +68,11 b' class AdaptedConfiguredObjectFactory(Component):'
68 68 # zi.implements(IAdaptedConfiguredObjectFactory)
69 69
70 70 def __init__(self, config, adaptee):
71 # print
72 # print "config pre:", config
71 73 super(AdaptedConfiguredObjectFactory, self).__init__(None, config=config)
74 # print
75 # print "config post:", config
72 76 self.adaptee = adaptee
73 77
74 78 def create(self):
@@ -67,11 +67,11 b' def is_secure(furl):'
67 67 elif furl.startswith("pbu://"):
68 68 return False
69 69 else:
70 raise ValueError("invalid furl: %s" % furl)
70 raise ValueError("invalid FURL: %s" % furl)
71 71
72 72
73 73 def is_valid(furl):
74 """Is the str a valid furl or not."""
74 """Is the str a valid FURL or not."""
75 75 if isinstance(furl, str):
76 76 if furl.startswith("pb://") or furl.startswith("pbu://"):
77 77 return True
@@ -88,11 +88,11 b' def find_furl(furl_or_file):'
88 88 furl = open(furl_or_file, 'r').read().strip()
89 89 if is_valid(furl):
90 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 94 def get_temp_furlfile(filename):
95 """Return a temporary furl file."""
95 """Return a temporary FURL file."""
96 96 return tempfile.mktemp(dir=os.path.dirname(filename),
97 97 prefix=os.path.basename(filename))
98 98
@@ -132,6 +132,7 b' def make_tub(ip, port, secure, cert_file):'
132 132 strport = "tcp:%i" % port
133 133 else:
134 134 strport = "tcp:%i:interface=%s" % (port, ip)
135 log.msg("Starting listener with [secure=%r] on: %s" % (secure, strport))
135 136 listener = tub.listenOn(strport)
136 137
137 138 return tub, listener
@@ -147,7 +148,7 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
147 148
148 149 Attributes
149 150 ----------
150 Interfaces : Config
151 interfaces : Config
151 152 A Config instance whose values are sub-Config objects having two
152 153 keys: furl_file and interface_chain.
153 154
@@ -160,7 +161,7 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
160 161 cert_file = Str('', config=True)
161 162 location = Str('', config=True)
162 163 reuse_furls = Bool(False, config=True)
163 Interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
164 interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
164 165
165 166 def __init__(self, config, adaptee):
166 167 super(FCServiceFactory, self).__init__(config, adaptee)
@@ -171,11 +172,14 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
171 172 self.location = '127.0.0.1'
172 173
173 174 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)
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 self.reuse_furls:
179 log.msg("Reusing FURL file: %s" % fullfile)
180 else:
178 181 if os.path.isfile(fullfile):
182 log.msg("Removing old FURL file: %s" % fullfile)
179 183 os.remove(fullfile)
180 184
181 185 def _get_security_file(self, filename):
@@ -185,11 +189,14 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
185 189 """Create and return the Foolscap tub with everything running."""
186 190
187 191 self.tub, self.listener = make_tub(
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))
192 self.ip, self.port, self.secure,
193 self._get_security_file(self.cert_file)
194 )
195 # log.msg("Interfaces to register [%r]: %r" % \
196 # (self.__class__, self.interfaces))
191 197 if not self.secure:
192 log.msg("WARNING: running with no security: %s" % self.__class__.__name__)
198 log.msg("WARNING: running with no security: %s" % \
199 self.__class__.__name__)
193 200 reactor.callWhenRunning(self.set_location_and_register)
194 201 return self.tub
195 202
@@ -206,10 +213,11 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
206 213 def adapt_to_interfaces(self, d):
207 214 """Run through the interfaces, adapt and register."""
208 215
209 for ifname, ifconfig in self.Interfaces.iteritems():
216 for ifname, ifconfig in self.interfaces.iteritems():
210 217 ff = self._get_security_file(ifconfig.furl_file)
211 log.msg("Adapting %r to interface: %s" % (self.adaptee, ifname))
212 log.msg("Saving furl for interface [%s] to file: %s" % (ifname, ff))
218 log.msg("Adapting [%s] to interface: %s" % \
219 (self.adaptee.__class__.__name__, ifname))
220 log.msg("Saving FURL for interface [%s] to file: %s" % (ifname, ff))
213 221 check_furl_file_security(ff, self.secure)
214 222 adaptee = self.adaptee
215 223 for i in ifconfig.interface_chain:
@@ -28,7 +28,7 b' from IPython.config.loader import Config, NoConfigDefault'
28 28
29 29 from IPython.core.application import (
30 30 ApplicationWithDir,
31 BaseAppArgParseConfigLoader
31 AppWithDirArgParseConfigLoader
32 32 )
33 33
34 34 from IPython.core import release
@@ -49,7 +49,7 b' from IPython.kernel.fcutil import FCServiceFactory'
49 49 #-----------------------------------------------------------------------------
50 50
51 51
52 # The default client interfaces for FCClientServiceFactory.Interfaces
52 # The default client interfaces for FCClientServiceFactory.interfaces
53 53 default_client_interfaces = Config()
54 54 default_client_interfaces.Task.interface_chain = [
55 55 'IPython.kernel.task.ITaskController',
@@ -57,6 +57,7 b' default_client_interfaces.Task.interface_chain = ['
57 57 ]
58 58
59 59 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
60
60 61 default_client_interfaces.MultiEngine.interface_chain = [
61 62 'IPython.kernel.multiengine.IMultiEngine',
62 63 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
@@ -69,7 +70,7 b' default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()'
69 70
70 71
71 72
72 # The default engine interfaces for FCEngineServiceFactory.Interfaces
73 # The default engine interfaces for FCEngineServiceFactory.interfaces
73 74 default_engine_interfaces = Config()
74 75 default_engine_interfaces.Default.interface_chain = [
75 76 'IPython.kernel.enginefc.IFCControllerBase'
@@ -90,7 +91,7 b' class FCClientServiceFactory(FCServiceFactory):'
90 91 """A Foolscap implementation of the client services."""
91 92
92 93 cert_file = Str('ipcontroller-client.pem', config=True)
93 Interfaces = Instance(klass=Config, kw=default_client_interfaces,
94 interfaces = Instance(klass=Config, kw=default_client_interfaces,
94 95 allow_none=False, config=True)
95 96
96 97
@@ -98,7 +99,7 b' class FCEngineServiceFactory(FCServiceFactory):'
98 99 """A Foolscap implementation of the engine services."""
99 100
100 101 cert_file = Str('ipcontroller-engine.pem', config=True)
101 Interfaces = Instance(klass=dict, kw=default_engine_interfaces,
102 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
102 103 allow_none=False, config=True)
103 104
104 105
@@ -124,10 +125,6 b' cl_args = ('
124 125 help='The hostname or ip that clients should connect to.',
125 126 metavar='FCClientServiceFactory.location')
126 127 ),
127 (('-x',), dict(
128 action='store_false', dest='FCClientServiceFactory.secure', default=NoConfigDefault,
129 help='Turn off all client security.')
130 ),
131 128 # Engine config
132 129 (('--engine-ip',), dict(
133 130 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
@@ -144,10 +141,6 b' cl_args = ('
144 141 help='The hostname or ip that engines should connect to.',
145 142 metavar='FCEngineServiceFactory.location')
146 143 ),
147 (('-y',), dict(
148 action='store_false', dest='FCEngineServiceFactory.secure', default=NoConfigDefault,
149 help='Turn off all engine security.')
150 ),
151 144 # Global config
152 145 (('--log-to-file',), dict(
153 146 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
@@ -156,33 +149,61 b' cl_args = ('
156 149 (('-r','--reuse-furls'), dict(
157 150 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
158 151 help='Try to reuse all FURL files.')
152 ),
153 (('-ns','--no-security'), dict(
154 action='store_false', dest='Global.secure', default=NoConfigDefault,
155 help='Turn off SSL encryption for all connections.')
159 156 )
160 157 )
161 158
162 159
163 class IPControllerAppCLConfigLoader(BaseAppArgParseConfigLoader):
160 class IPControllerAppCLConfigLoader(AppWithDirArgParseConfigLoader):
164 161
165 162 arguments = cl_args
166 163
167 164
168 _default_config_file_name = 'ipcontroller_config.py'
165 default_config_file_name = 'ipcontroller_config.py'
169 166
170 167
171 168 class IPControllerApp(ApplicationWithDir):
172 169
173 170 name = 'ipcontroller'
171 app_dir_basename = 'cluster'
174 172 description = 'Start the IPython controller for parallel computing.'
175 config_file_name = _default_config_file_name
176 default_log_level = logging.DEBUG
173 config_file_name = default_config_file_name
174 default_log_level = logging.WARN
177 175
178 176 def create_default_config(self):
179 177 super(IPControllerApp, self).create_default_config()
180 178 self.default_config.Global.reuse_furls = False
179 self.default_config.Global.secure = True
181 180 self.default_config.Global.import_statements = []
182 181 self.default_config.Global.log_dir_name = 'log'
183 182 self.default_config.Global.security_dir_name = 'security'
184 183 self.default_config.Global.log_to_file = False
185 184
185 def create_command_line_config(self):
186 """Create and return a command line config loader."""
187 return IPControllerAppCLConfigLoader(
188 description=self.description,
189 version=release.version
190 )
191
192 def post_load_command_line_config(self):
193 # Now setup reuse_furls
194 if hasattr(self.command_line_config.Global, 'reuse_furls'):
195 self.command_line_config.FCClientServiceFactory.reuse_furls = \
196 self.command_line_config.Global.reuse_furls
197 self.command_line_config.FCEngineServiceFactory.reuse_furls = \
198 self.command_line_config.Global.reuse_furls
199 del self.command_line_config.Global.reuse_furls
200 if hasattr(self.command_line_config.Global, 'secure'):
201 self.command_line_config.FCClientServiceFactory.secure = \
202 self.command_line_config.Global.secure
203 self.command_line_config.FCEngineServiceFactory.secure = \
204 self.command_line_config.Global.secure
205 del self.command_line_config.Global.secure
206
186 207 def pre_construct(self):
187 208 # Now set the security_dir and log_dir and create them. We use
188 209 # the names an construct the absolute paths.
@@ -200,13 +221,6 b' class IPControllerApp(ApplicationWithDir):'
200 221 self.security_dir = self.master_config.Global.security_dir = security_dir
201 222 self.log_dir = self.master_config.Global.log_dir = log_dir
202 223
203 # Now setup reuse_furls
204 if hasattr(self.master_config.Global, 'reuse_furls'):
205 self.master_config.FCClientServiceFactory.reuse_furls = \
206 self.master_config.Global.reuse_furls
207 self.master_config.FCEngineServiceFactory.reuse_furls = \
208 self.master_config.Global.reuse_furls
209
210 224 def construct(self):
211 225 # I am a little hesitant to put these into InteractiveShell itself.
212 226 # But that might be the place for them
@@ -214,7 +228,7 b' class IPControllerApp(ApplicationWithDir):'
214 228
215 229 self.start_logging()
216 230 self.import_statements()
217
231
218 232 # Create the service hierarchy
219 233 self.main_service = service.MultiService()
220 234 # The controller service
@@ -242,9 +256,10 b' class IPControllerApp(ApplicationWithDir):'
242 256 statements = self.master_config.Global.import_statements
243 257 for s in statements:
244 258 try:
259 log.msg("Executing statement: '%s'" % s)
245 260 exec s in globals(), locals()
246 261 except:
247 log.msg("Error running import statement: %s" % s)
262 log.msg("Error running statement: %s" % s)
248 263
249 264 def start_app(self):
250 265 # Start the controller service and set things running
General Comments 0
You need to be logged in to leave comments. Login now