def test_logging_no_hang(self): '''Try to ensure Popen.check_call doesn't hang when trying to do logging''' # To ensure the logger keyword arg is implemented in a way that # doesn't cause hangs, and since the use of logger causes blocking # behavior, spawn a non-blocking subprocess that spawns a blocking # subprocess. If the non-blocking subprocess doesn't complete # in a reasonable amount of time, kill both and fail cmd = [ sys.executable, "-c", "from solaris_install import Popen; import logging; " "Popen.check_call(['/usr/bin/pkg', 'foo'], " "logger=logging.getLogger())" ] popen = Popen(cmd, stdout=Popen.DEVNULL, stderr=Popen.DEVNULL) for wait_count in xrange(15): # If it's not done nearly instantly, something is wrong. # However, give the benefit of the doubt by waiting up to # 5 seconds for completion if popen.poll() is not None: break else: time.sleep(0.5) else: popen.kill() self.fail("subprocess hung while attempting logging")
def test_logging_no_hang(self): '''Try to ensure Popen.check_call doesn't hang when trying to do logging''' # To ensure the logger keyword arg is implemented in a way that # doesn't cause hangs, and since the use of logger causes blocking # behavior, spawn a non-blocking subprocess that spawns a blocking # subprocess. If the non-blocking subprocess doesn't complete # in a reasonable amount of time, kill both and fail cmd = [sys.executable, "-c", "from solaris_install import Popen; import logging; " "Popen.check_call(['/usr/bin/pkg', 'foo'], " "logger=logging.getLogger())"] popen = Popen(cmd, stdout=Popen.DEVNULL, stderr=Popen.DEVNULL) for wait_count in xrange(15): # If it's not done nearly instantly, something is wrong. # However, give the benefit of the doubt by waiting up to # 5 seconds for completion if popen.poll() is not None: break else: time.sleep(0.5) else: popen.kill() self.fail("subprocess hung while attempting logging")
def _fork_proc(cmd, timeout=15): '''Run a command in a forked process, with a timeout. Kills the process on timeout. Logs errors. Handles processes with large amounts of data so check_call() is not used. Args: - cmd: a list of commandline arguments - timeout: timeout in seconds Returns: - Return status: - return status of the command run, if command completes. - SupportInfo.PH_TIMEOUT if timeout occurs. - stdout and stderr of the run process. ''' timeout_tenths = timeout * 10 def read_subproc(subproc, outbuf, errbuf): intoutbuf = interrbuf = "" try: intoutbuf = subproc.stdout.read() outbuf = "".join([outbuf, intoutbuf]) except IOError as err: if err.errno != errno.EAGAIN: raise try: interrbuf = subproc.stderr.read() errbuf = "".join([errbuf, interrbuf]) except IOError as err: if err.errno != errno.EAGAIN: raise return (outbuf, errbuf) # Can throw an child_exception if command cannot be started. subproc = Popen(cmd, stdout=Popen.PIPE, stderr=Popen.PIPE) flags = fcntl.fcntl(subproc.stdout.fileno(), fcntl.F_GETFL) fcntl.fcntl(subproc.stdout.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK) flags = fcntl.fcntl(subproc.stderr.fileno(), fcntl.F_GETFL) fcntl.fcntl(subproc.stderr.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK) (outbuf, errbuf) = read_subproc(subproc, "", "") while subproc.poll() is None and timeout_tenths > 0: timeout_tenths -= 1 time.sleep(0.1) (outbuf, errbuf) = read_subproc(subproc, outbuf, errbuf) if subproc.returncode is None: subproc.terminate() return (SupportInfo.PH_TIMEOUT, outbuf, errbuf) else: (outbuf, errbuf) = read_subproc(subproc, outbuf, errbuf) return (subproc.returncode, outbuf, errbuf)
def test_devnull(self): '''Test using Popen.DEVNULL for stdin''' popen = Popen(["/usr/bin/cat"], stdin=Popen.DEVNULL, stdout=Popen.PIPE) # Use PIPE for stdout as, for a failure case, the subprocess call # could hang indefinitely, so we can't block on it for wait_count in xrange(10): # If it's not done nearly instantly, something is wrong. # However, give the benefit of the doubt by waiting up to # 5 seconds for completion if popen.poll() is not None: break else: time.sleep(0.5) else: popen.kill() self.fail("stdin=Popen.DEVNULL did not work") stdout = popen.communicate()[0] self.assertEqual("", stdout)
def _transfer(self): '''Method to transfer from the source to the destination''' if self.give_progress: # Start up the ProgressMon to report progress # while the actual transfer is taking place. self.pmon = ProgressMon(logger=self.logger) # Note: startmonitor assumes there is another thread creating a # file system. If this is not the case (as may be when testing # this module in abnormal conditions), startmonitor will hang. # Just create the self.dst as a directory in this case. self.pmon.startmonitor(self.dst, self.total_size, 0, 100) # Perform the transfer specific operations. try: for trans_val in self._transfer_list: # Get the arguments for the transfer process arglist = trans_val.get(SVR4_ARGS).split(' ') # Parse the components to determine the transfer action if trans_val.get(ACTION) == 'install': self.check_cancel_event() self.logger.info("Installing SVR4 packages") cmd = [AbstractSVR4.PKGADD] + arglist + \ trans_val.get(CONTENTS) elif trans_val.get(ACTION) == 'uninstall': self.check_cancel_event() self.logger.info("Uninstalling SVR4 packages") cmd = [AbstractSVR4.PKGRM] + arglist + \ trans_val.get(CONTENTS) else: self.logger.warning("Transfer action, %s, is not valid" % trans_val.get(ACTION)) self.check_cancel_event() continue if self.dry_run: self.logger.debug("Would execute the following transfer " "command: %s" % cmd) else: self.logger.debug("Executing the following transfer " "command: %s" % cmd) self.check_cancel_event() pkg_proc = Popen(cmd, shell=False, stdout=Popen.PIPE, stderr=Popen.STDOUT) while 1: self.check_cancel_event() pkgoutput = pkg_proc.stdout.readline() if not pkgoutput: retcode = pkg_proc.poll() if retcode != 0: self.svr4_process = None raise OSError(retcode, "SVR4 transfer error while " "adding packages") break pkgoutput = pkgoutput[:-1] if not pkgoutput.strip(): continue self.logger.debug("%s", pkgoutput) self.svr4_process = None finally: if self.pmon: self.pmon.done = True self.pmon.wait() self.pmon = None
def _transfer(self): '''Method to transfer from the source to the destination''' if self.give_progress: # Start up the ProgressMon to report progress # while the actual transfer is taking place. self.pmon = ProgressMon(logger=self.logger) # Note: startmonitor assumes there is another thread creating a # file system. If this is not the case (as may be when testing # this module in abnormal conditions), startmonitor will hang. # Just create the self.dst as a directory in this case. self.pmon.startmonitor(self.dst, self.total_size, 0, 100) # Perform the transfer specific operations. try: for trans_val in self._transfer_list: # Get the arguments for the transfer process arglist = trans_val.get(SVR4_ARGS).split(' ') # Parse the components to determine the transfer action if trans_val.get(ACTION) == 'install': self.check_cancel_event() self.logger.info("Installing SVR4 packages") cmd = [AbstractSVR4.PKGADD] + arglist + \ trans_val.get(CONTENTS) elif trans_val.get(ACTION) == 'uninstall': self.check_cancel_event() self.logger.info("Uninstalling SVR4 packages") cmd = [AbstractSVR4.PKGRM] + arglist + \ trans_val.get(CONTENTS) else: self.logger.warning("Transfer action, %s, is not valid" % trans_val.get(ACTION)) self.check_cancel_event() continue if self.dry_run: self.logger.debug("Would execute the following transfer " "command: %s" % cmd) else: self.logger.debug("Executing the following transfer " "command: %s" % cmd) self.check_cancel_event() pkg_proc = Popen(cmd, shell=False, stdout=Popen.PIPE, stderr=Popen.STDOUT) while 1: self.check_cancel_event() pkgoutput = pkg_proc.stdout.readline() if not pkgoutput: retcode = pkg_proc.poll() if retcode != 0: self.svr4_process = None raise OSError( retcode, "SVR4 transfer error while " "adding packages") break pkgoutput = pkgoutput[:-1] if not pkgoutput.strip(): continue self.logger.debug("%s", pkgoutput) self.svr4_process = None finally: if self.pmon: self.pmon.done = True self.pmon.wait() self.pmon = None