AutoBackups/src/app.py

276 lines
10 KiB
Python

"""
AutoBackups - Aplicación Principal
Sistema automatizado de backup para proyectos Simatic S7
"""
import sys
import os
import logging
from pathlib import Path
from datetime import datetime
# Agregar el directorio src al path para imports
current_dir = Path(__file__).parent
src_dir = current_dir
sys.path.insert(0, str(src_dir))
# Imports de módulos propios
from models.config_model import Config
from models.project_model import ProjectManager
from utils.file_utils import DiskSpaceChecker
from services.basic_backup_service import BasicBackupService
class AutoBackupsApp:
"""Aplicación principal de AutoBackups"""
def __init__(self):
self.config = None
self.project_manager = None
self.discovery_service = None
self.disk_checker = None
self.logger = None
# Inicializar aplicación
self._setup_logging()
self._load_configuration()
self._initialize_services()
def _setup_logging(self):
"""Configurar sistema de logging"""
try:
# Crear directorio de logs si no existe
logs_dir = Path(__file__).parent / ".logs"
logs_dir.mkdir(exist_ok=True)
# Nombre del archivo de log con timestamp
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
log_filename = logs_dir / f"autobackups_{timestamp}.log"
# Configurar logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_filename, encoding='utf-8'),
logging.StreamHandler(sys.stdout)
]
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"AutoBackups iniciado - Log: {log_filename}")
except Exception as e:
print(f"Error configurando logging: {e}")
sys.exit(1)
def _load_configuration(self):
"""Cargar configuración del sistema"""
try:
self.logger.info("Cargando configuración...")
self.config = Config()
self.logger.info("Configuración cargada exitosamente")
# Mostrar información básica de configuración
self.logger.info(f"Directorios de observación: {len(self.config.observation_directories)}")
self.logger.info(f"Destino de backups: {self.config.backup_destination}")
except Exception as e:
self.logger.error(f"Error cargando configuración: {e}")
sys.exit(1)
def _initialize_services(self):
"""Inicializar servicios principales"""
try:
self.logger.info("Inicializando servicios...")
# Project Manager
self.project_manager = ProjectManager()
self.logger.info("Project Manager inicializado")
# Disk Space Checker
self.disk_checker = DiskSpaceChecker()
self.logger.info("Disk Space Checker inicializado")
# Basic Backup Service (Fase 1)
self.backup_service = BasicBackupService(self.config)
self.logger.info("Basic Backup Service inicializado")
# Project Discovery Service (temporalmente comentado)
# self.discovery_service = ProjectDiscoveryService(self.config, self.project_manager)
# self.logger.info("Project Discovery Service inicializado")
self.logger.info("Todos los servicios inicializados correctamente")
except Exception as e:
self.logger.error(f"Error inicializando servicios: {e}")
sys.exit(1)
def check_system_requirements(self) -> bool:
"""Verificar requerimientos del sistema"""
try:
self.logger.info("Verificando requerimientos del sistema...")
# Verificar espacio en disco
backup_destination = self.config.backup_destination
min_space_mb = self.config.get_min_free_space_mb()
free_space_mb = self.disk_checker.get_free_space_mb(backup_destination)
if free_space_mb < min_space_mb:
self.logger.error(
f"Espacio insuficiente en destino de backup. "
f"Disponible: {free_space_mb:.1f}MB, "
f"Requerido: {min_space_mb}MB"
)
return False
self.logger.info(f"Espacio en disco OK: {free_space_mb:.1f}MB disponibles")
# Verificar Everything API (opcional en Fase 1)
if hasattr(self, 'backup_service'):
if self.backup_service.check_system_requirements():
self.logger.info("Requerimientos del sistema verificados")
else:
self.logger.warning("Algunos requerimientos fallaron")
else:
self.logger.warning("Backup service no disponible")
# Verificar directorios de observación
missing_dirs = []
for obs_dir in self.config.observation_directories:
if not Path(obs_dir["path"]).exists():
missing_dirs.append(obs_dir["path"])
if missing_dirs:
self.logger.warning(f"Directorios de observación no encontrados: {missing_dirs}")
self.logger.info("Verificación de requerimientos completada")
return True
except Exception as e:
self.logger.error(f"Error verificando requerimientos del sistema: {e}")
return False
def discover_projects(self) -> int:
"""Descubrir proyectos en directorios de observación"""
try:
self.logger.info("Iniciando descubrimiento de proyectos...")
# Usar el servicio básico de backup
if hasattr(self, 'backup_service'):
projects = self.backup_service.discover_projects_basic()
else:
projects = []
# Agregar proyectos al manager
for project_info in projects:
self.project_manager.add_or_update_project(project_info)
msg = f"Descubrimiento completado: {len(projects)} proyectos"
self.logger.info(msg)
return len(projects)
except Exception as e:
self.logger.error(f"Error en descubrimiento de proyectos: {e}")
return 0
def show_system_status(self):
"""Mostrar estado actual del sistema"""
try:
self.logger.info("=== ESTADO DEL SISTEMA ===")
# Información de configuración
self.logger.info(f"Directorios de observación configurados: {len(self.config.observation_directories)}")
self.logger.info(f"Destino de backups: {self.config.backup_destination}")
# Información de proyectos
all_projects = self.project_manager.get_all_projects()
enabled_projects = self.project_manager.get_enabled_projects()
self.logger.info(f"Total de proyectos: {len(all_projects)}")
self.logger.info(f"Proyectos habilitados: {len(enabled_projects)}")
# Información de espacio en disco
backup_dest = self.config.backup_destination
total_mb, used_mb, free_mb = self.disk_checker.get_disk_usage_info(backup_dest)
self.logger.info(f"Espacio en disco (destino backup):")
self.logger.info(f" Total: {total_mb:.1f}MB")
self.logger.info(f" Usado: {used_mb:.1f}MB")
self.logger.info(f" Libre: {free_mb:.1f}MB")
# Información de Everything API
if self.discovery_service.everything_searcher:
self.logger.info("Everything API: Disponible")
else:
self.logger.info("Everything API: No disponible")
self.logger.info("=== FIN ESTADO DEL SISTEMA ===")
except Exception as e:
self.logger.error(f"Error mostrando estado del sistema: {e}")
def run_initial_setup(self):
"""Ejecutar configuración inicial de la aplicación"""
try:
self.logger.info("=== CONFIGURACIÓN INICIAL DE AUTOBACKUPS ===")
# Verificar requerimientos del sistema
if not self.check_system_requirements():
self.logger.error("Los requerimientos del sistema no se cumplen")
return False
# Descubrir proyectos
projects_found = self.discover_projects()
if projects_found == 0:
self.logger.warning("No se encontraron proyectos para backup")
# Mostrar estado del sistema
self.show_system_status()
self.logger.info("=== CONFIGURACIÓN INICIAL COMPLETADA ===")
return True
except Exception as e:
self.logger.error(f"Error en configuración inicial: {e}")
return False
def main():
"""Función principal"""
try:
print("AutoBackups - Sistema de Backup Automatizado")
print("=" * 50)
# Crear y configurar aplicación
app = AutoBackupsApp()
# Ejecutar configuración inicial
if app.run_initial_setup():
app.logger.info("AutoBackups configurado correctamente")
# TODO: En las siguientes fases:
# - Iniciar scheduler de backups
# - Iniciar interfaz web Flask
# - Configurar tareas en background
print("\nConfiguración inicial completada.")
print("Revisa el archivo de log para más detalles.")
else:
print("Error en la configuración inicial. Revisa los logs.")
sys.exit(1)
except KeyboardInterrupt:
print("\nAplicación interrumpida por el usuario")
except Exception as e:
print(f"Error inesperado: {e}")
sys.exit(1)
if __name__ == "__main__":
main()