#!/usr/bin/env python3 ################################################################################# ##### ogBoot installer script ######## ##### Autor: Antonio Emmanuel Guerrero Silva ######## ################################################################################# import platform, os, sys, subprocess, datetime, shutil, argparse, time, pwd, glob, zipfile, urllib.request global UBUNTU_OS_VERSION, OPENGNGYS_VERSION, PYTHON_VERSION, DEPENDENCIES2, INSTALL_OGBOOT_TARGET, LOG_FILE, CHECKPKG, INSTALLPKG, PATH, PROGRAM_DIR, OPENGNSYS_SERVER, UPDATEPKGLIST SERVER_OPENGNSYS = "172.17.8.82" UPDATEPKGLIST = "" UBUNTU_OS_VERSION = "18" OPENGNGYS_VERSION = "1.2.0" PYTHON_VERSION = 3 INSTALL_TARGET="/opt/ogboot" INSTALL_OPENGNSYS_TARGET = "/opt/opengnsys" INSTALL_OGBOOT_TARGET = "/opt/ogboot" WORKDIR="/tmp/ogboot_installer" DEPENDENCIES2 = [] INSTALLPKG="" PROGRAM_DIR = os.path.dirname(os.path.realpath(sys.argv[0])) PROGRAM_NAME = os.path.basename(sys.argv[0]) OPENGNSYS_SERVER = "opengnsys.es" CHECKPKG="" DEFAULTDEV = "" DEVICE = [] SERVERIP = [] NETIP = [] NETMASK = [] NETBROAD = [] ROUTERIP = [] BRANCH = sys.argv[1] if len(sys.argv) > 1 else "main" TFTPSERV = "tftpd-hpa" ENABLESERVICE = "systemctl enable $service.service" DISABLESERVICE = "systemctl disable $service.service" APACHESERV = "apache2" APACHECFGDIR = "/etc/apache2" APACHESITESDIR = "sites-available" APACHEOGSITE = "ogboot" APACHEUSER = "www-data" APACHEGROUP = "www-data" APACHEENABLEMODS = "a2enmod headers ssl rewrite proxy_fcgi fastcgi actions alias" APACHEENABLESSL = "a2ensite default-ssl" APACHEENABLEOG = f"a2ensite {APACHEOGSITE}" APACHEMAKECERT = "make-ssl-cert generate-default-snakeoil --force-overwrite" SAMBASERV = "smbd" SAMBACFGDIR = "/etc/samba" TFTPCFGDIR = "/var/lib/tftpboot" PHPFPMSERV = "php7.2-fpm" INETDCFGDIR = "/etc/xinetd.d/" INETDSERV = "xinetd" OPENGNSYS_CLIENT_PASSWD="og" OPENGNSYS_CLIENT_USER="opengnsys" GIT_REPO="ssh://git@ognproject.evlt.uma.es:21987/opengnsys/ogboot.git" if os.path.isdir(f"{PROGRAM_DIR}/../installer"): REMOTE = 0 else: REMOTE = 1 #DOWNLOAD_URL = f"https://{OPENGNSYS_SERVER}/trac/downloads" #CODE_URL = f"https://codeload.github.com/opengnsys/OpenGnsys/zip/{BRANCH}" #API_URL = "https://api.github.com/repos/opengnsys/OpenGnsys" PATH = os.environ.get("PATH", "") + f":{INSTALL_OGBOOT_TARGET}/bin" OG_LOG_FILE = f"{INSTALL_OGBOOT_TARGET}/log/{PROGRAM_NAME[:-3]}.log" LOG_FILE = f"/tmp/{os.path.basename(OG_LOG_FILE)}" if shutil.which("service"): STARTSERVICE = "service $service restart" STOPSERVICE = "service $service stop" else: STARTSERVICE = "/etc/init.d/$service restart" STOPSERVICE = "/etc/init.d/$service stop" required_packages_18 = [ "apache2", "arp-scan", "automake", "build-essential", "btrfs-progs", "composer", "curl", "ctorrent", "debootstrap", "g++-multilib", "gawk", "gettext", "graphviz", "grub-efi-amd64-signed", "isc-dhcp-server", "jq", "libapache2-mod-php", "libdbi-dev", "libdbi1", "libev-dev", "libjansson-dev", "liblz4-tool", "libssl-dev", "moreutils", "netpipes", "php", "php-bcmath", "php-cli", "php-curl", "php-fpm", "php-gd", "php-json", "php-ldap", "php-mbstring", "php-mysql", "php-pdo", "php-pear", "php-xml", "php-zip", "procps", "coreutils", "rsync", "samba", "schroot", "shim-signed", "squashfs-tools", "subversion", "tftp-hpa", "tftpd-hpa", "udpcast", "unzip", "wakeonlan", "wget", "xinetd" ] required_packages_22 = [ "apache2", "arp-scan", "automake", "build-essential", "btrfs-progs", "composer", "curl", "ctorrent", "debootstrap", "g++-multilib", "gawk", "gettext", "graphviz", "grub-efi-amd64-signed", "isc-dhcp-server", "jq", "libapache2-mod-php", "libdbi-dev", "libdbi1", "libev-dev", "libjansson-dev", "liblz4-tool", "libssl-dev", "moreutils", "netpipes", "php", "php-bcmath", "php-cli", "php-curl", "php-fpm", "php-gd", "php-json", "php-ldap", "php-mbstring", "php-mysql", "php-pdo", "php-pear", "php-xml", "php-zip", "procps", "coreutils", "rsync", "samba", "schroot", "shim-signed", "squashfs-tools", "subversion", "tftp-hpa", "tftpd-hpa", "udpcast", "unzip", "wakeonlan", "wget", "xinetd" ] ############################################################################### ###::::::::::::::::::::::::::::::: UTILS :::::::::::::::::::::::::::::::::::### ############################################################################### def echoAndLog(message): datetime_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_file = LOG_FILE print(message) with open(log_file, "a") as file: file.write(f"{datetime_now}\tINFO\t{message}\n") def warningAndLog(message): datetime_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_entry = f"{datetime_now}\t{message}" print(message) with open(LOG_FILE, "a") as log_file: log_file.write(f"{datetime_now}\tWARN\t{message}\n") def errorAndLog(message): datetime_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_entry = f"{datetime_now}\t{message}" print(message) with open(LOG_FILE, "a") as log_file: log_file.write(f"{datetime_now}\tERROR\t{message}\n") def check_python_version(): try: python_version = platform.python_version() python_version_tuple = tuple(map(int, python_version.split('.'))) if python_version_tuple >= (PYTHON_VERSION, 0): echoAndLog(f"Versión de python instalada: {python_version}") else: errorAndLog(f"Versión de python es inferior a la requerida. Version instalada: {python_version}" + ".") exit() except Exception as e: errorAndLog(f"Problema al verificar la versión de Python: {e}") exit() def check_distribution(): if os.path.exists("/etc/os-release"): with open("/etc/os-release", "r") as file: for line in file: if line.startswith("VERSION"): VERSION = line.split("=")[1].strip().strip('"') break if VERSION.startswith(UBUNTU_OS_VERSION + "."): return echoAndLog(f"La instalación de OpenGnsys {OPENGNGYS_VERSION} se ha probado con funcionalidad completa sobre Ubuntu {UBUNTU_OS_VERSION}") go_on = input("Desea continuar? [s/N]: ") if go_on.upper() != "S": errorAndLog("Abandonando la instalación.") exit() def cidr2mask(cidr): args = [5 - (cidr // 8), 255, 255, 255, 255, (255 << (8 - (cidr % 8))) & 255, 0, 0, 0] if args[0] > 1: args = args[args[0]:] else: args = args[1:] return f"{args[0]}.{args[1]}.{args[2]}.{args[3]}" def downloadCode(url): if len(url) != 1: errorAndLog("Invalid number of parameters") exit(1) subprocess.run(["GIT_SSH_COMMAND=ssh -o StrictHostKeyChecking=accept-new git archive --remote=" + url + " --format zip --output opengnsys.zip --prefix=opengnsys/ " + BRANCH + " && unzip opengnsys.zip"], shell=True) if subprocess.returncode != 0: errorAndLog("Error getting OpenGnsys code from " + url) return 1 subprocess.run(["rm -f opengnsys.zip"], shell=True) echoAndLog("downloadCode(): code was downloaded") return 0 ############################################################################### ###:::::::::::::::::::::::::::::: INSTALL ::::::::::::::::::::::::::::::::::### ############################################################################### def is_installed(package): try: subprocess.run(["dpkg", "-s", package], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True except subprocess.CalledProcessError: return False def get_missing_packages(packages): faltantes = [] for package in packages: if not is_installed(package): faltantes.append(package) return faltantes def install_packages(missing, log_packages_file=f"/tmp/installed_packages.log"): if not missing: warningAndLog("Todos los paquetes ya están instalados.") return echoAndLog("Actualizando el sistema...") subprocess.run(["sudo", "apt-get", "update"], check=True) with open(log_packages_file, "a") as log: for package in missing: subprocess.run(["sudo", "apt-get", "install", "--force-yes", "-y", package], check=True) echoAndLog(f"{package} instalado correctamente.") log.write(package + "\n") echoAndLog("Todos los paquetes faltantes han sido instalados.") def autoConfigure(): os_info = platform.uname() OSDISTRIB = os_info.system.lower() OSVERSION = os_info.release.split('.')[0] if OSDISTRIB in ['linux', 'linux2']: if OSDISTRIB == 'linux': with open('/etc/os-release', 'r') as f: os_release = dict(line.strip().split('=') for line in f) OSDISTRIB = os_release.get('ID', '').lower() OSVERSION = os_release.get('VERSION_ID', '').split('.')[0] else: lsb_info = subprocess.check_output(['lsb_release', '-is']).decode().strip() OSDISTRIB = lsb_info.lower() lsb_version = subprocess.check_output(['lsb_release', '-rs']).decode().strip() OSVERSION = lsb_version.split('.')[0] # Convertir distribución a minúsculas y obtener solo el 1er número de versión OSDISTRIB = OSDISTRIB.lower() OSVERSION = OSVERSION.split('.')[0] # Configuración según la distribución GNU/Linux (usar minúsculas) echoAndLog(f"Distribución de OS Linux: {OSDISTRIB} {OSVERSION}") if OSDISTRIB in ['ubuntu', 'debian', 'linuxmint']: DEPENDENCIES2= [] elif OSDISTRIB in ['fedora', 'centos']: DEPENDENCIES2 = ['htop'] if OSDISTRIB == 'centos': UPDATEPKGLIST = f"yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-{OSVERSION}.noarch.rpm http://rpms.remirepo.net/enterprise/remi-release-{OSVERSION}.rpm" else: errorAndLog("Distribution not supported by OpenGnsys.") exit(1) else: errorAndLog("Unknown Linux distribution.") exit(1) def generate_config_url(): with open('/etc/os-release', 'r') as file: lines = file.readlines() codename = None version = None for line in lines: if line.startswith('VERSION_CODENAME') or line.startswith('UBUNTU_CODENAME'): codename = line.split('=')[1].strip().strip('"') elif line.startswith('VERSION_ID'): version = line.split('=')[1].strip().strip('"') arch = os.uname().machine return f"https://dl.cloudsmith.io/public/isc/kea-2-0/config.deb.txt?distro=ubuntu&codename={codename}&version={version}&arch={arch}" def downloadComposer(): #echoAndLog("Downloading composer.phar...") os.makedirs(os.path.join(WORKDIR, "ogboot", "bin"), exist_ok=True) subprocess.run(["curl", "-sS", "-o", os.path.join(WORKDIR, "ogboot", "bin", "composer.phar"), "https://getcomposer.org/installer"], check=True) if not os.path.isfile(os.path.join(WORKDIR, "ogboot", "bin", "composer.phar")): errorAndLog("Failed to download composer.phar") return 1 echoAndLog("composer.phar downloaded to /opt/ogboot/bin") return 0 def install_swagger_ui(): # Define la URL del archivo de Swagger UI que quieres descargar swagger_ui_url = "https://github.com/swagger-api/swagger-ui/archive/refs/heads/master.zip" # Define la ruta donde quieres descomprimir Swagger UI swagger_ui_path = "/tmp/swagger-ui" # Define la ruta de destino para los archivos de Swagger UI destination_path = os.path.join(INSTALL_TARGET, "public") # Crea los directorios si no existen os.makedirs(swagger_ui_path, exist_ok=True) os.makedirs(destination_path, exist_ok=True) # Descarga el archivo de Swagger UI urllib.request.urlretrieve(swagger_ui_url, "/tmp/swagger-ui.zip") # Descomprime el archivo de Swagger UI en la ruta especificada with zipfile.ZipFile("/tmp/swagger-ui.zip", "r") as zip_ref: zip_ref.extractall(swagger_ui_path) # Copia los archivos de Swagger UI al directorio de destino for file_path in glob.glob(os.path.join(swagger_ui_path, "swagger-ui-master", "dist", "*")): shutil.copy(file_path, destination_path) # Elimina el archivo descargado y el directorio temporal os.remove("/tmp/swagger-ui.zip") shutil.rmtree(swagger_ui_path) # Genera el archivo swagger.json os.system(f"{os.path.join(INSTALL_TARGET, 'vendor', 'bin', 'openapi')} {INSTALL_TARGET}/src/OgBootBundle/Controller/ -o {destination_path}/swagger.json") echoAndLog(f"Swagger UI instalado en {destination_path}.") def create_ogboot_project(path_opengnsys_base): try: pwd.getpwnam('ogboot') warningAndLog("El usuario 'ogboot' ya existe") except KeyError: subprocess.run(["sudo", "useradd", "-m", "ogboot"]) #PROGRAM_DIR #echoAndLog(f"creando enlace simbólico de {PROGRAM_DIR} a {WORKDIR}/ogboot") #os.symlink(PROGRAM_DIR, f"{WORKDIR}/ogboot") #os.symlink(WORKDIR, path_opengnsys_base) if os.path.exists(path_opengnsys_base): if not os.path.isdir(path_opengnsys_base): raise NotADirectoryError(f"{path_opengnsys_base} existe y no es un directorio.") else: warningAndLog(f"El directorio {path_opengnsys_base} ya existe.") else: os.makedirs(path_opengnsys_base) subprocess.run(["sudo", "chown", "-R", "ogboot:ogboot", path_opengnsys_base]) #with open('/etc/hosts', 'r') as hosts_file: # hosts_content = hosts_file.read() #if 'opengnsys' not in hosts_content: # with open('/etc/hosts', 'a') as hosts_file: # hosts_file.write(f'{SERVER_OPENGNSYS} opengnsys\n') # echoAndLog(f"Entrada {SERVER_OPENGNSYS} opengnsys' agregada a /etc/hosts") with open('/etc/hosts', 'r') as hosts_file: hosts_content = hosts_file.read() if f'{SERVER_OPENGNSYS} opengnsys' not in hosts_content: with open('/etc/hosts', 'a') as hosts_file: hosts_file.write(f'{SERVER_OPENGNSYS} opengnsys\n') echoAndLog(f"Entrada {SERVER_OPENGNSYS} opengnsys] agregada a /etc/hosts") else: warningAndLog(f"La entrada '{SERVER_OPENGNSYS} opengnsys' ya existe en /etc/hosts" ) echoAndLog("Creando esqueleto de la aplicación Symfony...") downloadComposer() # Copiar los archivos .env y composer.json primero echoAndLog(f"Copiando archivos .env y composer.json... de {WORKDIR}/ogboot/.env a {path_opengnsys_base}/.env") shutil.copy(f"{WORKDIR}/ogboot/.env", os.path.join(path_opengnsys_base, ".env")) shutil.copy(f"{WORKDIR}/ogboot/composer.json", os.path.join(path_opengnsys_base, "composer.json")) echoAndLog(f".env y composer.json copiados a {path_opengnsys_base}") bin_source = os.path.join(WORKDIR, "ogboot/bin") bin_dest = os.path.join(path_opengnsys_base, "bin") src_source = os.path.join(WORKDIR, "ogboot/src") src_dest = os.path.join(path_opengnsys_base, "src") config_source = os.path.join(WORKDIR, "ogboot/config") config_dest = os.path.join(path_opengnsys_base, "config") lib_source = os.path.join(WORKDIR, "ogboot/lib") lib_dest = os.path.join(path_opengnsys_base, "lib") if os.path.exists(bin_dest): shutil.rmtree(bin_dest) shutil.copytree(bin_source, bin_dest) if os.path.exists(src_dest): shutil.rmtree(src_dest) shutil.copytree(src_source, src_dest) if os.path.exists(config_dest): shutil.rmtree(config_dest) shutil.copytree(config_source, config_dest) if os.path.exists(lib_dest): shutil.rmtree(lib_dest) shutil.copytree(lib_source, lib_dest) os.makedirs(os.path.join(INSTALL_TARGET, "etc")) subprocess.run(["sudo", "chmod", "-R", "755", path_opengnsys_base]) subprocess.run(["sudo", "chown", "-R", "ogboot:ogboot", path_opengnsys_base]) # Ejecutar Composer como el usuario 'ogboot' para instalar el proyecto Symfony # result = subprocess.run(["sudo", "-u", "ogboot", "composer", "install", "--no-interaction", "--working-dir", path_opengnsys_base]) os.chdir(os.path.join(path_opengnsys_base, 'bin')) result = subprocess.run(["sudo", "-u", "ogboot", "php", os.path.join(path_opengnsys_base, "bin", "composer.phar"), "install", "--no-interaction", "--working-dir", path_opengnsys_base]) if result.returncode != 0: errorAndLog("Error al crear el proyecto Symfony usando Composer") return os.chdir(path_opengnsys_base) result = subprocess.run(["sudo", "-u", "ogboot", "php", os.path.join(path_opengnsys_base, "bin", "composer.phar"), "install", "--no-interaction", "--working-dir", path_opengnsys_base]) # Eliminar composer.lock si existe composer_lock_path = os.path.join(path_opengnsys_base, "composer.lock") if os.path.exists(composer_lock_path): os.remove(composer_lock_path) install_swagger_ui() # Instalar Swagger UI echoAndLog("Esqueleto de la aplicación creado y archivo composer.lock eliminado.") def createDirs(INSTALL_TARGET): if not os.path.exists(INSTALL_TARGET): try: os.makedirs(INSTALL_TARGET) os.makedirs(os.path.join(INSTALL_TARGET, "client")) echoAndLog(f"Directorio {INSTALL_TARGET} creado correctamente.") except OSError: errorAndLog("Error while creating directory paths!") exit(1) else: echoAndLog(f"Directory {INSTALL_TARGET} already exists.") ############################################################################### ###:::::::::::::::::::::::::::: CONFIGURE ::::::::::::::::::::::::::::::::::### ############################################################################### def install_isc_kea(): url = generate_config_url() print(f"URL generada: {url}") print("Ejecutando curl para obtener el archivo de configuración del repositorio KEA...") subprocess.run(["curl", "-1sLf", url, ">", "/etc/apt/sources.list.d/isc-kea-2-0.list"], check=True) print("El archivo de configuración del repositorio KEA ha sido guardado en /etc/apt/sources.list.d/isc-kea-2-0.list") print("Descargando y agregando la clave GPG del repositorio KEA...") subprocess.run(["curl", "-1sLf", "https://dl.cloudsmith.io/public/isc/kea-2-0/gpg.8029D4AFA58CBB5E.key", "|", "gpg", "--dearmor", ">>", "/usr/share/keyrings/isc-kea-2-0-archive-keyring.gpg"], check=True) print("La clave GPG del repositorio KEA ha sido descargada y agregada correctamente") print("Ejecutando apt-get update...") subprocess.run(["apt-get", "update"], check=True) print("Comprobando disponibilidad de los paquetes...") if subprocess.run(["apt-cache", "show", "isc-kea-common"], capture_output=True).returncode == 0: print("El paquete isc-kea-common está disponible para ser instalado.") print("Descargando e instalando el paquete isc-kea-common...") subprocess.run(["apt-get", "install", "-y", "isc-kea-common"], check=True) print("El paquete isc-kea-common ha sido descargado e instalado correctamente.") else: print("El paquete isc-kea-common no está disponible en los repositorios apt.") if subprocess.run(["apt-cache", "show", "isc-kea-dhcp4-server"], capture_output=True).returncode == 0: print("El paquete isc-kea-dhcp4-server está disponible para ser instalado.") print("Descargando e instalando el paquete isc-kea-dhcp4-server...") subprocess.run(["apt-get", "install", "-y", "isc-kea-dhcp4-server"], check=True) print("El paquete isc-kea-dhcp4-server ha sido descargado e instalado correctamente.") else: print("El paquete isc-kea-dhcp4-server no está disponible en los repositorios apt.") if subprocess.run(["apt-cache", "show", "isc-kea-dhcp6-server"], capture_output=True).returncode == 0: print("El paquete isc-kea-dhcp6-server está disponible para ser instalado.") print("Descargando e instalando el paquete isc-kea-dhcp6-server...") subprocess.run(["apt-get", "install", "-y", "isc-kea-dhcp6-server"], check=True) print("El paquete isc-kea-dhcp6-server ha sido descargado e instalado correctamente.") else: print("El paquete isc-kea-dhcp6-server no está disponible en los repositorios apt.") if subprocess.run(["apt-cache", "show", "isc-kea-dhcp-ddns-server"], capture_output=True).returncode == 0: print("El paquete isc-kea-dhcp-ddns-server está disponible para ser instalado.") print("Descargando e instalando el paquete isc-kea-dhcp-ddns-server...") subprocess.run(["apt-get", "install", "-y", "isc-kea-dhcp-ddns-server"], check=True) print("El paquete isc-kea-dhcp-ddns-server ha sido descargado e instalado correctamente.") else: print("El paquete isc-kea-dhcp-ddns-server no está disponible en los repositorios apt.") if subprocess.run(["apt-cache", "show", "isc-kea-ctrl-agent"], capture_output=True).returncode == 0: print("El paquete isc-kea-ctrl-agent está disponible para ser instalado.") print("Descargando e instalando el paquete isc-kea-ctrl-agent...") subprocess.run(["apt-get", "install", "-y", "isc-kea-ctrl-agent"], check=True) print("El paquete isc-kea-ctrl-agent ha sido descargado e instalado correctamente.") else: print("El paquete isc-kea-ctrl-agent no está disponible en los repositorios apt.") def install_kea(): print(f"{install_kea.__name__}(): Instalación de muestra para el servicio DHCP de Kea.") def backupFile(file): if not os.path.isfile(file): warningAndLog(f"File {file} doesn't exist") return echoAndLog(f"Making backup of {file}") shutil.copy2(file, f"{file}-LAST") dateymd = datetime.datetime.now().strftime("%Y%m%d") backup_file = f"{file}-{dateymd}" if not os.path.isfile(backup_file): shutil.copy2(file, backup_file) echoAndLog(f"Backup of {file} successful") def isc_keaDhcpConfigure(): print(f"{isc_keaDhcpConfigure.__name__}(): Configuración de muestra para el servicio DHCP de Kea.") errcode = 0 i = 0 interfaces = "[" #DEVICE = ["eth0", "eth1"] # Define the DEVICE variable with appropriate values #NETMASK = "255.255.255.0" # Replace with the actual value of NETMASK #NETIP = "192.168.0.1" # Replace with the actual value of NETIP #ROUTERIP = "192.168.0.1" # Replace with the actual value of ROUTERIP DNSIP = "192.168.0.1" # Replace with the actual value of DNSIP #SERVERIP = "192.168.0.1" # Replace with the actual value of SERVERIP # Rest of the code... # Define the NETMASK variable # Construir la lista de interfaces print(NETIP) print(NETMASK) #CIDR = mask2cidr(NETMASK) #print(CIDR) # Salida: 24 print(ROUTERIP) print(DNSIP) with open("/etc/kea/kea-dhcp4.conf", "w") as file: file.write( f""" "interfaces": {interfaces}, "SERVERIP": "{SERVERIP}", "NETIP": "{NETIP}", "NETMASK": "{NETMASK}", "ROUTERIP": "{ROUTERIP}", "DNSIP": "{DNSIP}" """ ) # Si hubo errores al configurar, muestra un mensaje de error y sale de la función if errcode != 0: print(f"{isc_keaDhcpConfigure.__name__}(): Error al configurar el servicio DHCP de Kea.") return 1 print(f"{isc_keaDhcpConfigure.__name__}(): Configuración de muestra para el servicio DHCP de Kea configurada en \"/etc/kea/kea-dhcp4.conf\".") return 0 def testPxe(): echoAndLog(f"Checking TFTP service... please wait.") subprocess.run(["echo", "test"], stdout=open(f"{TFTPCFGDIR}/testpxe", "w")) try: subprocess.run(["tftp", "-v", "127.0.0.1", "-c", "get", "testpxe", "/tmp/testpxe"], check=True) echoAndLog("TFTP service is OK.") except subprocess.CalledProcessError: errorAndLog("TFTP service is down.") os.remove(f"{TFTPCFGDIR}/testpxe") def tftpConfigure(): if TFTPSERV: echoAndLog(f"TFTPSERV está configurado: {TFTPSERV}") inetd_cfg_path = f"{INETDCFGDIR}/{TFTPSERV}" if os.path.isfile(inetd_cfg_path): errorAndLog(f"El archivo de configuración de inetd existe: {inetd_cfg_path}") with open(inetd_cfg_path, "r+") as file: content = file.read() new_content = content.replace("disable.*", "disable = no") file.seek(0) file.write(new_content) file.truncate() echoAndLog(f"Archivo de configuración de inetd modificado: {inetd_cfg_path}") else: service = TFTPSERV echoAndLog(f"Habilitando y arrancando el servicio {service}.service") subprocess.run(["systemctl", "enable", f"{service}.service"], check=True) subprocess.run(["systemctl", "start", f"{service}.service"], check=True) service = INETDSERV echoAndLog(f"Habilitando y arrancando el servicio {service}.service") subprocess.run(["systemctl", "enable", f"{service}.service"], check=True) subprocess.run(["systemctl", "start", f"{service}.service"], check=True) #Crear directorio /var/lib/tftpboot if not os.path.exists(TFTPCFGDIR): os.makedirs(TFTPCFGDIR) echoAndLog(f"Directorio {TFTPCFGDIR} creado.") #Descargar oglive echoAndLog("Downloading oglive...") #Temporalmente se copia desde ~/oglive subprocess.run(["cp", "-r", f"{PROGRAM_DIR}/../../oglive/ogLive-5.11.0-r20210413", f"/var/lib/tftpboot/"]) #Crear enlace simbólico de oglive-5.11.0-r20210413 a /var/lib/tftpboot/ogLive subprocess.run(["ln", "-s", f"/var/lib/tftpboot/ogLive-5.11.0-r20210413", "/var/lib/tftpboot/ogLive"]) #Crear enlace simbólico de /var/lib/tftpboot/ogLive a /var/lib/tftpboot/ogLive/ogclient subprocess.run(["ln", "-s", "/var/lib/tftpboot/ogLive", "/var/lib/tftpboot/ogclient"]) symlink_target = f"{INSTALL_TARGET}/tftpboot" echoAndLog(f"Creando enlace simbólico de /var/lib/tftpboot a {symlink_target}") if not os.path.exists(symlink_target): os.symlink("/var/lib/tftpboot", symlink_target) os.chown(symlink_target, pwd.getpwnam("ogboot").pw_uid, pwd.getpwnam("ogboot").pw_gid) else: warningAndLog(f"El enlace simbólico ya existe: {symlink_target}") def servicesCompilation(): hayErrores = 0 process = subprocess.run(["make"], cwd=f"{WORKDIR}/ogboot/sources/clients/ogAdmClient") subprocess.run(["mv", f"{WORKDIR}/ogboot/sources/clients/ogAdmClient/ogAdmClient", f"{WORKDIR}/ogboot/client/shared/bin"]) if process.returncode != 0: echoAndLog(f"{servicesCompilation.__name__}(): error while compiling OpenGnsys Admin Client") hayErrores = 1 return hayErrores def copyInterfaceAdm(): hayErrores = 0 cp_process = subprocess.run(["cp", "-ar", f"{WORKDIR}/ogboot/sources/interface", f"{INSTALL_TARGET}/client/interfaceAdm"]) if cp_process.returncode != 0: errorAndLog(f"Error while copying Administration Interface Folder") hayErrores = 1 return hayErrores def copyClientFiles(): errstatus = 0 echoAndLog(f"Copying OpenGnsys Client files.") source_files = glob.glob(f"{WORKDIR}/ogboot/client/shared/*") # Copy each file individually for file in source_files: cp_process = subprocess.run(["cp", "-a", file, f"{INSTALL_TARGET}/client"]) if cp_process.returncode != 0: errorAndLog(f"Error while copying client structure: {file}") errstatus = 1 echoAndLog(f"Copying OpenGnsys Cloning Engine files.") os.makedirs(f"{INSTALL_TARGET}/client/lib/engine/bin", exist_ok=True) engine_files = glob.glob(f"{WORKDIR}/ogboot/client/engine/*.lib*") # Copiar cada archivo individualmente for file in engine_files: cp_engine_process = subprocess.run(["cp", "-a", file, f"{INSTALL_TARGET}/client/lib/engine/bin"]) if cp_engine_process.returncode != 0: errorAndLog(f"Error while copying engine files: {file}") errstatus = 1 if errstatus == 0: echoAndLog(f"Client copy files success.") else: errorAndLog(f"Client copy files with errors") return errstatus def cidr2mask(bits): args = [5 - (bits // 8), 255, 255, 255, 255, (255 << (8 - (bits % 8))) & 255, 0, 0, 0] if args[0] > 1: args = args[args[0]:] else: args = args[1:] return ".".join(str(arg) for arg in args) def mask2cidr(mask): addr = mask.split(".") cidr = 0 for i in addr: cidr += bin(int(i)).count("1") return cidr def getNetworkSettings(): DHCPNET = "127.0.0.1" #print("getNetworkSettings(): Detecting network parameters.") output = subprocess.check_output(["ip", "-o", "link", "show", "up"]).decode("utf-8") lines = output.strip().split("\n") for line in lines: dev = line.split(":")[1].split("@")[0].strip() output = subprocess.check_output(["ip", "-o", "addr", "show", "dev", dev]).decode("utf-8") addr_lines = output.strip().split("\n") for addr_line in addr_lines: addr_parts = addr_line.split() cidr_netmask = addr_parts[3].split("/")[1] cidr_netmask = int(cidr_netmask) if cidr_netmask >= 0 and cidr_netmask <= 32: netmask = ".".join([str((0xffffffff << (32 - cidr_netmask) >> i) & 0xff) for i in [24, 16, 8, 0]]) if addr_parts[2] == "inet": DEVICE.append(dev) SERVERIP.append(addr_parts[3].split("/")[0]) NETMASK.append(netmask) NETBROAD.append(addr_parts[5]) NETIP.append(addr_parts[3].split("/")[0]) ROUTERIP.append(subprocess.check_output(["ip", "route", "list", "default"]).decode("utf-8").split()[2]) if DHCPNET == NETIP[-1]: DEFAULTDEV = dev else: DEFAULTDEV = DEFAULTDEV if "DEFAULTDEV" in locals() else dev if len(NETIP) == 0 or len(NETMASK) == 0: return (1) else: return (0) def openGnsysConfigure(): i = 0 dev = "" CONSOLEURL = "" CONSOLEURL = f"https://{SERVER_OPENGNSYS}/opengnsys" with open(f"{WORKDIR}/ogboot/etc/ogAdmClient.cfg") as file: content = file.read() content = content.replace("SERVERIP", SERVER_OPENGNSYS) content = content.replace("OPENGNSYSURL", CONSOLEURL) with open(f"{INSTALL_TARGET}/client/etc/ogAdmClient-eth0.cfg", "w") as outfile: outfile.write(content) os.link(f"{INSTALL_TARGET}/client/etc/ogAdmClient-eth0.cfg", f"{INSTALL_TARGET}/client/etc/ogAdmClient.cfg") TZ = subprocess.check_output(["timedatectl", "status"]).decode().split("\n")[2].split(":")[1].strip() with open(f"{INSTALL_TARGET}/client/etc/engine.cfg", "a") as file: file.write(f"# OpenGnsys Server timezone.\nTZ=\"{TZ.replace(' ', '')}\"\n") echoAndLog(f"OpenGnsys config files created.") def mount_NFS(): if subprocess.call(["sudo", "mount", "-t", "nfs", "ognartefactos.evlt.uma.es:/", "/mnt"]) == 0: echoAndLog("Sistema NFS montado correctamente.") else: errorAndLog("No se pudo montar el sistema NFS.") exit(1) subprocess.call(["ls", "/mnt/"]) subprocess.call(["sudo", "cp", "-r", "/mnt/srv/artefactos/ipxe/", "/tmp"]) os.chdir("/tmp/ipxe/src") if subprocess.call(["sudo", "make", "-j", "4"]) == 0: echoAndLog("Directorio /tmp/ipxe/src montado correctamente.") else: errorAndLog("ERROR\tNo se pudo montar el directorio /tmp/ipxe/src.") exit(1) if subprocess.call(["sudo", "make", "bin/undionly.kpxe", "EMBED=/opt/opengnsys/tftpboot/ipxe_scripts/dhcp_boot.ipxe"]) == 0: echoAndLog("Fichero de arranque montado correctamente.") else: errorAndLog("No se pudo montar el fichero de arranque.") exit(1) subprocess.call(["sudo", "cp", "bin/undionly.kpxe", "/opt/opengnsys/tftpboot"]) if subprocess.call(["sudo", "make", "bin-x86_64-efi/ipxe.efi", "EMBED=/opt/opengnsys/tftpboot/ipxe_scripts/dhcp_boot.ipxe"]) == 0: echoAndLog("Fichero EFI construido correctamente.") else: errorAndLog("No se pudo construir el fichero EFI.") exit(1) subprocess.call(["sudo", "cp", "bin-x86_64-efi/ipxe.efi", "/opt/opengnsys/tftpboot"]) def generate_ipxe_script(): ip_address_server = subprocess.check_output(["ifconfig", "eth0"]).decode().split("\n")[1].split()[1] template = os.path.join(WORKDIR, "ogboot/etc/dhcp_boot.ipxe.tmpl") ipxe_output = "/opt/ogboot/tftpboot/ipxe_scripts/dhcp_boot.ipxe" os.makedirs(os.path.dirname(ipxe_output), exist_ok=True) shutil.copy(template, ipxe_output) with open(ipxe_output, "r") as ipxe_file: ipxe_content = ipxe_file.read() ipxe_content = ipxe_content.replace("__SERVERIP__", ip_address_server) with open(ipxe_output, "w") as ipxe_file: ipxe_file.write(ipxe_content) # Reemplazar SERVERIP con la dirección IP en la plantilla y guardarla en el archivo de salida # with open(template, "r") as tmpl_file: # template_content = tmpl_file.read() # ipxe_content = template_content.replace("SERVERIP", ip_address_server) # with open(ipxe_output, "w") as ipxe_file: # ipxe_file.write(ipxe_content) template_default = os.path.join(WORKDIR, "ogboot/tftpboot/ipxe_scripts/default.ipxe") default_output = os.path.join(INSTALL_TARGET, "tftpboot/ipxe_scripts/default.ipxe") with open(template_default, "r") as default_tmpl_file: default_template_content = default_tmpl_file.read() default_ipxe_content = default_template_content.replace("__SERVERIP__", ip_address_server) with open(default_output, "w") as default_ipxe_file: default_ipxe_file.write(default_ipxe_content) echoAndLog("Archivos ipxe creados correctamente.") def smbConfigure(): #echoAndLog(f"{smbConfigure.__name__}(): Configuring Samba service.") backupFile(f"{SAMBACFGDIR}/smb.conf") # Copiar plantilla de recursos para OpenGnsys with open(os.path.join(WORKDIR, 'ogboot/etc/smb-ogboot.conf.tmpl'), 'r') as tmpl_file: template = tmpl_file.read() replaced_template = template.replace('__OGBOOTDIR__', INSTALL_OPENGNSYS_TARGET) with open(os.path.join(SAMBACFGDIR, 'smb-ogboot.conf'), 'w') as conf_file: conf_file.write(replaced_template) # Configurar y recargar Samba" subprocess.run(["perl", "-pi", "-e", "s/WORKGROUP/OPENGNSYS/; s/server string \=.*/server string \= ogBoot Samba Server/", f"{SAMBACFGDIR}/smb.conf"]) if "smb-ogboot" not in open(f"{SAMBACFGDIR}/smb.conf").read(): with open(f"{SAMBACFGDIR}/smb.conf", "a") as file: file.write(f"include = {SAMBACFGDIR}/smb-ogboot.conf\n") service = SAMBASERV subprocess.run(["systemctl", "enable", f"{service}.service"]) subprocess.run(["systemctl", "restart", f"{service}.service"]) # Comprobar si se ha configurado correctamente Samba if subprocess.run(["systemctl", "is-active", f"{service}.service"]).returncode == 0: echoAndLog(f"{service} service started successfully.") else: errorAndLog(f"Failed to start {service} service.") return 1 # Establecer la contraseña para el usuario opengnsys smbpasswd_command = f"(echo {OPENGNSYS_CLIENT_PASSWD}; echo {OPENGNSYS_CLIENT_PASSWD}) | sudo smbpasswd -s -a {OPENGNSYS_CLIENT_USER}" if "Python 3.7" in {PYTHON_VERSION}: result = subprocess.run(smbpasswd_command, shell=True, capture_output=True, text=True) if result.returncode == 0: echoAndLog(f"La contraseña para el usuario {OPENGNSYS_CLIENT_USER} se ha establecido correctamente.") else: errorAndLog(f"Error al establecer la contraseña: {result.stderr}") else: process = subprocess.Popen(smbpasswd_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode == 0: echoAndLog(f"La contraseña para el usuario {OPENGNSYS_CLIENT_USER} se ha establecido correctamente.") else: errorAndLog(f"Error al establecer la contraseña: {stderr}") echoAndLog(f"Added Samba configuration.") return 0 ############################################################################### ###:::::::::::::::::::::::::::::::: MAIN :::::::::::::::::::::::::::::::::::### ############################################################################### echoAndLog(f"Starting installation of ogBoot.") if os.geteuid() != 0: errorAndLog("Este programa debe ejecutarse con privilegios de root.") exit(1) if os.path.exists(os.path.join(INSTALL_OGBOOT_TARGET + "/doc/")): warningAndLog(f"ogBoot ya esta instalado. Ejecute {INSTALL_OGBOOT_TARGET}/lib/ogboot_devel_update.py\" con privilegios de root para actualizar.") exit(2) echoAndLog("Verificando la distribución y la versión de Python.") check_distribution() check_python_version() echoAndLog("Verificando el sistema operativo.") autoConfigure() echoAndLog("Instalando paquetes necesarios.") Missing = get_missing_packages (required_packages_18) install_packages(Missing) echoAndLog("Obteniendo la configuración de red por defecto.") if getNetworkSettings() != 0: errorAndLog("Error reading default network settings.") exit(1) echoAndLog("Configurando repositorios de paquetes.") if REMOTE == 1: downloadCode(GIT_REPO) if os.system("echo $?") != 0: errorAndLog("Error while getting code from the repository") exit(1) else: if not os.path.exists(f"{WORKDIR}/ogboot"): echoAndLog(f"No existe {WORKDIR}/ogboot") if not os.path.exists(WORKDIR): os.makedirs(WORKDIR) errorAndLog(f"ogBoot directory not found, create a symbolic link to the directory where the code is located {WORKDIR} To {os.path.dirname(PROGRAM_DIR)}") os.symlink(os.path.dirname(PROGRAM_DIR), f"{WORKDIR}/ogboot") echoAndLog("Creando directorios.") createDirs(INSTALL_TARGET) if os.system("echo $?") != 0: errorAndLog("Error while creating directory paths!") exit(1) echoAndLog("Creando proyecto ogBoot.") create_ogboot_project(INSTALL_TARGET) if os.system("echo $?") != 0: errorAndLog("Error while creating skeleton directory!") exit(1) echoAndLog("Configurando servicio TFTP.") tftpConfigure() echoAndLog("Compilar código fuente de los servicios de OpenGnsys") servicesCompilation() if subprocess.run(["echo", "$?"]).returncode != 0: errorAndLog("Error while compiling OpenGnsys services") exit(1) echoAndLog("Copiar carpeta Interface entre administración y motor de clonación") copyInterfaceAdm() if subprocess.run(["echo", "$?"]).returncode != 0: errorAndLog("Error while copying Administration Interface") exit(1) echoAndLog("Crear la estructura de los accesos al servidor desde el cliente (shared)") copyClientFiles() if subprocess.run(["echo", "$?"]).returncode != 0: errorAndLog("Error creating client structure") echoAndLog("Configurando servicios IPXE") generate_ipxe_script() echoAndLog("Configurando openGnsys") openGnsysConfigure() echoAndLog("Montando sistema NFS") mount_NFS() echoAndLog("Configurando Samba") smbConfigure() echoAndLog(f"ogBoot installation finished.")