#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Este script elimina la imagen que recibe como parámetro (y todos sus archivos asociados), moviendo los archivos a la papelera (respetando el subdirectorio correspondiente a la OU, si fuera el caso), o eliminándolos permanentemente si se especifica el parámetro "-p". Es similar al script bash original (cuyo nombre es "deleteimage", a secas), pero este no incluía la funcionalidad papelera. Llama al script "updateRepoInfo.py", para actualizar la información del repositorio. Parámetros ------------ sys.argv[1] - Nombre completo de la imagen a eliminar (con o sin ruta), pero incluyendo el subdirectorio correspondiente a la OU, si es el caso. - Ejemplo1: image1.img - Ejemplo2: /opt/opengnsys/ogrepository/images/image1.img - Ejemplo3: ou_subdir/image1.img - Ejemplo4: /ou_subdir/image1.img - Ejemplo5: /opt/opengnsys/ogrepository/images/ou_subdir/image1.img sys.argv[2] - Parámetro opcional para especificar que la eliminación sea permanente (sin papelera). - Ejemplo: -p Sintaxis ---------- ./deleteImage.py [ou_subdir/]image_name|/image_path/image_name [-p] Ejemplos --------- ./deleteImage.py image1.img -p ./deleteImage.py /opt/opengnsys/ogrepository/images/image1.img -p ./deleteImage.py ou_subdir/image1.img -p ./deleteImage.py /ou_subdir/image1.img ./deleteImage.py /opt/opengnsys/ogrepository/images/ou_subdir/image1.img """ # -------------------------------------------------------------------------------------------- # IMPORTS # -------------------------------------------------------------------------------------------- import os import sys import shutil import pwd import grp import subprocess # -------------------------------------------------------------------------------------------- # VARIABLES # -------------------------------------------------------------------------------------------- script_name = os.path.basename(__file__) repo_path = '/opt/opengnsys/ogrepository/images/' # No borrar la barra final trash_path = '/opt/opengnsys/ogrepository/images_trash/' update_repo_script = '/opt/opengnsys/ogrepository/bin/updateRepoInfo.py' # -------------------------------------------------------------------------------------------- # FUNCTIONS # -------------------------------------------------------------------------------------------- def show_help(): """ Imprime la ayuda, cuando se ejecuta el script con el parámetro "help". """ help_text = f""" Sintaxis: {script_name} [ou_subdir/]image_name|/image_path/image_name [-p] Ejemplo1: {script_name} image1.img -p Ejemplo2: {script_name} /opt/opengnsys/ogrepository/images/image1.img -p Ejemplo3: {script_name} ou_subdir/image1.img -p Ejemplo4: {script_name} /ou_subdir/image1.img Ejemplo5: {script_name} /opt/opengnsys/ogrepository/images/ou_subdir/image1.img """ print(help_text) def check_params(): """ Comprueba que se haya enviado la cantidad correcta de parámetros, y en el formato correcto. Si no es así, muestra un mensaje de error, y sale del script. LLama a la función "show_help" cuando se ejecuta el script con el parámetro "help". """ # Si se ejecuta el script sin parámetros, se muestra un error y la ayuda, y se sale del script: if len(sys.argv) == 1: print(f"{script_name} Error: Formato incorrecto: Se debe especificar al menos 1 parámetro") show_help() sys.exit(0) # Si se ejecuta el script con el parámetro "help", se muestra la ayuda, y se sale del script: elif len(sys.argv) == 2 and sys.argv[1] == "help": show_help() sys.exit(1) # Si se ejecuta el script con el parámetro "help" y más parámetros, se muestra un error y la ayuda, y se sale del script: elif len(sys.argv) > 2 and sys.argv[1] == "help": print(f"{script_name} Error: Formato incorrecto: Para invocar la ayuda, se debe especificar 'help' como único parámetro") show_help() sys.exit(2) # Si se ejecuta el script con 2 parámetros y el segundo es diferente de "-p", se muestra un error y la ayuda, y se sale del script: elif len(sys.argv) == 3 and sys.argv[2] != "-p": print(f"{script_name} Error: Formato incorrecto: El segundo parámetro solo puede ser '-p'") show_help() sys.exit(3) # Si se ejecuta el script con más de 2 parámetros, se muestra un error y la ayuda, y se sale del script: elif len(sys.argv) > 3: print(f"{script_name} Error: Formato incorrecto: Se debe especificar 1 o 2 parámetros") show_help() sys.exit(4) def build_file_path(): """ Construye la ruta completa al archivo a eliminar (agregando "/opt/opengnsys/images/" si no se ha especificado en el parámetro). """ param_path = sys.argv[1] # Si la ruta comienza con una barra, pero que no corresponde a "repo_path" # (porque corresponderá al subdirectorio de una OU), eliminamos la barra: if param_path.startswith('/') and not param_path.startswith(repo_path): param_path = param_path.lstrip('/') # Construimos la ruta completa: if not param_path.startswith(repo_path): file_path = os.path.join(repo_path, param_path) else: file_path = param_path return file_path def create_trash_folder(): """ Crea el directorio correspondiente a la papelera, y le asigna propietarios y permisos. Evidentemente, esta función solo es llamada cuando no existe el directorio. """ # Obtenemos el UID del usuario "root" y el GID del grupo "opengnsys": uid = pwd.getpwnam('root').pw_uid gid = grp.getgrnam('opengnsys').gr_gid # Creamos el directorio correspondiente a la papelera: os.mkdir(trash_path) # Asignamos el usuario y el grupo propietarios del directorio: os.chown(trash_path, uid, gid) # Asignamos permisos "775" al directorio : os.chmod(trash_path, 0o775) def delete_normal_image(file_path, method, extensions): """ Elimina la imagen "normal" que recibe en el parámetro "file_path", y todos sus archivos asociados, moviéndolos a la papelera o eliminándolos permanentemente (en función del parámetro "method"). """ # Iteramos las extensiones de los archivos, y construimos la ruta completa de cada uno de ellos: for ext in extensions: file_to_remove = f"{file_path}{ext}" # Si el archivo actual existe, lo eliminamos o lo movemos a la papelera # (dependiendo del valor del parámetro "method"): if os.path.exists(file_to_remove): if method == 'trash': shutil.move(file_to_remove, trash_path) elif method == 'permanent': os.remove(file_to_remove) def delete_ou_image(file_path, method, extensions): """ Elimina la imagen basada en OU que recibe en el parámetro "file_path", y todos sus archivos asociados, moviéndolos a la papelera o eliminándolos permanentemente (en función del parámetro "method"). """ # Iteramos las extensiones de los archivos, y construimos la ruta completa de cada uno de ellos: for ext in extensions: file_to_remove = f"{file_path}{ext}" # Si el archivo actual existe, lo eliminamos o lo movemos a la papelera (dependiendo del valor del parámetro "method"), # y en el último caso lo situamos en un subdirectorio correspondiente a la OU: if os.path.exists(file_to_remove): if method == 'trash': ou_subdir = file_to_remove.split('/')[4] # Comprobamos si en la papelera existe un subdirectorio correspondiente a la OU (y si no existe lo creamos): if not os.path.exists(f"{trash_path}{ou_subdir}"): os.mkdir(f"{trash_path}{ou_subdir}") shutil.move(file_to_remove, f"{trash_path}{ou_subdir}") elif method == 'permanent': os.remove(file_to_remove) def update_repo_info(): """ Actualiza la información del repositorio, ejecutando el script "updateRepoInfo.py". Como se ve, es necesario que el script se ejecute como sudo, o dará error. """ try: result = subprocess.run(['sudo', 'python3', update_repo_script], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as error: print(f"Error Output: {error.stderr.decode()}") sys.exit(3) except Exception as error: print(f"Se ha producido un error inesperado: {error}") sys.exit(4) # -------------------------------------------------------------------------------------------- # MAIN # -------------------------------------------------------------------------------------------- def main(): """ """ # Evaluamos si se ha enviado la cantidad correcta de parámetros, y en el formato correcto: check_params() # Obtenemos la ruta completa al archivo a eliminar: file_path = build_file_path() # Si no existe el archivo de imagen, imprimimos un mensaje de error y salimos del script: if not os.path.exists(file_path): print("Image file doesn't exist") sys.exit(5) # Comprobamos si existe el directorio correspondiente a la papelera, y en caso contrario lo creamos: if not os.path.exists(trash_path): print("Creating trash folder...") create_trash_folder() # Especificamos el método de eliminación (permanente o utilizando la papelera): if len(sys.argv) == 3 and sys.argv[2] == "-p": method = 'permanent' else: method = 'trash' # Creamos una lista con las extensiones de los archivos asociados a la imagen # (incluyendo ninguna extensión, que corresponde a la propia imagen): extensions = ['', '.size', '.sum', '.full.sum', '.torrent', '.info', '.info.checked'] # Evaluamos la cantidad de barras que hay en la ruta de la imagen, para diferenciar entre imágenes "normales" y basadas en OU # (y llamamos a la función correspondiente para eliminarla): if file_path.count('/') == 5: print("Deleting normal image...") delete_normal_image(file_path, method, extensions) elif file_path.count('/') == 6: print("Deleting OU based image...") delete_ou_image(file_path, method, extensions) # Actualizamos la información del repositorio, ejecutando el script "updateRepoInfo.py": print("Updating Repository Info...") update_repo_info() # -------------------------------------------------------------------------------------------- if __name__ == "__main__": main() # --------------------------------------------------------------------------------------------