Files
Desarrollo_docker/generar_contenedores.py
T

242 lines
8.4 KiB
Python

import os
import uuid
import shutil
import json
import socket
import subprocess
import petname
import hashlib
import platform
from datetime import datetime
# Archivo JSON para guardar los datos de los contenedores
CONTAINER_DATA_FILE = 'containers.json'
# Nombre y etiqueta para la imagen base
BASE_IMAGE_TAG = 'debian_vscode:tag'
#Lita de puertos internos
PUERTOS_INTERNOS = [3000, 5000, 8000, 8080, 17000]
# Numero de conteineres a crear
NUM_CONTAINERS = 3
# -------------------------------
# Función: Comprobar si un puerto está libre con nmap
# -------------------------------
def is_port_available(port):
# Ejecuta nmap para comprobar si el puerto está abierto
command = f"nmap -p {port} 127.0.0.1"
print(f"[INFO] Ejecutando nmap para el puerto {port}...")
result = subprocess.run(command, shell=True, capture_output=True, text=True)
# Muestra el resultado del comando nmap
print(f"[DEBUG] Resultado de nmap para el puerto {port}:\n{result.stdout}")
# Analiza el resultado para ver si el puerto está cerrado
if "closed" in result.stdout:
return True # Puerto libre
else:
return False # Puerto ocupado
# -------------------------------
# Función: Ejecutar contenedor y guardar datos
# -------------------------------
def run_docker_compose(internal_ports=None):
# Genera un UUID único
unique_uuid = str(uuid.uuid4())
# Genera un nombre único para el contenedor
uuid_palabras = petname.Generate(3, separator='-')
# Nombres únicos para el servicio, contenedor y la red
service_name = f"{uuid_palabras}"
container_name = f"{uuid_palabras}"
network_name = f"alpine_network_{unique_uuid}"
# Nombre de la imagen local a usar
image_tag = BASE_IMAGE_TAG # Usar la imagen local directamente
# Nombre del archivo docker-compose nuevo
new_docker_compose_file = f'docker-compose-{unique_uuid}.yml'
try:
# Configuración personalizada de puertos
ports_mapping = []
custom_ports = []
host_port = 27000 # Puerto inicial
print(f"[INFO] Iniciando la configuración de puertos a partir del puerto {host_port}")
if internal_ports:
for internal_port in internal_ports:
print(f"[INFO] Configurando puerto interno: {internal_port}")
# Buscar el siguiente puerto disponible usando nmap
while host_port <= 65000:
if is_port_available(host_port):
print(f"[INFO] Asignando puerto {host_port} para el puerto interno {internal_port}...")
custom_ports.append(f" - \"{host_port}:{internal_port}\"")
ports_mapping.append({
"host_port": host_port,
"internal_port": internal_port
})
host_port += 1 # Incrementa el puerto para el siguiente uso
break
else:
print(f"[WARNING] Puerto {host_port} ocupado, probando el siguiente...")
host_port += 1 # Incrementa si el puerto está ocupado
if host_port > 65000:
raise Exception("Se superó el límite de puertos disponibles.")
custom_ports_yaml = "\n".join(custom_ports)
print(f"[INFO] Puertos personalizados configurados:\n{custom_ports_yaml}")
else:
custom_ports_yaml = "" # No agrega puertos si no se especifican
print("[INFO] No se especificaron puertos internos.")
# Genera el contenido del archivo docker-compose dinámicamente
docker_compose_content = f"""
version: '3.8'
services:
{service_name}:
image: {image_tag} # Usar la imagen base directamente
container_name: {container_name}
networks:
- {network_name}
restart: always
tty: true
volumes:
- ./app:/app
ports:
{custom_ports_yaml}
command: tail -f /dev/null # Mantener activo el contenedor
networks:
{network_name}:
driver: bridge
"""
# Guarda el archivo docker-compose generado
with open(new_docker_compose_file, 'w') as file:
file.write(docker_compose_content)
# Muestra el contenido generado para depuración
print(f"[DEBUG] Contenido del archivo {new_docker_compose_file}:\n")
print(docker_compose_content)
# Ejecuta docker-compose con el archivo nuevo y captura la salida
print("[INFO] Ejecutando docker compose...")
result = subprocess.run(
f'docker compose -f {new_docker_compose_file} up -d --no-build',
shell=True,
capture_output=True,
text=True
)
# Muestra el resultado del comando
if result.returncode != 0:
print(f"[ERROR] Error al ejecutar docker compose:\n{result.stderr}")
raise Exception("Error al ejecutar docker-compose")
else:
print(f"[INFO] Contenedor iniciado exitosamente:\n{result.stdout}")
# Mostrar contenedores activos y detenidos
print("[DEBUG] Contenedores activos y detenidos:")
subprocess.run("docker ps -a", shell=True)
# Obtener el ID del contenedor creado
container_id = subprocess.getoutput(f"docker ps -qf name={container_name}")
if not container_id:
print(f"[ERROR] No se pudo obtener el ID del contenedor {container_name}.")
raise Exception("No se pudo obtener el ID del contenedor")
print(f"[INFO] ID del contenedor: {container_id}")
# Mostrar logs del contenedor si está detenido
print("[INFO] Mostrando logs del contenedor:")
subprocess.run(f"docker logs {container_id}", shell=True)
# Guardar los datos del contenedor en el archivo JSON
save_container_data({
'id': container_id,
'name': container_name,
'network': network_name,
'image': image_tag,
'compose_file': new_docker_compose_file,
'creation_timestamp': datetime.now().isoformat(),
'ports': ports_mapping # Agrega la información de los puertos mapeados
})
except Exception as e:
print(f"[ERROR] Error: {str(e)}")
finally:
# Eliminar el archivo docker-compose generado si existe
if os.path.exists(new_docker_compose_file):
print(f"[INFO] Eliminando archivo temporal: {new_docker_compose_file}")
os.remove(new_docker_compose_file)
# -------------------------------
# Función: Guardar datos del contenedor en JSON
# -------------------------------
def save_container_data(container_data):
# Cargar datos existentes si el archivo existe y no está vacío
if os.path.exists(CONTAINER_DATA_FILE) and os.path.getsize(CONTAINER_DATA_FILE) > 0:
with open(CONTAINER_DATA_FILE, 'r') as file:
try:
data = json.load(file) # Cargar datos existentes
except json.JSONDecodeError:
data = [] # Si hay error al leer, inicializar como lista vacía
else:
# Crear el archivo vacío y usar una lista vacía
with open(CONTAINER_DATA_FILE, 'w') as file:
json.dump([], file)
data = [] # Inicializar como lista vacía
# Agregar nuevo contenedor
data.append(container_data)
# Guardar datos actualizados
with open(CONTAINER_DATA_FILE, 'w') as file:
json.dump(data, file, indent=4)
# -------------------------------
# Función: Limpiar imágenes huérfanas
# -------------------------------
def clean_unused_images():
print("➤ Eliminando imágenes huérfanas...")
os.system('docker image prune -f')
# -------------------------------
# Función: Limpiar redes huérfanas
# -------------------------------
def clean_unused_networks():
print("➤ Eliminando redes huérfanas...")
os.system('docker network prune -f')
######################################### -------------------------------
# Ejecución del script
######################################### -------------------------------
if __name__ == "__main__":
# Crear contenedores y guardarlos en el JSON
for _ in range(NUM_CONTAINERS):
run_docker_compose(internal_ports=PUERTOS_INTERNOS)
print("➤ Contenedores creados y guardados en el JSON")
# Limpiar imágenes huérfanas
clean_unused_images()
# Limpiar redes huérfanas
clean_unused_networks()