##// END OF EJS Templates
Fix warning on startup if user didn't have personal copies of cluster config....
Fernando Perez -
Show More
@@ -1,450 +1,463 b''
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 shutil
21 import shutil
22 import sys
22 import sys
23 import warnings
23
24
24 from twisted.python import log
25 from twisted.python import log
25
26
26 from IPython.core import release
27 from IPython.core import release
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.config.loader import PyFileConfigLoader
28 from IPython.core.application import Application
29 from IPython.core.application import Application
29 from IPython.core.component import Component
30 from IPython.core.component import Component
31 from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir
30 from IPython.utils.traitlets import Unicode, Bool
32 from IPython.utils.traitlets import Unicode, Bool
31 from IPython.utils import genutils
33 from IPython.utils import genutils
32
34
33 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
34 # Imports
36 # Warnings control
35 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Twisted generates annoying warnings with Python 2.6, as will do other code
39 # that imports 'sets' as of today
40 warnings.filterwarnings('ignore', 'the sets module is deprecated',
41 DeprecationWarning )
36
42
43 # This one also comes from Twisted
44 warnings.filterwarnings('ignore', 'the sha module is deprecated',
45 DeprecationWarning)
46
47 #-----------------------------------------------------------------------------
48 # Classes and functions
49 #-----------------------------------------------------------------------------
37
50
38 class ClusterDirError(Exception):
51 class ClusterDirError(Exception):
39 pass
52 pass
40
53
41
54
42 class PIDFileError(Exception):
55 class PIDFileError(Exception):
43 pass
56 pass
44
57
45
58
46 class ClusterDir(Component):
59 class ClusterDir(Component):
47 """An object to manage the cluster directory and its resources.
60 """An object to manage the cluster directory and its resources.
48
61
49 The cluster directory is used by :command:`ipcontroller`,
62 The cluster directory is used by :command:`ipcontroller`,
50 :command:`ipcontroller` and :command:`ipcontroller` to manage the
63 :command:`ipcontroller` and :command:`ipcontroller` to manage the
51 configuration, logging and security of these applications.
64 configuration, logging and security of these applications.
52
65
53 This object knows how to find, create and manage these directories. This
66 This object knows how to find, create and manage these directories. This
54 should be used by any code that want's to handle cluster directories.
67 should be used by any code that want's to handle cluster directories.
55 """
68 """
56
69
57 security_dir_name = Unicode('security')
70 security_dir_name = Unicode('security')
58 log_dir_name = Unicode('log')
71 log_dir_name = Unicode('log')
59 pid_dir_name = Unicode('pid')
72 pid_dir_name = Unicode('pid')
60 security_dir = Unicode(u'')
73 security_dir = Unicode(u'')
61 log_dir = Unicode(u'')
74 log_dir = Unicode(u'')
62 pid_dir = Unicode(u'')
75 pid_dir = Unicode(u'')
63 location = Unicode(u'')
76 location = Unicode(u'')
64
77
65 def __init__(self, location):
78 def __init__(self, location):
66 super(ClusterDir, self).__init__(None)
79 super(ClusterDir, self).__init__(None)
67 self.location = location
80 self.location = location
68
81
69 def _location_changed(self, name, old, new):
82 def _location_changed(self, name, old, new):
70 if not os.path.isdir(new):
83 if not os.path.isdir(new):
71 os.makedirs(new)
84 os.makedirs(new)
72 self.security_dir = os.path.join(new, self.security_dir_name)
85 self.security_dir = os.path.join(new, self.security_dir_name)
73 self.log_dir = os.path.join(new, self.log_dir_name)
86 self.log_dir = os.path.join(new, self.log_dir_name)
74 self.pid_dir = os.path.join(new, self.pid_dir_name)
87 self.pid_dir = os.path.join(new, self.pid_dir_name)
75 self.check_dirs()
88 self.check_dirs()
76
89
77 def _log_dir_changed(self, name, old, new):
90 def _log_dir_changed(self, name, old, new):
78 self.check_log_dir()
91 self.check_log_dir()
79
92
80 def check_log_dir(self):
93 def check_log_dir(self):
81 if not os.path.isdir(self.log_dir):
94 if not os.path.isdir(self.log_dir):
82 os.mkdir(self.log_dir)
95 os.mkdir(self.log_dir)
83
96
84 def _security_dir_changed(self, name, old, new):
97 def _security_dir_changed(self, name, old, new):
85 self.check_security_dir()
98 self.check_security_dir()
86
99
87 def check_security_dir(self):
100 def check_security_dir(self):
88 if not os.path.isdir(self.security_dir):
101 if not os.path.isdir(self.security_dir):
89 os.mkdir(self.security_dir, 0700)
102 os.mkdir(self.security_dir, 0700)
90 os.chmod(self.security_dir, 0700)
103 os.chmod(self.security_dir, 0700)
91
104
92 def _pid_dir_changed(self, name, old, new):
105 def _pid_dir_changed(self, name, old, new):
93 self.check_pid_dir()
106 self.check_pid_dir()
94
107
95 def check_pid_dir(self):
108 def check_pid_dir(self):
96 if not os.path.isdir(self.pid_dir):
109 if not os.path.isdir(self.pid_dir):
97 os.mkdir(self.pid_dir, 0700)
110 os.mkdir(self.pid_dir, 0700)
98 os.chmod(self.pid_dir, 0700)
111 os.chmod(self.pid_dir, 0700)
99
112
100 def check_dirs(self):
113 def check_dirs(self):
101 self.check_security_dir()
114 self.check_security_dir()
102 self.check_log_dir()
115 self.check_log_dir()
103 self.check_pid_dir()
116 self.check_pid_dir()
104
117
105 def load_config_file(self, filename):
118 def load_config_file(self, filename):
106 """Load a config file from the top level of the cluster dir.
119 """Load a config file from the top level of the cluster dir.
107
120
108 Parameters
121 Parameters
109 ----------
122 ----------
110 filename : unicode or str
123 filename : unicode or str
111 The filename only of the config file that must be located in
124 The filename only of the config file that must be located in
112 the top-level of the cluster directory.
125 the top-level of the cluster directory.
113 """
126 """
114 loader = PyFileConfigLoader(filename, self.location)
127 loader = PyFileConfigLoader(filename, self.location)
115 return loader.load_config()
128 return loader.load_config()
116
129
117 def copy_config_file(self, config_file, path=None, overwrite=False):
130 def copy_config_file(self, config_file, path=None, overwrite=False):
118 """Copy a default config file into the active cluster directory.
131 """Copy a default config file into the active cluster directory.
119
132
120 Default configuration files are kept in :mod:`IPython.config.default`.
133 Default configuration files are kept in :mod:`IPython.config.default`.
121 This function moves these from that location to the working cluster
134 This function moves these from that location to the working cluster
122 directory.
135 directory.
123 """
136 """
124 if path is None:
137 if path is None:
125 import IPython.config.default
138 import IPython.config.default
126 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
139 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
127 path = os.path.sep.join(path)
140 path = os.path.sep.join(path)
128 src = os.path.join(path, config_file)
141 src = os.path.join(path, config_file)
129 dst = os.path.join(self.location, config_file)
142 dst = os.path.join(self.location, config_file)
130 if not os.path.isfile(dst) or overwrite:
143 if not os.path.isfile(dst) or overwrite:
131 shutil.copy(src, dst)
144 shutil.copy(src, dst)
132
145
133 def copy_all_config_files(self, path=None, overwrite=False):
146 def copy_all_config_files(self, path=None, overwrite=False):
134 """Copy all config files into the active cluster directory."""
147 """Copy all config files into the active cluster directory."""
135 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
148 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
136 u'ipcluster_config.py']:
149 u'ipcluster_config.py']:
137 self.copy_config_file(f, path=path, overwrite=overwrite)
150 self.copy_config_file(f, path=path, overwrite=overwrite)
138
151
139 @classmethod
152 @classmethod
140 def create_cluster_dir(csl, cluster_dir):
153 def create_cluster_dir(csl, cluster_dir):
141 """Create a new cluster directory given a full path.
154 """Create a new cluster directory given a full path.
142
155
143 Parameters
156 Parameters
144 ----------
157 ----------
145 cluster_dir : str
158 cluster_dir : str
146 The full path to the cluster directory. If it does exist, it will
159 The full path to the cluster directory. If it does exist, it will
147 be used. If not, it will be created.
160 be used. If not, it will be created.
148 """
161 """
149 return ClusterDir(cluster_dir)
162 return ClusterDir(cluster_dir)
150
163
151 @classmethod
164 @classmethod
152 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
165 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
153 """Create a cluster dir by profile name and path.
166 """Create a cluster dir by profile name and path.
154
167
155 Parameters
168 Parameters
156 ----------
169 ----------
157 path : str
170 path : str
158 The path (directory) to put the cluster directory in.
171 The path (directory) to put the cluster directory in.
159 profile : str
172 profile : str
160 The name of the profile. The name of the cluster directory will
173 The name of the profile. The name of the cluster directory will
161 be "cluster_<profile>".
174 be "cluster_<profile>".
162 """
175 """
163 if not os.path.isdir(path):
176 if not os.path.isdir(path):
164 raise ClusterDirError('Directory not found: %s' % path)
177 raise ClusterDirError('Directory not found: %s' % path)
165 cluster_dir = os.path.join(path, u'cluster_' + profile)
178 cluster_dir = os.path.join(path, u'cluster_' + profile)
166 return ClusterDir(cluster_dir)
179 return ClusterDir(cluster_dir)
167
180
168 @classmethod
181 @classmethod
169 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
182 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
170 """Find an existing cluster dir by profile name, return its ClusterDir.
183 """Find an existing cluster dir by profile name, return its ClusterDir.
171
184
172 This searches through a sequence of paths for a cluster dir. If it
185 This searches through a sequence of paths for a cluster dir. If it
173 is not found, a :class:`ClusterDirError` exception will be raised.
186 is not found, a :class:`ClusterDirError` exception will be raised.
174
187
175 The search path algorithm is:
188 The search path algorithm is:
176 1. ``os.getcwd()``
189 1. ``os.getcwd()``
177 2. ``ipython_dir``
190 2. ``ipython_dir``
178 3. The directories found in the ":" separated
191 3. The directories found in the ":" separated
179 :env:`IPCLUSTER_DIR_PATH` environment variable.
192 :env:`IPCLUSTER_DIR_PATH` environment variable.
180
193
181 Parameters
194 Parameters
182 ----------
195 ----------
183 ipython_dir : unicode or str
196 ipython_dir : unicode or str
184 The IPython directory to use.
197 The IPython directory to use.
185 profile : unicode or str
198 profile : unicode or str
186 The name of the profile. The name of the cluster directory
199 The name of the profile. The name of the cluster directory
187 will be "cluster_<profile>".
200 will be "cluster_<profile>".
188 """
201 """
189 dirname = u'cluster_' + profile
202 dirname = u'cluster_' + profile
190 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
203 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
191 if cluster_dir_paths:
204 if cluster_dir_paths:
192 cluster_dir_paths = cluster_dir_paths.split(':')
205 cluster_dir_paths = cluster_dir_paths.split(':')
193 else:
206 else:
194 cluster_dir_paths = []
207 cluster_dir_paths = []
195 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
208 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
196 for p in paths:
209 for p in paths:
197 cluster_dir = os.path.join(p, dirname)
210 cluster_dir = os.path.join(p, dirname)
198 if os.path.isdir(cluster_dir):
211 if os.path.isdir(cluster_dir):
199 return ClusterDir(cluster_dir)
212 return ClusterDir(cluster_dir)
200 else:
213 else:
201 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
214 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
202
215
203 @classmethod
216 @classmethod
204 def find_cluster_dir(cls, cluster_dir):
217 def find_cluster_dir(cls, cluster_dir):
205 """Find/create a cluster dir and return its ClusterDir.
218 """Find/create a cluster dir and return its ClusterDir.
206
219
207 This will create the cluster directory if it doesn't exist.
220 This will create the cluster directory if it doesn't exist.
208
221
209 Parameters
222 Parameters
210 ----------
223 ----------
211 cluster_dir : unicode or str
224 cluster_dir : unicode or str
212 The path of the cluster directory. This is expanded using
225 The path of the cluster directory. This is expanded using
213 :func:`IPython.utils.genutils.expand_path`.
226 :func:`IPython.utils.genutils.expand_path`.
214 """
227 """
215 cluster_dir = genutils.expand_path(cluster_dir)
228 cluster_dir = genutils.expand_path(cluster_dir)
216 if not os.path.isdir(cluster_dir):
229 if not os.path.isdir(cluster_dir):
217 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
230 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
218 return ClusterDir(cluster_dir)
231 return ClusterDir(cluster_dir)
219
232
220
233
221 # Default command line options for IPython cluster applications.
234 # Default command line options for IPython cluster applications.
222 cl_args = (
235 cl_args = (
223 (('--ipython-dir',), dict(
236 (('--ipython-dir',), dict(
224 dest='Global.ipython_dir',type=unicode,
237 dest='Global.ipython_dir',type=unicode,
225 help='Set to override default location of Global.ipython_dir.',
238 help='Set to override default location of Global.ipython_dir.',
226 metavar='Global.ipython_dir') ),
239 metavar='Global.ipython_dir') ),
227 (('-p', '--profile',), dict(
240 (('-p', '--profile',), dict(
228 dest='Global.profile',type=unicode,
241 dest='Global.profile',type=unicode,
229 help=
242 help=
230 """The string name of the profile to be used. This determines the name
243 """The string name of the profile to be used. This determines the name
231 of the cluster dir as: cluster_<profile>. The default profile is named
244 of the cluster dir as: cluster_<profile>. The default profile is named
232 'default'. The cluster directory is resolve this way if the
245 'default'. The cluster directory is resolve this way if the
233 --cluster-dir option is not used.""",
246 --cluster-dir option is not used.""",
234 metavar='Global.profile') ),
247 metavar='Global.profile') ),
235 (('--cluster-dir',), dict(
248 (('--cluster-dir',), dict(
236 dest='Global.cluster_dir',type=unicode,
249 dest='Global.cluster_dir',type=unicode,
237 help="""Set the cluster dir. This overrides the logic used by the
250 help="""Set the cluster dir. This overrides the logic used by the
238 --profile option.""",
251 --profile option.""",
239 metavar='Global.cluster_dir') ),
252 metavar='Global.cluster_dir') ),
240 (('--work-dir',), dict(
253 (('--work-dir',), dict(
241 dest='Global.work_dir',type=unicode,
254 dest='Global.work_dir',type=unicode,
242 help='Set the working dir for the process.',
255 help='Set the working dir for the process.',
243 metavar='Global.work_dir') ),
256 metavar='Global.work_dir') ),
244 (('--clean-logs',), dict(
257 (('--clean-logs',), dict(
245 dest='Global.clean_logs', action='store_true',
258 dest='Global.clean_logs', action='store_true',
246 help='Delete old log flies before starting.') ),
259 help='Delete old log flies before starting.') ),
247 (('--no-clean-logs',), dict(
260 (('--no-clean-logs',), dict(
248 dest='Global.clean_logs', action='store_false',
261 dest='Global.clean_logs', action='store_false',
249 help="Don't Delete old log flies before starting.") ),
262 help="Don't Delete old log flies before starting.") ),
250 )
263 )
251
264
252
265
253 class ApplicationWithClusterDir(Application):
266 class ApplicationWithClusterDir(Application):
254 """An application that puts everything into a cluster directory.
267 """An application that puts everything into a cluster directory.
255
268
256 Instead of looking for things in the ipython_dir, this type of application
269 Instead of looking for things in the ipython_dir, this type of application
257 will use its own private directory called the "cluster directory"
270 will use its own private directory called the "cluster directory"
258 for things like config files, log files, etc.
271 for things like config files, log files, etc.
259
272
260 The cluster directory is resolved as follows:
273 The cluster directory is resolved as follows:
261
274
262 * If the ``--cluster-dir`` option is given, it is used.
275 * If the ``--cluster-dir`` option is given, it is used.
263 * If ``--cluster-dir`` is not given, the application directory is
276 * If ``--cluster-dir`` is not given, the application directory is
264 resolve using the profile name as ``cluster_<profile>``. The search
277 resolve using the profile name as ``cluster_<profile>``. The search
265 path for this directory is then i) cwd if it is found there
278 path for this directory is then i) cwd if it is found there
266 and ii) in ipython_dir otherwise.
279 and ii) in ipython_dir otherwise.
267
280
268 The config file for the application is to be put in the cluster
281 The config file for the application is to be put in the cluster
269 dir and named the value of the ``config_file_name`` class attribute.
282 dir and named the value of the ``config_file_name`` class attribute.
270 """
283 """
271
284
272 auto_create_cluster_dir = True
285 auto_create_cluster_dir = True
273
286
274 cl_arguments = Application.cl_arguments + cl_args
287 cl_arguments = Application.cl_arguments + cl_args
275
288
276 def create_default_config(self):
289 def create_default_config(self):
277 super(ApplicationWithClusterDir, self).create_default_config()
290 super(ApplicationWithClusterDir, self).create_default_config()
278 self.default_config.Global.profile = u'default'
291 self.default_config.Global.profile = u'default'
279 self.default_config.Global.cluster_dir = u''
292 self.default_config.Global.cluster_dir = u''
280 self.default_config.Global.work_dir = os.getcwd()
293 self.default_config.Global.work_dir = os.getcwd()
281 self.default_config.Global.log_to_file = False
294 self.default_config.Global.log_to_file = False
282 self.default_config.Global.clean_logs = False
295 self.default_config.Global.clean_logs = False
283
296
284 def find_resources(self):
297 def find_resources(self):
285 """This resolves the cluster directory.
298 """This resolves the cluster directory.
286
299
287 This tries to find the cluster directory and if successful, it will
300 This tries to find the cluster directory and if successful, it will
288 have done:
301 have done:
289 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
302 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
290 the application.
303 the application.
291 * Sets ``self.cluster_dir`` attribute of the application and config
304 * Sets ``self.cluster_dir`` attribute of the application and config
292 objects.
305 objects.
293
306
294 The algorithm used for this is as follows:
307 The algorithm used for this is as follows:
295 1. Try ``Global.cluster_dir``.
308 1. Try ``Global.cluster_dir``.
296 2. Try using ``Global.profile``.
309 2. Try using ``Global.profile``.
297 3. If both of these fail and ``self.auto_create_cluster_dir`` is
310 3. If both of these fail and ``self.auto_create_cluster_dir`` is
298 ``True``, then create the new cluster dir in the IPython directory.
311 ``True``, then create the new cluster dir in the IPython directory.
299 4. If all fails, then raise :class:`ClusterDirError`.
312 4. If all fails, then raise :class:`ClusterDirError`.
300 """
313 """
301
314
302 try:
315 try:
303 cluster_dir = self.command_line_config.Global.cluster_dir
316 cluster_dir = self.command_line_config.Global.cluster_dir
304 except AttributeError:
317 except AttributeError:
305 cluster_dir = self.default_config.Global.cluster_dir
318 cluster_dir = self.default_config.Global.cluster_dir
306 cluster_dir = genutils.expand_path(cluster_dir)
319 cluster_dir = genutils.expand_path(cluster_dir)
307 try:
320 try:
308 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
321 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
309 except ClusterDirError:
322 except ClusterDirError:
310 pass
323 pass
311 else:
324 else:
312 self.log.info('Using existing cluster dir: %s' % \
325 self.log.info('Using existing cluster dir: %s' % \
313 self.cluster_dir_obj.location
326 self.cluster_dir_obj.location
314 )
327 )
315 self.finish_cluster_dir()
328 self.finish_cluster_dir()
316 return
329 return
317
330
318 try:
331 try:
319 self.profile = self.command_line_config.Global.profile
332 self.profile = self.command_line_config.Global.profile
320 except AttributeError:
333 except AttributeError:
321 self.profile = self.default_config.Global.profile
334 self.profile = self.default_config.Global.profile
322 try:
335 try:
323 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
336 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
324 self.ipython_dir, self.profile)
337 self.ipython_dir, self.profile)
325 except ClusterDirError:
338 except ClusterDirError:
326 pass
339 pass
327 else:
340 else:
328 self.log.info('Using existing cluster dir: %s' % \
341 self.log.info('Using existing cluster dir: %s' % \
329 self.cluster_dir_obj.location
342 self.cluster_dir_obj.location
330 )
343 )
331 self.finish_cluster_dir()
344 self.finish_cluster_dir()
332 return
345 return
333
346
334 if self.auto_create_cluster_dir:
347 if self.auto_create_cluster_dir:
335 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
348 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
336 self.ipython_dir, self.profile
349 self.ipython_dir, self.profile
337 )
350 )
338 self.log.info('Creating new cluster dir: %s' % \
351 self.log.info('Creating new cluster dir: %s' % \
339 self.cluster_dir_obj.location
352 self.cluster_dir_obj.location
340 )
353 )
341 self.finish_cluster_dir()
354 self.finish_cluster_dir()
342 else:
355 else:
343 raise ClusterDirError('Could not find a valid cluster directory.')
356 raise ClusterDirError('Could not find a valid cluster directory.')
344
357
345 def finish_cluster_dir(self):
358 def finish_cluster_dir(self):
346 # Set the cluster directory
359 # Set the cluster directory
347 self.cluster_dir = self.cluster_dir_obj.location
360 self.cluster_dir = self.cluster_dir_obj.location
348
361
349 # These have to be set because they could be different from the one
362 # These have to be set because they could be different from the one
350 # that we just computed. Because command line has the highest
363 # that we just computed. Because command line has the highest
351 # priority, this will always end up in the master_config.
364 # priority, this will always end up in the master_config.
352 self.default_config.Global.cluster_dir = self.cluster_dir
365 self.default_config.Global.cluster_dir = self.cluster_dir
353 self.command_line_config.Global.cluster_dir = self.cluster_dir
366 self.command_line_config.Global.cluster_dir = self.cluster_dir
354
367
355 # Set the search path to the cluster directory
356 self.config_file_paths = (self.cluster_dir,)
357
358 def find_config_file_name(self):
368 def find_config_file_name(self):
359 """Find the config file name for this application."""
369 """Find the config file name for this application."""
360 # For this type of Application it should be set as a class attribute.
370 # For this type of Application it should be set as a class attribute.
361 if not hasattr(self, 'config_file_name'):
371 if not hasattr(self, 'config_file_name'):
362 self.log.critical("No config filename found")
372 self.log.critical("No config filename found")
363
373
364 def find_config_file_paths(self):
374 def find_config_file_paths(self):
365 # Set the search path to the cluster directory
375 # Include our own config directory last, so that users can still find
366 self.config_file_paths = (self.cluster_dir,)
376 # our shipped copies of builtin config files even if they don't have
377 # them in their ipython cluster directory.
378 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
379 self.config_file_paths = (self.cluster_dir, conf_dir)
367
380
368 def pre_construct(self):
381 def pre_construct(self):
369 # The log and security dirs were set earlier, but here we put them
382 # The log and security dirs were set earlier, but here we put them
370 # into the config and log them.
383 # into the config and log them.
371 config = self.master_config
384 config = self.master_config
372 sdir = self.cluster_dir_obj.security_dir
385 sdir = self.cluster_dir_obj.security_dir
373 self.security_dir = config.Global.security_dir = sdir
386 self.security_dir = config.Global.security_dir = sdir
374 ldir = self.cluster_dir_obj.log_dir
387 ldir = self.cluster_dir_obj.log_dir
375 self.log_dir = config.Global.log_dir = ldir
388 self.log_dir = config.Global.log_dir = ldir
376 pdir = self.cluster_dir_obj.pid_dir
389 pdir = self.cluster_dir_obj.pid_dir
377 self.pid_dir = config.Global.pid_dir = pdir
390 self.pid_dir = config.Global.pid_dir = pdir
378 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
391 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
379 config.Global.work_dir = unicode(genutils.expand_path(config.Global.work_dir))
392 config.Global.work_dir = unicode(genutils.expand_path(config.Global.work_dir))
380 # Change to the working directory. We do this just before construct
393 # Change to the working directory. We do this just before construct
381 # is called so all the components there have the right working dir.
394 # is called so all the components there have the right working dir.
382 self.to_work_dir()
395 self.to_work_dir()
383
396
384 def to_work_dir(self):
397 def to_work_dir(self):
385 wd = self.master_config.Global.work_dir
398 wd = self.master_config.Global.work_dir
386 if unicode(wd) != unicode(os.getcwd()):
399 if unicode(wd) != unicode(os.getcwd()):
387 os.chdir(wd)
400 os.chdir(wd)
388 self.log.info("Changing to working dir: %s" % wd)
401 self.log.info("Changing to working dir: %s" % wd)
389
402
390 def start_logging(self):
403 def start_logging(self):
391 # Remove old log files
404 # Remove old log files
392 if self.master_config.Global.clean_logs:
405 if self.master_config.Global.clean_logs:
393 log_dir = self.master_config.Global.log_dir
406 log_dir = self.master_config.Global.log_dir
394 for f in os.listdir(log_dir):
407 for f in os.listdir(log_dir):
395 if f.startswith(self.name + u'-') and f.endswith('.log'):
408 if f.startswith(self.name + u'-') and f.endswith('.log'):
396 os.remove(os.path.join(log_dir, f))
409 os.remove(os.path.join(log_dir, f))
397 # Start logging to the new log file
410 # Start logging to the new log file
398 if self.master_config.Global.log_to_file:
411 if self.master_config.Global.log_to_file:
399 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
412 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
400 logfile = os.path.join(self.log_dir, log_filename)
413 logfile = os.path.join(self.log_dir, log_filename)
401 open_log_file = open(logfile, 'w')
414 open_log_file = open(logfile, 'w')
402 else:
415 else:
403 open_log_file = sys.stdout
416 open_log_file = sys.stdout
404 log.startLogging(open_log_file)
417 log.startLogging(open_log_file)
405
418
406 def write_pid_file(self, overwrite=False):
419 def write_pid_file(self, overwrite=False):
407 """Create a .pid file in the pid_dir with my pid.
420 """Create a .pid file in the pid_dir with my pid.
408
421
409 This must be called after pre_construct, which sets `self.pid_dir`.
422 This must be called after pre_construct, which sets `self.pid_dir`.
410 This raises :exc:`PIDFileError` if the pid file exists already.
423 This raises :exc:`PIDFileError` if the pid file exists already.
411 """
424 """
412 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
425 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
413 if os.path.isfile(pid_file):
426 if os.path.isfile(pid_file):
414 pid = self.get_pid_from_file()
427 pid = self.get_pid_from_file()
415 if not overwrite:
428 if not overwrite:
416 raise PIDFileError(
429 raise PIDFileError(
417 'The pid file [%s] already exists. \nThis could mean that this '
430 'The pid file [%s] already exists. \nThis could mean that this '
418 'server is already running with [pid=%s].' % (pid_file, pid)
431 'server is already running with [pid=%s].' % (pid_file, pid)
419 )
432 )
420 with open(pid_file, 'w') as f:
433 with open(pid_file, 'w') as f:
421 self.log.info("Creating pid file: %s" % pid_file)
434 self.log.info("Creating pid file: %s" % pid_file)
422 f.write(repr(os.getpid())+'\n')
435 f.write(repr(os.getpid())+'\n')
423
436
424 def remove_pid_file(self):
437 def remove_pid_file(self):
425 """Remove the pid file.
438 """Remove the pid file.
426
439
427 This should be called at shutdown by registering a callback with
440 This should be called at shutdown by registering a callback with
428 :func:`reactor.addSystemEventTrigger`. This needs to return
441 :func:`reactor.addSystemEventTrigger`. This needs to return
429 ``None``.
442 ``None``.
430 """
443 """
431 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
444 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
432 if os.path.isfile(pid_file):
445 if os.path.isfile(pid_file):
433 try:
446 try:
434 self.log.info("Removing pid file: %s" % pid_file)
447 self.log.info("Removing pid file: %s" % pid_file)
435 os.remove(pid_file)
448 os.remove(pid_file)
436 except:
449 except:
437 self.log.warn("Error removing the pid file: %s" % pid_file)
450 self.log.warn("Error removing the pid file: %s" % pid_file)
438
451
439 def get_pid_from_file(self):
452 def get_pid_from_file(self):
440 """Get the pid from the pid file.
453 """Get the pid from the pid file.
441
454
442 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
455 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
443 """
456 """
444 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
457 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
445 if os.path.isfile(pid_file):
458 if os.path.isfile(pid_file):
446 with open(pid_file, 'r') as f:
459 with open(pid_file, 'r') as f:
447 pid = int(f.read().strip())
460 pid = int(f.read().strip())
448 return pid
461 return pid
449 else:
462 else:
450 raise PIDFileError('pid file not found: %s' % pid_file)
463 raise PIDFileError('pid file not found: %s' % pid_file)
General Comments 0
You need to be logged in to leave comments. Login now