diff --git a/client/interfaceAdm/InventarioHardware.py b/client/interfaceAdm/InventarioHardware.py old mode 100644 new mode 100755 index 1c55736..5793bfe --- a/client/interfaceAdm/InventarioHardware.py +++ b/client/interfaceAdm/InventarioHardware.py @@ -3,13 +3,27 @@ import sys def main(output_file): # Ejecutar el comando `listHardwareInfo.py` y capturar el resultado - result = subprocess.run(["python3", "/opt/opengnsys/scripts/listHardwareInfo.py"], capture_output=True, text=True, check=True) - file_path = result.stdout.strip() # Obtener la ruta del archivo de salida de `listHardwareInfo.py` + try: + print(f"------------------------------------------ loading listHardwareInfo.py") + result = subprocess.run( + ["python3", "/opt/opengnsys/scripts/listHardwareInfo.py"], + capture_output=True, text=True, check=True + ) + output_lines = result.stdout.strip().split('\n') + file_path = output_lines[-1] # Obtener la última línea como la ruta del archivo de salida + print(f"------------------------------------------ archivo:{file_path}") + + # Leer desde la segunda línea del archivo y escribir en el archivo de salida especificado + with open(file_path, 'r') as input_file, open(output_file, 'w') as output: + lines = input_file.readlines()[1:] # Saltar la primera línea + output.writelines(lines) - # Leer desde la segunda línea del archivo y escribir en el archivo de salida especificado - with open(file_path, 'r') as input_file, open(output_file, 'w') as output: - lines = input_file.readlines()[1:] # Saltar la primera línea - output.writelines(lines) + except subprocess.CalledProcessError as e: + print("Error ejecutando listHardwareInfo.py:", e.stderr, file=sys.stderr) + sys.exit(e.returncode) + except FileNotFoundError as e: + print(f"Archivo no encontrado: {e.filename}", file=sys.stderr) + sys.exit(1) if __name__ == "__main__": if len(sys.argv) != 2: diff --git a/client/lib/engine/bin/InventoryLib.lib b/client/lib/engine/bin/InventoryLib.lib deleted file mode 100644 index 3dd0836..0000000 --- a/client/lib/engine/bin/InventoryLib.lib +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python3 - -import os -import stat - -#def ogGetArch(): -#def ogGetOsType(): -#def ogGetOsUuid(): -#def ogGetSerialNumber(): - -#/** -# ogIsEfiActive -#@brief Comprueba si el sistema tiene activo el arranque EFI. -#*/ ## -def ogIsEfiActive(): - try: - return stat.S_ISDIR (os.stat ('/sys/firmware/efi').st_mode) - except: - return False - -#def ogListHardwareInfo(): -#def ogListSoftware(): -#def ogGetOsVersion(): diff --git a/client/lib/engine/bin/InventoryLib.py b/client/lib/engine/bin/InventoryLib.py new file mode 100755 index 0000000..1f1d7ff --- /dev/null +++ b/client/lib/engine/bin/InventoryLib.py @@ -0,0 +1,379 @@ +import glob +import platform +import sys +import os +import subprocess +import tempfile +import re +import json +import shutil +import sqlite3 +from SystemLib import ogMount, ogGetOsType, ogRaiseError, ogHelp, ogGetOsVersion, ogGetHivePath, ogListRegistryKeys, ogGetRegistryValue, ogGetIpAddress + +sys.path.append('/opt/opengnsys/lib/engine/bin') +from SystemLib import ogEcho +#from Disklib import ogDiskToDev +#from engine.FileLib import * +#from engine.RegistryLib import * +#from engine.FileSystemLib import * + +MSG_HARDWAREINVENTORY = "Inventario de hardware de la máquina" + +def ogGetArch(): + if len(sys.argv) > 1 and sys.argv[1] == "help": + ogHelp(sys.argv[0], sys.argv[0], sys.argv[0] + " => x86_64") + return + + if platform.machine().endswith("64"): + print("x86_64") + else: + print("i386") + +def ogGetOsType(): + # Si se solicita, mostrar ayuda. + if len(sys.argv) > 1 and sys.argv[1] == "help": + ogHelp(sys.argv[0], sys.argv[0] + " int_ndisk int_npartition", sys.argv[0] + " 1 2 => Linux") + return + ogGetOsVersion(sys.argv[1:]).split(':')[0] + +def ogGetOsUuid(): + # Si se solicita, mostrar ayuda. + if len(sys.argv) > 1 and sys.argv[1] == "help": + ogHelp(sys.argv[0], sys.argv[0] + " int_ndisk int_nfilesys", sys.argv[0] + " 1 2 => 540e47c6-8e78-4178-aa46-042e4803fb16") + return + + # Error si no se reciben 2 parametros. + if len(sys.argv) != 3: + ogRaiseError(OG_ERR_FORMAT) + return + + # Montar la particion, si no lo estaba previamente. + MNTDIR = ogMount(sys.argv[1], sys.argv[2]) + if not MNTDIR: + return + + # Obtener UUID según el tipo de sistema operativo. + os_type = ogGetOsType(sys.argv[1], sys.argv[2]) + if os_type == "Linux": + # Leer el UUID del sistema de ficheros raíz o el fichero de identificador. + uuid = subprocess.check_output(["findmnt", "-no", "UUID", MNTDIR], stderr=subprocess.DEVNULL).decode().strip() or open(os.path.join(MNTDIR, "etc", "machine-id")).read().strip() + print(uuid) + elif os_type == "Windows": + # Leer identificador en clave de registro. + uuid = ogGetRegistryValue(MNTDIR, "SOFTWARE", "\\Microsoft\\Cryptography\\MachineGuid") + print(uuid) + +def ogGetSerialNumber(): + # Si se solicita, mostrar ayuda. + if len(sys.argv) > 1 and sys.argv[1] == "help": + ogHelp(sys.argv[0], sys.argv[0], sys.argv[0] + " => 123456") + return + + # Obtener nº de serie (ignorar los no especificados). + SERIALNO = subprocess.check_output(["dmidecode", "-s", "system-serial-number"]).decode().strip() + SERIALNO = re.sub(r"(not specified|to be filled|invalid entry|default string)", "", SERIALNO, flags=re.IGNORECASE) + SERIALNO = SERIALNO.replace(" ", "") + SERIALNO = SERIALNO[:25] if len(SERIALNO) > 25 else SERIALNO + if SERIALNO: + print(SERIALNO) + + return 0 + +def ogIsEfiActive(): + return os.path.isdir("/sys/firmware/efi") + +import subprocess +import os +import sys + +def parse_lshw_output(): + try: + # Ejecutar lshw en formato JSON para un fácil procesamiento + lshw_output = subprocess.check_output(["lshw", "-json"], text=True) + lshw_data = json.loads(lshw_output) # Convertir la salida JSON a un diccionario + + # Extraer información relevante en el formato clave=valor + parsed_output = [] + + # Ejemplo de datos clave que podríamos extraer + if "product" in lshw_data: + parsed_output.append(f"product={lshw_data['product']}") + + if "vendor" in lshw_data: + parsed_output.append(f"vendor={lshw_data['vendor']}") + + if "configuration" in lshw_data and "memory" in lshw_data["configuration"]: + parsed_output.append(f"memory={lshw_data['configuration']['memory']}") + + # Recorrer los dispositivos para obtener información de CPU, almacenamiento, etc. + for item in lshw_data.get("children", []): + if item["class"] == "processor": + parsed_output.append(f"cpu={item.get('product', 'Unknown')}") + elif item["class"] == "memory" and "size" in item: + parsed_output.append(f"total_memory={item['size']}") + elif item["class"] == "disk": + parsed_output.append(f"disk={item.get('product', 'Unknown')}") + + # Devolver los datos combinados + return "\n".join(parsed_output) + + except subprocess.CalledProcessError as e: + print(f"Error al ejecutar lshw: {e}") + return "Error al obtener información de hardware" + +def ogListHardwareInfo(): + # Ejecutar dmidecode y obtener tipo de chasis + try: + output = subprocess.check_output('echo "cha=$(dmidecode -s chassis-type)" | grep -v "Other"', shell=True).decode().strip() + except subprocess.CalledProcessError: + output = "cha=Unknown" + + # Detectar BIOS o UEFI + firmware = "boo=UEFI" if os.path.isdir("/sys/firmware/efi") else "boo=BIOS" + print(firmware) + + # Ejecutar y analizar lshw + lshw_output = parse_lshw_output() + + # Combina y devuelve los resultados + return f"{output}\n{firmware}\n{lshw_output}" + +def ogListSoftware(disk, partition): + # Error si no se reciben 2 parametros + if disk is None or partition is None: + og_raise_error("OG_ERR_FORMAT") + return + + # Obtener tipo de sistema de archivos y montarlo + mnt_dir = og_mount(disk, partition) + os_type = og_get_os_type(disk, partition) + + # Ficheros temporales + apps_file = tempfile.NamedTemporaryFile(delete=False) + tmp_file = tempfile.NamedTemporaryFile(delete=False) + + try: + if os_type == "Linux": + # Procesar paquetes dpkg + pkg_dir = os.path.join(mnt_dir, "var/lib/dpkg") + if os.path.exists(pkg_dir): + with open(os.path.join(pkg_dir, "status"), "r") as status_file: + for line in status_file: + # Process lines to extract software info + pass + # Procesar paquetes RPM + pkg_dir = os.path.join(mnt_dir, "var/lib/rpm") + if os.path.exists(pkg_dir): + # Execute rpm command if available + if shutil.which("rpm"): + subprocess.run(["rpm", "--dbpath", pkg_dir, "-qa", "--qf", "%{NAME} %{VERSION}\n"], stdout=apps_file) + else: + # Compatibility mode for older systems + pass + # Procesar otros tipos de paquetes (pacman, snap, flatpak, etc.) + pass + elif os_type == "Windows": + # Procesar aplicaciones instaladas en Windows + hive_path = og_get_hive_path(mnt_dir, "software") + if hive_path: + subprocess.run(["hivexregedit", "--unsafe-printable-strings", "--export", hive_path, '\Microsoft\Windows\CurrentVersion\Uninstall'], stdout=tmp_file) + elif os_type == "MacOS": + # Procesar aplicaciones instaladas en MacOS + pass + elif os_type == "BSD": + # Procesar aplicaciones instaladas en FreeBSD + pass + else: + og_raise_error("OG_ERR_NOTOS", disk, partition) + finally: + # Eliminar archivos temporales + apps_file.close() + tmp_file.close() + os.remove(apps_file.name) + os.remove(tmp_file.name) + + # Mostrar sistema operativo y aplicaciones + og_get_os_version(disk, partition) + with open(apps_file.name, "r") as apps: + for line in sorted(set(apps.readlines())): + print(line.strip()) + +def ogGetOsVersion(ndisk, nfilesys): + # Variables locales. + MNTDIR = ogMount(ndisk, nfilesys) + TYPE = "" + VERSION = "" + IS64BIT = "" + + # Si se solicita, mostrar ayuda. + if len(sys.argv) > 1 and sys.argv[1] == "help": + ogHelp(sys.argv[0], sys.argv[0] + " int_ndisk int_nfilesys", sys.argv[0] + " 1 2 => Linux:Ubuntu precise (12.04 LTS) 64 bits") + return + + # Error si no se reciben 2 parametros. + if len(sys.argv) != 3: + ogRaiseError(OG_ERR_FORMAT) + return + + # Montar la particion, si no lo estaba previamente. + MNTDIR = ogMount(sys.argv[1], sys.argv[2]) + if not MNTDIR: + return + + # Buscar tipo de sistema operativo. + # Para GNU/Linux: leer descripción. + TYPE = "Linux" + FILE = os.path.join(MNTDIR, "etc", "os-release") + if os.path.exists(FILE): + with open(FILE, "r") as f: + for line in f: + if line.startswith("PRETTY_NAME"): + VERSION = line.split("=")[1].strip().strip('"') + break + + # Si no se puede obtener, buscar en ficheros del sistema. + if not VERSION: + FILE = os.path.join(MNTDIR, "etc", "lsb-release") + if os.path.exists(FILE): + with open(FILE, "r") as f: + for line in f: + if line.startswith("DESCRIPTION"): + VERSION = line.split("=")[1].strip().strip('"') + break + for DISTRIB in ["redhat", "SuSE", "mandrake", "gentoo"]: + FILE = os.path.join(MNTDIR, "etc", f"{DISTRIB}-release") + if os.path.exists(FILE): + with open(FILE, "r") as f: + VERSION = f.readline().strip() + break + FILE = os.path.join(MNTDIR, "etc", "arch-release") + if os.path.exists(FILE): + VERSION = "Arch Linux" + FILE = os.path.join(MNTDIR, "etc", "slackware-version") + if os.path.exists(FILE): + with open(FILE, "r") as f: + VERSION = f.read().strip() + + # Si no se encuentra, intentar ejecutar "lsb_release". + if not VERSION: + try: + output = subprocess.check_output(["chroot", MNTDIR, "lsb_release", "-d"], stderr=subprocess.DEVNULL).decode().strip() + VERSION = output.split(":")[1].strip() + except subprocess.CalledProcessError: + pass + + # Comprobar Linux de 64 bits. + if VERSION and os.path.exists(os.path.join(MNTDIR, "lib64")): + IS64BIT = "64 bits" + + # Para Android, leer fichero de propiedades. + if not VERSION: + TYPE = "Android" + FILE = os.path.join(MNTDIR, "android*", "system", "build.prop") + if glob.glob(FILE): + with open(glob.glob(FILE)[0], "r") as f: + lines = f.readlines() + brand = "" + release = "" + for line in lines: + if line.startswith("product.brand"): + brand = line.split("=")[1].strip() + elif line.startswith("build.version.release"): + release = line.split("=")[1].strip() + VERSION = f"Android {brand} {release}" + if os.path.exists(os.path.join(MNTDIR, "lib64")): + IS64BIT = "64 bits" + + # Para GNU/Hurd, comprobar fichero de inicio (basado en os-prober). + if not VERSION: + TYPE = "Hurd" + FILE = os.path.join(MNTDIR, "hurd", "init") + if os.path.exists(FILE): + VERSION = "GNU/Hurd" + + # Para Windows: leer la version del registro. + if not VERSION: + TYPE = "Windows" + FILE = ogGetHivePath(MNTDIR, "SOFTWARE") + if FILE: + try: + output = subprocess.check_output(["hivexsh", "load", FILE, "cd", "\\Microsoft\\Windows NT\\CurrentVersion", "lsval", "ProductName", "lsval", "DisplayVersion"], stderr=subprocess.DEVNULL).decode().strip() + lines = output.split("\n") + if len(lines) == 2: + VERSION = lines[1].strip() + if ogGetRegistryValue(MNTDIR, "SOFTWARE", "\\Microsoft\\Windows\\CurrentVersion\\ProgramW6432Dir"): + IS64BIT = "64 bits" + except subprocess.CalledProcessError: + pass + + # Para cargador Windows: buscar versión en fichero BCD (basado en os-prober). + if not VERSION: + TYPE = "WinLoader" + FILE = ogGetPath(MNTDIR, "boot", "bcd") + if not FILE: + FILE = ogGetPath(MNTDIR, "EFI", "Microsoft", "boot", "bcd") + if FILE: + for DISTRIB in ["Windows Recovery", "Windows Boot"]: + with open(FILE, "rb") as f: + if re.search(DISTRIB.encode(), f.read()): + VERSION = f"{DISTRIB} loader" + break + + # Para macOS: detectar kernel y completar con fichero plist de información del sistema. + if not VERSION: + TYPE = "MacOS" + FILE = os.path.join(MNTDIR, "mach_kernel") + if os.path.exists(FILE) and not subprocess.check_output(["file", "-b", FILE]).decode().strip().startswith("text"): + if subprocess.check_output(["file", "-b", FILE]).decode().strip().startswith("Mach-O"): + VERSION = "macOS" + if subprocess.check_output(["file", "-b", FILE]).decode().strip().startswith("Mach-O 64-bit"): + IS64BIT = "64 bits" + FILE = os.path.join(MNTDIR, "System", "Library", "CoreServices", "SystemVersion.plist") + if os.path.exists(FILE): + with open(FILE, "r") as f: + plist_data = f.read() + product_name = re.search(r"ProductName\s*(.*?)", plist_data) + product_version = re.search(r"ProductVersion\s*(.*?)", plist_data) + if product_name and product_version: + VERSION = f"{product_name.group(1)} {product_version.group(1)}" + FILE = os.path.join(MNTDIR, "com.apple.recovery.boot") + if os.path.exists(FILE) and VERSION: + VERSION = f"{VERSION} recovery" + + # Para FreeBSD: obtener datos del Kernel. + if not VERSION: + TYPE = "BSD" + FILE = os.path.join(MNTDIR, "boot", "kernel", "kernel") + if os.path.exists(FILE): + output = subprocess.check_output(["strings", FILE]).decode().strip() + match = re.search(r"@.*RELEASE", output) + if match: + VERSION = match.group().split("@")[0].strip() + if subprocess.check_output(["file", "-b", FILE]).decode().strip().endswith("x86-64"): + IS64BIT = "64 bits" + + # Para Solaris: leer el fichero de versión. + if not VERSION: + TYPE = "Solaris" + FILE = os.path.join(MNTDIR, "etc", "release") + if os.path.exists(FILE): + with open(FILE, "r") as f: + VERSION = f.readline().strip() + + # Para cargador GRUB, comprobar fichero de configuración. + if not VERSION: + TYPE = "GrubLoader" + for FILE in [os.path.join(MNTDIR, "grub", "menu.lst"), os.path.join(MNTDIR, "boot", "grub", "menu.lst")]: + if os.path.exists(FILE): + VERSION = "GRUB Loader" + break + for FILE in glob.glob(os.path.join(MNTDIR, "{,boot/}{grub{,2},EFI/*}/grub.cfg")): + if os.path.exists(FILE): + VERSION = "GRUB2 Loader" + break + + # Mostrar resultado y salir sin errores. + if VERSION: + print(f"{TYPE}:{VERSION} {IS64BIT}") + + return 0 diff --git a/client/shared/scripts/listHardwareInfo.py b/client/shared/scripts/listHardwareInfo.py old mode 100644 new mode 100755 index d920c73..9f633b1 --- a/client/shared/scripts/listHardwareInfo.py +++ b/client/shared/scripts/listHardwareInfo.py @@ -1,9 +1,10 @@ import subprocess import os import sys -sys.path.append('/opt/opengnsys/lib/engine/bin') # Agregar ruta de NetLib.py -from InventoryLib import ogListHardwareInfo +sys.path.append('/opt/opengnsys/lib/engine/bin') from NetLib import ogGetIpAddress +sys.path.append('/opt/opengnsys/lib/engine/bin') +from InventoryLib import ogListHardwareInfo def get_server_log_dir(): # Obtener el directorio de logs del servidor @@ -19,10 +20,10 @@ def get_server_log_dir(): def list_hardware_info(): oglog = os.getenv("OGLOG", "/tmp") # Usar /tmp como valor por defecto para OGLOG - + ip_address = ogGetIpAddress() # Fichero de listado de hardware basado en la IP obtenida hardfile = f"hard-{ogGetIpAddress()}" - + print(f"hardfile:{hardfile}") # Ejecutar ogListHardwareInfo y redirigir al archivo de listado hardware_info_path = os.path.join(oglog, hardfile) with open(hardware_info_path, 'w') as output_file: