#!/usr/bin/env python3 ################################################################################## ##### ogBoot installer script #### ##### Developed by: Luis Gerardo Romero García #### ##### Antonio Emmanuel Guerrero Silva #### ##### Last: 2024-07-08 #### ################################################################################## import platform, os, sys, subprocess, datetime, shutil, pwd, glob, logging, distro, re, json import tempfile ipxe_repo_url = "https://github.com/ipxe/ipxe.git" SAMBACFGDIR = "/etc/samba" TFTPCFGDIR = "/var/lib/tftpboot" PROGRAM = os.path.splitext(os.path.basename(sys.argv[0]))[0] PROGRAM_DIR = os.path.dirname(os.path.realpath(sys.argv[0])) REPO_DIR = os.path.realpath (os.path.join (os.path.dirname (sys.argv[0]), '..')) PROGRAM_NAME = os.path.basename(sys.argv[0]) config_file = os.path.join(PROGRAM_DIR, 'config.json') with open(config_file, 'r') as f: config = json.load(f) #OGCORE_IP = config["ogCore_ServerIP"] ogcore_ip_port = config['ogCore_ServerIP'] if ':' in ogcore_ip_port: OGCORE_IP, OGCORE_PORT = ogcore_ip_port.split(':') else: OGCORE_IP = ogcore_ip_port OGCORE_PORT = "8443" #Para el caso de que pasen una ip con puerto separamos la ip y el puerto #Pasamos el puerto para conexiones por http #No pasamos el puerto para conexiones tftp y parámetros del kernel #Si solo pasan la IP usaremos el puerto por defecto 8082 ogboot_ip_port = config['ogBoot_ServerIP'] if ':' in ogboot_ip_port: OGBOOT_IP, OGBOOT_PORT = ogboot_ip_port.split(':') else: OGBOOT_IP = ogboot_ip_port OGBOOT_PORT = "8082" oglive_iso_url = config["ogLive_Default"] INSTALL_OGBOOT_TARGET = config["ogBoot_Dir"] OPENGNSYS_CLIENT_USER = config["ogBootSambaUser"] OPENGNSYS_CLIENT_PASSWD = config["ogBootSambaPass"] DEFAULTDEV = "" DEVICE = [] SERVERIP = [] NETIP = [] NETMASK = [] NETBROAD = [] ROUTERIP = [] BRANCH = sys.argv[1] if len(sys.argv) > 1 else "main" UBUNTU_OS_VERSION = "24" PYTHON_VERSION = 3 os.environ['DEBIAN_FRONTEND'] = 'noninteractive' log_file = f'/var/log/{PROGRAM}.log' os.makedirs(os.path.dirname(log_file), exist_ok=True) subprocess.run(['touch', log_file]) subprocess.run(['chmod', '775', log_file]) #Configure the log logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s\t%(message)s', filename=f'/var/log/{PROGRAM}.log', filemode='a') logger = logging.getLogger() console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(levelname)s\t%(message)s') console_handler.setFormatter(formatter) logger.addHandler(console_handler) ############################################################################### ###::::::::::::::::::::::::::::::: UTILS :::::::::::::::::::::::::::::::::::### ############################################################################### 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): logger.info(f"Python version installed: {python_version}") else: logger.error(f"Python version is lower than required. Installed version: {python_version}" + ".") exit() except Exception as e: logger.error(f"Problem verifying Python version: {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 logger.info(f"The ogBoot installation has been tested with full functionality on Ubuntu. {UBUNTU_OS_VERSION}") go_on = input("Would you like to continue? [y/N]: ") if go_on.upper() != "Y": logger.error("Leaving the installation.") exit() ############################################################################### ###:::::::::::::::::::::::::::::: INSTALL ::::::::::::::::::::::::::::::::::### ############################################################################### def get_missing_packages(): PACKAGES_TO_INSTALL = [] OSDISTRIB = distro.name() OSVERSION = distro.version() logger.info(f"OSDISTRIB: {OSDISTRIB}") logger.info(f"OSVERSION: {OSVERSION}") match OSDISTRIB.lower(): case "ubuntu": match OSVERSION: case "20.04": PACKAGES_TO_INSTALL = ["vim", "curl", "htop"] case "18.04": PACKAGES_TO_INSTALL = ["nano", "wget", "tree"] case "22.04": PACKAGES_TO_INSTALL = ["nfs-common", "xorriso", "genisoimage", "syslinux", "liblzma-dev", "nginx", "arp-scan", "automake", "build-essential", "btrfs-progs", "composer", "curl", "ctorrent", "debootstrap", "g++-multilib", "gawk", "gettext", "graphviz", "grub-efi-amd64-signed", "jq", "libdbi-dev", "libdbi1t64", "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", "php8.1-common", "php-pear", "php-xml", "php-zip", "procps", "coreutils", "rsync", "samba", "samba-common-bin", "schroot", "shim-signed", "squashfs-tools", "subversion", "tftpd-hpa", "udpcast", "unzip", "wakeonlan", "wget", "xinetd", "jq", "moreutils", "net-tools", "isolinux", "syslinux"] case "24.04": PACKAGES_TO_INSTALL = ["nfs-common", "xorriso", "genisoimage", "syslinux", "liblzma-dev", "nginx", "arp-scan", "automake", "build-essential", "btrfs-progs", "composer", "curl", "ctorrent", "debootstrap", "g++-multilib", "gawk", "gettext", "graphviz", "grub-efi-amd64-signed", "jq", "libdbi-dev", "libdbi1t64", "libev-dev", "libjansson-dev", "liblz4-tool", "libssl-dev", "moreutils", "netpipes", "php8.3", "php8.3-bcmath", "php8.3-cli", "php8.3-curl", "php8.3-fpm", "php8.3-gd", "php8.3-ldap", "php8.3-mbstring", "php8.3-mysql", "php8.3-common", "php-pear", "php8.3-xml", "php8.3-zip", "procps", "coreutils", "rsync", "samba", "samba-common-bin", "schroot", "shim-signed", "squashfs-tools", "subversion", "tftpd-hpa", "udpcast", "unzip", "wakeonlan", "wget", "xinetd", "jq", "moreutils", "isolinux", "syslinux", "file"] case _: PACKAGES_TO_INSTALL = ["bash", "rsync"] #case "suse": # match OSVERSION: # case "15": # PACKAGES_TO_INSTALL = ["zypper", "mc", "gcc"] # case "12": # PACKAGES_TO_INSTALL = ["perl", "tar", "man"] # case _: # PACKAGES_TO_INSTALL = ["openssl", "ncurses", "zip"] #case "redhat": # match OSVERSION: # case "8": # PACKAGES_TO_INSTALL = ["yum", "tar", "perl"] # case "7": # PACKAGES_TO_INSTALL = ["bash", "rpm", "tcpdump"] # case _: # PACKAGES_TO_INSTALL = ["grep", "sed", "awk"] case _: logger.error("Distribution not supported by ogBoot.") exit(1) installed = [] for l in subprocess.run (['dpkg', '-s'] + PACKAGES_TO_INSTALL, capture_output=True, text=True).stdout.splitlines(): if l.startswith ('Package:'): installed.append (l.split (':')[1].strip()) faltantes = list (set(PACKAGES_TO_INSTALL) - set(installed)) logger.info(f"Packages to install: {faltantes}") return faltantes def install_packages(log_packages_file="/tmp/installed_packages.log"): missing = get_missing_packages() if not missing: logger.info("All packages are already installed.") return logger.info("Upgrading the system...") subprocess.run(["apt-get", "update"], check=True) subprocess.run( ["apt-get", "install", "--allow-change-held-packages", "-y", "--no-install-recommends"] + missing + ['apache2-'], check=True ) with open(log_packages_file, "a") as log: for package in missing: logger.info(f"{package} installed correctly.") log.write(package + "\n") logger.info("All missing packages have been installed.") # Check PHP version and install corresponding php-fpm package php_version = subprocess.check_output(["php", "-v"]).decode("utf-8") if "PHP 8.1" in php_version: subprocess.run(["apt-get", "install", "-y", "php8.1-fpm"], check=True) elif "PHP 8.3" in php_version: subprocess.run(["apt-get", "install", "-y", "php8.3-fpm"], check=True) else: logger.warning("PHP version not supported.") def add_sudoers_permissions(): sudoers_entry = """ opengnsys ALL=(ALL) NOPASSWD: /opt/bin/oglivecli opengnsys ALL=(root) NOPASSWD: /usr/bin/chmod, /usr/bin/chown, /usr/bin/md5sum, /usr/bin/smbpasswd, /usr/bin/cat, /usr/bin/tee, /usr/bin/sed, /usr/bin/gzip, /usr/bin/lz4, /usr/bin/cpio, /usr/bin/find, /bin/tee, /usr/bin/dd, /usr/bin/mkfs.ext4, /usr/bin/rsync opengnsys ALL=(root) NOPASSWD: __OGBOOT_TARGET__/lib/*.iso /mnt """ sudoers_file = '/etc/sudoers.d/ogboot' try: with open(sudoers_file, 'w') as file: file.write(sudoers_entry.replace ('__OGBOOT_TARGET__', INSTALL_OGBOOT_TARGET)) print("Sudoers permissions for 'opengnsys' added successfully.") except IOError as e: print(f"Failed to write to {sudoers_file}: {e}") def og_core_create_user(u): try: user_info = pwd.getpwnam(u) current_home = user_info.pw_dir logger.info(f"User {u} already exists with home {current_home}") if u == "opengnsys" and current_home != "/opt/opengnsys": logger.info(f"Updating home directory for user {u} to /opt/opengnsys") subprocess.run(["usermod", "-d", "/opt/opengnsys", "-m", u], check=True) logger.info(f"User {u} home changed successfully to /opt/opengnsys") else: logger.info(f"User {u} already has the correct home directory.") except KeyError: # El usuario no existe, crearlo con el home correcto, si es opengnsys le ponemos su home_dir como opt/opengnsys # Si no es opengnsys le creamos el home en /home/ home_dir = "/opt/opengnsys" if u == "opengnsys" else f"/home/{u}" logger.info(f"Creating user {u} with home {home_dir}") subprocess.run(["useradd", "--create-home", "-d", home_dir, "--shell", "/bin/bash", u], check=True) logger.info(f"User {u} created successfully with home {home_dir}") def og_boot_create_dirs(): if os.path.exists(INSTALL_OGBOOT_TARGET): if not os.path.isdir(INSTALL_OGBOOT_TARGET): raise NotADirectoryError(f"{INSTALL_OGBOOT_TARGET} exists and is not a directory.") else: logger.warning(f"{INSTALL_OGBOOT_TARGET} directory already exists.") else: try: # Crear los directorios necesarios os.makedirs("/opt/opengnsys", mode=0o775, exist_ok=True) subprocess.run(["chmod", "775", "/opt/opengnsys"]) os.makedirs(INSTALL_OGBOOT_TARGET, mode=0o775, exist_ok=True) # Cambiar el propietario de los directorios subprocess.run(["chown", "-R", "opengnsys:opengnsys", INSTALL_OGBOOT_TARGET]) logger.info(f"{INSTALL_OGBOOT_TARGET} directory created successfully.") except OSError: logger.error("Error while creating directory paths!") exit(1) def og_boot_symfony_install(): logger.info("Creating Symfony application skeleton...") try: # Copiar los archivos .env y composer.json primero env_src = os.path.join(f"{REPO_DIR}", ".env") composer_src = os.path.join(f"{REPO_DIR}", "composer.json") env_dest = os.path.join(f"{INSTALL_OGBOOT_TARGET}", ".env") composer_dest = os.path.join(f"{INSTALL_OGBOOT_TARGET}", "composer.json") shutil.copy(env_src, env_dest) shutil.copy(composer_src, composer_dest) logger.info(f"Copied environment source {env_src} to {env_dest}") logger.info(f"Copied composer source {composer_src} to {composer_dest}") # Cambiar permisos y propietario de los archivos copiados os.chmod(env_dest, 0o644) os.chmod(composer_dest, 0o644) shutil.chown(env_dest, user='opengnsys', group='opengnsys') shutil.chown(composer_dest, user='opengnsys', group='opengnsys') logger.info(f"Set permissions and owner for {env_dest} and {composer_dest}") # Añadir la línea OGCORE_API_URL utilizando OGCORE_IP y OGCORE_PORT ogcore_api_url = f'OGCORE_API_URL="https://{OGCORE_IP}:{OGCORE_PORT}"' with open(env_dest, 'a') as env_file: env_file.write(f"\n{ogcore_api_url}\n") logger.info(f"Added OGCORE_API_URL to {env_dest} with IP: {OGCORE_IP}") ogboot_ip = f'OGBOOT_IP="{OGBOOT_IP}"' with open(env_dest, 'a') as env_file: env_file.write(f"\n{ogboot_ip}\n") logger.info(f"Added OGBOOT_IP to {env_dest} with IP: {OGBOOT_IP}") ogboot_port = f'OGBOOT_PORT="{OGBOOT_PORT}"' with open(env_dest, 'a') as env_file: env_file.write(f"\n{ogboot_port}\n") logger.info(f"Added OGBOOT_PORT to {env_dest} with IP: {OGBOOT_PORT}") except Exception as e: logger.error(f"An error occurred while copying files or modifying .env: {e}") raise def og_boot_copy_files(): bin_source = os.path.join(REPO_DIR, "bin") bin_dest = os.path.join(INSTALL_OGBOOT_TARGET, "bin") src_source = os.path.join(REPO_DIR, "src") src_dest = os.path.join(INSTALL_OGBOOT_TARGET, "src") config_source = os.path.join(REPO_DIR, "config") config_dest = os.path.join(INSTALL_OGBOOT_TARGET, "config") lib_source = os.path.join(REPO_DIR, "lib") lib_dest = os.path.join(INSTALL_OGBOOT_TARGET, "lib") #os.makedirs("/tmp/opt", exist_ok=True) #subprocess.run(["chown", "-R", "ogboot:ogboot", "/tmp/opt"]) 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_OGBOOT_TARGET, "public"), mode=0o775, exist_ok=True) subprocess.run(["chmod", "-R", "775", INSTALL_OGBOOT_TARGET]) subprocess.run(["chown", "-R", "opengnsys:opengnsys", INSTALL_OGBOOT_TARGET]) def og_boot_composer_install(): # Ejecutar Composer como el usuario 'opengnsys' para instalar el proyecto Symfony result = subprocess.run(["sudo", "-u", "opengnsys", "composer", "install", "--no-interaction", "--working-dir", INSTALL_OGBOOT_TARGET]) if result.returncode != 0: logger.error("Error creating Symfony project using Composer") return # Ejecutar Composer como el usuario 'opengnsys' para actualizar el paquete doctrine/dbal result = subprocess.run(["sudo", "-u", "opengnsys", INSTALL_OGBOOT_TARGET+"/bin/composer.phar", "update", "doctrine/dbal", "--working-dir", INSTALL_OGBOOT_TARGET]) if result.returncode != 0: logger.error("Error updating doctrine/dbal package using Composer") return subprocess.call(["chown", "-R", "opengnsys:opengnsys", f"{INSTALL_OGBOOT_TARGET}/public"]) logger.info("Application skeleton created.") ############################################################################### ###:::::::::::::::::::::::::::: CONFIGURE ::::::::::::::::::::::::::::::::::### ############################################################################### # Obtener la UID y GID del usuario ogboot def get_ogboot_uid_gid(): try: user_info = pwd.getpwnam('opengnsys') uid = user_info.pw_uid gid = user_info.pw_gid return uid, gid except KeyError: raise Exception("El usuario 'opengnsys' no existe.") # Añadir líneas al fstab def add_fstab_entries(uid, gid): try: fstab_entries = [ f'{INSTALL_OGBOOT_TARGET}/lib/oglive.iso {INSTALL_OGBOOT_TARGET}/mnt iso9660 loop,ro,users,uid={uid},gid={gid},noauto 0 0\n', f'/var/lib/tftpboot/ogLive/ogclient.sqfs /tmp/ogclient_mount squashfs loop,ro,user,noauto 0 0\n' ] with open('/etc/fstab', 'r') as fstab: existing_entries = fstab.readlines() # Check if the entries already exist in /etc/fstab for entry in fstab_entries: if entry not in existing_entries: with open('/etc/fstab', 'a') as fstab: fstab.writelines(entry) logger.info("Entradas añadidas a /etc/fstab correctamente.") else: logger.info("Las entradas ya existen en /etc/fstab. No se añadieron nuevamente.") except IOError: raise Exception("Error al escribir en /etc/fstab.") # Añadir el usuario opengnsys al grupo disk def add_user_to_disk_group(): try: subprocess.run(['usermod', '-aG', 'disk', 'opengnsys'], check=True) logger.info("Usuario 'opengnsys' añadido al grupo 'disk' correctamente.") except subprocess.CalledProcessError: raise Exception("Error al añadir el usuario 'opengnsys' al grupo 'disk'.") def tftpConfigure(): logger.info("Configuring tftpd-hpa...") tftpd_config = """# /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/var/lib/tftpboot" TFTP_ADDRESS="0.0.0.0:69" TFTP_OPTIONS="--secure -v" """ with open("/tmp/tftpd-hpa", "w") as config_file: config_file.write(tftpd_config) shutil.move("/tmp/tftpd-hpa", "/etc/default/tftpd-hpa") logger.info("\t2-Creating and setting permissions for the TFTP directory...") os.makedirs(TFTPCFGDIR, exist_ok=True) logger.info("\t3-Setting permissions for /var/lib/tftpboot directory...") subprocess.run(f"chown -R tftp:opengnsys {TFTPCFGDIR}", shell=True, text=True, capture_output=True) subprocess.run(f"chmod -R 775 {TFTPCFGDIR}", shell=True, text=True, capture_output=True) subprocess.run("systemctl restart tftpd-hpa", shell=True, text=True, capture_output=True) symlink_target = f"{INSTALL_OGBOOT_TARGET}/tftpboot" logger.info(f"Creating symbolic link from {TFTPCFGDIR} to {symlink_target}") if not os.path.exists(symlink_target): os.symlink(TFTPCFGDIR, symlink_target) #os.lchown(symlink_target, pwd.getpwnam("tftp").pw_uid, pwd.getpwnam("opengnsys").pw_gid) else: logger.warning(f"The symbolic link already exists: {symlink_target}") logger.info("Downloading oglive...") try: result = subprocess.run( [INSTALL_OGBOOT_TARGET+"/bin/oglivecli", "download", oglive_iso_url], check=True, capture_output=True, text=True ) # Comprobar si oglivecli ha fallado if result.returncode != 0: try: # Parsear la salida como JSON error_output = json.loads(result.stdout) if error_output.get("status") == "error": logger.error(f"oglivecli error: {error_output.get('error')}") except json.JSONDecodeError: logger.error("Failed to parse oglivecli error output.") logger.error("Continuing with the installation despite oglivecli failure.") else: logger.info("Successful download") symlink_target_ogLive = f"{INSTALL_OGBOOT_TARGET}/tftpboot/ogLive" symlink_target_ogclient = f"{INSTALL_OGBOOT_TARGET}/tftpboot/ogclient" if os.path.exists(symlink_target_ogLive): subprocess.run(["chown", "-R", f"tftp:opengnsys", f"{INSTALL_OGBOOT_TARGET}/tftpboot"], check=True) os.lchown(symlink_target_ogLive, pwd.getpwnam("tftp").pw_uid, pwd.getpwnam("opengnsys").pw_gid) os.lchown(symlink_target_ogclient, pwd.getpwnam("tftp").pw_uid, pwd.getpwnam("opengnsys").pw_gid) logger.info(f"Changing properties for {symlink_target_ogLive} and {symlink_target_ogclient}") else: logger.error(f"{symlink_target_ogLive} link does not exist.") except subprocess.CalledProcessError as e: logger.error(f"Subprocess failed: {e}") logger.error("Continuing with the installation...") def get_first_network_interface_with_traffic(): with open('/proc/net/dev') as f: for line in f: if ':' in line: parts = line.split(':') if len(parts) > 1: interface = parts[0].strip() if interface != "lo": traffic_data = parts[1].strip().split() received_bytes = int(traffic_data[0]) transmitted_bytes = int(traffic_data[8]) if received_bytes > 0 or transmitted_bytes > 0: return interface def install_ipxe(): clone_dir = "/tmp/ipxe_repo" if os.path.exists(f"{INSTALL_OGBOOT_TARGET}/tftpboot/undionly.kpxe"): logger.info('iPXE already present--not compiling again') return True if not os.path.exists(clone_dir): os.makedirs(clone_dir) logger.info(f"Cloning the repository {ipxe_repo_url}") if subprocess.call(["git", "-c", "http.sslVerify=false", "clone", ipxe_repo_url, clone_dir]) == 0: logger.info("Repository cloned successfully.") else: logger.error(f"ERROR: Could not clone the repository {ipxe_repo_url}.") return False else: logger.info(f"Repository already exists at {clone_dir}") cwd = os.getcwd() os.chdir(f"{clone_dir}/src") logger.info("Generating make of undionly.kpxe:") if subprocess.run(["make", "-s", "bin/undionly.kpxe", f"EMBED={INSTALL_OGBOOT_TARGET}/tftpboot/ipxe_scripts/dhcp_boot.ipxe"], capture_output=True).returncode == 0: logger.info("Boot file mounted correctly.") else: logger.error("Failed to mount boot file.") return False logger.info("Copying undionly.kpxe with user opengnsys:") subprocess.call(["cp", "bin/undionly.kpxe", f"{INSTALL_OGBOOT_TARGET}/tftpboot"]) logger.info("Generating make of ipxe.efi:") if subprocess.run(["make", "-s", "bin-x86_64-efi/ipxe.efi", f"EMBED={INSTALL_OGBOOT_TARGET}/tftpboot/ipxe_scripts/dhcp_boot.ipxe"], capture_output=True).returncode == 0: logger.info("Properly constructed EFI file.") else: logger.error("Could not build EFI file.") return False subprocess.call(["cp", "bin-x86_64-efi/ipxe.efi", f"{INSTALL_OGBOOT_TARGET}/tftpboot"]) subprocess.call(["cp", f"{REPO_DIR}/tftpboot/grub.exe", f"{INSTALL_OGBOOT_TARGET}/tftpboot/"]) os.makedirs(f"{INSTALL_OGBOOT_TARGET}/tftpboot/ipxe_scripts/templates", exist_ok=True) subprocess.call(["cp", "-r", f"{REPO_DIR}/tftpboot/ipxe_scripts/templates/.", f"{INSTALL_OGBOOT_TARGET}/tftpboot/ipxe_scripts/templates"]) subprocess.run(["chmod", "-R", "775", f"{INSTALL_OGBOOT_TARGET}/tftpboot/"]) subprocess.call(["chown", "-R", "opengnsys:opengnsys", f"{INSTALL_OGBOOT_TARGET}/tftpboot/"]) os.chdir(cwd) return True def get_ip_address(interface): try: result = subprocess.check_output(["ip", "addr", "show", interface]).decode() for line in result.split('\n'): if "inet " in line: ip_address = line.strip().split()[1].split('/')[0] return ip_address except subprocess.CalledProcessError as e: logger.error(f"Error get address IP: {e}") return None def generate_ipxe_script(): ip_address_server = OGBOOT_IP ip_address = re.match(r"^(.*?):", ip_address_server) ip_address = ip_address.group(1) if ip_address else ip_address_server template = os.path.join(REPO_DIR, "etc/dhcp_boot.ipxe.tmpl") ipxe_output = f"{INSTALL_OGBOOT_TARGET}/tftpboot/ipxe_scripts/dhcp_boot.ipxe" os.makedirs(os.path.dirname(ipxe_output), mode=0o775, exist_ok=True) #shutil.copy(template, ipxe_output) with open(template, "r") as ipxe_file: ipxe_content = ipxe_file.read() ipxe_content = ipxe_content.replace("__SERVERIP__", ip_address) with open(ipxe_output, "w") as ipxe_file: ipxe_file.write(ipxe_content) template_default = os.path.join(REPO_DIR, "etc/default.ipxe.tmpl") default_output = os.path.join(INSTALL_OGBOOT_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) with open(default_output, "w") as default_ipxe_file: default_ipxe_file.write(default_ipxe_content) logger.info("ipxe files created correctly.") def user_exists(user): try: result = subprocess.run(["pdbedit", "-L", "-u", user], capture_output=True, text=True) return user in result.stdout except subprocess.CalledProcessError as e: logger.error(f"Error checking if user exists: {e}") return False def smbConfigure(): smb_conf = f"{SAMBACFGDIR}/smb.conf" if os.path.exists (smb_conf): dateymd = datetime.datetime.now().strftime("%Y%m%d") shutil.copy2 (smb_conf, f"{smb_conf}-{dateymd}") # Copiar plantilla de recursos para OpenGnsys with open(os.path.join(REPO_DIR, 'etc/smb-ogboot.conf.tmpl'), 'r') as tmpl_file: template = tmpl_file.read() replaced_template = template.replace('__OGBOOTDIR__', INSTALL_OGBOOT_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/", smb_conf]) if "smb-ogboot" not in open(smb_conf).read(): with open(smb_conf, "a") as file: file.write(f"include = {SAMBACFGDIR}/smb-ogboot.conf\n") service = "smbd" logger.info(f"Enabling {service} service.") subprocess.run(["systemctl", "enable", f"{service}.service"]) logger.info(f"Restarting {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: logger.info(f"{service} service started successfully.") else: logger.error(f"Failed to start {service} service.") return 1 # Ejecutar el comando smbpasswd para agregar el usuario de Samba try: if user_exists(OPENGNSYS_CLIENT_USER): logger.info(f"{OPENGNSYS_CLIENT_USER} user exists. Changing password...") extra_params = [] else: logger.info(f"{OPENGNSYS_CLIENT_USER} user does not exist. Registering user...") extra_params = ['-a'] subprocess.run( ["smbpasswd"] + extra_params + [OPENGNSYS_CLIENT_USER], input=f"{OPENGNSYS_CLIENT_PASSWD}\n{OPENGNSYS_CLIENT_PASSWD}\n", text=True, capture_output=True, check=True ) logger.info("Add/Modify user: Operation completed successfully.") except subprocess.CalledProcessError as e: logger.error(f"Error adding/modifying user: {e}") return 0 def setup_nginx(): try: # Obtener la IP del servidor ip_address_server = OGBOOT_IP port_address_server = OGBOOT_PORT php_version = get_php_fpm_version() # Leer y modificar la plantilla de configuración de nginx template_path = os.path.join(REPO_DIR, "etc/nginxServer.conf.tmpl") with open(template_path, 'r') as nginx_file: nginx_content = nginx_file.read() nginx_content = nginx_content.replace("__SERVERIP__", ip_address_server) nginx_content = nginx_content.replace("__PORT__", port_address_server) nginx_content = nginx_content.replace("__PHPVERSION__", php_version) nginx_content = nginx_content.replace("__ROOT__", INSTALL_OGBOOT_TARGET) nginx_content = nginx_content.replace("__TFTPPATH__", f"{INSTALL_OGBOOT_TARGET}/tftpboot") # Ruta de destino para la configuración de nginx nginx_output = "/etc/nginx/sites-available/ogboot.conf" with open(nginx_output, 'w') as nginx_file: nginx_file.write(nginx_content) logger.info("Nginx configuration file created successfully.") # Crear el enlace simbólico en sites-enabled subprocess.run(["ln", "-sf", nginx_output, "/etc/nginx/sites-enabled/ogboot.conf"]) logger.info("Symbolic link for nginx configuration created successfully.") # Modificar el archivo de configuración de nginx para ejecutarse como ogboot nginx_conf_path = "/etc/nginx/nginx.conf" with open(nginx_conf_path, 'r') as nginx_conf_file: nginx_conf_content = nginx_conf_file.read() nginx_conf_content = nginx_conf_content.replace("user www-data;", "user opengnsys;") with open(nginx_conf_path, 'w') as nginx_conf_file: nginx_conf_file.write(nginx_conf_content) logger.info("Nginx configuration file modified to run as opengnsys.") # Reiniciar el servicio de samba subprocess.run(["systemctl", "restart", "nginx.service"]) except subprocess.CalledProcessError as e: logger.error(f"Subprocess error: {e}") exit(1) except OSError as e: logger.error(f"OS error: {e}") exit(1) def get_php_fpm_version(): try: # Obtener la versión de PHP php_version_output = subprocess.check_output(["php", "-v"]).decode() # Extraer la versión principal y secundaria (por ejemplo, "7.4") match = re.search(r"PHP (\d+\.\d+)", php_version_output) if match: php_version = match.group(1) return php_version else: raise RuntimeError("No se pudo determinar la versión de PHP.") except subprocess.CalledProcessError as e: logger.error(f"Error al obtener la versión de PHP: {e}") exit(1) def modify_php_fpm_config(): php_version = get_php_fpm_version() php_fpm_conf_path = f"/etc/php/{php_version}/fpm/pool.d/www.conf" new_fpm_conf_path = f"/etc/php/{php_version}/fpm/pool.d/ogboot.conf" socket_path = f"/run/php/php{php_version}-fpm-ogboot.sock" if os.path.exists(new_fpm_conf_path): logger.info(f"Archivo {new_fpm_conf_path} ya existe. No se realizarán modificaciones.") return try: # Copiar www.conf a ogboot.conf subprocess.run(["cp", php_fpm_conf_path, new_fpm_conf_path], check=True) logger.info(f"Archivo {php_fpm_conf_path} copiado a {new_fpm_conf_path}") # Leer el archivo copiado opengnsys.conf with open(new_fpm_conf_path, 'r') as file: config_lines = file.readlines() # Modificar las líneas necesarias with open(new_fpm_conf_path, 'w') as file: for line in config_lines: if line.startswith('[www]'): file.write('[ogboot]\n') # Cambiar el nombre del pool elif line.startswith('user ='): file.write('user = opengnsys\n') elif line.startswith('group ='): file.write('group = opengnsys\n') elif line.startswith('listen ='): file.write(f'listen = {socket_path}\n') # Cambiar el nombre del socket elif line.startswith('listen.owner ='): file.write('listen.owner = opengnsys\n') elif line.startswith('listen.group ='): file.write('listen.group = opengnsys\n') else: file.write(line) logger.info(f"Archivo {new_fpm_conf_path} modificado correctamente.") # Reiniciar el servicio PHP-FPM subprocess.run(["systemctl", "restart", f"php{php_version}-fpm"], check=True) logger.info("Servicio PHP-FPM reiniciado correctamente.") subprocess.run(["systemctl", "restart", "nginx.service"]) # Verificar que el socket se ha creado if os.path.exists(socket_path): logger.info(f"Socket {socket_path} creado correctamente.") else: logger.error(f"El socket {socket_path} no se ha creado.") exit(1) except Exception as e: logger.error(f"Ocurrió un error: {e}") exit(1) ############################################################################### ###:::::::::::::::::::::::::::::::: MAIN :::::::::::::::::::::::::::::::::::### ############################################################################### logger.info(f":::::::::::::::::::::::: Starting ogBoot installation ::::::::::::::::::::::::") logger.info("environment variables") logger.info(f"OGCORE_IP:{OGCORE_IP}") logger.info(f"INSTALL_OGBOOT_TARGET:{INSTALL_OGBOOT_TARGET}") if os.geteuid() != 0: logger.error("This program must be run with root privileges..") exit(1) ## doc no existe nunca if os.path.exists(os.path.join(INSTALL_OGBOOT_TARGET, "/doc/")): logger.warning(f"ogBoot is already installed. Run {INSTALL_OGBOOT_TARGET}/lib/ogboot_devel_update.py with root privileges to update..") exit(2) try: logger.info("Verifying Python distribution and version.") check_distribution() check_python_version() except Exception as e: logger.error(f"Error verifying Python distribution or version: {e}") exit(1) try: logger.info("Installing necessary packages.") install_packages() except Exception as e: logger.error(f"Error installing necessary packages: {e}") exit(1) try: logger.info("Obtaining the default network configuration.") DEFAULTDEV = get_first_network_interface_with_traffic() logger.info(f"Network interface default:[{DEFAULTDEV}]") except Exception as e: logger.error(f"Error obtaining network configuration: {e}") exit(1) try: add_sudoers_permissions() except Exception as e: logger.error(f"Error adding sudoers permissions: {e}") exit(1) try: logger.info("Creating ogBoot project.") og_core_create_user("opengnsys") og_core_create_user(OPENGNSYS_CLIENT_USER) except Exception as e: logger.error(f"Error creating ogBoot project or users: {e}") exit(1) try: logger.info("Creating directories.") og_boot_create_dirs() except Exception as e: logger.error(f"Error creating directories: {e}") exit(1) try: logger.info("Copying installation files.") og_boot_copy_files() except Exception as e: logger.error(f"Error copying installation files: {e}") exit(1) try: logger.info("Installing Symfony.") og_boot_symfony_install() except Exception as e: logger.error(f"Error installing Symfony: {e}") exit(1) try: logger.info("Installing Composer.") og_boot_composer_install() except Exception as e: logger.error(f"Error installing Composer: {e}") exit(1) try: logger.info("Obteniendo UID y GID del usuario 'opengnsys'.") uid, gid = get_ogboot_uid_gid() logger.info("Añadiendo entradas al archivo /etc/fstab.") add_fstab_entries(uid, gid) logger.info("Añadiendo el usuario 'opengnsys' al grupo 'disk'.") add_user_to_disk_group() except Exception as e: logger.error(f"Error durante la configuración: {e}") exit(1) try: logger.info("Configuring tftpd-hpa service.") tftpConfigure() except Exception as e: logger.error(f"Error configuring tftpd-hpa service: {e}") exit(1) try: logger.info("Configuring IPXE services") generate_ipxe_script() except Exception as e: logger.error(f"Error configuring IPXE services: {e}") exit(1) try: logger.info("Installing iPXE") if not install_ipxe(): logger.error(f"Error installing iPXE") exit(1) except Exception as e: logger.error(f"Error installing iPXE: {e}") exit(1) try: logger.info("Setup nginx") setup_nginx() except Exception as e: logger.error(f"Error setting up nginx: {e}") exit(1) try: logger.info("Configure php fpm") modify_php_fpm_config() except Exception as e: logger.error(f"Error configuring php fpm: {e}") exit(1) try: logger.info("Configuring Samba") smbConfigure() except Exception as e: logger.error(f"Error configuring Samba: {e}") exit(1) logger.info(f"ogBoot installation finished.") logging.shutdown() console_handler.close()