diff --git a/non_graf_installer/python-installer/oginstaller-v3.py b/non_graf_installer/python-installer/oginstaller-v3.py index 8a84932..9707f0b 100644 --- a/non_graf_installer/python-installer/oginstaller-v3.py +++ b/non_graf_installer/python-installer/oginstaller-v3.py @@ -7,12 +7,28 @@ import time # Importar time para simular el progreso import threading # Importar threading para leer el log en tiempo real import socket import sys # Importar sys para leer los argumentos del script +import logging # Importar el módulo logging CONFIGS_DIR = "/tmp/oginstall" os.makedirs(CONFIGS_DIR, exist_ok=True) REPO_URL = "https://ognproject.evlt.uma.es/gitea/opengnsys/ogcore.git" +# Configurar logging +try: + if not os.path.exists(CONFIGS_DIR): + os.makedirs(CONFIGS_DIR, exist_ok=True) # Crear el directorio si no existe + LOG_FILE = os.path.join(CONFIGS_DIR, "debug.log") + logging.basicConfig( + filename=LOG_FILE, + level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s", + ) + logging.debug("Inicio del programa") # Mensaje inicial para verificar que el log se crea +except Exception as e: + print(f"[ERROR] No se pudo configurar el logging: {e}") + print(f"[ERROR] Verifica los permisos del directorio: {CONFIGS_DIR}") + exit(1) # Salir si no se puede configurar el logging def get_network_interfaces(): """Obtiene los nombres de las interfaces de red disponibles en el servidor.""" @@ -30,20 +46,48 @@ def get_network_interfaces(): def get_available_versions(): """Obtiene la lista de versiones desde el archivo JSON remoto.""" try: - # Determinar la URL según el argumento recibido - if len(sys.argv) > 1 and sys.argv[1].lower() == "devel": - url = "https://ognproject.evlt.uma.es/debian-opengnsys/versions-dev.json" - elif len(sys.argv) > 1 and sys.argv[1].lower() == "nightly": - return None # No hay versiones disponibles para nightly + # Validar si se pasa un argumento + if len(sys.argv) > 1: + arg = sys.argv[1].strip().lower() + logging.debug(f"Argumento recibido: {arg}") # Usar logging en lugar de print + + # Validar explícitamente los valores permitidos + if arg == "devel": + url = "https://ognproject.evlt.uma.es/debian-opengnsys/versions-dev.json" + elif arg == "nightly": + logging.debug("No hay versiones disponibles para nightly.") + raise ValueError("No hay versiones disponibles para nightly.") + else: + logging.debug(f"Argumento no reconocido: {arg}. Usando versiones de producción.") + url = "https://ognproject.evlt.uma.es/debian-opengnsys/versions-prod.json" else: + logging.debug("No se pasó ningún argumento. Usando versiones de producción.") url = "https://ognproject.evlt.uma.es/debian-opengnsys/versions-prod.json" + + # Realizar la solicitud HTTP + logging.debug(f"Realizando solicitud HTTP a: {url}") response = requests.get(url, timeout=10) response.raise_for_status() # Lanza una excepción si la respuesta no es 200 OK - data = response.json() - return data.get("versions", []) - except requests.RequestException: - # Silenciar errores y devolver una lista vacía - return [] + + # Registrar el contenido de la respuesta para depuración + logging.debug(f"Contenido de la respuesta: {response.text}") + + # Intentar analizar el JSON + try: + data = response.json() + except ValueError as e: + logging.error(f"Error al analizar el JSON: {e}") + raise RuntimeError(f"El contenido de la respuesta no es un JSON válido: {e}") + + # Validar que el JSON contiene la clave "versions" + versions = data.get("versions", []) + if not versions: + raise ValueError("La lista de versiones está vacía o no existe la clave 'versions'.") + logging.debug(f"Versiones obtenidas: {versions}") + return versions + except (requests.RequestException, ValueError, RuntimeError) as e: + logging.error(f"No se pudo obtener la lista de versiones: {e}") + raise RuntimeError(f"Error crítico: {e}") # Lanzar una excepción crítica def get_default_ip(): """Obtiene la IP asociada a la interfaz por defecto del servidor.""" @@ -105,6 +149,23 @@ class ComponentSelectionForm(npyscreen.ActionForm): values=self.versions, scroll_exit=True) self.tag.value = [0] # Marcar "latest" (o la primera opción) por defecto + # Agregar un cuadro de texto para mostrar el log + self.log_box = self.add(npyscreen.BoxTitle, name="Log de depuración", max_height=10, scroll_exit=True) + + def update_log(self): + """Actualiza el cuadro de texto con el contenido del archivo de log.""" + try: + with open(LOG_FILE, "r") as log_file: + lines = log_file.readlines() + self.log_box.values = lines[-self.log_box.height:] # Mostrar solo las últimas líneas + self.log_box.display() + except Exception as e: + logging.error(f"Error al leer el archivo de log: {e}") + + def while_waiting(self): + """Actualizar el log mientras se espera interacción del usuario.""" + self.update_log() + def on_ok(self): npyscreen.blank_terminal() selected_components = [self.components.values[i].lower() for i in self.components.value] # Convertir a minúsculas @@ -369,7 +430,7 @@ def install_components_with_ui(form, components, selected_tag): while True: line = log_reader.readline() if line: - form.update_log(log_reader.readlines()) + form.update_log([line]) # Actualizar el log línea por línea time.sleep(0.1) log_thread = threading.Thread(target=tail_log, daemon=True) @@ -528,9 +589,19 @@ class MyApp(npyscreen.NPSAppManaged): if __name__ == "__main__": try: + logging.debug("Ejecutando la aplicación principal") MyApp().run() + except RuntimeError as e: + print(f"[ERROR] {e}") + logging.error(f"[ERROR] {e}") + exit(1) # Salir con un código de error + except KeyboardInterrupt: + logging.warning("El programa fue interrumpido por el usuario (Ctrl-C)") except Exception as e: - print(f"[ERROR] Ocurrió un error: {e}") + logging.error(f"[ERROR] Ocurrió un error inesperado: {e}") finally: + # Asegurarse de que todos los mensajes de log se escriban en el archivo + logging.debug("Finalizando el programa y cerrando el log") + logging.shutdown() # Restaurar el terminal al estado normal npyscreen.wrapper_basic(lambda stdscr: None)