def setup_tunnel(address, port): """ Setup tunnel to `address` and `port` assuming: - The remote login name matches the local login name. - `port` is available on the local host. - 'plink' is available on Windows, 'ssh' on other platforms. - No user interaction is required to connect via 'plink'/'ssh'. address: string IPv4 address to tunnel to. port: int Port at `address` to tunnel to. Returns ``(local_address, local_port)``. """ logname = 'tunnel-%s-%d.log' % (address, port) logname = os.path.join(os.getcwd(), logname) stdout = open(logname, 'w') user = getpass.getuser() if sys.platform == 'win32': # pragma no cover stdin = open('nul:', 'r') args = ['plink', '-ssh', '-l', user, '-L', '%d:localhost:%d' % (port, port), address] else: stdin = open('/dev/null', 'r') args = ['ssh', '-l', user, '-L', '%d:localhost:%d' % (port, port), address] tunnel_proc = ShellProc(args, stdin=stdin, stdout=stdout, stderr=STDOUT) sock = socket.socket(socket.AF_INET) address = ('127.0.0.1', port) for retry in range(20): time.sleep(.5) exitcode = tunnel_proc.poll() if exitcode is not None: msg = 'ssh tunnel process exited with exitcode %d,' \ ' output in %s' % (exitcode, logname) logging.error(msg) raise RuntimeError(msg) try: sock.connect(address) except socket.error as exc: if exc.args[0] != errno.ECONNREFUSED and \ exc.args[0] != errno.ENOENT: raise else: atexit.register(_cleanup_tunnel, tunnel_proc, logname) sock.close() return address _cleanup_tunnel(tunnel_proc, logname) raise RuntimeError('Timeout trying to connect through tunnel to %s' % address)
def _start_tunnel(address, port, args, user, identity, prefix): """ Start an ssh tunnel process. """ if '@' in address: user, host = address.split('@') else: user = user or getpass.getuser() host = address if sys.platform == 'win32': # pragma no cover cmd = ['plink', '-batch', '-ssh'] else: cmd = ['ssh'] cmd += ['-l', user] if identity: cmd += ['-i', identity] cmd += ['-N', '-x', '-T'] # plink doesn't support '-n' (no stdin) cmd += args + [host] logname = '%s-%s-%s.log' % (prefix, host, port) logname = os.path.join(os.getcwd(), logname) stdout = open(logname, 'w') tunnel_proc = None try: tunnel_proc = ShellProc(cmd, stdout=stdout, stderr=STDOUT) except Exception as exc: raise RuntimeError("Can't create ssh tunnel process from %s: %s" % (cmd, exc)) time.sleep(1) exitcode = tunnel_proc.poll() if exitcode is not None: raise RuntimeError('ssh tunnel process for %s:%s exited with exitcode' ' %d, output in %s' % (address, port, exitcode, logname)) return (_cleanup_tunnel, tunnel_proc, stdout, logname, os.getpid())
def _start_tunnel(address, port, args, user, identity, prefix): """ Start an ssh tunnel process. """ if "@" in address: user, host = address.split("@") else: user = user or getpass.getuser() host = address if sys.platform == "win32": # pragma no cover cmd = ["plink", "-batch", "-ssh"] else: cmd = ["ssh"] cmd += ["-l", user] if identity: cmd += ["-i", identity] cmd += ["-N", "-x", "-T"] # plink doesn't support '-n' (no stdin) cmd += args + [host] logname = "%s-%s-%s.log" % (prefix, host, port) logname = os.path.join(os.getcwd(), logname) stdout = open(logname, "w") tunnel_proc = None try: tunnel_proc = ShellProc(cmd, stdout=stdout, stderr=STDOUT) except Exception as exc: raise RuntimeError("Can't create ssh tunnel process from %s: %s" % (cmd, exc)) time.sleep(1) exitcode = tunnel_proc.poll() if exitcode is not None: raise RuntimeError( "ssh tunnel process for %s:%s exited with exitcode" " %d, output in %s" % (address, port, exitcode, logname) ) return (_cleanup_tunnel, tunnel_proc, stdout, logname, os.getpid())
def start_server(authkey='PublicKey', address=None, port=0, prefix='server', allowed_hosts=None, allowed_users=None, allow_shell=False, allowed_types=None, timeout=None, tunnel=False, resources=None, log_prefix=None): """ Start an :class:`ObjServerFactory` service in a separate process in the current directory. authkey: string Authorization key, must be matched by clients. address: string IPv4 address, hostname, or pipe name. Default is the host's default IPv4 address. port: int Server port (default of 0 implies next available port). Note that ports below 1024 typically require special privileges. If port is negative, then a local pipe is used for communication. prefix: string Prefix for server config file and stdout/stderr file. allowed_hosts: list(string) Host address patterns to check against. Required if `port` >= 0. Ignored if `allowed_users` is specified. allowed_users: dict Dictionary of users and corresponding public keys allowed access. If None, *any* user may access. If empty, no user may access. The host portions of user strings are used for address patterns. allow_shell: bool If True, :meth:`execute_command` and :meth:`load_model` are allowed. Use with caution! allowed_types: list(string) Names of types which may be created. If None, then allow types listed by :meth:`get_available_types`. If empty, no types are allowed. timeout: int Seconds to wait for server to start. Note that public key generation can take a while. The default value of None will use an internally computed value based on host type (and for Windows, the availability of pyWin32). tunnel: bool If True, report host IP address but listen for connections from a local SSH tunnel. resources: string Filename for resource configuration. log_prefix: string Name used to identify remote remote logging messages from server. Implies that the local process will be receiving the messages. Returns ``(server_proc, config_filename)``. """ if timeout is None: if sys.platform == 'win32' and not HAVE_PYWIN32: #pragma no cover timeout = 120 else: timeout = 30 server_key = prefix+'.key' server_cfg = prefix+'.cfg' server_out = prefix+'.out' for path in (server_cfg, server_out): if os.path.exists(path): os.remove(path) with open(server_key, 'w') as out: out.write('%s\n' % authkey) factory_path = pkg_resources.resource_filename('openmdao.main', 'objserverfactory.py') args = ['python', factory_path, '--port', str(port), '--prefix', prefix] if address is not None: args.extend(['--address', address]) if tunnel: args.append('--tunnel') if resources is not None: args.append('--resources') args.append(resources) if allowed_users is not None: write_authorized_keys(allowed_users, 'users.allow', logging.getLogger()) args.extend(['--users', 'users.allow']) else: args.append('--allow-public') if port >= 0: if allowed_hosts is None: allowed_hosts = [socket.gethostbyname(socket.gethostname())] if allowed_hosts[0].startswith('127.') and \ '127.0.0.1' not in allowed_hosts: allowed_hosts.append('127.0.0.1') with open('hosts.allow', 'w') as out: for pattern in allowed_hosts: out.write('%s\n' % pattern) if sys.platform != 'win32' or HAVE_PYWIN32: make_private('hosts.allow') else: #pragma no cover logging.warning("Can't make hosts.allow private") if allow_shell: args.append('--allow-shell') if allowed_types is not None: with open('types.allow', 'w') as out: for typname in allowed_types: out.write('%s\n' % typname) if sys.platform != 'win32' or HAVE_PYWIN32: make_private('types.allow') else: #pragma no cover logging.warning("Can't make types.allow private") args.extend(['--types', 'types.allow']) if log_prefix is not None: log_host = socket.gethostname() log_port = logging_port(log_host, log_host) args.extend(['--log-host', log_host, '--log-port', str(log_port)]) if log_prefix: # Could be null (for default). args.extend(['--log-prefix', log_prefix]) proc = ShellProc(args, stdout=server_out, stderr=STDOUT) try: # Wait for valid server_cfg file. retry = 0 while (not os.path.exists(server_cfg)) or \ (os.path.getsize(server_cfg) == 0): return_code = proc.poll() if return_code: error_msg = proc.error_message(return_code) raise RuntimeError('Server startup failed %s' % error_msg) retry += 1 if retry < 10*timeout: time.sleep(.1) # Hard to cause a startup timeout. else: #pragma no cover proc.terminate(timeout) raise RuntimeError('Server startup timeout') return (proc, server_cfg) finally: if os.path.exists(server_key): os.remove(server_key)
def start_server(authkey='PublicKey', address=None, port=0, prefix='server', allowed_hosts=None, allowed_users=None, allow_shell=False, allowed_types=None, timeout=None, tunnel=False, resources=None, log_prefix=None): """ Start an :class:`ObjServerFactory` service in a separate process in the current directory. authkey: string Authorization key; must be matched by clients. address: string IPv4 address, hostname, or pipe name. Default is the host's default IPv4 address. port: int Server port (default of 0 implies next available port). Note that ports below 1024 typically require special privileges. If port is negative, then a local pipe is used for communication. prefix: string Prefix for server config file and stdout/stderr file. allowed_hosts: list(string) Host address patterns to check against. Required if `port` >= 0. Ignored if `allowed_users` is specified. allowed_users: dict Dictionary of users and corresponding public keys allowed access. If None, *any* user may access. If empty, no user may access. The host portions of user strings are used for address patterns. allow_shell: bool If True, :meth:`execute_command` and :meth:`load_model` are allowed. Use with caution! allowed_types: list(string) Names of types which may be created. If None, then allow types listed by :meth:`get_available_types`. If empty, no types are allowed. timeout: int Seconds to wait for server to start. Note that public key generation can take a while. The default value of None will use an internally computed value based on host type (and for Windows, the availability of pyWin32). tunnel: bool If True, report host IP address but listen for connections from a local SSH tunnel. resources: string Filename for resource configuration. log_prefix: string Name used to identify remote remote logging messages from server. Implies that the local process will be receiving the messages. Returns ``(server_proc, config_filename)``. """ if timeout is None: if sys.platform == 'win32' and not HAVE_PYWIN32: # pragma no cover timeout = 120 else: timeout = 30 server_key = prefix + '.key' server_cfg = prefix + '.cfg' server_out = prefix + '.out' for path in (server_cfg, server_out): if os.path.exists(path): os.remove(path) with open(server_key, 'w') as out: out.write('%s\n' % authkey) factory_path = pkg_resources.resource_filename('openmdao.main', 'objserverfactory.py') args = ['python', factory_path, '--port', str(port), '--prefix', prefix] if address is not None: args.extend(['--address', address]) if tunnel: args.append('--tunnel') if resources is not None: args.append('--resources') args.append(resources) if allowed_users is not None: write_authorized_keys(allowed_users, 'users.allow', logging.getLogger()) args.extend(['--users', 'users.allow']) else: args.append('--allow-public') if port >= 0: if allowed_hosts is None: allowed_hosts = [socket.gethostbyname(socket.gethostname())] if allowed_hosts[0].startswith('127.') and \ '127.0.0.1' not in allowed_hosts: allowed_hosts.append('127.0.0.1') with open('hosts.allow', 'w') as out: for pattern in allowed_hosts: out.write('%s\n' % pattern) if sys.platform != 'win32' or HAVE_PYWIN32: make_private('hosts.allow') else: # pragma no cover logging.warning("Can't make hosts.allow private") if allow_shell: args.append('--allow-shell') if allowed_types is not None: with open('types.allow', 'w') as out: for typname in allowed_types: out.write('%s\n' % typname) if sys.platform != 'win32' or HAVE_PYWIN32: make_private('types.allow') else: # pragma no cover logging.warning("Can't make types.allow private") args.extend(['--types', 'types.allow']) if log_prefix is not None: log_host = socket.gethostname() log_port = logging_port(log_host, log_host) args.extend(['--log-host', log_host, '--log-port', str(log_port)]) if log_prefix: # Could be null (for default). args.extend(['--log-prefix', log_prefix]) proc = ShellProc(args, stdout=server_out, stderr=STDOUT) try: # Wait for valid server_cfg file. retry = 0 while (not os.path.exists(server_cfg)) or \ (os.path.getsize(server_cfg) == 0): return_code = proc.poll() if return_code: error_msg = proc.error_message(return_code) raise RuntimeError('Server startup failed %s' % error_msg) retry += 1 if retry < 10 * timeout: time.sleep(.1) # Hard to cause a startup timeout. else: # pragma no cover proc.terminate(timeout) raise RuntimeError('Server startup timeout') return (proc, server_cfg) finally: if os.path.exists(server_key): os.remove(server_key)