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 pull_images(self): try: self.client.images.get(self.image) except: logger.info( f"Docker image is missing. Try to pull {self.image} from repository." ) self.client.images.pull(repository=self.rep, tag=self.tag)
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 export_cmd( self, input_paths, output, scave_filter: Union[str, ScaveFilter] = None, recursive=True, options=None, print_selected_files=False, ): cmd = self._SCAVE_TOOL[:] cmd.append(self._EXPORT) cmd.append(self._OUTPUT) cmd.append(output) if scave_filter is not None: cmd.append(self._FILTER) if type(scave_filter) == str: cmd.append(self._config.escape(scave_filter)) else: cmd.append(scave_filter.build(escape=True)) if options is not None: cmd.extend(options) if len(input_paths) == 0: raise ValueError("no *.vec or *.sca files given.") # todo check if glob pattern exists first only then do this and the check opp_result_files = list() if any([_f for _f in input_paths if "*" in _f]): for file in input_paths: opp_result_files.extend(glob.glob(file, recursive=recursive)) else: opp_result_files.extend(input_paths) opp_result_files = [ f for f in opp_result_files if f.endswith(".vec") or f.endswith(".sca") ] if len(opp_result_files) == 0: raise ValueError("no opp input files selected.") log = "\n".join(opp_result_files) logger.info(f"found *.vec and *.sca:\n {log}") if print_selected_files: print("selected files:") for f in opp_result_files: print(f"\t{f}") cmd.extend(opp_result_files) return cmd
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 create_container(self, cmd="/init.sh", **run_args) -> Container: """ run container. If no command is given execute the default entry point '/init.sh' """ self.build_run_args(**run_args) # set name if given command = self.wrap_command(cmd) logger.info(f"{'#'*10} create container [image:{self.image}]") logger.debug(f"cmd: \n{pprint.pformat(command, indent=2)}") logger.debug(f"runargs: \n{pprint.pformat(self.run_args, indent=2)}") c: Container = self.client.containers.create( image=self.image, command=command, **self.run_args ) logger.info(f"{'#'*10} container created {c.name} [image:{self.image}]") return c
def run(self): logger.info("execute pre hooks") self.pre() logger.info("execute simulation") ret = self.dispatch_run() if ret != 0: raise RuntimeError("Error in Simulation") logger.info("execute post hooks") self.post() logger.info("done")
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(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 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 apply_reuse_policy(self): try: if self.name == "": return _container = self.client.containers.get(self.name) reuse_policy = self.reuse_policy if reuse_policy == DockerReuse.REMOVE_RUNNING: _container.stop() _container.remove() logger.info( f"stop and remove existing container with name '{self.name}'" ) elif reuse_policy == DockerReuse.REMOVE_STOPPED: if _container.status == "running": raise ValueError( f"container is still running but reuse policy is {reuse_policy}." ) _container.remove() logger.info(f"remove existing container with name '{self.name}'") elif ( reuse_policy == DockerReuse.REUSE_STOPPED or reuse_policy == DockerReuse.REUSE_RUNNING ): if _container.status == "running": _container.stop() logger.info(f"stop existing container with name '{self.name}'") elif reuse_policy == DockerReuse.NEW_ONLY: # container exists. --> error here raise ValueError( f"container exists with status: {_container.status}. Reuse policy {reuse_policy} " f"requires that container does not exist." ) else: raise ValueError(f"unknown reuse policy provided {reuse_policy}") except NotFound as notFoundErr: pass # ignore do nothing
def write(self, container_name, output: bytes, *args, **kwargs): logger.info(f"write output of {container_name} to {self.path}") os.makedirs(os.path.split(self.path)[0], exist_ok=True) with open(self.path, "w", encoding="utf-8") as log: log.write(output.decode("utf-8"))
def count_map(self): # lazy load data if needed if self._count_map is None: logger.info("load count map from HDF") self._count_map = self._count_p[self._count_slice, :] return self._count_map
def map(self): if self._map is None: logger.info("load map") self._map = self._map_p[self._map_slice, :] return self._map