From 649f99755f6086499e2419842ad3de9e9a615e2f 2009-10-23 23:36:09
From: Brian Granger <ellisonbg@gmail.com>
Date: 2009-10-23 23:36:09
Subject: [PATCH] ipcontroller/ipengine use the new clusterdir.py module.

---

diff --git a/IPython/core/application.py b/IPython/core/application.py
index 3c47fd7..97690cd 100644
--- a/IPython/core/application.py
+++ b/IPython/core/application.py
@@ -1,7 +1,13 @@
 #!/usr/bin/env python
 # encoding: utf-8
 """
-An application for IPython
+An application for IPython.
+
+All top-level applications should use the classes in this module for
+handling configuration and creating componenets.
+
+The job of an :class:`Application` is to create the master configuration 
+object and then create the components, passing the config to them.
 
 Authors:
 
@@ -25,13 +31,10 @@ Notes
 
 import logging
 import os
-
 import sys
-import traceback
-from copy import deepcopy
 
 from IPython.core import release
-from IPython.utils.genutils import get_ipython_dir, filefind
+from IPython.utils.genutils import get_ipython_dir
 from IPython.config.loader import (
     PyFileConfigLoader,
     ArgParseConfigLoader,
@@ -75,17 +78,17 @@ class ApplicationError(Exception):
 
 
 class Application(object):
-    """Load a config, construct an app and run it.
-    """
+    """Load a config, construct components and set them running."""
 
     name = 'ipython'
     description = 'IPython: an enhanced interactive Python shell.'
     config_file_name = 'ipython_config.py'
     default_log_level = logging.WARN
-    
 
     def __init__(self):
         self.init_logger()
+        # Track the default and actual separately because some messages are
+        # only printed if we aren't using the default.
         self.default_config_file_name = self.config_file_name
 
     def init_logger(self):
@@ -194,7 +197,7 @@ class Application(object):
 
         This sets ``self.ipythondir``, but the actual value that is passed
         to the application is kept in either ``self.default_config`` or
-        ``self.command_line_config``.  This also added ``self.ipythondir`` to
+        ``self.command_line_config``.  This also adds ``self.ipythondir`` to
         ``sys.path`` so config files there can be references by other config
         files.
         """
@@ -340,115 +343,3 @@ class Application(object):
             elif action == 'exit':
                 self.exit()
 
