225 lines
7.6 KiB
Python
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()
|