Files
scripts/linux/backups_manage/manage_backups.py
2026-02-18 17:06:56 -03:00

225 lines
7.6 KiB
Python

# Manage Backups V2.0 by Teccnia
# https://teccnia.com.br
#!/usr/bin/env python3
import os
import shutil
import time
import logging
from datetime import datetime, timedelta
from pathlib import Path
# ==========================================
# CONFIGURAÇÃO
# ==========================================
# Diretório base onde estão as pastas dos usuários FTP
DIRETORIO_BASE = "/home/ftpuser"
# Nome das pastas para ignorar na varredura de usuários
DIRETORIOS_IGNORAR = ['antigos', 'logs']
# Extensões para ignorar (não serão movidas nem deletadas)
# Exemplo: ['.exe', '.iso']
EXTENSOES_IGNORAR = ['.exe', '.iso']
# Configurações de Retenção
DIAS_MOVER = 15 # Arquivos com mais de X dias são movidos para 'antigos'
DIAS_EXCLUIR_ANTIGOS = 60 # Pastas em 'antigos' com mais de Y dias são excluídas
DIAS_RETENCAO_LOGS = 30 # Logs com mais de Z dias são excluídos
# ======= NÃO ALTERAR A PARTIR DESTE PONTO!!! =======
# Nomes de diretórios de sistema
NOME_DIR_ANTIGOS = "antigos"
NOME_DIR_LOGS = "logs"
# Caminhos completos (serão definidos dinamicamente se baseados no DIRETORIO_BASE)
DIR_LOGS = os.path.join(DIRETORIO_BASE, NOME_DIR_LOGS)
DIR_ANTIGOS = os.path.join(DIRETORIO_BASE, NOME_DIR_ANTIGOS)
# Data atual para organização
HOJE = datetime.now()
DATA_HOJE_STR = HOJE.strftime('%Y-%m-%d')
DATA_LOG_STR = HOJE.strftime('%d%m%Y')
# ==========================================
# CONFIGURAÇÃO DE LOGS
# ==========================================
def configurar_logger():
if not os.path.exists(DIR_LOGS):
try:
os.makedirs(DIR_LOGS)
except Exception as e:
print(f"ERRO CRÍTICO: Não foi possível criar diretório de logs {DIR_LOGS}: {e}")
exit(1)
arquivo_log = os.path.join(DIR_LOGS, f"{DATA_LOG_STR}.log")
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(arquivo_log),
logging.StreamHandler()
]
)
return logging.getLogger()
# ==========================================
# FUNÇÕES
# ==========================================
def idade_arquivo_dias(caminho_arquivo):
"""Retorna a idade do arquivo em dias."""
timestamp_arquivo = os.path.getmtime(caminho_arquivo)
data_arquivo = datetime.fromtimestamp(timestamp_arquivo)
diferenca = HOJE - data_arquivo
return diferenca.days
def listar_subdiretorios_usuarios(logger):
"""Retorna lista de subdiretórios de usuários, ignorando pastas de sistema."""
subdiretorios = []
if not os.path.exists(DIRETORIO_BASE):
logger.error(f"Diretório base não existe: {DIRETORIO_BASE}")
return []
try:
itens = os.listdir(DIRETORIO_BASE)
for item in itens:
caminho_completo = os.path.join(DIRETORIO_BASE, item)
if os.path.isdir(caminho_completo):
if item not in DIRETORIOS_IGNORAR:
subdiretorios.append(item)
except Exception as e:
logger.error(f"Erro ao listar diretório base: {e}")
return subdiretorios
def processar_arquivos_antigos(usuario, logger):
"""Move arquivos antigos do diretório do usuário para a pasta de arquivamento."""
origem = os.path.join(DIRETORIO_BASE, usuario)
destino_base = os.path.join(DIR_ANTIGOS, usuario)
if not os.path.exists(origem):
logger.warning(f"Diretório de origem não encontrado: {origem}")
return
arquivos_movidos = 0
try:
destino_criado = False
for arquivo in os.listdir(origem):
caminho_arquivo = os.path.join(origem, arquivo)
if not os.path.isfile(caminho_arquivo):
continue
_, ext = os.path.splitext(arquivo)
if ext.lower() in [e.lower() for e in EXTENSOES_IGNORAR]:
continue
idade = idade_arquivo_dias(caminho_arquivo)
if idade > DIAS_MOVER:
if not destino_criado:
os.makedirs(destino_base, exist_ok=True)
destino_criado = True
shutil.move(caminho_arquivo, os.path.join(destino_base, arquivo))
logger.info(f"Movido: {usuario}/{arquivo} ({idade} dias) -> {destino_base}")
arquivos_movidos += 1
except Exception as e:
logger.error(f"Erro ao processar usuário {usuario}: {e}")
if arquivos_movidos > 0:
logger.info(f"Usuário {usuario}: {arquivos_movidos} arquivos movidos.")
def limpar_arquivos_antigos(logger):
"""Remove ARQUIVOS antigos em 'antigos' recursivamente."""
if not os.path.exists(DIR_ANTIGOS):
return
logger.info("Verificando limpeza de backups antigos (estrutura plana)...")
arquivos_removidos = 0
try:
for root, dirs, files in os.walk(DIR_ANTIGOS):
for file in files:
caminho_arquivo = os.path.join(root, file)
# Verificar extensão ignorada
_, ext = os.path.splitext(file)
if ext.lower() in [e.lower() for e in EXTENSOES_IGNORAR]:
continue
try:
idade = idade_arquivo_dias(caminho_arquivo)
if idade > DIAS_EXCLUIR_ANTIGOS:
os.remove(caminho_arquivo)
logger.info(f"Removido backup antigo: {caminho_arquivo} ({idade} dias)")
arquivos_removidos += 1
except Exception as e:
logger.error(f"Erro ao verificar arquivo {caminho_arquivo}: {e}")
for root, dirs, files in os.walk(DIR_ANTIGOS, topdown=False):
for name in dirs:
caminho_dir = os.path.join(root, name)
if not os.listdir(caminho_dir): # Se estiver vazio
os.rmdir(caminho_dir)
logger.debug(f"Removido diretório vazio: {caminho_dir}")
except Exception as e:
logger.error(f"Erro ao limpar backups antigos: {e}")
if arquivos_removidos > 0:
logger.info(f"Total de backups antigos removidos: {arquivos_removidos}")
def rotacionar_logs(logger):
"""Remove logs antigos."""
if not os.path.exists(DIR_LOGS):
return
logger.info("Verificando rotação de logs...")
try:
for arquivo in os.listdir(DIR_LOGS):
caminho_arquivo = os.path.join(DIR_LOGS, arquivo)
if os.path.isfile(caminho_arquivo):
idade = idade_arquivo_dias(caminho_arquivo)
if idade > DIAS_RETENCAO_LOGS:
os.remove(caminho_arquivo)
logger.info(f"Log removido: {arquivo} ({idade} dias)")
except Exception as e:
logger.error(f"Erro ao rotacionar logs: {e}")
# ==========================================
# MAIN
# ==========================================
def main():
# Inicializa Logger
logger = configurar_logger()
logger.info("=== Iniciando execução do script de backup ===")
logger.info(f"Diretório Base: {DIRETORIO_BASE}")
# 1. Identificar usuários (subdiretórios)
usuarios = listar_subdiretorios_usuarios(logger)
logger.info(f"Usuários encontrados: {usuarios}")
# 2. Processar cada usuário
for usuario in usuarios:
processar_arquivos_antigos(usuario, logger)
# 3. Limpar pastas antigas de retenção
limpar_arquivos_antigos(logger)
# 4. Rotacionar logs
rotacionar_logs(logger)
logger.info("=== Execução finalizada com sucesso ===")
if __name__ == "__main__":
main()