-
-class AppWithDirArgParseConfigLoader(ArgParseConfigLoader):
-    """Default command line options for IPython based applications."""
-
-    def _add_other_arguments(self):
-        self.parser.add_argument('-ipythondir', '--ipython-dir', 
-            dest='Global.ipythondir',type=str,
-            help='Set to override default location of Global.ipythondir.',
-            default=NoConfigDefault,
-            metavar='Global.ipythondir')
-        self.parser.add_argument('-p','-profile', '--profile',
-            dest='Global.profile',type=str,
-            help='The string name of the profile to be used. This determines '
-            'the name of the application dir: basename_<profile>.  The basename is '
-            'determined by the particular application.  The default profile '
-            'is named "default".  This convention is used if the -app_dir '
-            'option is not used.',
-            default=NoConfigDefault,
-            metavar='Global.profile')
-        self.parser.add_argument('-log_level', '--log-level',
-            dest="Global.log_level",type=int,
-            help='Set the log level (0,10,20,30,40,50).  Default is 30.',
-            default=NoConfigDefault)
-        self.parser.add_argument('-app_dir', '--app-dir',
-            dest='Global.app_dir',type=str,
-            help='Set the application dir where everything for this '
-            'application will be found (including the config file). This '
-            'overrides the logic used by the profile option.',
-            default=NoConfigDefault,
-            metavar='Global.app_dir')
-
-
-class ApplicationWithDir(Application):
-    """An application that puts everything into a application directory.
-
-    Instead of looking for things in the ipythondir, this type of application
-    will use its own private directory called the "application directory"
-    for things like config files, log files, etc.
-
-    The application directory is resolved as follows:
-
-    * If the ``--app-dir`` option is given, it is used.
-    * If ``--app-dir`` is not given, the application directory is resolve using
-      ``app_dir_basename`` and ``profile`` as ``<app_dir_basename>_<profile>``.
-      The search path for this directory is then i) cwd if it is found there
-      and ii) in ipythondir otherwise.
-
-    The config file for the application is to be put in the application
-    dir and named the value of the ``config_file_name`` class attribute.
-    """
-
-    # The basename used for the application dir: <app_dir_basename>_<profile>
-    app_dir_basename = 'cluster'
-
-    def create_default_config(self):
-        super(ApplicationWithDir, self).create_default_config()
-        self.default_config.Global.profile = 'default'
-        # The application dir.  This is empty initially so the default is to
-        # try to resolve this using the profile.
-        self.default_config.Global.app_dir = ''
-
-    def create_command_line_config(self):
-        """Create and return a command line config loader."""
-        return AppWithDirArgParseConfigLoader(
-            description=self.description, 
-            version=release.version
-        )
-
-    def find_config_file_name(self):
-        """Find the config file name for this application."""
-        self.find_app_dir()
-        self.create_app_dir()
-
-    def find_app_dir(self):
-        """This resolves the app directory.
-
-        This method must set ``self.app_dir`` to the location of the app
-        dir.
-        """
-        # Instead, first look for an explicit app_dir
-        try:
-            self.app_dir = self.command_line_config.Global.app_dir
-        except AttributeError:
-            self.app_dir = self.default_config.Global.app_dir
-        self.app_dir = os.path.expandvars(os.path.expanduser(self.app_dir))
-        if not self.app_dir:
-            # Then look for a profile
-            try:
-                self.profile = self.command_line_config.Global.profile
-            except AttributeError:
-                self.profile = self.default_config.Global.profile
-            app_dir_name = self.app_dir_basename + '_' + self.profile
-            try_this = os.path.join(os.getcwd(), app_dir_name)
-            if os.path.isdir(try_this):
-                self.app_dir = try_this
-            else:
-                self.app_dir = os.path.join(self.ipythondir, app_dir_name)
-        # These have to be set because they could be different from the one
-        # that we just computed.  Because command line has the highest
-        # priority, this will always end up in the master_config.
-        self.default_config.Global.app_dir = self.app_dir
-        self.command_line_config.Global.app_dir = self.app_dir
-        self.log.info("Application directory set to: %s" % self.app_dir)
-
-    def create_app_dir(self):
-        """Make sure that the app dir exists."""
-        if not os.path.isdir(self.app_dir):
-            os.makedirs(self.app_dir, mode=0777)
-
-    def find_config_file_paths(self):
-        """Set the search paths for resolving the config file."""
-        self.config_file_paths = (self.app_dir,)
diff --git a/IPython/core/ipapp.py b/IPython/core/ipapp.py
index 1dad392..bba0348 100644
--- a/IPython/core/ipapp.py
+++ b/IPython/core/ipapp.py
@@ -1,7 +1,8 @@
 #!/usr/bin/env python
 # encoding: utf-8
 """
-The main IPython application object
+The :class:`~IPython.core.application.Application` object for the command
+line :command:`ipython` program.
 
 Authors:
 
@@ -34,13 +35,11 @@ from IPython.core.iplib import InteractiveShell
 from IPython.config.loader import (
     NoConfigDefault, 
     Config,
-    ConfigError,
     PyFileConfigLoader
 )
 
 from IPython.lib import inputhook
 
-from IPython.utils.ipstruct import Struct
 from IPython.utils.genutils import filefind, get_ipython_dir
 
 #-----------------------------------------------------------------------------
diff --git a/IPython/core/iplib.py b/IPython/core/iplib.py
index a89d6b4..ed2c887 100644
--- a/IPython/core/iplib.py
+++ b/IPython/core/iplib.py
@@ -182,7 +182,7 @@ class SeparateStr(Str):
 class InteractiveShell(Component, Magic):
     """An enhanced, interactive shell for Python."""
 
-    autocall = Enum((0,1,2), config=True)
+    autocall = Enum((0,1,2), default_value=1, config=True)
     autoedit_syntax = CBool(False, config=True)
     autoindent = CBool(True, config=True)
     automagic = CBool(True, config=True)
diff --git a/IPython/kernel/clusterdir.py b/IPython/kernel/clusterdir.py
new file mode 100644
index 0000000..2ab60c5
--- /dev/null
+++ b/IPython/kernel/clusterdir.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+The IPython cluster directory
+"""
+
+#-----------------------------------------------------------------------------
+#  Copyright (C) 2008-2009  The IPython Development Team
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import shutil
+
+from IPython.core import release
+from IPython.config.loader import PyFileConfigLoader
+from IPython.core.application import Application
+from IPython.core.component import Component
+from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
+from IPython.utils.traitlets import Unicode
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+
+class ClusterDir(Component):
+    """An object to manage the cluster directory and its resources.
+
+    The cluster directory is used by :command:`ipcontroller`, 
+    :command:`ipcontroller` and :command:`ipcontroller` to manage the
+    configuration, logging and security of these applications.
+
+    This object knows how to find, create and manage these directories. This
+    should be used by any code that want's to handle cluster directories.
+    """
+
+    security_dir_name = Unicode('security')
+    log_dir_name = Unicode('log')
+    security_dir = Unicode()
+    log_dir = Unicode('')
+    location = Unicode('')
+
+    def __init__(self, location):
+        super(ClusterDir, self).__init__(None)
+        self.location = location
+
+    def _location_changed(self, name, old, new):
+        if not os.path.isdir(new):
+            os.makedirs(new, mode=0777)
+        else:
+            os.chmod(new, 0777)
+        self.security_dir = os.path.join(new, self.security_dir_name)
+        self.log_dir = os.path.join(new, self.log_dir_name)
+
+    def _log_dir_changed(self, name, old, new):
+        if not os.path.isdir(new):
+            os.mkdir(new, 0777)
+        else:
+            os.chmod(new, 0777)
+
+    def _security_dir_changed(self, name, old, new):
+        if not os.path.isdir(new):
+            os.mkdir(new, 0700)
+        else:
+            os.chmod(new, 0700)
+
+    def load_config_file(self, filename):
+        """Load a config file from the top level of the cluster dir.
+
+        Parameters
+        ----------
+        filename : unicode or str
+            The filename only of the config file that must be located in
+            the top-level of the cluster directory.
+        """
+        loader = PyFileConfigLoader(filename, self.location)
+        return loader.load_config()
+
+    def copy_config_file(self, config_file, path=None):
+        """Copy a default config file into the active cluster directory.
+
+        Default configuration files are kept in :mod:`IPython.config.default`.
+        This function moves these from that location to the working cluster
+        directory.
+        """
+        if path is None:
+            import IPython.config.default
+            path = IPython.config.default.__file__.split(os.path.sep)[:-1]
+            path = os.path.sep.join(path)
+        src = os.path.join(path, config_file)
+        dst = os.path.join(self.location, config_file)
+        shutil.copy(src, dst)
+
+    def copy_all_config_files(self):
+        """Copy all config files into the active cluster directory."""
+        for f in ['ipcontroller_config.py', 'ipengine_config.py']:
+            self.copy_config_file(f)
+
+    @classmethod
+    def find_cluster_dir_by_profile(cls, path, profile='default'):
+        """Find/create a cluster dir by profile name and return its ClusterDir.
+
+        This will create the cluster directory if it doesn't exist.
+
+        Parameters
+        ----------
+        path : unicode or str
+            The directory path to look for the cluster directory in.
+        profile : unicode or str
+            The name of the profile.  The name of the cluster directory
+            will be "cluster_<profile>".
+        """
+        dirname = 'cluster_' + profile
+        cluster_dir = os.path.join(os.getcwd(), dirname)
+        if os.path.isdir(cluster_dir):
+            return ClusterDir(cluster_dir)
+        else:
+            if not os.path.isdir(path):
+                raise IOError("Directory doesn't exist: %s" % path)
+            cluster_dir = os.path.join(path, dirname)
+            return ClusterDir(cluster_dir)
+
+    @classmethod
+    def find_cluster_dir(cls, cluster_dir):
+        """Find/create a cluster dir and return its ClusterDir.
+
+        This will create the cluster directory if it doesn't exist.
+
+        Parameters
+        ----------
+        cluster_dir : unicode or str
+            The path of the cluster directory.  This is expanded using
+            :func:`os.path.expandvars` and :func:`os.path.expanduser`.
+        """
+        cluster_dir = os.path.expandvars(os.path.expanduser(cluster_dir))
+        return ClusterDir(cluster_dir)
+
+
+class AppWithClusterDirArgParseConfigLoader(ArgParseConfigLoader):
+    """Default command line options for IPython cluster applications."""
+
+    def _add_other_arguments(self):
+        self.parser.add_argument('-ipythondir', '--ipython-dir', 
+            dest='Global.ipythondir',type=str,
+            help='Set to override default location of Global.ipythondir.',
+            default=NoConfigDefault,
+            metavar='Global.ipythondir')
+        self.parser.add_argument('-p','-profile', '--profile',
+            dest='Global.profile',type=str,
+            help='The string name of the profile to be used. This determines '
+            'the name of the cluster dir as: cluster_<profile>. The default profile '
+            'is named "default".  The cluster directory is resolve this way '
+            'if the --cluster-dir option is not used.',
+            default=NoConfigDefault,
+            metavar='Global.profile')
+        self.parser.add_argument('-log_level', '--log-level',
+            dest="Global.log_level",type=int,
+            help='Set the log level (0,10,20,30,40,50).  Default is 30.',
+            default=NoConfigDefault)
+        self.parser.add_argument('-cluster_dir', '--cluster-dir',
+            dest='Global.cluster_dir',type=str,
+            help='Set the cluster dir. This overrides the logic used by the '
+            '--profile option.',
+            default=NoConfigDefault,
+            metavar='Global.cluster_dir')
+
+
+class ApplicationWithClusterDir(Application):
+    """An application that puts everything into a cluster directory.
+
+    Instead of looking for things in the ipythondir, this type of application
+    will use its own private directory called the "cluster directory"
+    for things like config files, log files, etc.
+
+    The cluster directory is resolved as follows:
+
+    * If the ``--cluster-dir`` option is given, it is used.
+    * If ``--cluster-dir`` is not given, the application directory is 
+      resolve using the profile name as ``cluster_<profile>``. The search 
+      path for this directory is then i) cwd if it is found there
+      and ii) in ipythondir otherwise.
+
+    The config file for the application is to be put in the cluster
+    dir and named the value of the ``config_file_name`` class attribute.
+    """
+
+    def create_default_config(self):
+        super(ApplicationWithClusterDir, self).create_default_config()
+        self.default_config.Global.profile = 'default'
+        self.default_config.Global.cluster_dir = ''
+
+    def create_command_line_config(self):
+        """Create and return a command line config loader."""
+        return AppWithClusterDirArgParseConfigLoader(
+            description=self.description, 
+            version=release.version
+        )
+
+    def find_config_file_name(self):
+        """Find the config file name for this application."""
+        # For this type of Application it should be set as a class attribute.
+        if not hasattr(self, 'config_file_name'):
+            self.log.critical("No config filename found")
+
+    def find_config_file_paths(self):
+        """This resolves the cluster directory and sets ``config_file_paths``.
+
+        This does the following:
+        * Create the :class:`ClusterDir` object for the application.
+        * Set the ``cluster_dir`` attribute of the application and config
+          objects.
+        * Set ``config_file_paths`` to point to the cluster directory.
+        """
+
+        # Create the ClusterDir object for managing everything
+        try:
+            cluster_dir = self.command_line_config.Global.cluster_dir
+        except AttributeError:
+            cluster_dir = self.default_config.Global.cluster_dir
+        cluster_dir = os.path.expandvars(os.path.expanduser(cluster_dir))
+        if cluster_dir:
+            # Just use cluster_dir
+            self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
+        else:
+            # Then look for a profile
+            try:
+                self.profile = self.command_line_config.Global.profile
+            except AttributeError:
+                self.profile = self.default_config.Global.profile
+            self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
+                self.ipythondir, self.profile)
+
+        # Set the cluster directory
+        self.cluster_dir = self.cluster_dir_obj.location
+        
+        # These have to be set because they could be different from the one
+        # that we just computed.  Because command line has the highest
+        # priority, this will always end up in the master_config.
+        self.default_config.Global.cluster_dir = self.cluster_dir
+        self.command_line_config.Global.cluster_dir = self.cluster_dir
+        self.log.info("Cluster directory set to: %s" % self.cluster_dir)
+
+        # Set the search path to the cluster directory
+        self.config_file_paths = (self.cluster_dir,)
diff --git a/IPython/kernel/configobjfactory.py b/IPython/kernel/configobjfactory.py
index 64a9f47..745cdfb 100644
--- a/IPython/kernel/configobjfactory.py
+++ b/IPython/kernel/configobjfactory.py
@@ -53,7 +53,7 @@ class ConfiguredObjectFactory(Component):
 class IAdaptedConfiguredObjectFactory(zi.Interface):
     """I am a component that adapts and configures an object.
 
-    This class is useful if you have the adapt a instance and configure it.
+    This class is useful if you have the adapt an instance and configure it.
     """
 
     def __init__(config, adaptee=None):
