ogrepository/bin/exportImage.py

202 lines
8.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Este script exporta la imagen especificada como primer parámetro (y sus archivos asociados), al repositorio remoto especificado como segundo parámetro,
con las credenciales del usuario especificado como tercer parámetro (en principio, mediante claves).
Realiza la acción contraria que el script "importImage.py", pero es preferible usar "exportImage.py" (porque permite buscar la imagen por ID).
Al acabar, ogCore debe llamar al script "updateRepoInfo.py" en el repositorio remoto, para actualizar la información de dicho repositorio.
Librerías Python requeridas: "paramiko" (se puede instalar con "sudo apt install python3-paramiko")
Parámetros
------------
sys.argv[1] - Nombre completo de la imagen a exportar (con o sin ruta).
- Ejemplo1: image1.img
- Ejemplo2: /opt/opengnsys/ogrepository/images/image1.img
sys.argv[2] - IP o hostname del repositorio remoto.
- Ejemplo1: 192.168.56.100
- Ejemplo2: remote_repo
sys.argv[3] - Usuario con el que conectar al repositorio remoto.
- Ejemplo1: remote_user
- Ejemplo2: root
Sintaxis
----------
./exportImage.py image_name|/image_path/image_name remote_host remote_user
Ejemplos
---------
./exportImage.py image1.img 192.168.56.100 user
./exportImage.py /opt/opengnsys/ogrepository/images/image1.img remote_hostname user
"""
# --------------------------------------------------------------------------------------------
# IMPORTS
# --------------------------------------------------------------------------------------------
import warnings
warnings.filterwarnings("ignore")
import os
import sys
import subprocess
import paramiko
import warnings
from systemd import journal
# --------------------------------------------------------------------------------------------
# VARIABLES
# --------------------------------------------------------------------------------------------
script_name = os.path.basename(__file__)
repo_path = '/opt/opengnsys/ogrepository/images/' # No borrar la barra final
# --------------------------------------------------------------------------------------------
# FUNCTIONS
# --------------------------------------------------------------------------------------------
def show_help():
""" Imprime la ayuda, cuando se ejecuta el script con el parámetro "help".
"""
help_text = f"""
Sintaxis: {script_name} image_name|/image_path/image_name remote_host remote_user
Ejemplo1: {script_name} image1.img 192.168.56.100 user
Ejemplo2: {script_name} /opt/opengnsys/ogrepository/images/image1.img remote_hostname user
"""
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 con el parámetro "help", se muestra la ayuda, y se sale del script:
if len(sys.argv) == 2 and sys.argv[1] == "help":
show_help()
sys.exit(0)
# Si se ejecuta el script con más o menos de 3 parámetros, se muestra un error y la ayuda, y se sale del script:
elif len(sys.argv) != 4:
print(f"{script_name} Error: Formato incorrecto: Se debe especificar 3 parámetros")
show_help()
sys.exit(1)
def build_file_path():
""" Construye la ruta completa al archivo a exportar
(agregando "/opt/opengnsys/ogrepository/images/" si no se ha especificado en el parámetro).
"""
param_path = sys.argv[1]
# 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 export_image(file_path, remote_host, remote_user):
""" Conecta al repositorio remoto por SSH e inicia un cliente SFTP.
Luego exporta la imagen al repositorio remoto (junto con sus archivos asociados).
"""
# 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.checked']
# 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())
# Intentamos conectar con el equipo remoto por SSH, e iniciar un cliente SFTP,
try: # y en caso de fallar devolvemos un error y salimos del script:
ssh_client.connect(remote_host, 22, remote_user) # Así se hace con claves
#ssh_client.connect(remote_host, 22, remote_user, 'opengnsys') # Así se haría con password
sftp_client = ssh_client.open_sftp()
except Exception as error_description:
journal.send(f"exportImage.py: Connection exception: {error_description}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
print(f"Connection has returned an exception: {error_description}")
sys.exit(4)
# Comprobamos si la imagen ya existe en el equipo remoto, en cuyo caso devolvemos un error y salimos del script:
try:
sftp_client.stat(file_path)
journal.send("exportImage.py: Image already exists on remote repository", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
print("Image already exists on remote repository.")
sys.exit(5)
except IOError:
print("As expected, image doesn't exist on remote repository.")
# Creamos un archivo de bloqueo en el servidor remoto:
journal.send("exportImage.py: Creating '.lock' file...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
sftp_client.open(f"{file_path}.lock", 'w')
# Exportamos la imagen al servidor remoto, junto con sus archivos asociados:
for ext in extensions:
sftp_client.put(f"{file_path}{ext}", f"{file_path}{ext}")
# Renombramos el archivo remoto ".info.checked" a ".info", para que lo pille el script "updateRepoInfo.py":
journal.send("exportImage.py: Renaming '.info.checked' file to '.info'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
sftp_client.rename(f"{file_path}.info.checked", f"{file_path}.info")
# Eliminamos el archivo de bloqueo del servidor remoto:
journal.send("exportImage.py: Removing '.lock' file...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
sftp_client.remove(f"{file_path}.lock")
# Cerramos el cliente SSH y el cliente SFTP:
journal.send("exportImage.py: Closing remote connection...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
ssh_client.close()
sftp_client.close()
# --------------------------------------------------------------------------------------------
# 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 exportar:
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):
journal.send("exportImage.py: Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
print("Image file doesn't exist")
sys.exit(2)
# Si la imagen está bloqueada, imprimimos un mensaje de error y salimos del script:
if os.path.exists(f"{file_path}.lock"):
journal.send("exportImage.py: Image is locked", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
print("Image is locked.")
sys.exit(3)
# Almacenamos la IP/hostname del repositorio remoto, y el usuario remoto (desde los parámetros):
remote_host = sys.argv[2]
remote_user = sys.argv[3]
# Exportamos la imagen al repositorio remoto:
export_image(file_path, remote_host, remote_user)
# --------------------------------------------------------------------------------------------
if __name__ == "__main__":
main()
# --------------------------------------------------------------------------------------------