def stop_scan_cleanup( self, kbdb: BaseDB, scan_id: str, ovas_process: psutil.Popen, # pylint: disable=arguments-differ ): """Set a key in redis to indicate the wrapper is stopped. It is done through redis because it is a new multiprocess instance and it is not possible to reach the variables of the grandchild process. Indirectly sends SIGUSR1 to the running openvas scan process via an invocation of openvas with the --scan-stop option to stop it.""" if kbdb: # Set stop flag in redis kbdb.stop_scan(scan_id) # Check if openvas is running if ovas_process.is_running(): # Cleaning in case of Zombie Process if ovas_process.status() == psutil.STATUS_ZOMBIE: logger.debug( '%s: Process with PID %s is a Zombie process.' ' Cleaning up...', scan_id, ovas_process.pid, ) ovas_process.wait() # Stop openvas process and wait until it stopped else: can_stop_scan = Openvas.stop_scan( scan_id, not self.is_running_as_root and self.sudo_available, ) if not can_stop_scan: logger.debug( 'Not possible to stop scan process: %s.', ovas_process, ) return logger.debug('Stopping process: %s', ovas_process) while ovas_process.is_running(): if ovas_process.status() == psutil.STATUS_ZOMBIE: ovas_process.wait() else: time.sleep(0.1) else: logger.debug( "%s: Process with PID %s already stopped", scan_id, ovas_process.pid, ) # Clean redis db for scan_db in kbdb.get_scan_databases(): self.main_db.release_database(scan_db)
def run_subprocess( command: Sequence[str], shell: bool = False, doexec: bool = True, monitor_log: logging.Logger = None, monitor_interval: int = 5, tile_id: str = None, ) -> bool: """Runs a subprocess with `psutil.Popen` and monitors its status. If subprocess returns non-zero exit code, STDERR is sent to the log. :param command: The command to execute. :param shell: Passed to `psutil.Popen`. Defaults to False. :param doexec: Do execute the subprocess or just print out the concatenated command. Used for testing. :param monitor_log: A resource logger, which is returned by :func:`~.recorder.configure_resource_logging`. :param monitor_interval: How often query the resource usage of the process? In seconds. :param tile_id: Used for monitoring only. :return: True/False on success/failure """ if doexec: cmd = " ".join(command) if shell: command = cmd log.debug(f"Tile {tile_id} command: {command}") start = time() popen = Popen(command, shell=shell, stderr=PIPE, stdout=PIPE) if monitor_log is not None: while True: sleep(monitor_interval) monitor_log.info( f"{tile_id}\t{popen.pid}\t{popen.cpu_times().user}" f"\t{popen.memory_info().rss}") if (not popen.is_running() or popen.status() == STATUS_ZOMBIE or popen.status() == STATUS_SLEEPING): break stdout, stderr = popen.communicate() err = stderr.decode(getpreferredencoding(do_setlocale=True)) out = stdout.decode(getpreferredencoding(do_setlocale=True)) finish = time() log.info(f"Tile {tile_id} finished in {(finish-start)/60} minutes") if popen.returncode != 0: log.error( f"Tile {tile_id} process returned with {popen.returncode}") else: log.debug( f"Tile {tile_id} process returned with {popen.returncode}") log.debug(f"Tile {tile_id} stdout: \n{out}") log.debug(f"Tile {tile_id} stderr: \n{err}") return True if popen.returncode == 0 else False else: log.debug(f"Tile {tile_id} not executing {command}") return True
def is_openvas_process_alive(openvas_process: psutil.Popen) -> bool: try: if openvas_process.status() == psutil.STATUS_ZOMBIE: logger.debug("Process is a Zombie, waiting for it to clean up") openvas_process.wait() except psutil.NoSuchProcess: return False return openvas_process.is_running()