oginstaller get oglives list from server or return default value
parent
36b8ee0250
commit
ee6c7c2003
|
@ -3,7 +3,6 @@ import os
|
|||
from git import Repo
|
||||
import subprocess # Importar el módulo subprocess
|
||||
import requests # Importar el módulo requests
|
||||
from tqdm import tqdm # Importar tqdm para la barra de progreso
|
||||
import time # Importar time para simular el progreso
|
||||
import threading # Importar threading para leer el log en tiempo real
|
||||
import socket
|
||||
|
@ -64,6 +63,25 @@ def get_default_ip():
|
|||
print(f"Error al obtener la IP por defecto: {e}")
|
||||
return "192.168.2.2" # Valor por defecto
|
||||
|
||||
def get_oglive_list():
|
||||
"""Obtiene la lista de valores de oglives desde la URL."""
|
||||
try:
|
||||
# Realizar la solicitud HTTP
|
||||
response = requests.get("https://ognproject.evlt.uma.es/oglive/", timeout=10)
|
||||
response.raise_for_status() # Lanza una excepción si la respuesta no es 200 OK
|
||||
|
||||
# Extraer los enlaces del contenido HTML
|
||||
from bs4 import BeautifulSoup
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
links = [a["href"] for a in soup.find_all("a", href=True) if "ogLive" in a["href"]]
|
||||
|
||||
# Ordenar los enlaces por la parte después del guion bajo
|
||||
sorted_links = sorted(links, key=lambda x: x.split("_")[1] if "_" in x else x, reverse=True)
|
||||
return sorted_links
|
||||
except Exception as e:
|
||||
print(f"Error al obtener la lista de oglives: {e}")
|
||||
return [] # Devolver una lista vacía en caso de error
|
||||
|
||||
# Variable global para la IP por defecto
|
||||
DEFAULT_IP = get_default_ip()
|
||||
|
||||
|
@ -150,7 +168,7 @@ class OgGuiForm(ComponentForm):
|
|||
|
||||
def configure_fields(self):
|
||||
self.fields["ogcoreUrl"] = {"widget": self.add(npyscreen.TitleText, name="URL API OgCore:", value="https://{}:8443".format(DEFAULT_IP))}
|
||||
self.fields["ogmercureUrl"] = {"widget": self.add(npyscreen.TitleText, name="Mercure URL:", value="https://{} gr:3000/.well-known/mercure".format(DEFAULT_IP))}
|
||||
self.fields["ogmercureUrl"] = {"widget": self.add(npyscreen.TitleText, name="Mercure URL:", value="https://{}:3000/.well-known/mercure".format(DEFAULT_IP))}
|
||||
|
||||
class OgDhcpForm(ComponentForm):
|
||||
component_name = "ogdhcp"
|
||||
|
@ -217,13 +235,57 @@ class OgBootForm(ComponentForm):
|
|||
component_name = "ogboot"
|
||||
|
||||
def configure_fields(self):
|
||||
# Obtener la lista de oglives
|
||||
oglives = get_oglive_list()
|
||||
if not oglives:
|
||||
oglives = ["https://ognproject.evlt.uma.es/oglive/ogLive-noble-6.8.0-31-generic-amd64-r20250116.538e3fa_20250120.iso"]
|
||||
npyscreen.notify_confirm("No se pudo obtener la lista de oglives. Usando un valor por defecto.", title="Error")
|
||||
|
||||
# Campo para seleccionar un oglive
|
||||
self.fields["ogliveUrl"] = {
|
||||
"widget": self.add(
|
||||
npyscreen.TitleSelectOne,
|
||||
name="Selecciona un OgLive:",
|
||||
values=oglives,
|
||||
scroll_exit=True,
|
||||
max_height=10 # Limitar la altura para listas largas
|
||||
)
|
||||
}
|
||||
|
||||
# Otros campos
|
||||
self.fields["ip"] = {"widget": self.add(npyscreen.TitleText, name="IP del servidor Boot:", value=DEFAULT_IP)}
|
||||
self.fields["port"] = {"widget": self.add(npyscreen.TitleText, name="Puerto Boot:", value="8082")}
|
||||
self.fields["ogcoreUrl"] = {"widget": self.add(npyscreen.TitleText, name="URL OgCore:", value=f"https://{DEFAULT_IP}:8443")}
|
||||
self.fields["ogliveUrl"] = {"widget": self.add(npyscreen.TitleText, name="URL OgLive:", value="https://ognproject.evlt.uma.es/oglive/ogLive-noble-6.8.0-31-generic-amd64-r20250116.538e3fa_20250120.iso")}
|
||||
self.fields["sambaUser"] = {"widget": self.add(npyscreen.TitleText, name="Usuario Samba:", value="opengnsys")}
|
||||
self.fields["sambaUserPass"] = {"widget": self.add(npyscreen.TitlePassword, name="Contraseña Samba:", value="og")}
|
||||
|
||||
def on_ok(self):
|
||||
# Obtener el oglive seleccionado
|
||||
selected_oglive_index = self.fields["ogliveUrl"]["widget"].value
|
||||
if selected_oglive_index:
|
||||
selected_oglive = self.fields["ogliveUrl"]["widget"].values[selected_oglive_index[0]]
|
||||
else:
|
||||
selected_oglive = None
|
||||
|
||||
# Guardar las configuraciones
|
||||
self.parentApp.configurations[self.component_name] = {
|
||||
"ogliveUrl": selected_oglive,
|
||||
"ip": self.fields["ip"]["widget"].value,
|
||||
"port": self.fields["port"]["widget"].value,
|
||||
"ogcoreUrl": self.fields["ogcoreUrl"]["widget"].value,
|
||||
"sambaUser": self.fields["sambaUser"]["widget"].value,
|
||||
"sambaUserPass": self.fields["sambaUserPass"]["widget"].value,
|
||||
}
|
||||
|
||||
# Continuar con el siguiente formulario
|
||||
self.parentApp.current_component_index += 1
|
||||
if self.parentApp.current_component_index < len(self.parentApp.selected_components):
|
||||
next_component = self.parentApp.selected_components[self.parentApp.current_component_index]
|
||||
self.parentApp.switchForm(next_component)
|
||||
else:
|
||||
self.parentApp.generate_debconf()
|
||||
self.parentApp.setNextForm(None)
|
||||
|
||||
class OgRepositoryForm(ComponentForm):
|
||||
component_name = "ogrepository"
|
||||
|
||||
|
@ -233,8 +295,50 @@ class OgRepositoryForm(ComponentForm):
|
|||
self.fields["sambaUser"] = {"widget": self.add(npyscreen.TitleText, name="Usuario Samba:", value="opengnsys")}
|
||||
self.fields["sambaUserPass"] = {"widget": self.add(npyscreen.TitlePassword, name="Contraseña Samba:", value="og")}
|
||||
|
||||
def install_components(components, selected_tag):
|
||||
"""Instala los componentes seleccionados usando el tag especificado."""
|
||||
class InstallationProgressForm(npyscreen.FormBaseNew):
|
||||
"""Formulario para mostrar el progreso de instalación y el log en tiempo real."""
|
||||
def create(self):
|
||||
# Crear la parte superior para el progreso de instalación
|
||||
self.progress_box = self.add(
|
||||
npyscreen.BoxTitle,
|
||||
name="Progreso de instalación",
|
||||
max_height=int(self.lines * 0.5), # Mitad superior
|
||||
scroll_exit=True
|
||||
)
|
||||
|
||||
# Crear la parte inferior para el log en tiempo real
|
||||
self.log_box = self.add(
|
||||
npyscreen.BoxTitle,
|
||||
name="Log en tiempo real",
|
||||
rely=int(self.lines * 0.5), # Mitad inferior
|
||||
scroll_exit=True
|
||||
)
|
||||
|
||||
def update_progress(self, message, current=0, total=0):
|
||||
"""Actualiza el progreso de instalación en la parte superior."""
|
||||
if total > 0:
|
||||
# Crear una barra de progreso personalizada
|
||||
progress_percentage = int((current / total) * 100)
|
||||
bar_length = 30 # Longitud de la barra
|
||||
filled_length = int(bar_length * current // total)
|
||||
bar = f"[{'=' * filled_length}{' ' * (bar_length - filled_length)}] {progress_percentage}%"
|
||||
self.progress_box.values.append(bar)
|
||||
self.progress_box.values.append(message)
|
||||
self.progress_box.display()
|
||||
|
||||
def update_log(self, log_lines):
|
||||
"""Actualiza el log en tiempo real en la parte inferior."""
|
||||
# Limpiar caracteres especiales de las líneas del log
|
||||
cleaned_lines = [self._clean_text(line) for line in log_lines]
|
||||
self.log_box.values = cleaned_lines[-self.log_box.height:] # Mostrar solo las últimas líneas
|
||||
self.log_box.display()
|
||||
|
||||
def _clean_text(self, text):
|
||||
"""Elimina caracteres especiales o no imprimibles del texto."""
|
||||
return ''.join(c if c.isprintable() else '?' for c in text)
|
||||
|
||||
def install_components_with_ui(form, components, selected_tag):
|
||||
"""Instala los componentes seleccionados mostrando el progreso y el log en tiempo real."""
|
||||
log_file_path = os.path.join(CONFIGS_DIR, "installation.log")
|
||||
installed_packages = [] # Lista de paquetes instalados correctamente
|
||||
failed_packages = [] # Lista de paquetes que fallaron
|
||||
|
@ -245,61 +349,44 @@ def install_components(components, selected_tag):
|
|||
try:
|
||||
with open(log_file_path, "w") as log_file:
|
||||
total_packages = len(components)
|
||||
|
||||
# Hilo para leer el log en tiempo real
|
||||
def tail_log():
|
||||
with open(log_file_path, "r") as log_reader:
|
||||
log_reader.seek(0, os.SEEK_END) # Ir al final del archivo
|
||||
while True:
|
||||
line = log_reader.readline()
|
||||
if line:
|
||||
form.update_log(log_reader.readlines())
|
||||
time.sleep(0.1)
|
||||
|
||||
log_thread = threading.Thread(target=tail_log, daemon=True)
|
||||
log_thread.start()
|
||||
|
||||
for index, package in enumerate(components, start=1):
|
||||
# Mostrar solo el progreso en la terminal
|
||||
print(f"Instalando paquete {index}/{total_packages}: {package}")
|
||||
log_file.write(f"\n--- Instalando paquete {index}/{total_packages}: {package} ---\n")
|
||||
# Actualizar el progreso en la parte superior con barra de progreso
|
||||
form.update_progress(f"Instalando paquete {index}/{total_packages}: {package}", current=index, total=total_packages)
|
||||
|
||||
# Crear una barra de progreso para el paquete
|
||||
with tqdm(total=100, desc=f"Instalando {package}", unit="%", ncols=80) as progress_bar:
|
||||
# Ejecutar el comando y redirigir toda la salida al archivo de registro
|
||||
install_command = f"DEBIAN_FRONTEND=noninteractive apt-get install -y {package}"
|
||||
process = subprocess.Popen(
|
||||
install_command, shell=True, text=True, stdout=log_file, stderr=log_file
|
||||
)
|
||||
install_command = f"DEBIAN_FRONTEND=noninteractive apt-get install -y {package}"
|
||||
process = subprocess.Popen(
|
||||
install_command, shell=True, text=True, stdout=log_file, stderr=log_file
|
||||
)
|
||||
|
||||
# Función para leer el log en tiempo real y actualizar la barra de progreso
|
||||
def monitor_log():
|
||||
with open(log_file_path, "r") as log_reader:
|
||||
log_reader.seek(0, os.SEEK_END) # Ir al final del archivo
|
||||
while process.poll() is None:
|
||||
line = log_reader.readline()
|
||||
if not line:
|
||||
time.sleep(0.1) # Esperar si no hay nuevas líneas
|
||||
continue
|
||||
# Actualizar la barra de progreso según las cadenas detectadas
|
||||
if "Se necesita descargar" in line:
|
||||
progress_bar.n = 10
|
||||
elif "Preparando para desempaquetar" in line:
|
||||
progress_bar.n = 30
|
||||
elif "Configurando" in line and package in line:
|
||||
progress_bar.n = 40
|
||||
progress_bar.refresh()
|
||||
# Esperar a que el proceso de instalación termine
|
||||
process.wait()
|
||||
|
||||
# Iniciar el hilo para monitorear el log
|
||||
log_thread = threading.Thread(target=monitor_log, daemon=True)
|
||||
log_thread.start()
|
||||
|
||||
# Esperar a que el proceso de instalación termine
|
||||
process.wait()
|
||||
|
||||
# Completar la barra de progreso
|
||||
progress_bar.n = 100
|
||||
progress_bar.refresh()
|
||||
|
||||
# Registrar errores en el archivo de registro
|
||||
if process.returncode != 0:
|
||||
error_message = f"Error al instalar el paquete {package}. Consulta el archivo de registro: {log_file_path}"
|
||||
print(error_message)
|
||||
log_file.write(f"\n{error_message}\n")
|
||||
failed_packages.append(package) # Agregar a la lista de fallos
|
||||
else:
|
||||
log_file.write(f"Paquete {package} instalado correctamente.\n")
|
||||
installed_packages.append(package) # Agregar a la lista de éxitos
|
||||
# Registrar errores en el archivo de registro
|
||||
if process.returncode != 0:
|
||||
error_message = f"Error al instalar el paquete {package}. Consulta el archivo de registro: {log_file_path}"
|
||||
form.update_progress(error_message)
|
||||
failed_packages.append(package) # Agregar a la lista de fallos
|
||||
else:
|
||||
form.update_progress(f"Paquete {package} instalado correctamente.")
|
||||
installed_packages.append(package) # Agregar a la lista de éxitos
|
||||
except Exception as e:
|
||||
with open(log_file_path, "a") as log_file:
|
||||
log_file.write(f"\nError durante la instalación de los paquetes: {e}\n")
|
||||
failed_packages.append("Error general durante la instalación")
|
||||
form.update_progress(f"Error durante la instalación: {e}")
|
||||
failed_packages.append("Error general durante la instalación")
|
||||
|
||||
# Registrar el tiempo de finalización
|
||||
end_time = time.time()
|
||||
|
@ -322,6 +409,9 @@ def install_components(components, selected_tag):
|
|||
# Mostrar el resumen en una ventana emergente
|
||||
npyscreen.notify_confirm(summary, title="Resumen de la instalación", wide=True)
|
||||
|
||||
# Mostrar el resumen en la parte superior (opcional, si quieres mantenerlo en el formulario)
|
||||
form.update_progress(summary)
|
||||
|
||||
class MyApp(npyscreen.NPSAppManaged):
|
||||
def onStart(self):
|
||||
self.addForm("MAIN", ComponentSelectionForm)
|
||||
|
@ -330,6 +420,7 @@ class MyApp(npyscreen.NPSAppManaged):
|
|||
self.addForm("ogdhcp", OgDhcpForm)
|
||||
self.addForm("ogboot", OgBootForm)
|
||||
self.addForm("ogrepository", OgRepositoryForm)
|
||||
self.addForm("INSTALLATION_PROGRESS", InstallationProgressForm)
|
||||
|
||||
def generate_debconf(self):
|
||||
# Comprobar si la clave pública ya existe
|
||||
|
@ -387,8 +478,10 @@ class MyApp(npyscreen.NPSAppManaged):
|
|||
# Silenciar el mensaje de configuraciones guardadas
|
||||
# print(f"\nConfiguraciones guardadas en: {output_file}")
|
||||
|
||||
# Llamar a la función de instalación después de generar las configuraciones
|
||||
install_components(self.selected_components, self.selected_tag)
|
||||
# Llamar al formulario de progreso
|
||||
form = self.getForm("INSTALLATION_PROGRESS")
|
||||
self.switchForm("INSTALLATION_PROGRESS")
|
||||
install_components_with_ui(form, self.selected_components, self.selected_tag)
|
||||
|
||||
if __name__ == "__main__":
|
||||
MyApp().run()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
GitPython
|
||||
npyscreen
|
||||
requests
|
||||
tqdm
|
||||
bs4
|
||||
|
|
Loading…
Reference in New Issue