diff --git a/IPython/kernel/ipcontrollerapp.py b/IPython/kernel/ipcontrollerapp.py
index 72936b3..f504d8b 100644
--- a/IPython/kernel/ipcontrollerapp.py
+++ b/IPython/kernel/ipcontrollerapp.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # encoding: utf-8
 """
-The IPython controller application
+The IPython controller application.
 """
 
 #-----------------------------------------------------------------------------
@@ -16,31 +16,25 @@ The IPython controller application
 #-----------------------------------------------------------------------------
 
 import copy
-import logging
 import os
 import sys
 
 from twisted.application import service
-from twisted.internet import reactor, defer
+from twisted.internet import reactor
 from twisted.python import log
 
 from IPython.config.loader import Config, NoConfigDefault
 
-from IPython.core.application import (
-    ApplicationWithDir, 
-    AppWithDirArgParseConfigLoader
+from IPython.kernel.clusterdir import (
+    ApplicationWithClusterDir, 
+    AppWithClusterDirArgParseConfigLoader
 )
 
 from IPython.core import release
 
-from IPython.utils.traitlets import Int, Str, Bool, Instance
-from IPython.utils.importstring import import_item
+from IPython.utils.traitlets import Str, Instance
 
 from IPython.kernel import controllerservice
-from IPython.kernel.configobjfactory import (
-    ConfiguredObjectFactory,
-    AdaptedConfiguredObjectFactory
-)
 
 from IPython.kernel.fcutil import FCServiceFactory
 
@@ -112,33 +106,45 @@ cl_args = (
     # Client config
     (('--client-ip',), dict(
         type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
-        help='The IP address or hostname the controller will listen on for client connections.',
+        help='The IP address or hostname the controller will listen on for '
+        'client connections.',
         metavar='FCClientServiceFactory.ip')
     ),
     (('--client-port',), dict(
         type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
-        help='The port the controller will listen on for client connections.',
+        help='The port the controller will listen on for client connections. '
+        'The default is to use 0, which will autoselect an open port.',
         metavar='FCClientServiceFactory.port')
     ),
     (('--client-location',), dict(
         type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
-        help='The hostname or ip that clients should connect to.',
+        help='The hostname or IP that clients should connect to. This does '
+        'not control which interface the controller listens on. Instead, this '
+        'determines the hostname/IP that is listed in the FURL, which is how '
+        'clients know where to connect. Useful if the controller is listening '
+        'on multiple interfaces.',
         metavar='FCClientServiceFactory.location')
     ),
     # Engine config
     (('--engine-ip',), dict(
         type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
-        help='The IP address or hostname the controller will listen on for engine connections.',
+        help='The IP address or hostname the controller will listen on for '
+        'engine connections.',
         metavar='FCEngineServiceFactory.ip')
     ),
     (('--engine-port',), dict(
         type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
-        help='The port the controller will listen on for engine connections.',
+        help='The port the controller will listen on for engine connections. '
+        'The default is to use 0, which will autoselect an open port.',
         metavar='FCEngineServiceFactory.port')
     ),
     (('--engine-location',), dict(
         type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
-        help='The hostname or ip that engines should connect to.',
+        help='The hostname or IP that engines should connect to. This does '
+        'not control which interface the controller listens on. Instead, this '
+        'determines the hostname/IP that is listed in the FURL, which is how '
+        'engines know where to connect. Useful if the controller is listening '
+        'on multiple interfaces.',
         metavar='FCEngineServiceFactory.location')
     ),
     # Global config
@@ -148,7 +154,9 @@ cl_args = (
     ),
     (('-r','--reuse-furls'), dict(
         action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
-        help='Try to reuse all FURL files.')
+        help='Try to reuse all FURL files. If this is not set all FURL files '
+        'are deleted before the controller starts. This must be set if '
+        'specific ports are specified by --engine-port or --client-port.')
     ),
     (('-ns','--no-security'), dict(
         action='store_false', dest='Global.secure', default=NoConfigDefault,
@@ -157,7 +165,7 @@ cl_args = (
 )
 
 
-class IPControllerAppCLConfigLoader(AppWithDirArgParseConfigLoader):
+class IPControllerAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
 
     arguments = cl_args
 
@@ -165,10 +173,9 @@ class IPControllerAppCLConfigLoader(AppWithDirArgParseConfigLoader):
 default_config_file_name = 'ipcontroller_config.py'
 
 
-class IPControllerApp(ApplicationWithDir):
+class IPControllerApp(ApplicationWithClusterDir):
 
     name = 'ipcontroller'
-    app_dir_basename = 'cluster'
     description = 'Start the IPython controller for parallel computing.'
     config_file_name = default_config_file_name
 
@@ -177,8 +184,6 @@ class IPControllerApp(ApplicationWithDir):
         self.default_config.Global.reuse_furls = False
         self.default_config.Global.secure = True
         self.default_config.Global.import_statements = []
-        self.default_config.Global.log_dir_name = 'log'
-        self.default_config.Global.security_dir_name = 'security'
         self.default_config.Global.log_to_file = False
 
     def create_command_line_config(self):
@@ -190,36 +195,24 @@ class IPControllerApp(ApplicationWithDir):
 
     def post_load_command_line_config(self):
         # Now setup reuse_furls
-        if hasattr(self.command_line_config.Global, 'reuse_furls'):
-            self.command_line_config.FCClientServiceFactory.reuse_furls = \
-                self.command_line_config.Global.reuse_furls
-            self.command_line_config.FCEngineServiceFactory.reuse_furls = \
-                self.command_line_config.Global.reuse_furls
-            del self.command_line_config.Global.reuse_furls
-        if hasattr(self.command_line_config.Global, 'secure'):
-            self.command_line_config.FCClientServiceFactory.secure = \
-                self.command_line_config.Global.secure
-            self.command_line_config.FCEngineServiceFactory.secure = \
-                self.command_line_config.Global.secure
-            del self.command_line_config.Global.secure
+        c = self.command_line_config
+        if hasattr(c.Global, 'reuse_furls'):
+            c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls
+            c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls
+            del c.Global.reuse_furls
+        if hasattr(c.Global, 'secure'):
+            c.FCClientServiceFactory.secure = c.Global.secure
+            c.FCEngineServiceFactory.secure = c.Global.secure
+            del c.Global.secure
 
     def pre_construct(self):
+        # The log and security dirs were set earlier, but here we put them
+        # into the config and log them.
         config = self.master_config
-        # Now set the security_dir and log_dir and create them.  We use
-        # the names an construct the absolute paths.
-        security_dir = os.path.join(config.Global.app_dir,
-                                    config.Global.security_dir_name)
-        log_dir = os.path.join(config.Global.app_dir, 
-                               config.Global.log_dir_name)
-        if not os.path.isdir(security_dir):
-            os.mkdir(security_dir, 0700)
-        else:
-            os.chmod(security_dir, 0700)
-        if not os.path.isdir(log_dir):
-            os.mkdir(log_dir, 0777)
-
-        self.security_dir = config.Global.security_dir = security_dir
-        self.log_dir = config.Global.log_dir = log_dir
+        sdir = self.cluster_dir_obj.security_dir
+        self.security_dir = config.Global.security_dir = sdir
+        ldir = self.cluster_dir_obj.log_dir
+        self.log_dir = config.Global.log_dir = ldir
         self.log.info("Log directory set to: %s" % self.log_dir)
         self.log.info("Security directory set to: %s" % self.security_dir)
 
diff --git a/IPython/kernel/ipengineapp.py b/IPython/kernel/ipengineapp.py
index 682bae8..c8c26b3 100644
--- a/IPython/kernel/ipengineapp.py
+++ b/IPython/kernel/ipengineapp.py
@@ -24,9 +24,9 @@ from twisted.python import log
 
 from IPython.config.loader import NoConfigDefault
 
-from IPython.core.application import (
-    ApplicationWithDir, 
-    AppWithDirArgParseConfigLoader
+from IPython.kernel.clusterdir import (
+    ApplicationWithClusterDir, 
+    AppWithClusterDirArgParseConfigLoader
 )
 from IPython.core import release
 
@@ -65,7 +65,7 @@ cl_args = (
 )
 
 
-class IPEngineAppCLConfigLoader(AppWithDirArgParseConfigLoader):
+class IPEngineAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
 
     arguments = cl_args
 
@@ -87,10 +87,9 @@ mpi.size = 0
 default_config_file_name = 'ipengine_config.py'
 
 
-class IPEngineApp(ApplicationWithDir):
+class IPEngineApp(ApplicationWithClusterDir):
 
     name = 'ipengine'
-    app_dir_basename = 'cluster'
     description = 'Start the IPython engine for parallel computing.'
     config_file_name = default_config_file_name
 
@@ -130,21 +129,10 @@ class IPEngineApp(ApplicationWithDir):
 
     def pre_construct(self):
         config = self.master_config
-        # Now set the security_dir and log_dir and create them.  We use
-        # the names an construct the absolute paths.
-        security_dir = os.path.join(config.Global.app_dir,
-                                    config.Global.security_dir_name)
-        log_dir = os.path.join(config.Global.app_dir,
-                               config.Global.log_dir_name)
-        if not os.path.isdir(security_dir):
-            os.mkdir(security_dir, 0700)
-        else:
-            os.chmod(security_dir, 0700)
-        if not os.path.isdir(log_dir):
-            os.mkdir(log_dir, 0777)
-
-        self.security_dir = config.Global.security_dir = security_dir
-        self.log_dir = config.Global.log_dir = log_dir
+        sdir = self.cluster_dir_obj.security_dir
+        self.security_dir = config.Global.security_dir = sdir
+        ldir = self.cluster_dir_obj.log_dir
+        self.log_dir = config.Global.log_dir = ldir
         self.log.info("Log directory set to: %s" % self.log_dir)
         self.log.info("Security directory set to: %s" % self.security_dir)
 
@@ -158,7 +146,7 @@ class IPEngineApp(ApplicationWithDir):
         else:
             # We should know what the app dir is
             try_this = os.path.join(
-                config.Global.app_dir, 
+                config.Global.cluster_dir, 
                 config.Global.security_dir,
                 config.Global.furl_file_name
             )
diff --git a/IPython/utils/genutils.py b/IPython/utils/genutils.py
index 4204354..e2c35b2 100644
--- a/IPython/utils/genutils.py
+++ b/IPython/utils/genutils.py
@@ -736,14 +736,14 @@ def get_home_dir():
         root=os.path.abspath(root).rstrip('\\')
         if isdir(os.path.join(root, '_ipython')):
             os.environ["IPYKITROOT"] = root
-        return root
+        return root.decode(sys.getfilesystemencoding())
     try:
         homedir = env['HOME']
         if not isdir(homedir):
             # in case a user stuck some string which does NOT resolve to a
             # valid path, it's as good as if we hadn't foud it
             raise KeyError
-        return homedir
+        return homedir.decode(sys.getfilesystemencoding())
     except KeyError:
         if os.name == 'posix':
             raise HomeDirError,'undefined $HOME, IPython can not proceed.'
@@ -755,7 +755,7 @@ def get_home_dir():
                     homedir = os.path.join(env['USERPROFILE'])
                     if not isdir(homedir):
                         raise HomeDirError
-                return homedir
+                return homedir.decode(sys.getfilesystemencoding())
             except KeyError:
                 try:
                     # Use the registry to get the 'My Documents' folder.
@@ -771,14 +771,14 @@ def get_home_dir():
                              'This is not a valid directory on your system.' %
                              homedir)
                         raise HomeDirError(e)
-                    return homedir
+                    return homedir.decode(sys.getfilesystemencoding())
                 except HomeDirError:
                     raise
                 except:
-                    return 'C:\\'
+                    return 'C:\\'.decode(sys.getfilesystemencoding())
         elif os.name == 'dos':
             # Desperate, may do absurd things in classic MacOS. May work under DOS.
-            return 'C:\\'
+            return 'C:\\'.decode(sys.getfilesystemencoding())
         else:
             raise HomeDirError,'support for your operating system not implemented.'
 
@@ -795,31 +795,6 @@ def get_ipython_dir():
                                            os.path.join(home_dir, ipdir_def)))
     return ipdir.decode(sys.getfilesystemencoding())
 
-def get_security_dir():
-    """Get the IPython security directory.
-    
-    This directory is the default location for all security related files,
-    including SSL/TLS certificates and FURL files.
-    
-    If the directory does not exist, it is created with 0700 permissions.
-    If it exists, permissions are set to 0700.
-    """
-    security_dir = os.path.join(get_ipython_dir(), 'security')
-    if not os.path.isdir(security_dir):
-        os.mkdir(security_dir, 0700)
-    else:
-        os.chmod(security_dir, 0700)
-    return security_dir
-
-def get_log_dir():
-    """Get the IPython log directory.
-    
-    If the log directory does not exist, it is created.
-    """
-    log_dir = os.path.join(get_ipython_dir(), 'log')
-    if not os.path.isdir(log_dir):
-        os.mkdir(log_dir, 0777)
-    return log_dir
 
 #****************************************************************************
 # strings and text