MEJORA: usar imagenes pre-construidas del registry de Gitea en lugar de build local para evitar bind-mount en Portainer
This commit is contained in:
+2
-2
@@ -1,8 +1,8 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Establecer variables de entorno
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Establecer directorio de trabajo
|
||||
WORKDIR /app
|
||||
|
||||
+3
-10
@@ -1,13 +1,10 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: git.controlmc.click/ginevra_oa/erp-efintel-2026/web:latest
|
||||
command: gunicorn config.asgi:application -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers 3
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
# Django necesita escuchar en 0.0.0.0 (ya lo hace gunicorn)
|
||||
volumes:
|
||||
- erp_media:/app/media
|
||||
- erp_static:/app/static
|
||||
@@ -35,10 +32,9 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
mem_limit: 512m
|
||||
# Redis no necesita puertos públicos ni etiquetas Traefik
|
||||
|
||||
celery:
|
||||
build: .
|
||||
image: git.controlmc.click/ginevra_oa/erp-efintel-2026/web:latest
|
||||
command: celery -A config worker -l info --concurrency=2
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
@@ -50,19 +46,16 @@ services:
|
||||
mem_limit: 512m
|
||||
|
||||
tax-api:
|
||||
build: ./tax_api
|
||||
image: git.controlmc.click/ginevra_oa/erp-efintel-2026/tax-api:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
mem_limit: 256m
|
||||
# Si la API de impuestos necesita ser expuesta al público por Traefik,
|
||||
# se deben agregar etiquetas similares a las del servicio 'web' con un ROUTER_NAME diferente.
|
||||
|
||||
networks:
|
||||
controlmc_proxy:
|
||||
external: true
|
||||
internal:
|
||||
# Red interna para que web, redis, celery y tax-api se comuniquen sin exponerse
|
||||
|
||||
volumes:
|
||||
erp_media:
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ wheel==0.42.0
|
||||
zope.interface==8.5
|
||||
|
||||
whitenoise==6.7.0
|
||||
django-storages==2.14.2
|
||||
django-storages==1.14.6
|
||||
boto3==1.34.69
|
||||
requests==2.31.0
|
||||
uvicorn[standard]
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import os
|
||||
import sys
|
||||
import django
|
||||
import json
|
||||
|
||||
# Set up Django environment
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||
django.setup()
|
||||
|
||||
from django.test import Client
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.urls import get_resolver, URLPattern, URLResolver
|
||||
|
||||
def get_all_urls(urlpatterns, prefix=''):
|
||||
urls = []
|
||||
for pattern in urlpatterns:
|
||||
if isinstance(pattern, URLPattern):
|
||||
# Try to build a valid URL by replacing common parameters
|
||||
url = prefix + str(pattern.pattern)
|
||||
url = url.replace('<int:pk>', '1')
|
||||
url = url.replace('<int:candidate_pk>', '1')
|
||||
url = url.replace('<int:po_pk>', '1')
|
||||
url = url.replace('<str:action>', 'approve')
|
||||
url = url.replace('^', '').replace('$', '')
|
||||
urls.append(url)
|
||||
elif isinstance(pattern, URLResolver):
|
||||
urls.extend(get_all_urls(pattern.url_patterns, prefix + str(pattern.pattern)))
|
||||
return urls
|
||||
|
||||
def run_analysis():
|
||||
User = get_user_model()
|
||||
# Try to get an existing admin or any user, or create a temporary one
|
||||
user = User.objects.filter(is_superuser=True).first() or User.objects.first()
|
||||
created_user = False
|
||||
if not user:
|
||||
user = User.objects.create_superuser('test_admin', 'admin@example.com', 'password123')
|
||||
created_user = True
|
||||
|
||||
client = Client()
|
||||
client.force_login(user)
|
||||
|
||||
resolver = get_resolver()
|
||||
urls = get_all_urls(resolver.url_patterns)
|
||||
|
||||
# Filter out admin, media, and tax_api endpoints
|
||||
urls = [u for u in urls if not u.startswith('admin/') and not u.startswith('media/') and 'tax_api' not in u]
|
||||
|
||||
# Prepend / to urls if needed
|
||||
urls = ['/' + u if not u.startswith('/') else u for u in urls]
|
||||
|
||||
results = []
|
||||
|
||||
for url in urls:
|
||||
# Ignore endpoints that aren't strictly GET or testable by simple GET
|
||||
if url == '/logout/':
|
||||
continue
|
||||
|
||||
try:
|
||||
response = client.get(url)
|
||||
status_code = response.status_code
|
||||
content_type = response.headers.get('Content-Type', '')
|
||||
|
||||
snippet = ""
|
||||
if 'application/json' in content_type:
|
||||
try:
|
||||
data = response.json()
|
||||
snippet = json.dumps(data)[:150] + ("..." if len(json.dumps(data)) > 150 else "")
|
||||
except Exception:
|
||||
snippet = response.content.decode('utf-8', errors='ignore')[:150]
|
||||
else:
|
||||
snippet = response.content.decode('utf-8', errors='ignore')[:150].replace('\n', ' ').strip()
|
||||
if len(response.content) > 150:
|
||||
snippet += "..."
|
||||
|
||||
results.append({
|
||||
'url': url,
|
||||
'status_code': status_code,
|
||||
'snippet': snippet,
|
||||
'content_type': content_type
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'url': url,
|
||||
'status_code': 'Error',
|
||||
'snippet': str(e),
|
||||
'content_type': 'N/A'
|
||||
})
|
||||
|
||||
# Cleanup user if we created it
|
||||
if created_user:
|
||||
user.delete()
|
||||
|
||||
return results
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Starting endpoints analysis...")
|
||||
results = run_analysis()
|
||||
|
||||
artifact_path = "/home/cheerry/.gemini/antigravity/brain/5fe9c8b0-cf58-4038-b407-4851abf7278b/django_endpoints.md"
|
||||
|
||||
with open(artifact_path, "w", encoding="utf-8") as f:
|
||||
f.write("# Django Endpoints Analysis\n\n")
|
||||
f.write("| Endpoint | Status Code | Content Type | Snippet |\n")
|
||||
f.write("|----------|-------------|--------------|---------|\n")
|
||||
for res in results:
|
||||
# Escape pipe symbols for markdown tables
|
||||
snippet = res['snippet'].replace('|', '\\|').replace('\n', ' ')
|
||||
f.write(f"| `{res['url']}` | {res['status_code']} | {res['content_type']} | `{snippet}` |\n")
|
||||
|
||||
print(f"Analysis successfully saved to {artifact_path}")
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
# ============================================
|
||||
# Script para construir y subir imágenes Docker
|
||||
# al Container Registry de Gitea (ControlMC)
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
REGISTRY="git.controlmc.click"
|
||||
OWNER="ginevra_oa"
|
||||
REPO="erp-efintel-2026"
|
||||
TAG="latest"
|
||||
|
||||
WEB_IMAGE="${REGISTRY}/${OWNER}/${REPO}/web:${TAG}"
|
||||
TAX_IMAGE="${REGISTRY}/${OWNER}/${REPO}/tax-api:${TAG}"
|
||||
|
||||
echo "============================================"
|
||||
echo " ERP Efintel - Build & Push al Registry"
|
||||
echo "============================================"
|
||||
|
||||
# Paso 1: Login en el registry de Gitea
|
||||
echo ""
|
||||
echo "[1/4] Iniciando sesión en el registry de Gitea..."
|
||||
echo " (Usa tu usuario de Gitea y un Access Token como contraseña)"
|
||||
docker login ${REGISTRY}
|
||||
|
||||
# Paso 2: Construir imagen web (Django)
|
||||
echo ""
|
||||
echo "[2/4] Construyendo imagen web (Django + Gunicorn)..."
|
||||
docker build -t ${WEB_IMAGE} .
|
||||
|
||||
# Paso 3: Construir imagen tax-api (FastAPI)
|
||||
echo ""
|
||||
echo "[3/4] Construyendo imagen tax-api (FastAPI)..."
|
||||
docker build -t ${TAX_IMAGE} ./tax_api
|
||||
|
||||
# Paso 4: Subir ambas imágenes al registry
|
||||
echo ""
|
||||
echo "[4/4] Subiendo imágenes al registry de Gitea..."
|
||||
docker push ${WEB_IMAGE}
|
||||
docker push ${TAX_IMAGE}
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " ¡Listo! Imágenes subidas exitosamente."
|
||||
echo " web: ${WEB_IMAGE}"
|
||||
echo " tax-api: ${TAX_IMAGE}"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Ahora ve a Portainer y haz 'Pull and redeploy'"
|
||||
Reference in New Issue
Block a user