##// END OF EJS Templates
use new ip<x>z_config.py defaults
MinRK -
Show More
@@ -1,538 +1,538
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython cluster directory
4 The IPython cluster directory
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 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import logging
21 import logging
22 import re
22 import re
23 import shutil
23 import shutil
24 import sys
24 import sys
25 import warnings
25 import warnings
26
26
27 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.config.configurable import Configurable
28 from IPython.config.configurable import Configurable
29 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.core.application import Application, BaseAppConfigLoader
30 from IPython.core.crashhandler import CrashHandler
30 from IPython.core.crashhandler import CrashHandler
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.utils.path import (
32 from IPython.utils.path import (
33 get_ipython_package_dir,
33 get_ipython_package_dir,
34 expand_path
34 expand_path
35 )
35 )
36 from IPython.utils.traitlets import Unicode
36 from IPython.utils.traitlets import Unicode
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Module errors
39 # Module errors
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class ClusterDirError(Exception):
42 class ClusterDirError(Exception):
43 pass
43 pass
44
44
45
45
46 class PIDFileError(Exception):
46 class PIDFileError(Exception):
47 pass
47 pass
48
48
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Class for managing cluster directories
51 # Class for managing cluster directories
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class ClusterDir(Configurable):
54 class ClusterDir(Configurable):
55 """An object to manage the cluster directory and its resources.
55 """An object to manage the cluster directory and its resources.
56
56
57 The cluster directory is used by :command:`ipengine`,
57 The cluster directory is used by :command:`ipengine`,
58 :command:`ipcontroller` and :command:`ipclsuter` to manage the
58 :command:`ipcontroller` and :command:`ipclsuter` to manage the
59 configuration, logging and security of these applications.
59 configuration, logging and security of these applications.
60
60
61 This object knows how to find, create and manage these directories. This
61 This object knows how to find, create and manage these directories. This
62 should be used by any code that want's to handle cluster directories.
62 should be used by any code that want's to handle cluster directories.
63 """
63 """
64
64
65 security_dir_name = Unicode('security')
65 security_dir_name = Unicode('security')
66 log_dir_name = Unicode('log')
66 log_dir_name = Unicode('log')
67 pid_dir_name = Unicode('pid')
67 pid_dir_name = Unicode('pid')
68 security_dir = Unicode(u'')
68 security_dir = Unicode(u'')
69 log_dir = Unicode(u'')
69 log_dir = Unicode(u'')
70 pid_dir = Unicode(u'')
70 pid_dir = Unicode(u'')
71 location = Unicode(u'')
71 location = Unicode(u'')
72
72
73 def __init__(self, location=u''):
73 def __init__(self, location=u''):
74 super(ClusterDir, self).__init__(location=location)
74 super(ClusterDir, self).__init__(location=location)
75
75
76 def _location_changed(self, name, old, new):
76 def _location_changed(self, name, old, new):
77 if not os.path.isdir(new):
77 if not os.path.isdir(new):
78 os.makedirs(new)
78 os.makedirs(new)
79 self.security_dir = os.path.join(new, self.security_dir_name)
79 self.security_dir = os.path.join(new, self.security_dir_name)
80 self.log_dir = os.path.join(new, self.log_dir_name)
80 self.log_dir = os.path.join(new, self.log_dir_name)
81 self.pid_dir = os.path.join(new, self.pid_dir_name)
81 self.pid_dir = os.path.join(new, self.pid_dir_name)
82 self.check_dirs()
82 self.check_dirs()
83
83
84 def _log_dir_changed(self, name, old, new):
84 def _log_dir_changed(self, name, old, new):
85 self.check_log_dir()
85 self.check_log_dir()
86
86
87 def check_log_dir(self):
87 def check_log_dir(self):
88 if not os.path.isdir(self.log_dir):
88 if not os.path.isdir(self.log_dir):
89 os.mkdir(self.log_dir)
89 os.mkdir(self.log_dir)
90
90
91 def _security_dir_changed(self, name, old, new):
91 def _security_dir_changed(self, name, old, new):
92 self.check_security_dir()
92 self.check_security_dir()
93
93
94 def check_security_dir(self):
94 def check_security_dir(self):
95 if not os.path.isdir(self.security_dir):
95 if not os.path.isdir(self.security_dir):
96 os.mkdir(self.security_dir, 0700)
96 os.mkdir(self.security_dir, 0700)
97 os.chmod(self.security_dir, 0700)
97 os.chmod(self.security_dir, 0700)
98
98
99 def _pid_dir_changed(self, name, old, new):
99 def _pid_dir_changed(self, name, old, new):
100 self.check_pid_dir()
100 self.check_pid_dir()
101
101
102 def check_pid_dir(self):
102 def check_pid_dir(self):
103 if not os.path.isdir(self.pid_dir):
103 if not os.path.isdir(self.pid_dir):
104 os.mkdir(self.pid_dir, 0700)
104 os.mkdir(self.pid_dir, 0700)
105 os.chmod(self.pid_dir, 0700)
105 os.chmod(self.pid_dir, 0700)
106
106
107 def check_dirs(self):
107 def check_dirs(self):
108 self.check_security_dir()
108 self.check_security_dir()
109 self.check_log_dir()
109 self.check_log_dir()
110 self.check_pid_dir()
110 self.check_pid_dir()
111
111
112 def load_config_file(self, filename):
112 def load_config_file(self, filename):
113 """Load a config file from the top level of the cluster dir.
113 """Load a config file from the top level of the cluster dir.
114
114
115 Parameters
115 Parameters
116 ----------
116 ----------
117 filename : unicode or str
117 filename : unicode or str
118 The filename only of the config file that must be located in
118 The filename only of the config file that must be located in
119 the top-level of the cluster directory.
119 the top-level of the cluster directory.
120 """
120 """
121 loader = PyFileConfigLoader(filename, self.location)
121 loader = PyFileConfigLoader(filename, self.location)
122 return loader.load_config()
122 return loader.load_config()
123
123
124 def copy_config_file(self, config_file, path=None, overwrite=False):
124 def copy_config_file(self, config_file, path=None, overwrite=False):
125 """Copy a default config file into the active cluster directory.
125 """Copy a default config file into the active cluster directory.
126
126
127 Default configuration files are kept in :mod:`IPython.config.default`.
127 Default configuration files are kept in :mod:`IPython.config.default`.
128 This function moves these from that location to the working cluster
128 This function moves these from that location to the working cluster
129 directory.
129 directory.
130 """
130 """
131 if path is None:
131 if path is None:
132 import IPython.config.default
132 import IPython.config.default
133 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
133 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
134 path = os.path.sep.join(path)
134 path = os.path.sep.join(path)
135 src = os.path.join(path, config_file)
135 src = os.path.join(path, config_file)
136 dst = os.path.join(self.location, config_file)
136 dst = os.path.join(self.location, config_file)
137 if not os.path.isfile(dst) or overwrite:
137 if not os.path.isfile(dst) or overwrite:
138 shutil.copy(src, dst)
138 shutil.copy(src, dst)
139
139
140 def copy_all_config_files(self, path=None, overwrite=False):
140 def copy_all_config_files(self, path=None, overwrite=False):
141 """Copy all config files into the active cluster directory."""
141 """Copy all config files into the active cluster directory."""
142 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
142 for f in [u'ipcontrollerz_config.py', u'ipenginez_config.py',
143 u'ipcluster_config.py']:
143 u'ipclusterz_config.py']:
144 self.copy_config_file(f, path=path, overwrite=overwrite)
144 self.copy_config_file(f, path=path, overwrite=overwrite)
145
145
146 @classmethod
146 @classmethod
147 def create_cluster_dir(csl, cluster_dir):
147 def create_cluster_dir(csl, cluster_dir):
148 """Create a new cluster directory given a full path.
148 """Create a new cluster directory given a full path.
149
149
150 Parameters
150 Parameters
151 ----------
151 ----------
152 cluster_dir : str
152 cluster_dir : str
153 The full path to the cluster directory. If it does exist, it will
153 The full path to the cluster directory. If it does exist, it will
154 be used. If not, it will be created.
154 be used. If not, it will be created.
155 """
155 """
156 return ClusterDir(location=cluster_dir)
156 return ClusterDir(location=cluster_dir)
157
157
158 @classmethod
158 @classmethod
159 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
159 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
160 """Create a cluster dir by profile name and path.
160 """Create a cluster dir by profile name and path.
161
161
162 Parameters
162 Parameters
163 ----------
163 ----------
164 path : str
164 path : str
165 The path (directory) to put the cluster directory in.
165 The path (directory) to put the cluster directory in.
166 profile : str
166 profile : str
167 The name of the profile. The name of the cluster directory will
167 The name of the profile. The name of the cluster directory will
168 be "clusterz_<profile>".
168 be "clusterz_<profile>".
169 """
169 """
170 if not os.path.isdir(path):
170 if not os.path.isdir(path):
171 raise ClusterDirError('Directory not found: %s' % path)
171 raise ClusterDirError('Directory not found: %s' % path)
172 cluster_dir = os.path.join(path, u'clusterz_' + profile)
172 cluster_dir = os.path.join(path, u'clusterz_' + profile)
173 return ClusterDir(location=cluster_dir)
173 return ClusterDir(location=cluster_dir)
174
174
175 @classmethod
175 @classmethod
176 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
176 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
177 """Find an existing cluster dir by profile name, return its ClusterDir.
177 """Find an existing cluster dir by profile name, return its ClusterDir.
178
178
179 This searches through a sequence of paths for a cluster dir. If it
179 This searches through a sequence of paths for a cluster dir. If it
180 is not found, a :class:`ClusterDirError` exception will be raised.
180 is not found, a :class:`ClusterDirError` exception will be raised.
181
181
182 The search path algorithm is:
182 The search path algorithm is:
183 1. ``os.getcwd()``
183 1. ``os.getcwd()``
184 2. ``ipython_dir``
184 2. ``ipython_dir``
185 3. The directories found in the ":" separated
185 3. The directories found in the ":" separated
186 :env:`IPCLUSTER_DIR_PATH` environment variable.
186 :env:`IPCLUSTER_DIR_PATH` environment variable.
187
187
188 Parameters
188 Parameters
189 ----------
189 ----------
190 ipython_dir : unicode or str
190 ipython_dir : unicode or str
191 The IPython directory to use.
191 The IPython directory to use.
192 profile : unicode or str
192 profile : unicode or str
193 The name of the profile. The name of the cluster directory
193 The name of the profile. The name of the cluster directory
194 will be "clusterz_<profile>".
194 will be "clusterz_<profile>".
195 """
195 """
196 dirname = u'clusterz_' + profile
196 dirname = u'clusterz_' + profile
197 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
197 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
198 if cluster_dir_paths:
198 if cluster_dir_paths:
199 cluster_dir_paths = cluster_dir_paths.split(':')
199 cluster_dir_paths = cluster_dir_paths.split(':')
200 else:
200 else:
201 cluster_dir_paths = []
201 cluster_dir_paths = []
202 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
202 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
203 for p in paths:
203 for p in paths:
204 cluster_dir = os.path.join(p, dirname)
204 cluster_dir = os.path.join(p, dirname)
205 if os.path.isdir(cluster_dir):
205 if os.path.isdir(cluster_dir):
206 return ClusterDir(location=cluster_dir)
206 return ClusterDir(location=cluster_dir)
207 else:
207 else:
208 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
208 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
209
209
210 @classmethod
210 @classmethod
211 def find_cluster_dir(cls, cluster_dir):
211 def find_cluster_dir(cls, cluster_dir):
212 """Find/create a cluster dir and return its ClusterDir.
212 """Find/create a cluster dir and return its ClusterDir.
213
213
214 This will create the cluster directory if it doesn't exist.
214 This will create the cluster directory if it doesn't exist.
215
215
216 Parameters
216 Parameters
217 ----------
217 ----------
218 cluster_dir : unicode or str
218 cluster_dir : unicode or str
219 The path of the cluster directory. This is expanded using
219 The path of the cluster directory. This is expanded using
220 :func:`IPython.utils.genutils.expand_path`.
220 :func:`IPython.utils.genutils.expand_path`.
221 """
221 """
222 cluster_dir = expand_path(cluster_dir)
222 cluster_dir = expand_path(cluster_dir)
223 if not os.path.isdir(cluster_dir):
223 if not os.path.isdir(cluster_dir):
224 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
224 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
225 return ClusterDir(location=cluster_dir)
225 return ClusterDir(location=cluster_dir)
226
226
227
227
228 #-----------------------------------------------------------------------------
228 #-----------------------------------------------------------------------------
229 # Command line options
229 # Command line options
230 #-----------------------------------------------------------------------------
230 #-----------------------------------------------------------------------------
231
231
232 class ClusterDirConfigLoader(BaseAppConfigLoader):
232 class ClusterDirConfigLoader(BaseAppConfigLoader):
233
233
234 def _add_cluster_profile(self, parser):
234 def _add_cluster_profile(self, parser):
235 paa = parser.add_argument
235 paa = parser.add_argument
236 paa('-p', '--profile',
236 paa('-p', '--profile',
237 dest='Global.profile',type=unicode,
237 dest='Global.profile',type=unicode,
238 help=
238 help=
239 """The string name of the profile to be used. This determines the name
239 """The string name of the profile to be used. This determines the name
240 of the cluster dir as: cluster_<profile>. The default profile is named
240 of the cluster dir as: cluster_<profile>. The default profile is named
241 'default'. The cluster directory is resolve this way if the
241 'default'. The cluster directory is resolve this way if the
242 --cluster-dir option is not used.""",
242 --cluster-dir option is not used.""",
243 metavar='Global.profile')
243 metavar='Global.profile')
244
244
245 def _add_cluster_dir(self, parser):
245 def _add_cluster_dir(self, parser):
246 paa = parser.add_argument
246 paa = parser.add_argument
247 paa('--cluster-dir',
247 paa('--cluster-dir',
248 dest='Global.cluster_dir',type=unicode,
248 dest='Global.cluster_dir',type=unicode,
249 help="""Set the cluster dir. This overrides the logic used by the
249 help="""Set the cluster dir. This overrides the logic used by the
250 --profile option.""",
250 --profile option.""",
251 metavar='Global.cluster_dir')
251 metavar='Global.cluster_dir')
252
252
253 def _add_work_dir(self, parser):
253 def _add_work_dir(self, parser):
254 paa = parser.add_argument
254 paa = parser.add_argument
255 paa('--work-dir',
255 paa('--work-dir',
256 dest='Global.work_dir',type=unicode,
256 dest='Global.work_dir',type=unicode,
257 help='Set the working dir for the process.',
257 help='Set the working dir for the process.',
258 metavar='Global.work_dir')
258 metavar='Global.work_dir')
259
259
260 def _add_clean_logs(self, parser):
260 def _add_clean_logs(self, parser):
261 paa = parser.add_argument
261 paa = parser.add_argument
262 paa('--clean-logs',
262 paa('--clean-logs',
263 dest='Global.clean_logs', action='store_true',
263 dest='Global.clean_logs', action='store_true',
264 help='Delete old log flies before starting.')
264 help='Delete old log flies before starting.')
265
265
266 def _add_no_clean_logs(self, parser):
266 def _add_no_clean_logs(self, parser):
267 paa = parser.add_argument
267 paa = parser.add_argument
268 paa('--no-clean-logs',
268 paa('--no-clean-logs',
269 dest='Global.clean_logs', action='store_false',
269 dest='Global.clean_logs', action='store_false',
270 help="Don't Delete old log flies before starting.")
270 help="Don't Delete old log flies before starting.")
271
271
272 def _add_arguments(self):
272 def _add_arguments(self):
273 super(ClusterDirConfigLoader, self)._add_arguments()
273 super(ClusterDirConfigLoader, self)._add_arguments()
274 self._add_cluster_profile(self.parser)
274 self._add_cluster_profile(self.parser)
275 self._add_cluster_dir(self.parser)
275 self._add_cluster_dir(self.parser)
276 self._add_work_dir(self.parser)
276 self._add_work_dir(self.parser)
277 self._add_clean_logs(self.parser)
277 self._add_clean_logs(self.parser)
278 self._add_no_clean_logs(self.parser)
278 self._add_no_clean_logs(self.parser)
279
279
280
280
281 #-----------------------------------------------------------------------------
281 #-----------------------------------------------------------------------------
282 # Crash handler for this application
282 # Crash handler for this application
283 #-----------------------------------------------------------------------------
283 #-----------------------------------------------------------------------------
284
284
285
285
286 _message_template = """\
286 _message_template = """\
287 Oops, $self.app_name crashed. We do our best to make it stable, but...
287 Oops, $self.app_name crashed. We do our best to make it stable, but...
288
288
289 A crash report was automatically generated with the following information:
289 A crash report was automatically generated with the following information:
290 - A verbatim copy of the crash traceback.
290 - A verbatim copy of the crash traceback.
291 - Data on your current $self.app_name configuration.
291 - Data on your current $self.app_name configuration.
292
292
293 It was left in the file named:
293 It was left in the file named:
294 \t'$self.crash_report_fname'
294 \t'$self.crash_report_fname'
295 If you can email this file to the developers, the information in it will help
295 If you can email this file to the developers, the information in it will help
296 them in understanding and correcting the problem.
296 them in understanding and correcting the problem.
297
297
298 You can mail it to: $self.contact_name at $self.contact_email
298 You can mail it to: $self.contact_name at $self.contact_email
299 with the subject '$self.app_name Crash Report'.
299 with the subject '$self.app_name Crash Report'.
300
300
301 If you want to do it now, the following command will work (under Unix):
301 If you want to do it now, the following command will work (under Unix):
302 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
302 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
303
303
304 To ensure accurate tracking of this issue, please file a report about it at:
304 To ensure accurate tracking of this issue, please file a report about it at:
305 $self.bug_tracker
305 $self.bug_tracker
306 """
306 """
307
307
308 class ClusterDirCrashHandler(CrashHandler):
308 class ClusterDirCrashHandler(CrashHandler):
309 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
309 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
310
310
311 message_template = _message_template
311 message_template = _message_template
312
312
313 def __init__(self, app):
313 def __init__(self, app):
314 contact_name = release.authors['Brian'][0]
314 contact_name = release.authors['Brian'][0]
315 contact_email = release.authors['Brian'][1]
315 contact_email = release.authors['Brian'][1]
316 bug_tracker = 'http://github.com/ipython/ipython/issues'
316 bug_tracker = 'http://github.com/ipython/ipython/issues'
317 super(ClusterDirCrashHandler,self).__init__(
317 super(ClusterDirCrashHandler,self).__init__(
318 app, contact_name, contact_email, bug_tracker
318 app, contact_name, contact_email, bug_tracker
319 )
319 )
320
320
321
321
322 #-----------------------------------------------------------------------------
322 #-----------------------------------------------------------------------------
323 # Main application
323 # Main application
324 #-----------------------------------------------------------------------------
324 #-----------------------------------------------------------------------------
325
325
326 class ApplicationWithClusterDir(Application):
326 class ApplicationWithClusterDir(Application):
327 """An application that puts everything into a cluster directory.
327 """An application that puts everything into a cluster directory.
328
328
329 Instead of looking for things in the ipython_dir, this type of application
329 Instead of looking for things in the ipython_dir, this type of application
330 will use its own private directory called the "cluster directory"
330 will use its own private directory called the "cluster directory"
331 for things like config files, log files, etc.
331 for things like config files, log files, etc.
332
332
333 The cluster directory is resolved as follows:
333 The cluster directory is resolved as follows:
334
334
335 * If the ``--cluster-dir`` option is given, it is used.
335 * If the ``--cluster-dir`` option is given, it is used.
336 * If ``--cluster-dir`` is not given, the application directory is
336 * If ``--cluster-dir`` is not given, the application directory is
337 resolve using the profile name as ``cluster_<profile>``. The search
337 resolve using the profile name as ``cluster_<profile>``. The search
338 path for this directory is then i) cwd if it is found there
338 path for this directory is then i) cwd if it is found there
339 and ii) in ipython_dir otherwise.
339 and ii) in ipython_dir otherwise.
340
340
341 The config file for the application is to be put in the cluster
341 The config file for the application is to be put in the cluster
342 dir and named the value of the ``config_file_name`` class attribute.
342 dir and named the value of the ``config_file_name`` class attribute.
343 """
343 """
344
344
345 command_line_loader = ClusterDirConfigLoader
345 command_line_loader = ClusterDirConfigLoader
346 crash_handler_class = ClusterDirCrashHandler
346 crash_handler_class = ClusterDirCrashHandler
347 auto_create_cluster_dir = True
347 auto_create_cluster_dir = True
348 # temporarily override default_log_level to INFO
348 # temporarily override default_log_level to INFO
349 default_log_level = logging.INFO
349 default_log_level = logging.INFO
350
350
351 def create_default_config(self):
351 def create_default_config(self):
352 super(ApplicationWithClusterDir, self).create_default_config()
352 super(ApplicationWithClusterDir, self).create_default_config()
353 self.default_config.Global.profile = u'default'
353 self.default_config.Global.profile = u'default'
354 self.default_config.Global.cluster_dir = u''
354 self.default_config.Global.cluster_dir = u''
355 self.default_config.Global.work_dir = os.getcwd()
355 self.default_config.Global.work_dir = os.getcwd()
356 self.default_config.Global.log_to_file = False
356 self.default_config.Global.log_to_file = False
357 self.default_config.Global.log_url = None
357 self.default_config.Global.log_url = None
358 self.default_config.Global.clean_logs = False
358 self.default_config.Global.clean_logs = False
359
359
360 def find_resources(self):
360 def find_resources(self):
361 """This resolves the cluster directory.
361 """This resolves the cluster directory.
362
362
363 This tries to find the cluster directory and if successful, it will
363 This tries to find the cluster directory and if successful, it will
364 have done:
364 have done:
365 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
365 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
366 the application.
366 the application.
367 * Sets ``self.cluster_dir`` attribute of the application and config
367 * Sets ``self.cluster_dir`` attribute of the application and config
368 objects.
368 objects.
369
369
370 The algorithm used for this is as follows:
370 The algorithm used for this is as follows:
371 1. Try ``Global.cluster_dir``.
371 1. Try ``Global.cluster_dir``.
372 2. Try using ``Global.profile``.
372 2. Try using ``Global.profile``.
373 3. If both of these fail and ``self.auto_create_cluster_dir`` is
373 3. If both of these fail and ``self.auto_create_cluster_dir`` is
374 ``True``, then create the new cluster dir in the IPython directory.
374 ``True``, then create the new cluster dir in the IPython directory.
375 4. If all fails, then raise :class:`ClusterDirError`.
375 4. If all fails, then raise :class:`ClusterDirError`.
376 """
376 """
377
377
378 try:
378 try:
379 cluster_dir = self.command_line_config.Global.cluster_dir
379 cluster_dir = self.command_line_config.Global.cluster_dir
380 except AttributeError:
380 except AttributeError:
381 cluster_dir = self.default_config.Global.cluster_dir
381 cluster_dir = self.default_config.Global.cluster_dir
382 cluster_dir = expand_path(cluster_dir)
382 cluster_dir = expand_path(cluster_dir)
383 try:
383 try:
384 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
384 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
385 except ClusterDirError:
385 except ClusterDirError:
386 pass
386 pass
387 else:
387 else:
388 self.log.info('Using existing cluster dir: %s' % \
388 self.log.info('Using existing cluster dir: %s' % \
389 self.cluster_dir_obj.location
389 self.cluster_dir_obj.location
390 )
390 )
391 self.finish_cluster_dir()
391 self.finish_cluster_dir()
392 return
392 return
393
393
394 try:
394 try:
395 self.profile = self.command_line_config.Global.profile
395 self.profile = self.command_line_config.Global.profile
396 except AttributeError:
396 except AttributeError:
397 self.profile = self.default_config.Global.profile
397 self.profile = self.default_config.Global.profile
398 try:
398 try:
399 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
399 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
400 self.ipython_dir, self.profile)
400 self.ipython_dir, self.profile)
401 except ClusterDirError:
401 except ClusterDirError:
402 pass
402 pass
403 else:
403 else:
404 self.log.info('Using existing cluster dir: %s' % \
404 self.log.info('Using existing cluster dir: %s' % \
405 self.cluster_dir_obj.location
405 self.cluster_dir_obj.location
406 )
406 )
407 self.finish_cluster_dir()
407 self.finish_cluster_dir()
408 return
408 return
409
409
410 if self.auto_create_cluster_dir:
410 if self.auto_create_cluster_dir:
411 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
411 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
412 self.ipython_dir, self.profile
412 self.ipython_dir, self.profile
413 )
413 )
414 self.log.info('Creating new cluster dir: %s' % \
414 self.log.info('Creating new cluster dir: %s' % \
415 self.cluster_dir_obj.location
415 self.cluster_dir_obj.location
416 )
416 )
417 self.finish_cluster_dir()
417 self.finish_cluster_dir()
418 else:
418 else:
419 raise ClusterDirError('Could not find a valid cluster directory.')
419 raise ClusterDirError('Could not find a valid cluster directory.')
420
420
421 def finish_cluster_dir(self):
421 def finish_cluster_dir(self):
422 # Set the cluster directory
422 # Set the cluster directory
423 self.cluster_dir = self.cluster_dir_obj.location
423 self.cluster_dir = self.cluster_dir_obj.location
424
424
425 # These have to be set because they could be different from the one
425 # These have to be set because they could be different from the one
426 # that we just computed. Because command line has the highest
426 # that we just computed. Because command line has the highest
427 # priority, this will always end up in the master_config.
427 # priority, this will always end up in the master_config.
428 self.default_config.Global.cluster_dir = self.cluster_dir
428 self.default_config.Global.cluster_dir = self.cluster_dir
429 self.command_line_config.Global.cluster_dir = self.cluster_dir
429 self.command_line_config.Global.cluster_dir = self.cluster_dir
430
430
431 def find_config_file_name(self):
431 def find_config_file_name(self):
432 """Find the config file name for this application."""
432 """Find the config file name for this application."""
433 # For this type of Application it should be set as a class attribute.
433 # For this type of Application it should be set as a class attribute.
434 if not hasattr(self, 'default_config_file_name'):
434 if not hasattr(self, 'default_config_file_name'):
435 self.log.critical("No config filename found")
435 self.log.critical("No config filename found")
436 else:
436 else:
437 self.config_file_name = self.default_config_file_name
437 self.config_file_name = self.default_config_file_name
438
438
439 def find_config_file_paths(self):
439 def find_config_file_paths(self):
440 # Set the search path to to the cluster directory. We should NOT
440 # Set the search path to to the cluster directory. We should NOT
441 # include IPython.config.default here as the default config files
441 # include IPython.config.default here as the default config files
442 # are ALWAYS automatically moved to the cluster directory.
442 # are ALWAYS automatically moved to the cluster directory.
443 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
443 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
444 self.config_file_paths = (self.cluster_dir,)
444 self.config_file_paths = (self.cluster_dir,)
445
445
446 def pre_construct(self):
446 def pre_construct(self):
447 # The log and security dirs were set earlier, but here we put them
447 # The log and security dirs were set earlier, but here we put them
448 # into the config and log them.
448 # into the config and log them.
449 config = self.master_config
449 config = self.master_config
450 sdir = self.cluster_dir_obj.security_dir
450 sdir = self.cluster_dir_obj.security_dir
451 self.security_dir = config.Global.security_dir = sdir
451 self.security_dir = config.Global.security_dir = sdir
452 ldir = self.cluster_dir_obj.log_dir
452 ldir = self.cluster_dir_obj.log_dir
453 self.log_dir = config.Global.log_dir = ldir
453 self.log_dir = config.Global.log_dir = ldir
454 pdir = self.cluster_dir_obj.pid_dir
454 pdir = self.cluster_dir_obj.pid_dir
455 self.pid_dir = config.Global.pid_dir = pdir
455 self.pid_dir = config.Global.pid_dir = pdir
456 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
456 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
457 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
457 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
458 # Change to the working directory. We do this just before construct
458 # Change to the working directory. We do this just before construct
459 # is called so all the components there have the right working dir.
459 # is called so all the components there have the right working dir.
460 self.to_work_dir()
460 self.to_work_dir()
461
461
462 def to_work_dir(self):
462 def to_work_dir(self):
463 wd = self.master_config.Global.work_dir
463 wd = self.master_config.Global.work_dir
464 if unicode(wd) != unicode(os.getcwd()):
464 if unicode(wd) != unicode(os.getcwd()):
465 os.chdir(wd)
465 os.chdir(wd)
466 self.log.info("Changing to working dir: %s" % wd)
466 self.log.info("Changing to working dir: %s" % wd)
467
467
468 def start_logging(self):
468 def start_logging(self):
469 # Remove old log files
469 # Remove old log files
470 if self.master_config.Global.clean_logs:
470 if self.master_config.Global.clean_logs:
471 log_dir = self.master_config.Global.log_dir
471 log_dir = self.master_config.Global.log_dir
472 for f in os.listdir(log_dir):
472 for f in os.listdir(log_dir):
473 if re.match(r'%s-\d+\.(log|err|out)'%self.name,f):
473 if re.match(r'%s-\d+\.(log|err|out)'%self.name,f):
474 # if f.startswith(self.name + u'-') and f.endswith('.log'):
474 # if f.startswith(self.name + u'-') and f.endswith('.log'):
475 os.remove(os.path.join(log_dir, f))
475 os.remove(os.path.join(log_dir, f))
476 # Start logging to the new log file
476 # Start logging to the new log file
477 if self.master_config.Global.log_to_file:
477 if self.master_config.Global.log_to_file:
478 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
478 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
479 logfile = os.path.join(self.log_dir, log_filename)
479 logfile = os.path.join(self.log_dir, log_filename)
480 open_log_file = open(logfile, 'w')
480 open_log_file = open(logfile, 'w')
481 elif self.master_config.Global.log_url:
481 elif self.master_config.Global.log_url:
482 open_log_file = None
482 open_log_file = None
483 else:
483 else:
484 open_log_file = sys.stdout
484 open_log_file = sys.stdout
485 if open_log_file is not None:
485 if open_log_file is not None:
486 self.log.removeHandler(self._log_handler)
486 self.log.removeHandler(self._log_handler)
487 self._log_handler = logging.StreamHandler(open_log_file)
487 self._log_handler = logging.StreamHandler(open_log_file)
488 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
488 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
489 self._log_handler.setFormatter(self._log_formatter)
489 self._log_handler.setFormatter(self._log_formatter)
490 self.log.addHandler(self._log_handler)
490 self.log.addHandler(self._log_handler)
491 # log.startLogging(open_log_file)
491 # log.startLogging(open_log_file)
492
492
493 def write_pid_file(self, overwrite=False):
493 def write_pid_file(self, overwrite=False):
494 """Create a .pid file in the pid_dir with my pid.
494 """Create a .pid file in the pid_dir with my pid.
495
495
496 This must be called after pre_construct, which sets `self.pid_dir`.
496 This must be called after pre_construct, which sets `self.pid_dir`.
497 This raises :exc:`PIDFileError` if the pid file exists already.
497 This raises :exc:`PIDFileError` if the pid file exists already.
498 """
498 """
499 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
499 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
500 if os.path.isfile(pid_file):
500 if os.path.isfile(pid_file):
501 pid = self.get_pid_from_file()
501 pid = self.get_pid_from_file()
502 if not overwrite:
502 if not overwrite:
503 raise PIDFileError(
503 raise PIDFileError(
504 'The pid file [%s] already exists. \nThis could mean that this '
504 'The pid file [%s] already exists. \nThis could mean that this '
505 'server is already running with [pid=%s].' % (pid_file, pid)
505 'server is already running with [pid=%s].' % (pid_file, pid)
506 )
506 )
507 with open(pid_file, 'w') as f:
507 with open(pid_file, 'w') as f:
508 self.log.info("Creating pid file: %s" % pid_file)
508 self.log.info("Creating pid file: %s" % pid_file)
509 f.write(repr(os.getpid())+'\n')
509 f.write(repr(os.getpid())+'\n')
510
510
511 def remove_pid_file(self):
511 def remove_pid_file(self):
512 """Remove the pid file.
512 """Remove the pid file.
513
513
514 This should be called at shutdown by registering a callback with
514 This should be called at shutdown by registering a callback with
515 :func:`reactor.addSystemEventTrigger`. This needs to return
515 :func:`reactor.addSystemEventTrigger`. This needs to return
516 ``None``.
516 ``None``.
517 """
517 """
518 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
518 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
519 if os.path.isfile(pid_file):
519 if os.path.isfile(pid_file):
520 try:
520 try:
521 self.log.info("Removing pid file: %s" % pid_file)
521 self.log.info("Removing pid file: %s" % pid_file)
522 os.remove(pid_file)
522 os.remove(pid_file)
523 except:
523 except:
524 self.log.warn("Error removing the pid file: %s" % pid_file)
524 self.log.warn("Error removing the pid file: %s" % pid_file)
525
525
526 def get_pid_from_file(self):
526 def get_pid_from_file(self):
527 """Get the pid from the pid file.
527 """Get the pid from the pid file.
528
528
529 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
529 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
530 """
530 """
531 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
531 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
532 if os.path.isfile(pid_file):
532 if os.path.isfile(pid_file):
533 with open(pid_file, 'r') as f:
533 with open(pid_file, 'r') as f:
534 pid = int(f.read().strip())
534 pid = int(f.read().strip())
535 return pid
535 return pid
536 else:
536 else:
537 raise PIDFileError('pid file not found: %s' % pid_file)
537 raise PIDFileError('pid file not found: %s' % pid_file)
538
538
General Comments 0
You need to be logged in to leave comments. Login now