From 9c6419f702b58695c83e6847d2ada97f7cf03021 2013-01-19 05:15:45 From: MinRK Date: 2013-01-19 05:15:45 Subject: [PATCH] improve default ipc file locations When transport is IPC, the default location for the IPC files should be in the security dir. This ensures that is the case for both the `ipython kernel` and `ipython notebook` cases. It already made sense in `ipython [qt]console`. --- diff --git a/IPython/zmq/kernelapp.py b/IPython/zmq/kernelapp.py index fea4bfe..a35eb30 100644 --- a/IPython/zmq/kernelapp.py +++ b/IPython/zmq/kernelapp.py @@ -62,6 +62,7 @@ kernel_aliases.update({ 'stdin' : 'KernelApp.stdin_port', 'f' : 'KernelApp.connection_file', 'parent': 'KernelApp.parent', + 'transport': 'KernelApp.transport', }) if sys.platform.startswith('win'): kernel_aliases['interrupt'] = 'KernelApp.interrupt' @@ -98,7 +99,6 @@ class KernelApp(BaseIPythonApplication): heartbeat = Instance(Heartbeat) session = Instance('IPython.zmq.session.Session') ports = Dict() - _full_connection_file = Unicode() # inherit config file name from parent: parent_appname = Unicode(config=True) @@ -112,8 +112,16 @@ class KernelApp(BaseIPythonApplication): # connection info: transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True) - ip = Unicode(LOCALHOST, config=True, + ip = Unicode(config=True, help="Set the IP or interface on which the kernel will listen.") + def _ip_default(self): + if self.transport == 'ipc': + if self.connection_file: + return os.path.splitext(self.abs_connection_file)[0] + '-ipc' + else: + return 'kernel-ipc' + else: + return LOCALHOST hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]") shell_port = Integer(0, config=True, help="set the shell (ROUTER) port [default: random]") iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]") @@ -122,9 +130,16 @@ class KernelApp(BaseIPythonApplication): help="""JSON file in which to store connection info [default: kernel-.json] This file will contain the IP, ports, and authentication key needed to connect - clients to this kernel. By default, this file will be created in the security-dir + clients to this kernel. By default, this file will be created in the security dir of the current profile, but can be specified by absolute path. """) + @property + def abs_connection_file(self): + if os.path.basename(self.connection_file) == self.connection_file: + return os.path.join(self.profile_dir.security_dir, self.connection_file) + else: + return self.connection_file + # streams, etc. no_stdout = Bool(False, config=True, help="redirect stdout to the null device") @@ -141,7 +156,7 @@ class KernelApp(BaseIPythonApplication): """) interrupt = Integer(0, config=True, help="""ONLY USED ON WINDOWS - Interrupt this process when the parent is signalled. + Interrupt this process when the parent is signaled. """) def init_crash_handler(self): @@ -158,11 +173,20 @@ class KernelApp(BaseIPythonApplication): def _bind_socket(self, s, port): iface = '%s://%s' % (self.transport, self.ip) - if port <= 0 and self.transport == 'tcp': - port = s.bind_to_random_port(iface) - else: - c = ':' if self.transport == 'tcp' else '-' - s.bind(iface + c + str(port)) + if self.transport == 'tcp': + if port <= 0: + port = s.bind_to_random_port(iface) + else: + s.bind("tcp://%s:%i" % (self.ip, port)) + elif self.transport == 'ipc': + if port <= 0: + for port in range(1,1024): + path = "%s-%i" % (self.ip, port) + if not os.path.exists(path): + break + else: + path = "%s-%i" % (self.ip, port) + s.bind("ipc://%s" % path) return port def load_connection_file(self): @@ -179,7 +203,7 @@ class KernelApp(BaseIPythonApplication): s = f.read() cfg = json.loads(s) self.transport = cfg.get('transport', self.transport) - if self.ip == LOCALHOST and 'ip' in cfg: + if self.ip == self._ip_default() and 'ip' in cfg: # not overridden by config or cl_args self.ip = cfg['ip'] for channel in ('hb', 'shell', 'iopub', 'stdin'): @@ -192,19 +216,15 @@ class KernelApp(BaseIPythonApplication): def write_connection_file(self): """write connection info to JSON file""" - if os.path.basename(self.connection_file) == self.connection_file: - cf = os.path.join(self.profile_dir.security_dir, self.connection_file) - else: - cf = self.connection_file + cf = self.abs_connection_file + self.log.debug("Writing connection file: %s", cf) write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport, shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port, iopub_port=self.iopub_port) - - self._full_connection_file = cf def cleanup_connection_file(self): - cf = self._full_connection_file - self.log.debug("cleaning up connection file: %r", cf) + cf = self.abs_connection_file + self.log.debug("Cleaning up connection file: %s", cf) try: os.remove(cf) except (IOError, OSError): diff --git a/IPython/zmq/kernelmanager.py b/IPython/zmq/kernelmanager.py index 94438e5..78b095b 100644 --- a/IPython/zmq/kernelmanager.py +++ b/IPython/zmq/kernelmanager.py @@ -684,7 +684,20 @@ class KernelManager(Configurable): transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True) - ip = Unicode(LOCALHOST, config=True) + ip = Unicode(LOCALHOST, config=True, + help="""Set the kernel\'s IP address [default localhost]. + If the IP address is something other than localhost, then + Consoles on other machines will be able to connect + to the Kernel, so be careful!""" + ) + def _ip_default(self): + if self.transport == 'ipc': + if self.connection_file: + return os.path.splitext(self.connection_file)[0] + '-ipc' + else: + return 'kernel-ipc' + else: + return LOCALHOST def _ip_changed(self, name, old, new): if new == '*': self.ip = '0.0.0.0' @@ -706,8 +719,8 @@ class KernelManager(Configurable): _stdin_channel = Any _hb_channel = Any _connection_file_written=Bool(False) - - def __del__(self): + + def __del__(self): self.cleanup_connection_file() #--------------------------------------------------------------------------