def run_vadere(self): ret = 255 logger.info("Run vadere in container") try: self.build_and_start_vadere_only() ret = 0 # all good if we reached this. except RuntimeError as cErr: logger.error(cErr) ret = 255 except KeyboardInterrupt as K: logger.info("KeyboardInterrupt detected. Shutdown. ") ret = 128 + signal.SIGINT raise finally: # always stop container and delete if no error occurred err_state = ret logger.debug(f"cleanup with ret={ret}") # TODO: does not work # if self.vadere_runner is not None: # self.vadere_runner.container_cleanup(has_error_state=err_state) # self.opp_runner.container_cleanup(has_error_state=err_state) return ret
def run_simulation_omnet_sumo(self): ret = 255 # fail self.build_opp_runner() try: sumo_args = self.ns["sumo_args"] if self.ns["create_sumo_container"]: self.build_sumo_runner() self.sumo_runner.single_launcher( traci_port=sumo_args.get_value("--port"), bind=sumo_args.get_value("--bind"), ) if self.ns["override-host-config"]: self.ns["opp_args"].add_override( f"--sumo-host={self.sumo_runner.name}:{sumo_args.get_value('--port')}" ) # start OMNeT++ container and attach to it logger.info(f"start simulation {self.ns['run_name']} ...") opp_ret = self.opp_runner.exec_opp_run( arg_list=self.ns["opp_args"], result_dir=self.ns["result_dir"], experiment_label=self.ns["experiment_label"], run_args_override={}, ) ret = opp_ret["StatusCode"] if ret != 0: raise RuntimeError( f"OMNeT++ container exited with StatusCode '{ret}'") if self.sumo_runner is not None: try: self.sumo_runner.container.wait(timeout=600) except ReadTimeout: logger.error( f"Timeout (60s) reached while waiting for sumo container to finished" ) ret = 255 except RuntimeError as cErr: logger.error(cErr) ret = 255 except KeyboardInterrupt as K: logger.info("KeyboardInterrupt detected. Shutdown. ") ret = 128 + signal.SIGINT raise finally: # always stop container and delete if no error occurred err_state = ret != 0 logger.debug(f"cleanup with ret={ret}") if self.sumo_runner is not None: self.sumo_runner.container_cleanup(has_error_state=err_state) self.opp_runner.container_cleanup(has_error_state=err_state) return ret
def run_simulation_vadere_ctl(self): ret = 255 logger.info( "Control vadere without omnetpp. Client: controller, server: vadere, port: 9999" ) output_dir = os.path.join( os.getcwd(), f"results/vadere_controlled_{self.ns['experiment_label']}/vadere.d", ) os.makedirs(output_dir, exist_ok=True) self.build_control_runner() try: if self.ns["create_vadere_container"]: self.build_and_start_vadere_runner(port=9999, output_dir=output_dir) logger.info(f"start simulation {self.ns['run_name']} ...") ctl_ret = self.exec_control_runner(mode="client") ret = ctl_ret["StatusCode"] if ret != 0: raise RuntimeError( f"Control container exited with StatusCode '{ret}'") if self.vadere_runner is not None: try: self.vadere_runner.container.wait( timeout=self.ns["v_wait_timeout"]) except ReadTimeout: logger.error( f"Timeout ({self.ns['v_wait_timeout']}) reached while waiting for vadere container to finished" ) ret = 255 except RuntimeError as cErr: logger.error(cErr) ret = 255 except KeyboardInterrupt as K: logger.info("KeyboardInterrupt detected. Shutdown. ") ret = 128 + signal.SIGINT raise finally: # always stop container and delete if no error occurred err_state = ret != 0 logger.debug(f"cleanup with ret={ret}") if self.vadere_runner is not None: self.vadere_runner.container_cleanup(has_error_state=err_state) if self.control_runner is not None: self.control_runner.container_cleanup( has_error_state=err_state) return ret
def exec(self, cmd): scave_cmd = subprocess.Popen( cmd, cwd=os.path.curdir, shell=False, stdin=None, env=os.environ.copy(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) try: scave_cmd.wait() if scave_cmd.returncode != 0: logger.error(f"return code was {scave_cmd.returncode}") logger.error("command:") logger.error(f"{pp.pprint(cmd)}") print(scave_cmd.stdout.read().decode("utf-8")) print(scave_cmd.stderr.read().decode("utf-8")) else: logger.info(f"return code was {scave_cmd.returncode}") print(scave_cmd.stdout.read().decode("utf-8")) except subprocess.TimeoutExpired: logger.info(f"scavetool timeout reached. Kill it") os.kill(scave_cmd.pid, signal.SIGKILL) time.sleep(0.5) if scave_cmd.returncode is None: logger.error("scavetool still not dead after SIGKILL") raise logger.info(f"return code: {scave_cmd.returncode}")
def run_simulation_omnet_vadere(self): ret = 255 self.build_opp_runner() try: if self.ns["create_vadere_container"]: self.build_and_start_vadere_runner() if self.ns["override-host-config"]: self.ns["opp_args"].add( f"--vadere-host={self.vadere_runner.name}") # start OMNeT++ container and attach to it. logger.info(f"start simulation {self.ns['run_name']} ...") opp_ret = self.opp_runner.exec_opp_run( arg_list=self.ns["opp_args"], result_dir=self.ns["result_dir"], experiment_label=self.ns["experiment_label"], run_args_override={}, ) ret = opp_ret["StatusCode"] if ret != 0: raise RuntimeError( f"OMNeT++ container exited with StatusCode '{ret}'") if self.vadere_runner is not None: try: self.vadere_runner.container.wait( timeout=self.ns["v_wait_timeout"]) except ReadTimeout: logger.error( f"Timeout ({self.ns['v_wait_timeout']}) reached while waiting for vadere container to finished" ) ret = 255 except RuntimeError as cErr: logger.error(cErr) ret = 255 except KeyboardInterrupt as K: logger.info("KeyboardInterrupt detected. Shutdown. ") ret = 128 + signal.SIGINT raise finally: # always stop container and delete if no error occurred err_state = ret != 0 logger.debug(f"cleanup with ret={ret}") if self.vadere_runner is not None: self.vadere_runner.container_cleanup(has_error_state=err_state) self.opp_runner.container_cleanup(has_error_state=err_state) return ret
def load_df_from_scave( self, input_paths: Union[str, List[str]], scave_filter: Union[str, ScaveFilter] = None, recursive=True, converters=None, ) -> pd.DataFrame: """ Directly load data into Dataframe from *.vec and *.sca files without creating a csv file first. Use stdout of scavetool to create Dataframe. Helpful variant for automated scripts to reduce memory footprint. :param input_paths: List of glob patters search for *.vec and *.sca files :param scave_filter: (default: None) string based filter for scavetool see #print_filter_help for syntax :param recursive: (default: True) use recursive glob patterns :return: """ if type(input_paths) == str: input_paths = [input_paths] cmd = self.export_cmd( input_paths=input_paths, output="-", # read from stdout of scavetool scave_filter=scave_filter, recursive=recursive, options=["-F", "CSV-R"], ) print(" ".join(cmd)) stdout, stderr = self.read_stdout(cmd, encoding="") if stdout == b"": logger.error("error executing scavetool") print(str(stderr, encoding="utf8")) return pd.DataFrame() if converters is None: converters = ScaveConverter() # skip first row (container output) df = pd.read_csv( io.BytesIO(stdout), encoding="utf-8", converters=converters.get(), ) return df
def read_stdout(self, cmd, encoding="utf-8"): scave_cmd = subprocess.Popen( cmd, cwd=os.path.curdir, stdin=None, env=os.environ.copy(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) try: out, err = scave_cmd.communicate(timeout=self.timeout) if encoding != "": return out.decode(encoding), err.decode(encoding) else: return out, err except subprocess.TimeoutExpired: logger.error("Timout reached") scave_cmd.kill() return b"", io.StringIO("timeout reached")
def run(self, cmd, perform_cleanup=True, **run_args): err = False self.pull_images() try: self._container = self.create_container(cmd, **run_args) logger.info( f"start container {self._container.name} with {{detach: {self.detach}," f" remove: {self.cleanupPolicy}, journal_tag: {self.journal_tag}}}" ) self._container.start() if not self.detach: ret = self.wait() else: ret = {"Error": None, "StatusCode": 0} except (KeyboardInterrupt, SystemExit) as kInter: logger.warning( f"KeyboardInterrupt. Stop Container {self._container.name} ..." ) err = True # stop but do not delete container raise # re-raise so other parts can react to SIGINT except ReadTimeout as e: logger.error("wait timeout reached") err = True # stop but do not delete container raise RuntimeError(e) except docker.errors.APIError as e: logger.error(f"some API error occurred") logger.error(e.explanation) err = True # stop but do not delete container raise RuntimeError(e) except BaseException as e: logger.error(f"some error occurred") err = True # stop but do not delete container raise RuntimeError(e) finally: if not self.detach and perform_cleanup: self.container_cleanup(has_error_state=err) return ret
def wait(self, timeout=-1): if timeout > 0: ret = self._container.wait(timeout=timeout) else: ret = self._container.wait() if ret["StatusCode"] != 0: logger.error(f"{'#' * 80}") logger.error(f"{'#' * 80}") logger.error(f"Command returned {ret['StatusCode']}") if ( "log_config" in self.run_args and self.run_args["log_config"].type == LogConfig.types.JOURNALD ): logger.error( f"For full container output see: journalctl -b CONTAINER_TAG={self.journal_tag} --all" ) container_log = self._container.logs() if container_log != b"": logger.error(f'Container Log:\n {container_log.decode("utf-8")}') logger.error(f"{'#' * 80}") logger.error(f"{'#' * 80}") return ret