ogrepository/bin/backupImage.py

189 lines
7.9 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Este script hace un backup de la imagen especificada como primer parámetro (y sus archivos asociados), en el equipo remoto especificado como segundo parámetro,
con las credenciales del usuario especificado como tercer parámetro (en principio, mediante claves), y en la ruta remota especificada como cuarto parámetro.
Realiza la misma acción que el script "exportImage.py", pero con la salvedad de que requiere la ruta remota en la que se copiará la imagen, y que no requiere que el equipo remoto sea un repositorio.
Lo que si es necesario es que ambos equipos puedan conectar por SSH mediante claves (que deben haberse generado y distribuido previamente).
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 copiar (SIN ruta).
- Ejemplo1: image1.img
- Ejemplo2: image2.img
sys.argv[2] - IP o hostname del equipo remoto.
- Ejemplo1: 192.168.56.100
- Ejemplo2: remote_repo
sys.argv[3] - Usuario con el que conectar al equipo remoto.
- Ejemplo1: remote_user
- Ejemplo2: root
sys.argv[4] - Ruta remota en la que se copiará la imagen.
- Ejemplo1: /tmp
- Ejemplo2: /home/opengnsys
Sintaxis
----------
./backupImage.py image_name remote_host remote_user remote_path
Ejemplos
---------
./backupImage.py image1.img 192.168.56.100 user /tmp
./backupImage.py image2.img remote_hostname user /home/opengnsys
"""
# --------------------------------------------------------------------------------------------
# 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 remote_host remote_user remote_path
Ejemplo1: {script_name} image1.img 192.168.56.100 user /tmp
Ejemplo2: {script_name} image2.img remote_hostname user /home/opengnsys
"""
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 4 parámetros, se muestra un error y la ayuda, y se sale del script:
elif len(sys.argv) != 5:
print(f"{script_name} Error: Formato incorrecto: Se debe especificar 4 parámetros")
show_help()
sys.exit(1)
def backup_image(image_name, remote_host, remote_user, remote_path):
""" Conecta al equipo remoto por SSH e inicia un cliente SFTP.
Luego copia la imagen al equipo 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', '.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(hostname=remote_host, port=22, username=remote_user, passphrase='')
sftp_client = ssh_client.open_sftp()
except Exception as error_description:
journal.send(f"backupImage.py: Connection exception: {error_description}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
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(f"{remote_path}{image_name}")
journal.send("backupImage.py: Image already exists on remote host", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print("Image already exists on remote host.")
sys.exit(5)
except IOError:
print("As expected, image doesn't exist on remote host.")
# Copiamos la imagen al equipo remoto, junto con sus archivos asociados:
for ext in extensions:
sftp_client.put(f"{repo_path}{image_name}{ext}", f"{remote_path}{image_name}{ext}")
# Renombramos el archivo remoto ".info.checked" a ".info", para que lo pille el script "updateRepoInfo.py":
journal.send("backupImage.py: Renaming '.info.checked' file to '.info'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
sftp_client.rename(f"{remote_path}{image_name}.info.checked", f"{remote_path}{image_name}.info")
# Cerramos el cliente SSH y el cliente SFTP:
journal.send("backupImage.py: Closing remote connection...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
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 el nombre de la imagen a copiar (desde los parámetros):
image_name = sys.argv[1]
# Si no existe el archivo de imagen, imprimimos un mensaje de error y salimos del script:
if not os.path.exists(f"{repo_path}{image_name}"):
journal.send("backupImage.py: Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
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"{repo_path}{image_name}.lock"):
journal.send("backupImage.py: Image is locked", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print("Image is locked.")
sys.exit(3)
# Almacenamos la IP/hostname del equipo remoto, el usuario remoto y la ruta remota (desde los parámetros):
remote_host = sys.argv[2]
remote_user = sys.argv[3]
remote_path = sys.argv[4]
# Si el úitimo carácter de "remote_path" no es una barra, la añadimos:
if remote_path[-1] != "/":
remote_path = f"{remote_path}/"
# Copiamos la imagen al equipo remoto:
backup_image(image_name, remote_host, remote_user, remote_path)
# --------------------------------------------------------------------------------------------
if __name__ == "__main__":
main()
# --------------------------------------------------------------------------------------------