diff --git a/app/classes/shared/cmd.py b/app/classes/shared/cmd.py index 06f29434..1099f3d5 100644 --- a/app/classes/shared/cmd.py +++ b/app/classes/shared/cmd.py @@ -9,7 +9,6 @@ logger = logging.getLogger(__name__) from app.classes.shared.console import console from app.classes.shared.helpers import helper -from app.classes.shared.tasks import tasks_manager from app.classes.web.websocket_helper import websocket_helper try: @@ -26,6 +25,10 @@ class MainPrompt(cmd.Cmd): # overrides the default Prompt prompt = "Crafty Controller v{} > ".format(helper.get_version_string()) + def __init__(self, tasks_manager): + super().__init__() + self.tasks_manager = tasks_manager + @staticmethod def emptyline(): pass @@ -48,7 +51,7 @@ class MainPrompt(cmd.Cmd): self._clean_shutdown() console.info('Waiting for main thread to stop') while True: - if tasks_manager.get_main_thread_run_status(): + if self.tasks_manager.get_main_thread_run_status(): sys.exit(0) time.sleep(1) diff --git a/app/classes/shared/controller.py b/app/classes/shared/controller.py index cf849c40..3e0c3b1b 100644 --- a/app/classes/shared/controller.py +++ b/app/classes/shared/controller.py @@ -135,7 +135,6 @@ class Controller: def stop_all_servers(self): servers = self.list_running_servers() - print(servers) logger.info("Found {} running server(s)".format(len(servers))) console.info("Found {} running server(s)".format(len(servers))) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 6f5c27ec..421e2437 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -19,7 +19,7 @@ logger = logging.getLogger(__name__) try: - from pexpect.popen_spawn import PopenSpawn + import pexpect except ModuleNotFoundError as e: logger.critical("Import Error: Unable to load {} module".format(e, e.name)) @@ -120,47 +120,24 @@ class Server: console.info("Launching Server {} with command {}".format(self.name, self.server_command)) if os.name == "nt": - logger.info("Windows Detected - launching cmd") + logger.info("Windows Detected") self.server_command = self.server_command.replace('\\', '/') - logging.info("Opening CMD prompt") - self.process = pexpect.popen_spawn.PopenSpawn('cmd \r\n', timeout=None, encoding=None) - - drive_letter = self.server_path[:1] - - if drive_letter.lower() != "c": - logger.info("Server is not on the C drive, changing drive letter to {}:".format(drive_letter)) - self.process.send("{}:\r\n".format(drive_letter)) - - logging.info("changing directories to {}".format(self.server_path.replace('\\', '/'))) - self.process.send('cd {} \r\n'.format(self.server_path.replace('\\', '/'))) - logging.info("Sending command {} to CMD".format(self.server_command)) - self.process.send(self.server_command + "\r\n") - - self.is_crashed = False else: - logger.info("Linux Detected - launching Bash") - self.process = pexpect.popen_spawn.PopenSpawn('/bin/bash \n', timeout=None, encoding=None) + logger.info("Linux Detected") - logger.info("Changing directory to {}".format(self.server_path)) - self.process.send('cd {} \n'.format(self.server_path)) - - logger.info("Sending server start command: {} to shell".format(self.server_command)) - self.process.send(self.server_command + '\n') - self.is_crashed = False + logger.info("Starting server in {p} with command: {c}".format(p=self.server_path, c=self.server_command)) + self.process = pexpect.spawn(self.server_command, cwd=self.server_path, timeout=None, encoding=None) + self.is_crashed = False ts = time.time() self.start_time = str(datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')) if psutil.pid_exists(self.process.pid): - parent = psutil.Process(self.process.pid) - time.sleep(.5) - children = parent.children(recursive=True) - for c in children: - self.PID = c.pid - logger.info("Server {} running with PID {}".format(self.name, self.PID)) - console.info("Server {} running with PID {}".format(self.name, self.PID)) - self.is_crashed = False - stats.record_stats() + self.PID = self.process.pid + logger.info("Server {} running with PID {}".format(self.name, self.PID)) + console.info("Server {} running with PID {}".format(self.name, self.PID)) + self.is_crashed = False + stats.record_stats() else: logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.PID)) console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.PID)) @@ -201,13 +178,13 @@ class Server: if x >= 30: logger.info("Server {} is still running - Forcing the process down".format(server_name)) console.info("Server {} is still running - Forcing the process down".format(server_name)) - self.killpid(server_pid) + self.process.terminate(force=True) logger.info("Stopped Server {} with PID {}".format(server_name, server_pid)) console.info("Stopped Server {} with PID {}".format(server_name, server_pid)) else: - self.killpid(self.PID) + self.process.terminate(force=True) # massive resetting of variables self.cleanup_server_object() @@ -240,10 +217,15 @@ class Server: return running try: - running = psutil.pid_exists(self.PID) + alive = self.process.isalive() + if type(alive) is not bool: + self.last_rc = alive + running = False + else: + running = alive except Exception as e: - logger.error("Unable to find if server PID exists: {}".format(self.PID)) + logger.error("Unable to find if server PID exists: {}".format(self.PID), exc_info=True) pass return running diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index f1a060c3..a6405753 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -174,9 +174,4 @@ class TasksManager: def log_watcher(self): console.debug('in log_watcher') helper.check_for_old_logs(db_helper) - schedule.every(6).hours.do(lambda: helper.check_for_old_logs(db_helper)) - - - - -tasks_manager = TasksManager() + schedule.every(6).hours.do(lambda: helper.check_for_old_logs(db_helper)) \ No newline at end of file diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 8241c7f3..0ec639d1 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -324,7 +324,7 @@ class PanelHandler(BaseHandler): user_data = json.loads(self.get_secure_cookie("user_data")) exec_user = db_helper.get_user(user_data['user_id']) - if not exec_user.superuser: + if not exec_user['superuser']: self.redirect("/panel/error?error=Unauthorized access: not superuser") return False elif server_id is None: @@ -569,4 +569,4 @@ class PanelHandler(BaseHandler): "Edited role {} (RID:{}) with servers {}".format(role_name, role_id, servers), server_id=0, source_ip=self.get_remote_ip()) - self.redirect("/panel/panel_config") \ No newline at end of file + self.redirect("/panel/panel_config") diff --git a/app/config/version.json b/app/config/version.json index 35afb1e0..67dbc605 100644 --- a/app/config/version.json +++ b/app/config/version.json @@ -1,5 +1,5 @@ { "major": 4, "minor": 0, - "sub": "Alpha 2" -} \ No newline at end of file + "sub": "Alpha 2+noshell" +} diff --git a/main.py b/main.py index 7ef4b02f..d905f842 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,7 @@ from app.classes.shared.helpers import helper from app.classes.shared.models import installer from app.classes.shared.controller import controller +from app.classes.shared.tasks import TasksManager from app.classes.shared.cmd import MainPrompt @@ -68,6 +69,11 @@ if __name__ == '__main__': help="Sets logging level to debug." ) + parser.add_argument('-d', '--daemon', + action='store_true', + help="Runs Crafty in daemon mode (no prompt)" + ) + args = parser.parse_args() helper.ensure_logging_setup() @@ -91,15 +97,6 @@ if __name__ == '__main__': installer.create_tables() installer.default_settings() - # now the tables are created, we can load the tasks_manger - from app.classes.shared.tasks import tasks_manager - - tasks_manager.start_webserver() - tasks_manager.start_scheduler() - - # slowing down reporting just for a 1/2 second so messages look cleaner - time.sleep(.5) - # init servers logger.info("Initializing all servers defined") console.info("Initializing all servers defined") @@ -107,6 +104,15 @@ if __name__ == '__main__': controller.init_all_servers() servers = controller.list_defined_servers() + # now the tables are created, we can load the tasks_manger + tasks_manager = TasksManager() + + tasks_manager.start_webserver() + tasks_manager.start_scheduler() + + # slowing down reporting just for a 1/2 second so messages look cleaner + time.sleep(.5) + # start stats logging tasks_manager.start_stats_recording() @@ -116,11 +122,24 @@ if __name__ == '__main__': # this should always be last tasks_manager.start_main_kill_switch_watcher() - Crafty = MainPrompt() - Crafty.cmdloop() - - # our main loop - eventually a shell - # while True: - # if tasks_manager.get_main_thread_run_status(): - # sys.exit(0) - # time.sleep(1) + Crafty = MainPrompt(tasks_manager) + if not args.daemon: + Crafty.cmdloop() + else: + print("Crafty started in daemon mode, no shell will be printed") + while True: + try: + if tasks_manager.get_main_thread_run_status(): + break + time.sleep(1) + except KeyboardInterrupt: + logger.info("Recieved SIGTERM, stopping Crafty") + break + + logger.info("Stopping all server daemons / threads") + console.info("Stopping all server daemons / threads - This may take a few seconds") + Crafty._clean_shutdown() + while True: + if tasks_manager.get_main_thread_run_status(): + sys.exit(0) + time.sleep(1)