From 99adaa20027c4e6895707657da072456de03271b Mon Sep 17 00:00:00 2001 From: ggil Date: Fri, 15 Nov 2024 13:18:54 +0100 Subject: [PATCH] refs #610 - API improvements --- api/repo_api.py | 141 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 35 deletions(-) diff --git a/api/repo_api.py b/api/repo_api.py index c7637b9..c7b2da9 100644 --- a/api/repo_api.py +++ b/api/repo_api.py @@ -147,6 +147,67 @@ def search_process(process, string_to_search): # --------------------------------------------------------- +def check_remote_connection(remote_ip, remote_user): + """ Comprueba la conexión SSH/SFTP con el servidor remoto que recibe como primer parámetro. + Se utiliza para chequear la conexión antes de importar o exportar una imagen. + """ + try: + # Iniciamos un cliente SSH: + ssh_client = paramiko.SSHClient() + # Establecemos la política por defecto para localizar la llave del host localmente: + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + # Conectamos con el equipo remoto por SSH: + ssh_client.connect(remote_ip, 22, remote_user) # Así se hace con claves + #ssh_client.connect(remote_ip, 22, remote_user, 'opengnsys') # Así se haría con password + + # Iniciamos un cliente SFTP: + sftp_client = ssh_client.open_sftp() + + # Retornamos "True", porque hemos conseguido conectar: + return True + + # Si se produce una excepción, retornamos "False": + except Exception: + return False + + +# --------------------------------------------------------- + + +def check_remote_image(remote_ip, remote_user, image_file_path): + """ Conecta con el servidor remoto que recibe como primer parámetro, + para comprobar si la imagen que recibe como tercer parámetro existe, o si está bloqueada. + Se utiliza para chequear la imagen antes de importarla. + """ + # Iniciamos un cliente SSH: + ssh_client = paramiko.SSHClient() + # Establecemos la política por defecto para localizar la llave del host localmente: + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + # Conectamos con el equipo remoto por SSH: + ssh_client.connect(remote_ip, 22, remote_user) # Así se hace con claves + #ssh_client.connect(remote_ip, 22, remote_user, 'opengnsys') # Así se haría con password + + # Iniciamos un cliente SFTP: + sftp_client = ssh_client.open_sftp() + + # Si la imagen no existe, retornamos el mensaje correspondiente: + if not os.path.exists(image_file_path): + return "Remote image not found" + + # Si la imagen existe pero está bloqueada, retornamos el mensaje correspondiente: + if os.path.exists(f"{image_file_path}.lock"): + return "Remote image is locked" + + # Cerramos el cliente SSH y el cliente SFTP: + ssh_client.close() + sftp_client.close() + + +# --------------------------------------------------------- + + def check_lock_local(image_file_path, job_id): """ Cada minuto comprueba si existe un archivo ".lock" asociado a la imagen que recibe como parámetro (lo que significará que hay una tarea en curso), en el repositorio local. @@ -634,9 +695,30 @@ def import_image(): remote_ip = json_data.get("repo_ip") remote_user = json_data.get("user") + # Comprobamos la conexión con el equipo remoto, y si falla salimos del endpoint, retornando un error: + connection_OK = check_remote_connection(remote_ip, remote_user) + if connection_OK == False: + return jsonify({ + "success": False, + "exception": "Can't connect to remote server" + }), 400 + # Construimos la ruta de la imagen: image_file_path = f"{repo_path}{image_name}" + # Comprobamos si la imagen remota no existe o está bloqueada, en cuyos casos salimos del endpoint y retornamos el error correspondiente: + check_image = check_remote_image(remote_ip, remote_user, image_file_path) + if check_image == "Remote image not found": + return jsonify({ + "success": False, + "exception": "Remote image not found" + }), 400 + elif check_image == "Remote image is locked": + return jsonify({ + "success": False, + "exception": "Remote image is locked" + }), 400 + # Construimos la llamada al script: cmd = ['sudo', 'python3', f"{script_path}/importImage.py", image_file_path, remote_ip, remote_user] @@ -666,30 +748,14 @@ def import_image(): }), 500 except subprocess.CalledProcessError as error: return jsonify({ - "success": False, - "process exception": str(error) - }), 500 + "success": False, + "process exception": str(error) + }), 500 except Exception as error_description: - if "exit status 2" in str(error_description): - return jsonify({ - "success": False, - "exception": "Can't connect to remote server" - }), 400 - elif "exit status 3" in str(error_description): - return jsonify({ - "success": False, - "exception": "Remote image not found" - }), 400 - elif "exit status 4" in str(error_description): - return jsonify({ - "success": False, - "exception": "Remote image is locked" - }), 400 - else: - return jsonify({ - "success": False, - "exception": str(error_description) - }), 500 + return jsonify({ + "success": False, + "exception": str(error_description) + }), 500 # --------------------------------------------------------- @@ -711,15 +777,30 @@ def export_image(): # Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso): param_dict = get_image_params(image_id, "repo") - # Evaluamos los parámetros obtenidos, para construir la ruta de la imagen, o para devover un error si no se ha encontrado la imagen: + # Evaluamos los parámetros obtenidos, para construir la ruta de la imagen, o para devover un error si no se ha encontrado la imagen (o si está bloqueada): if param_dict: image_file_path = f"{param_dict['name']}.{param_dict['extension']}" + # Si la imagen existe pero está bloqueada, devolvemos un error: + if os.path.exists(f"{repo_path}{image_file_path}.lock"): + return jsonify({ + "success": False, + "exception": "Image is locked" + }), 400 else: return jsonify({ "success": False, "error": "Image not found" }), 400 + # Comprobamos la conexión con el equipo remoto, y si falla salimos del endpoint, retornando un error: + connection_OK = check_remote_connection(remote_ip, remote_user) + + if connection_OK == False: + return jsonify({ + "success": False, + "exception": "Can't connect to remote server" + }), 400 + # Construimos la llamada al script: cmd = ['sudo', 'python3', f"{script_path}/exportImage.py", image_file_path, remote_ip, remote_user] @@ -753,17 +834,7 @@ def export_image(): "process exception": str(error) }), 500 except Exception as error_description: - if "exit status 3" in str(error_description): - return jsonify({ - "success": False, - "exception": "Image is locked" - }), 400 - elif "exit status 4" in str(error_description): - return jsonify({ - "success": False, - "exception": "Can't connect to remote server" - }), 400 - elif "exit status 5" in str(error_description): + if "exit status 5" in str(error_description): return jsonify({ "success": False, "exception": "Image already exists on remote server"