def login(self, nic_index=0, timeout=LOGIN_TIMEOUT): """ Log into the guest via SSH/Telnet/Netcat. If timeout expires while waiting for output from the guest (e.g. a password prompt or a shell prompt) -- fail. @param nic_index: The index of the NIC to connect to. @param timeout: Time (seconds) before giving up logging into the guest. @return: A ShellSession object. """ error.context("logging into '%s'" % self.name) username = self.params.get("username", "") password = self.params.get("password", "") prompt = self.params.get("shell_prompt", "[\#\$]") linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) client = self.params.get("shell_client") address = self.get_address(nic_index) port = self.get_port(int(self.params.get("shell_port"))) log_filename = ("session-%s-%s.log" % (self.name, virt_utils.generate_random_string(4))) session = virt_remote.remote_login(client, address, port, username, password, prompt, linesep, log_filename, timeout) session.set_status_test_command(self.params.get("status_test_command", "")) return session
def __init__(self, test, params, image_name, blkdebug_cfg="", prompt=r"qemu-io>\s*$", log_filename=None, io_options=""): self.type = "" if log_filename: log_filename += "-" + virt_utils.generate_random_string(4) self.output_func = virt_utils.log_line self.output_params = (log_filename, ) else: self.output_func = None self.output_params = () self.output_prefix = "" self.prompt = prompt self.blkdebug_cfg = blkdebug_cfg self.qemu_io_cmd = virt_utils.get_path( test.bindir, params.get("qemu_io_binary", "qemu-io")) self.io_options = io_options self.run_command = False self.image_name = image_name self.blkdebug_cfg = blkdebug_cfg
def login(self, nic_index=0, timeout=LOGIN_TIMEOUT): """ Log into the guest via SSH/Telnet/Netcat. If timeout expires while waiting for output from the guest (e.g. a password prompt or a shell prompt) -- fail. @param nic_index: The index of the NIC to connect to. @param timeout: Time (seconds) before giving up logging into the guest. @return: A ShellSession object. """ error.context("logging into '%s'" % self.name) username = self.params.get("username", "") password = self.params.get("password", "") prompt = self.params.get("shell_prompt", "[\#\$]") linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) client = self.params.get("shell_client") address = self.get_address(nic_index) port = self.get_port(int(self.params.get("shell_port"))) log_filename = ("session-%s-%s.log" % (self.name, virt_utils.generate_random_string(4))) session = virt_utils.remote_login(client, address, port, username, password, prompt, linesep, log_filename, timeout) session.set_status_test_command( self.params.get("status_test_command", "")) return session
def copy_files_from(self, guest_path, host_path, nic_index=0, verbose=False, timeout=COPY_FILES_TIMEOUT): """ Transfer files from the guest. @param host_path: Guest path @param guest_path: Host path @param nic_index: The index of the NIC to connect to. @param verbose: If True, log some stats using logging.debug (RSS only) @param timeout: Time (seconds) before giving up on doing the remote copy. """ error.context("receiving file(s) from '%s'" % self.name) username = self.params.get("username", "") password = self.params.get("password", "") client = self.params.get("file_transfer_client") address = self.get_address(nic_index) port = self.get_port(int(self.params.get("file_transfer_port"))) log_filename = ( "transfer-%s-from-%s-%s.log" % (self.name, address, virt_utils.generate_random_string(4))) virt_utils.copy_files_from(address, client, username, password, port, guest_path, host_path, log_filename, verbose, timeout)
def copy_files_from(self, guest_path, host_path, nic_index=0, limit="", verbose=False, timeout=COPY_FILES_TIMEOUT): """ Transfer files from the guest. @param host_path: Guest path @param guest_path: Host path @param nic_index: The index of the NIC to connect to. @param limit: Speed limit of file transfer. @param verbose: If True, log some stats using logging.debug (RSS only) @param timeout: Time (seconds) before giving up on doing the remote copy. """ error.context("receiving file(s) from '%s'" % self.name) username = self.params.get("username", "") password = self.params.get("password", "") client = self.params.get("file_transfer_client") address = self.get_address(nic_index) port = self.get_port(int(self.params.get("file_transfer_port"))) log_filename = ("transfer-%s-from-%s-%s.log" % (self.name, address, virt_utils.generate_random_string(4))) virt_remote.copy_files_from(address, client, username, password, port, guest_path, host_path, limit, log_filename, verbose, timeout)
def _generate_unique_id(self): """ Generate a unique identifier for this VM """ while True: self.instance = time.strftime("%Y%m%d-%H%M%S-") + virt_utils.generate_random_string(8) if not glob.glob("/tmp/*%s" % self.instance): break
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = virt_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" % virt_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} while True: for vm in env.get_all_vms(): if not vm.is_alive(): continue try: vm.monitor.screendump(filename=temp_filename, debug=False) except kvm_monitor.MonitorError, e: logging.warn(e) continue except AttributeError, e: continue if not os.path.exists(temp_filename): logging.warn("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warn("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass screendump_filename = os.path.join(screendump_dir, "%s_%s.jpg" % (vm.name, time.strftime("%Y-%m-%d_%H-%M-%S"))) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except NameError: pass os.unlink(temp_filename)
def cmd(self, cmd, args=None, timeout=CMD_TIMEOUT, debug=True, fd=None): """ Send a QMP monitor command and return the response. Note: an id is automatically assigned to the command and the response is checked for the presence of the same id. @param cmd: Command to send @param args: A dict containing command arguments, or None @param timeout: Time duration to wait for response @param debug: Whether to print the commands being sent and responses @param fd: file object or file descriptor to pass @return: The response received @raise MonitorLockError: Raised if the lock cannot be acquired @raise MonitorSocketError: Raised if a socket error occurs @raise MonitorProtocolError: Raised if no response is received @raise QMPCmdError: Raised if the response is an error message (the exception's args are (cmd, args, data) where data is the error data) """ self._log_command(cmd, debug) if not self._acquire_lock(): raise MonitorLockError("Could not acquire exclusive lock to send " "QMP command '%s'" % cmd) try: # Read any data that might be available self._read_objects() # Send command id = virt_utils.generate_random_string(8) cmdobj = self._build_cmd(cmd, args, id) if fd is not None: if self._passfd is None: self._passfd = virt_passfd_setup.import_passfd() # If command includes a file descriptor, use passfd module self._passfd.sendfd(self._socket, fd, json.dumps(cmdobj) + "\n") else: self._send(json.dumps(cmdobj) + "\n") # Read response r = self._get_response(id, timeout) if r is None: raise MonitorProtocolError("Received no response to QMP " "command '%s', or received a " "response with an incorrect id" % cmd) if "return" in r: ret = r["return"] if ret: self._log_response(cmd, ret, debug) return ret if "error" in r: raise QMPCmdError(cmd, args, r["error"]) finally: self._lock.release()
def _generate_unique_id(self): """ Generate a unique identifier for this VM """ while True: self.instance = (time.strftime("%Y%m%d-%H%M%S-") + virt_utils.generate_random_string(4)) if not glob.glob("/tmp/*%s" % self.instance): break
def get_backup_name(filename, backup_dir, good): if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) if good: backup_filename = "%s.backup" % basename else: backup_filename = "%s.bad.%s" % (basename, virt_utils.generate_random_string(4)) return os.path.join(backup_dir, backup_filename)
def get_backup_name(filename, backup_dir, good): if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) if good: backup_filename = "%s.backup" % basename else: backup_filename = ( "%s.bad.%s" % (basename, virt_utils.generate_random_string(4))) return os.path.join(backup_dir, backup_filename)
def cmd(self, cmd, args=None, timeout=20, debug=True): """ Send a QMP monitor command and return the response. Note: an id is automatically assigned to the command and the response is checked for the presence of the same id. @param cmd: Command to send @param args: A dict containing command arguments, or None @param timeout: Time duration to wait for response @return: The response received @raise MonitorLockError: Raised if the lock cannot be acquired @raise MonitorSocketError: Raised if a socket error occurs @raise MonitorProtocolError: Raised if no response is received @raise QMPCmdError: Raised if the response is an error message (the exception's args are (cmd, args, data) where data is the error data) """ if debug: logging.debug("(monitor %s) Sending command '%s'", self.name, cmd) if not self._acquire_lock(20): raise MonitorLockError("Could not acquire exclusive lock to send " "QMP command '%s'" % cmd) try: # Read any data that might be available self._read_objects() # Send command id = virt_utils.generate_random_string(8) self._send(json.dumps(self._build_cmd(cmd, args, id)) + "\n") # Read response r = self._get_response(id, timeout) if r is None: raise MonitorProtocolError("Received no response to QMP " "command '%s', or received a " "response with an incorrect id" % cmd) if "return" in r: if debug and r["return"]: logging.debug("(monitor %s) " "Response to '%s'", self.name, cmd) o = str(r["return"]) for l in o.splitlines(): logging.debug("(monitor %s) %s", self.name, l) return r["return"] if "error" in r: raise QMPCmdError(cmd, args, r["error"]) finally: self._lock.release()
def copy_files_to(self, host_path, guest_path, nic_index=0, verbose=False, timeout=600): """ Transfer files to the remote host(guest). @param host_path: Host path @param guest_path: Guest path @param nic_index: The index of the NIC to connect to. @param verbose: If True, log some stats using logging.debug (RSS only) @param timeout: Time (seconds) before giving up on doing the remote copy. """ error.context("sending file(s) to '%s'" % self.name) username = self.params.get("username", "") password = self.params.get("password", "") client = self.params.get("file_transfer_client") address = self.get_address(nic_index) port = self.get_port(int(self.params.get("file_transfer_port"))) log_filename = ("transfer-%s-to-%s-%s.log" % (self.name, address, virt_utils.generate_random_string(4))) virt_utils.copy_files_to(address, client, username, password, port, host_path, guest_path, log_filename, verbose, timeout)
def run_file_transfer(test, params, env): """ Transfer a file back and forth between host and guest. 1) Boot up a VM. 2) Create a large file by dd on host. 3) Copy this file from host to guest. 4) Copy this file from guest to host. 5) Check if file transfers ended good. @param test: KVM test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) dir_name = test.tmpdir transfer_timeout = int(params.get("transfer_timeout")) transfer_type = params.get("transfer_type") tmp_dir = params.get("tmp_dir", "/tmp/") clean_cmd = params.get("clean_cmd", "rm -f") filesize = int(params.get("filesize", 4000)) count = int(filesize / 10) if count == 0: count = 1 host_path = os.path.join(dir_name, "tmp-%s" % virt_utils.generate_random_string(8)) host_path2 = host_path + ".2" cmd = "dd if=/dev/zero of=%s bs=10M count=%d" % (host_path, count) guest_path = (tmp_dir + "file_transfer-%s" % virt_utils.generate_random_string(8)) try: logging.info("Creating %dMB file on host", filesize) utils.run(cmd) if transfer_type == "remote": logging.info("Transfering file host -> guest, timeout: %ss", transfer_timeout) t_begin = time.time() vm.copy_files_to(host_path, guest_path, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info( "File transfer host -> guest succeed, " "estimated throughput: %.2fMB/s", throughput) logging.info("Transfering file guest -> host, timeout: %ss", transfer_timeout) t_begin = time.time() vm.copy_files_from(guest_path, host_path2, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info( "File transfer guest -> host succeed, " "estimated throughput: %.2fMB/s", throughput) else: raise error.TestError("Unknown test file transfer mode %s" % transfer_type) if (utils.hash_file(host_path, method="md5") != utils.hash_file( host_path2, method="md5")): raise error.TestFail("File changed after transfer host -> guest " "and guest -> host") finally: logging.info('Cleaning temp file on guest') session.cmd("%s %s" % (clean_cmd, guest_path)) logging.info('Cleaning temp files on host') try: os.remove(host_path) os.remove(host_path2) except OSError: pass session.close()
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = virt_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join( temp_dir, "scrdump-%s.ppm" % virt_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} counter = {} while True: for vm in env.get_all_vms(): if vm not in counter.keys(): counter[vm] = 0 if not vm.is_alive(): continue try: vm.screendump(filename=temp_filename, debug=False) except kvm_monitor.MonitorError, e: logging.warn(e) continue except AttributeError, e: continue if not os.path.exists(temp_filename): logging.warn("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warn("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass counter[vm] += 1 screendump_filename = os.path.join(screendump_dir, "%04d.jpg" % counter[vm]) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except IOError, error_detail: logging.warning( "VM '%s' failed to produce a " "screendump: %s", vm.name, error_detail) # Decrement the counter as we in fact failed to # produce a converted screendump counter[vm] -= 1 except NameError: pass os.unlink(temp_filename)
def __init__(self, command=None, id=None, auto_close=False, echo=False, linesep="\n"): """ Initialize the class and run command as a child process. @param command: Command to run, or None if accessing an already running server. @param id: ID of an already running server, if accessing a running server, or None if starting a new one. @param auto_close: If True, close() the instance automatically when its reference count drops to zero (default False). @param echo: Boolean indicating whether echo should be initially enabled for the pseudo terminal running the subprocess. This parameter has an effect only when starting a new server. @param linesep: Line separator to be appended to strings sent to the child process by sendline(). """ self.id = id or virt_utils.generate_random_string(8) # Define filenames for communication with server base_dir = "/tmp/kvm_spawn" try: os.makedirs(base_dir) except: pass ( self.shell_pid_filename, self.status_filename, self.output_filename, self.inpipe_filename, self.lock_server_running_filename, self.lock_client_starting_filename, ) = _get_filenames(base_dir, self.id) # Remember some attributes self.auto_close = auto_close self.echo = echo self.linesep = linesep # Make sure the 'readers' and 'close_hooks' attributes exist if not hasattr(self, "readers"): self.readers = [] if not hasattr(self, "close_hooks"): self.close_hooks = [] # Define the reader filenames self.reader_filenames = dict( (reader, _get_reader_filename(base_dir, self.id, reader)) for reader in self.readers ) # Let the server know a client intends to open some pipes; # if the executed command terminates quickly, the server will wait for # the client to release the lock before exiting lock_client_starting = _lock(self.lock_client_starting_filename) # Start the server (which runs the command) if command: sub = subprocess.Popen( "%s %s" % (sys.executable, __file__), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) # Send parameters to the server sub.stdin.write("%s\n" % self.id) sub.stdin.write("%s\n" % echo) sub.stdin.write("%s\n" % ",".join(self.readers)) sub.stdin.write("%s\n" % command) # Wait for the server to complete its initialization while not "Server %s ready" % self.id in sub.stdout.readline(): pass # Open the reading pipes self.reader_fds = {} try: assert _locked(self.lock_server_running_filename) for reader, filename in self.reader_filenames.items(): self.reader_fds[reader] = os.open(filename, os.O_RDONLY) except: pass # Allow the server to continue _unlock(lock_client_starting)
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = virt_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join( temp_dir, "scrdump-%s.ppm" % virt_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} while True: for vm in env.get_all_vms(): if not vm.is_alive(): continue try: vm.monitor.screendump(filename=temp_filename, debug=False) except kvm_monitor.MonitorError, e: logging.warning(e) continue except AttributeError, e: continue if not os.path.exists(temp_filename): logging.warning("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warning("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass screendump_filename = os.path.join( screendump_dir, "%s_%s.jpg" % (vm.name, time.strftime("%Y-%m-%d_%H-%M-%S"))) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except NameError: pass os.unlink(temp_filename)
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = virt_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" % virt_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} counter = {} while True: for vm in env.get_all_vms(): if vm not in counter.keys(): counter[vm] = 0 if not vm.is_alive(): continue try: vm.screendump(filename=temp_filename, debug=False) except kvm_monitor.MonitorError, e: logging.warn(e) continue except AttributeError, e: logging.warn(e) continue if not os.path.exists(temp_filename): logging.warn("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warn("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass counter[vm] += 1 screendump_filename = os.path.join(screendump_dir, "%04d.jpg" % counter[vm]) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except IOError, error_detail: logging.warning("VM '%s' failed to produce a " "screendump: %s", vm.name, error_detail) # Decrement the counter as we in fact failed to # produce a converted screendump counter[vm] -= 1 except NameError: pass os.unlink(temp_filename)
def run_file_transfer(test, params, env): """ Transfer a file back and forth between host and guest. 1) Boot up a VM. 2) Create a large file by dd on host. 3) Copy this file from host to guest. 4) Copy this file from guest to host. 5) Check if file transfers ended good. @param test: KVM test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) dir_name = test.tmpdir transfer_timeout = int(params.get("transfer_timeout")) transfer_type = params.get("transfer_type") tmp_dir = params.get("tmp_dir", "/tmp/") clean_cmd = params.get("clean_cmd", "rm -f") filesize = int(params.get("filesize", 4000)) count = int(filesize / 10) if count == 0: count = 1 host_path = os.path.join(dir_name, "tmp-%s" % virt_utils.generate_random_string(8)) host_path2 = host_path + ".2" cmd = "dd if=/dev/zero of=%s bs=10M count=%d" % (host_path, count) guest_path = (tmp_dir + "file_transfer-%s" % virt_utils.generate_random_string(8)) try: logging.info("Creating %dMB file on host", filesize) utils.run(cmd) if transfer_type == "remote": logging.info("Transfering file host -> guest, timeout: %ss", transfer_timeout) t_begin = time.time() vm.copy_files_to(host_path, guest_path, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info("File transfer host -> guest succeed, " "estimated throughput: %.2fMB/s", throughput) logging.info("Transfering file guest -> host, timeout: %ss", transfer_timeout) t_begin = time.time() vm.copy_files_from(guest_path, host_path2, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info("File transfer guest -> host succeed, " "estimated throughput: %.2fMB/s", throughput) else: raise error.TestError("Unknown test file transfer mode %s" % transfer_type) if (utils.hash_file(host_path, method="md5") != utils.hash_file(host_path2, method="md5")): raise error.TestFail("File changed after transfer host -> guest " "and guest -> host") finally: logging.info('Cleaning temp file on guest') session.cmd("%s %s" % (clean_cmd, guest_path)) logging.info('Cleaning temp files on host') try: os.remove(host_path) os.remove(host_path2) except OSError: pass session.close()
def __init__(self, command=None, id=None, auto_close=False, echo=False, linesep="\n"): """ Initialize the class and run command as a child process. @param command: Command to run, or None if accessing an already running server. @param id: ID of an already running server, if accessing a running server, or None if starting a new one. @param auto_close: If True, close() the instance automatically when its reference count drops to zero (default False). @param echo: Boolean indicating whether echo should be initially enabled for the pseudo terminal running the subprocess. This parameter has an effect only when starting a new server. @param linesep: Line separator to be appended to strings sent to the child process by sendline(). """ self.id = id or virt_utils.generate_random_string(8) # Define filenames for communication with server base_dir = "/tmp/kvm_spawn" try: os.makedirs(base_dir) except Exception: pass (self.shell_pid_filename, self.status_filename, self.output_filename, self.inpipe_filename, self.lock_server_running_filename, self.lock_client_starting_filename) = _get_filenames(base_dir, self.id) # Remember some attributes self.auto_close = auto_close self.echo = echo self.linesep = linesep # Make sure the 'readers' and 'close_hooks' attributes exist if not hasattr(self, "readers"): self.readers = [] if not hasattr(self, "close_hooks"): self.close_hooks = [] # Define the reader filenames self.reader_filenames = dict( (reader, _get_reader_filename(base_dir, self.id, reader)) for reader in self.readers) # Let the server know a client intends to open some pipes; # if the executed command terminates quickly, the server will wait for # the client to release the lock before exiting lock_client_starting = _lock(self.lock_client_starting_filename) # Start the server (which runs the command) if command: sub = subprocess.Popen("%s %s" % (sys.executable, __file__), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Send parameters to the server sub.stdin.write("%s\n" % self.id) sub.stdin.write("%s\n" % echo) sub.stdin.write("%s\n" % ",".join(self.readers)) sub.stdin.write("%s\n" % command) # Wait for the server to complete its initialization while not "Server %s ready" % self.id in sub.stdout.readline(): pass # Open the reading pipes self.reader_fds = {} try: assert(_locked(self.lock_server_running_filename)) for reader, filename in self.reader_filenames.items(): self.reader_fds[reader] = os.open(filename, os.O_RDONLY) except Exception: pass # Allow the server to continue _unlock(lock_client_starting)