oginstaller get oglives list from server or return default value
parent
36b8ee0250
commit
ee6c7c2003
|
@ -3,7 +3,6 @@ import os
|
||||||
from git import Repo
|
from git import Repo
|
||||||
import subprocess # Importar el módulo subprocess
|
import subprocess # Importar el módulo subprocess
|
||||||
import requests # Importar el módulo requests
|
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 time # Importar time para simular el progreso
|
||||||
import threading # Importar threading para leer el log en tiempo real
|
import threading # Importar threading para leer el log en tiempo real
|
||||||
import socket
|
import socket
|
||||||
|
@ -64,6 +63,25 @@ def get_default_ip():
|
||||||
print(f"Error al obtener la IP por defecto: {e}")
|
print(f"Error al obtener la IP por defecto: {e}")
|
||||||
return "192.168.2.2" # Valor por defecto
|
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
|
# Variable global para la IP por defecto
|
||||||
DEFAULT_IP = get_default_ip()
|
DEFAULT_IP = get_default_ip()
|
||||||
|
|
||||||
|
@ -150,7 +168,7 @@ class OgGuiForm(ComponentForm):
|
||||||
|
|
||||||
def configure_fields(self):
|
def configure_fields(self):
|
||||||
self.fields["ogcoreUrl"] = {"widget": self.add(npyscreen.TitleText, name="URL API OgCore:", value="https://{}:8443".format(DEFAULT_IP))}
|
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):
|
class OgDhcpForm(ComponentForm):
|
||||||
component_name = "ogdhcp"
|
component_name = "ogdhcp"
|
||||||
|
@ -217,13 +235,57 @@ class OgBootForm(ComponentForm):
|
||||||
component_name = "ogboot"
|
component_name = "ogboot"
|
||||||
|
|
||||||
def configure_fields(self):
|
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["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["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["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["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")}
|
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):
|
class OgRepositoryForm(ComponentForm):
|
||||||
component_name = "ogrepository"
|
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["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")}
|
self.fields["sambaUserPass"] = {"widget": self.add(npyscreen.TitlePassword, name="Contraseña Samba:", value="og")}
|
||||||
|
|
||||||
def install_components(components, selected_tag):
|
class InstallationProgressForm(npyscreen.FormBaseNew):
|
||||||
"""Instala los componentes seleccionados usando el tag especificado."""
|
"""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")
|
log_file_path = os.path.join(CONFIGS_DIR, "installation.log")
|
||||||
installed_packages = [] # Lista de paquetes instalados correctamente
|
installed_packages = [] # Lista de paquetes instalados correctamente
|
||||||
failed_packages = [] # Lista de paquetes que fallaron
|
failed_packages = [] # Lista de paquetes que fallaron
|
||||||
|
@ -245,60 +349,43 @@ def install_components(components, selected_tag):
|
||||||
try:
|
try:
|
||||||
with open(log_file_path, "w") as log_file:
|
with open(log_file_path, "w") as log_file:
|
||||||
total_packages = len(components)
|
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):
|
for index, package in enumerate(components, start=1):
|
||||||
# Mostrar solo el progreso en la terminal
|
# Actualizar el progreso en la parte superior con barra de progreso
|
||||||
print(f"Instalando paquete {index}/{total_packages}: {package}")
|
form.update_progress(f"Instalando paquete {index}/{total_packages}: {package}", current=index, total=total_packages)
|
||||||
log_file.write(f"\n--- Instalando paquete {index}/{total_packages}: {package} ---\n")
|
|
||||||
|
|
||||||
# Crear una barra de progreso para el paquete
|
# 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}"
|
install_command = f"DEBIAN_FRONTEND=noninteractive apt-get install -y {package}"
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
install_command, shell=True, text=True, stdout=log_file, stderr=log_file
|
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()
|
|
||||||
|
|
||||||
# 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
|
# Esperar a que el proceso de instalación termine
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|
||||||
# Completar la barra de progreso
|
|
||||||
progress_bar.n = 100
|
|
||||||
progress_bar.refresh()
|
|
||||||
|
|
||||||
# Registrar errores en el archivo de registro
|
# Registrar errores en el archivo de registro
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
error_message = f"Error al instalar el paquete {package}. Consulta el archivo de registro: {log_file_path}"
|
error_message = f"Error al instalar el paquete {package}. Consulta el archivo de registro: {log_file_path}"
|
||||||
print(error_message)
|
form.update_progress(error_message)
|
||||||
log_file.write(f"\n{error_message}\n")
|
|
||||||
failed_packages.append(package) # Agregar a la lista de fallos
|
failed_packages.append(package) # Agregar a la lista de fallos
|
||||||
else:
|
else:
|
||||||
log_file.write(f"Paquete {package} instalado correctamente.\n")
|
form.update_progress(f"Paquete {package} instalado correctamente.")
|
||||||
installed_packages.append(package) # Agregar a la lista de éxitos
|
installed_packages.append(package) # Agregar a la lista de éxitos
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
with open(log_file_path, "a") as log_file:
|
form.update_progress(f"Error durante la instalación: {e}")
|
||||||
log_file.write(f"\nError durante la instalación de los paquetes: {e}\n")
|
|
||||||
failed_packages.append("Error general durante la instalación")
|
failed_packages.append("Error general durante la instalación")
|
||||||
|
|
||||||
# Registrar el tiempo de finalización
|
# Registrar el tiempo de finalización
|
||||||
|
@ -322,6 +409,9 @@ def install_components(components, selected_tag):
|
||||||
# Mostrar el resumen en una ventana emergente
|
# Mostrar el resumen en una ventana emergente
|
||||||
npyscreen.notify_confirm(summary, title="Resumen de la instalación", wide=True)
|
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):
|
class MyApp(npyscreen.NPSAppManaged):
|
||||||
def onStart(self):
|
def onStart(self):
|
||||||
self.addForm("MAIN", ComponentSelectionForm)
|
self.addForm("MAIN", ComponentSelectionForm)
|
||||||
|
@ -330,6 +420,7 @@ class MyApp(npyscreen.NPSAppManaged):
|
||||||
self.addForm("ogdhcp", OgDhcpForm)
|
self.addForm("ogdhcp", OgDhcpForm)
|
||||||
self.addForm("ogboot", OgBootForm)
|
self.addForm("ogboot", OgBootForm)
|
||||||
self.addForm("ogrepository", OgRepositoryForm)
|
self.addForm("ogrepository", OgRepositoryForm)
|
||||||
|
self.addForm("INSTALLATION_PROGRESS", InstallationProgressForm)
|
||||||
|
|
||||||
def generate_debconf(self):
|
def generate_debconf(self):
|
||||||
# Comprobar si la clave pública ya existe
|
# Comprobar si la clave pública ya existe
|
||||||
|
@ -387,8 +478,10 @@ class MyApp(npyscreen.NPSAppManaged):
|
||||||
# Silenciar el mensaje de configuraciones guardadas
|
# Silenciar el mensaje de configuraciones guardadas
|
||||||
# print(f"\nConfiguraciones guardadas en: {output_file}")
|
# print(f"\nConfiguraciones guardadas en: {output_file}")
|
||||||
|
|
||||||
# Llamar a la función de instalación después de generar las configuraciones
|
# Llamar al formulario de progreso
|
||||||
install_components(self.selected_components, self.selected_tag)
|
form = self.getForm("INSTALLATION_PROGRESS")
|
||||||
|
self.switchForm("INSTALLATION_PROGRESS")
|
||||||
|
install_components_with_ui(form, self.selected_components, self.selected_tag)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
MyApp().run()
|
MyApp().run()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
GitPython
|
GitPython
|
||||||
npyscreen
|
npyscreen
|
||||||
requests
|
requests
|
||||||
tqdm
|
bs4
|
||||||
|
|
Loading…
Reference in New Issue