diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b18266 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.log +manifest-* +*.bak diff --git a/TpDevOpsProject.md b/TpDevOpsProject.md index 1a6b608..67dcf2f 100644 --- a/TpDevOpsProject.md +++ b/TpDevOpsProject.md @@ -54,7 +54,12 @@ Versionning spĂ©cifique des images Docker #đ TP DevOps Windows - Stack ComplĂšte Locale (CorrigĂ© & OptimisĂ©) + + #đ PRĂ-REQUIS WINDOWS - Installation Pas Ă Pas + +Avant tout, bien penser Ă ACTIVER la fonction de VIRTUALISATION dans le BIOS du systeme de votre pc + #đ§ 1. PrĂ©paration du systĂšme (PowerShell Administrateur) # Ouvrir PowerShell en tant qu'ADMINISTRATEUR (clic droit â ExĂ©cuter en tant qu'administrateur) @@ -71,6 +76,7 @@ wsl --set-default-version 2 # 4. RedĂ©marrer l'ordinateur (OBLIGATOIRE) Restart-Computer + #đ„ 2. Installation des outils (aprĂšs redĂ©marrage) # 1. Installer Chocolatey (package manager Windows) @@ -80,6 +86,7 @@ iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocola # 2. Installer tous les outils choco install -y git docker-desktop vscode kubernetes-cli minikube terraform helm postman + #đ§ 3. Configuration WSL2 et Ubuntu # VĂ©rifier l'installation WSL @@ -98,7 +105,10 @@ sudo apt install -y python3 python3-pip python3-venv nodejs npm curl wget echo "alias k=kubectl" >> ~/.bashrc source ~/.bashrc exit # Retour Ă PowerShell + + #đ ĂTAPE 1 : CONFIGURATION DOCKER DESKTOP + #âïž Configuration manuelle obligatoire : Ouvrir Docker Desktop aprĂšs installation @@ -142,7 +152,10 @@ docker run hello-world # VĂ©rifier l'intĂ©gration WSL2 wsl -d Ubuntu-22.04 -e docker version # Doit fonctionner sans erreur + + #đ ĂTAPE 2 : STRUCTURE DU PROJET OPTIMISĂE + #đïž CrĂ©ation de la structure : # CrĂ©er le dossier principal @@ -177,9 +190,14 @@ C:\DevOpsProject\ âââ .github\workflows\ # CI/CD âââ config\ # Fichiers de config âââ docs\ # Documentation + + #đ ĂTAPE 3 : APPLICATION PYTHON CORRIGĂE + #3.1 Fichier : src\app\requirements.txt +# commentaire de Oualim : Ce fichier installera les dĂ©pendances dans le conteneur, pas sur votre machine + fastapi==0.104.1 uvicorn[standard]==0.24.0 pydantic==2.5.0 @@ -187,6 +205,7 @@ prometheus-client==0.19.0 python-dotenv==1.0.0 pytest==7.4.3 httpx==0.25.1 + #3.2 Fichier : src\app\main.py (CORRIGĂ) from fastapi import FastAPI, Request, Response, HTTPException @@ -399,7 +418,11 @@ USER devopsuser # Commande de dĂ©marrage CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"] + + + #đł ĂTAPE 4 : DOCKER COMPOSE CORRIGĂ + #4.1 Fichier : docker\docker-compose.yml (RECOMMENCĂ) version: '3.8' @@ -521,6 +544,7 @@ volumes: name: portainer-data app-logs: name: app-logs + #4.2 Fichier : docker\prometheus.yml (Ă CRĂER) global: @@ -564,6 +588,7 @@ scrape_configs: # alertmanagers: # - static_configs: # - targets: [] + #4.3 ExĂ©cution Docker Compose : # Se placer dans le dossier docker @@ -582,7 +607,10 @@ docker-compose logs app curl http://localhost:8000 # ou dans PowerShell Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing + + #âžïž ĂTAPE 5 : KUBERNETES SIMPLIFIĂ POUR WINDOWS + #5.1 Activer Kubernetes dans Docker Desktop : 1. Docker Desktop â Settings (roue crantĂ©e) @@ -590,6 +618,7 @@ Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing 3. â Enable Kubernetes 4. â Show system containers (optional) 5. Apply & Restart (patienter 2-3 minutes) + #5.2 VĂ©rification : # VĂ©rifier que Kubernetes fonctionne @@ -601,6 +630,7 @@ kubectl get nodes kubectl get pods --all-namespaces # Doit montrer les pods systĂšme + #5.3 Fichier : kubernetes\manifests\namespace.yaml apiVersion: v1 @@ -610,6 +640,7 @@ metadata: labels: name: devops-demo environment: development + #5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU) apiVersion: v1 @@ -622,6 +653,7 @@ data: APP_NAME: "devops-windows-app" LOG_LEVEL: "INFO" PYTHONUNBUFFERED: "1" + #5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIĂ) apiVersion: apps/v1 @@ -695,6 +727,7 @@ spec: protocol: TCP name: http type: NodePort # CORRIGĂ : NodePort au lieu de LoadBalancer pour Windows + #5.6 DĂ©ploiement Kubernetes : # 1. Build l'image Docker avec un tag spĂ©cifique @@ -718,7 +751,10 @@ kubectl get svc -n devops-demo devops-app-service -o jsonpath='{.spec.ports[0].n # 5. AccĂ©der Ă l'application # http://localhost:[PORT] (ex: http://localhost:30456) + + #đïž ĂTAPE 6 : TERRAFORM SIMPLIFIĂ (OPTIONNEL) + #â ïž IMPORTANT : Terraform + Docker sur Windows/WSL2 est complexe. #Je recommande de SAUTER cette Ă©tape pour les dĂ©butants. Si vous voulez quand mĂȘme essayer : @@ -838,6 +874,7 @@ output "application_url" { output "namespace" { value = kubernetes_namespace.devops.metadata[0].name } + #6.2 Utilisation Terraform : cd C:\DevOpsProject\terraform @@ -853,7 +890,10 @@ terraform apply # Pour dĂ©truire terraform destroy + + #đŠ ĂTAPE 7 : HELM SIMPLE POUR WINDOWS + #7.1 CrĂ©ation d'un chart Helm simple : cd C:\DevOpsProject\kubernetes\helm @@ -910,6 +950,7 @@ app: monitoring: enabled: true prometheusScrape: true + #7.4 Fichier : kubernetes\helm\devops-chart\templates\deployment.yaml apiVersion: apps/v1 @@ -956,6 +997,7 @@ spec: port: {{ .Values.app.service.targetPort }} initialDelaySeconds: 10 periodSeconds: 15 + #7.5 Installation avec Helm : cd C:\DevOpsProject\kubernetes\helm @@ -971,7 +1013,10 @@ helm upgrade devops-release ./devops-chart -n devops-demo # DĂ©sinstaller helm uninstall devops-release -n devops-demo + + #đ ĂTAPE 8 : GITHUB ACTIONS CORRIGĂ + #8.1 Fichier : .github\workflows\ci-cd.yml (PRATIQUE) name: CI/CD DevOps Windows @@ -1070,7 +1115,10 @@ jobs: echo "kubectl apply -f kubernetes/manifests/" echo "ou" echo "helm upgrade --install ..." + + #đ ĂTAPE 9 : MONITORING FONCTIONNEL + #9.1 Dashboard Grafana prĂȘt Ă l'emploi : # CrĂ©er un dossier pour les dashboards Grafana @@ -1102,6 +1150,7 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards } } '@ | Out-File -FilePath "C:\DevOpsProject\docker\grafana-dashboards\dashboard.json" -Encoding UTF8 + #9.2 AccĂšs aux interfaces : â AprĂšs docker-compose up -d : @@ -1117,7 +1166,10 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards 1. Application K8s : http://localhost:[NODE_PORT] (trouvez le port avec : kubectl get svc -n devops-demo) + + #đ ïž ĂTAPE 10 : SCRIPTS PRATIQUES + #10.1 Script : scripts\setup.ps1 (AMĂLIORĂ) # DevOps Windows Setup Script @@ -1386,7 +1438,10 @@ Write-Host "â Toutes les ressources ont Ă©tĂ© nettoyĂ©es" -ForegroundColor Gre Write-Host "" Write-Host "Pour recommencer :" -ForegroundColor Cyan Write-Host " .\setup.ps1" -ForegroundColor Gray + + #đŻ VALIDATION FINALE + #Testez votre installation : # 1. Lancer le setup @@ -1444,7 +1499,7 @@ Votre stack DevOps Windows est maintenant fonctionnelle et prĂȘte Ă l'emploi ! # Commentaire de Oualim -# Avant d'aller plus loin, les partie 6,7 et 8 n'Ă©tant pas encore abordĂ©e Ă cette Ă©tape, en lançant uniquement les commandes de la partie 4.3 on se retrouvera avec des containeurs orphelins : +# Avant d'aller plus loin, les #6, #7 et #8 n'Ă©tant pas encore abordĂ©e Ă cette Ă©tape, en lançant uniquement les commandes de le #3 on se retrouvera avec des containeurs orphelins : PS C:\DevOpsProject\docker> docker-compose ps "....Found orphan containers ([gitea logstash kibana filebeat elasticsearch devops-db])...." diff --git a/docs/ProcĂ©dureGit.md b/docs/ProcĂ©dureGit.md index 65c43b6..91bded7 100644 --- a/docs/ProcĂ©dureGit.md +++ b/docs/ProcĂ©dureGit.md @@ -16,4 +16,7 @@ - se connecter pour ouvrir l'accĂšs ==> "url = https://git..." (url ==> C:\DevOpsProject\.git\config) - "git push origin main" +# Puller une partie de projet modifiĂ© en preservant les modifs non pushĂ© + - + - diff --git a/gitea/gitea-data/gitea/indexers/issues.bleve/store/root.bolt b/gitea/gitea-data/gitea/indexers/issues.bleve/store/root.bolt index 5133646..420632c 100644 Binary files a/gitea/gitea-data/gitea/indexers/issues.bleve/store/root.bolt and b/gitea/gitea-data/gitea/indexers/issues.bleve/store/root.bolt differ diff --git a/gitea/gitea-data/gitea/queues/common/000095.log b/gitea/gitea-data/gitea/queues/common/000095.log deleted file mode 100644 index e69de29..0000000 diff --git a/gitea/gitea-data/gitea/queues/common/CURRENT b/gitea/gitea-data/gitea/queues/common/CURRENT index 6274e55..3182b19 100644 --- a/gitea/gitea-data/gitea/queues/common/CURRENT +++ b/gitea/gitea-data/gitea/queues/common/CURRENT @@ -1 +1 @@ -MANIFEST-000096 +MANIFEST-000114 diff --git a/gitea/gitea-data/gitea/queues/common/CURRENT.bak b/gitea/gitea-data/gitea/queues/common/CURRENT.bak index 0ab25fa..b59a6ba 100644 --- a/gitea/gitea-data/gitea/queues/common/CURRENT.bak +++ b/gitea/gitea-data/gitea/queues/common/CURRENT.bak @@ -1 +1 @@ -MANIFEST-000094 +MANIFEST-000112 diff --git a/gitea/gitea-data/gitea/queues/common/LOG b/gitea/gitea-data/gitea/queues/common/LOG index e54c641..ad9649a 100644 --- a/gitea/gitea-data/gitea/queues/common/LOG +++ b/gitea/gitea-data/gitea/queues/common/LOG @@ -415,3 +415,84 @@ 13:52:44.428084 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] 13:52:44.486849 db@janitor F·3 G·0 13:52:44.487042 db@open done T·69.246442ms +=============== Feb 5, 2026 (UTC) =============== +15:51:14.399455 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +15:51:14.439535 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:51:14.440100 db@open opening +15:51:14.443037 journal@recovery F·1 +15:51:14.444002 journal@recovery recovering @93 +15:51:14.457130 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:51:14.511329 db@janitor F·3 G·0 +15:51:14.511866 db@open done T·71.613432ms +=============== Feb 6, 2026 (UTC) =============== +10:49:29.095596 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +10:49:29.131170 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:49:29.131550 db@open opening +10:49:29.135461 journal@recovery F·1 +10:49:29.135730 journal@recovery recovering @95 +10:49:29.141437 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:49:29.199095 db@janitor F·3 G·0 +10:49:29.199560 db@open done T·67.8483ms +=============== Feb 6, 2026 (UTC) =============== +10:53:40.580960 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +10:53:40.591365 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:53:40.591700 db@open opening +10:53:40.593746 journal@recovery F·1 +10:53:40.594013 journal@recovery recovering @97 +10:53:40.604447 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:53:40.712208 db@janitor F·3 G·0 +10:53:40.712621 db@open done T·120.78394ms +=============== Feb 6, 2026 (UTC) =============== +10:57:24.598143 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +10:57:24.616721 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:57:24.617237 db@open opening +10:57:24.618928 journal@recovery F·1 +10:57:24.619220 journal@recovery recovering @99 +10:57:24.622811 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +10:57:24.658530 db@janitor F·3 G·0 +10:57:24.658711 db@open done T·41.279095ms +=============== Feb 6, 2026 (UTC) =============== +11:00:06.298412 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +11:00:06.310703 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +11:00:06.311328 db@open opening +11:00:06.316598 journal@recovery F·1 +11:00:06.317192 journal@recovery recovering @101 +11:00:06.325703 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +11:00:06.374535 db@janitor F·3 G·0 +11:00:06.374849 db@open done T·63.190584ms +=============== Feb 6, 2026 (UTC) =============== +11:50:03.854543 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +11:50:03.864227 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +11:50:03.865796 db@open opening +11:50:03.872207 journal@recovery F·1 +11:50:03.872558 journal@recovery recovering @103 +11:50:03.876753 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +11:50:03.949425 db@janitor F·3 G·0 +11:50:03.950338 db@open done T·84.322748ms +=============== Feb 6, 2026 (UTC) =============== +12:45:29.925234 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +12:45:29.952459 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +12:45:29.953662 db@open opening +12:45:29.959031 journal@recovery F·1 +12:45:29.959375 journal@recovery recovering @105 +12:45:29.963600 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +12:45:30.026778 db@janitor F·3 G·0 +12:45:30.027106 db@open done T·73.277756ms +=============== Feb 7, 2026 (UTC) =============== +15:37:46.707349 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +15:37:46.739671 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:37:46.740550 db@open opening +15:37:46.745371 journal@recovery F·1 +15:37:46.745766 journal@recovery recovering @107 +15:37:46.751116 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:37:46.811638 db@janitor F·3 G·0 +15:37:46.811822 db@open done T·70.8136ms +=============== Feb 7, 2026 (UTC) =============== +15:41:07.560631 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +15:41:07.573670 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:41:07.574246 db@open opening +15:41:07.576253 journal@recovery F·1 +15:41:07.576509 journal@recovery recovering @109 +15:41:07.579359 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00] +15:41:07.617133 db@janitor F·3 G·0 +15:41:07.617309 db@open done T·42.89556ms diff --git a/gitea/gitea-data/gitea/queues/common/MANIFEST-000096 b/gitea/gitea-data/gitea/queues/common/MANIFEST-000096 deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/.dockerignore b/src/app/.dockerignore new file mode 100644 index 0000000..888cad2 --- /dev/null +++ b/src/app/.dockerignore @@ -0,0 +1,16 @@ +__pycache__ +*.pyc +.pytest_cache +.coverage +.git +.gitignore +README.md +Dockerfile +.dockerignore +.env +*.log +node_modules +.vscode +.idea +tests/ +docs/ \ No newline at end of file diff --git a/src/app/Dockerfile b/src/app/Dockerfile index df74c30..aa0a7c5 100644 --- a/src/app/Dockerfile +++ b/src/app/Dockerfile @@ -1,66 +1,32 @@ -# ========================== -# STAGE 1 : Construction -# ========================== -FROM python:3.11-slim AS builder +# Phase de base +FROM python:3.11-slim AS base WORKDIR /app -# Installer les dĂ©pendances systĂšme RUN apt-get update && apt-get install -y --no-install-recommends \ - build-essential \ - libpq-dev \ - gcc \ - postgresql-client \ - && rm -rf /var/lib/apt/lists/* + build-essential libpq-dev gcc libpq5 && rm -rf /var/lib/apt/lists/* -# CrĂ©er un environnement virtuel +RUN pip install --upgrade pip + +COPY src/app/requirements.txt . RUN python -m venv /venv ENV PATH="/venv/bin:$PATH" +RUN /venv/bin/pip install --no-cache-dir -r requirements.txt -# Installer les dĂ©pendances -COPY src/app/requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - - -# ========================== -# STAGE 2 : Production -# ========================== +# Phase finale FROM python:3.11-slim AS runtime -# DĂ©finir le rĂ©pertoire de travail -WORKDIR /app +WORKDIR /app # đŽ AjoutĂ© : dĂ©finit le rĂ©pertoire de travail -# Installer les bibliothĂšques systĂšme -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq5 \ - && rm -rf /var/lib/apt/lists/* - -# đ„ Installe curl ici -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* - - -# CrĂ©er un utilisateur non-root -RUN useradd -m -u 1000 devopsuser - -# Copier l'environnement virtuel -COPY --from=builder /venv /venv +COPY --from=base /venv /venv ENV PATH="/venv/bin:$PATH" -# Copier le code COPY src/app /app +COPY TpDevOpsProject.md /app/TpDevOpsProject.md -# Changer les droits -RUN chown -R devopsuser:devopsuser /app +RUN useradd -m -u 1000 devopsuser && chown -R devopsuser:devopsuser /app USER devopsuser -# Variables d'environnement -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 -ENV ENV=production -ENV HOSTNAME=devops-container -ENV PYTHONPATH="/app" - EXPOSE 8000 -# Lancer l'application -CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"] \ No newline at end of file +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "/app"] \ No newline at end of file diff --git a/src/app/__pycache__/main.cpython-314.pyc b/src/app/__pycache__/main.cpython-314.pyc new file mode 100644 index 0000000..27ac07d Binary files /dev/null and b/src/app/__pycache__/main.cpython-314.pyc differ diff --git a/src/app/main.py b/src/app/main.py index 78e3c0b..38f8b0d 100644 --- a/src/app/main.py +++ b/src/app/main.py @@ -1,153 +1,79 @@ -# ========================== -# IMPORTS DES DĂPENDANCES -# ========================== +import traceback +import os +from pathlib import Path from fastapi import FastAPI, Request, HTTPException, Response +from fastapi.templating import Jinja2Templates +from fastapi.responses import HTMLResponse from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST import time -import os import logging -from typing import Dict +import markdown -# Import du routeur pour /users from routes import router as routes_app -# ========================== -# CONFIGURATION DE L'APPLICATION -# ========================== -# Configuration du logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -# CrĂ©ation de l'application FastAPI -app = FastAPI( - title="DevOps Windows API", - description="Application de dĂ©monstration DevOps sous Windows", - version="1.0.0" -) +app = FastAPI(title="DevOps Windows API", description="Application de dĂ©monstration DevOps sous Windows", version="1.0.0") -# Inclusion du routeur (doit ĂȘtre aprĂšs la crĂ©ation de 'app') -app.include_router(routes_app, prefix="/users", tags=["users"]) +# đč Utilise un chemin absolu pour le dossier templates +BASE_DIR = Path(__file__).resolve().parent +templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) -# ========================== -# MĂTRIQUES PROMETHEUS -# ========================== -REQUEST_COUNT = Counter( - 'http_requests_total', - 'Total des requĂȘtes HTTP', - ['method', 'endpoint', 'status'] -) +app.include_router(routes_app, prefix="/users", tags=["users"]) -REQUEST_LATENCY = Histogram( - 'http_request_duration_seconds', - 'Temps de rĂ©ponse HTTP', - ['method', 'endpoint'] -) +REQUEST_COUNT = Counter('http_requests_total', 'Total des requĂȘtes HTTP', ['method', 'endpoint', 'status']) +REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'Temps de rĂ©ponse HTTP', ['method', 'endpoint']) -# ========================== -# MIDDLEWARE DE MONITORING -# ========================== @app.middleware("http") async def monitor_requests(request: Request, call_next): - """Middleware pour suivre les requĂȘtes et mesurer la latence.""" start_time = time.time() - try: response = await call_next(request) status_code = str(response.status_code) except Exception as e: status_code = "500" - response = Response( - content=f"Erreur serveur : {str(e)}", - status_code=500 - ) - + response = Response(content=f"Erreur serveur : {str(e)}", status_code=500) process_time = time.time() - start_time - - # Enregistrement des mĂ©triques - REQUEST_COUNT.labels( - method=request.method, - endpoint=request.url.path, - status=status_code - ).inc() - - REQUEST_LATENCY.labels( - method=request.method, - endpoint=request.url.path - ).observe(process_time) - - # Ajout du temps de traitement dans les headers + REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path, status=status_code).inc() + REQUEST_LATENCY.labels(method=request.method, endpoint=request.url.path).observe(process_time) response.headers["X-Process-Time"] = f"{process_time:.3f}s" - return response -# ========================== -# ENDPOINTS PRINCIPAUX -# ========================== +@app.get("/", response_class=HTMLResponse) +async def home(request: Request): + md_file_path = "/app/TpDevOpsProject.md" + try: + with open(md_file_path, "r", encoding="utf-8") as f: + md_content = f.read() + html_content = markdown.markdown(md_content) + except Exception as e: + html_content = f"
{traceback.format_exc()}"
-@app.get("/")
-async def home():
- """Endpoint racine - Statut de l'application."""
- return {
- "message": "đ DevOps Stack Windows - Fonctionnel !",
- "environment": os.getenv("ENV", "development"),
- "status": "running",
- "hostname": os.getenv("HOSTNAME", "windows-devops"),
- "version": "1.0.0"
- }
+ header_banner = "đ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ DevOps Stack Windows - Fonctionnel ! $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
+
+ try:
+ return templates.TemplateResponse("index.html", {
+ "request": request,
+ "header": header_banner,
+ "content": html_content
+ })
+ except Exception as e:
+ return HTMLResponse(f"{traceback.format_exc()}", status_code=500)
@app.get("/health")
-async def health():
- """Health check pour Kubernetes."""
- return {
- "status": "healthy",
- "timestamp": time.time(),
- "service": "devops-app"
- }
+async def health(): return {"status": "healthy", "timestamp": time.time(), "service": "devops-app"}
@app.get("/metrics")
async def metrics():
- """Endpoint pour Prometheus."""
- try:
- data = generate_latest()
- return Response(
- content=data,
- media_type=CONTENT_TYPE_LATEST,
- headers={"Cache-Control": "no-cache"}
- )
- except Exception as e:
- logger.error(f"Erreur lors de la génération des métriques : {e}")
- raise HTTPException(status_code=500, detail="Ăchec de la gĂ©nĂ©ration des mĂ©triques")
+ try: return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST)
+ except Exception as e: raise HTTPException(status_code=500, detail="Ăchec des mĂ©triques")
@app.get("/info")
-async def info():
- """Informations systĂšme."""
- return {
- "python_version": "3.11",
- "platform": "windows",
- "service": "FastAPI DevOps",
- "features": ["docker", "kubernetes", "monitoring", "ci-cd"]
- }
+async def info(): return {
+ "python_version": "3.11", "platform": "windows", "service": "FastAPI DevOps",
+ "features": ["docker", "kubernetes", "monitoring", "ci-cd"]
+}
@app.get("/env")
-async def show_env():
- """Affiche les variables d'environnement (sécurisées)."""
- safe_env = {
- "ENV": os.getenv("ENV", "not-set"),
- "HOSTNAME": os.getenv("HOSTNAME", "not-set"),
- "PYTHON_VERSION": os.getenv("PYTHON_VERSION", "not-set")
- }
- return safe_env
-
-# ==========================
-# LANCEMENT EN DĂVELOPPEMENT
-# ==========================
-if __name__ == "__main__":
- import uvicorn
- logger.info("Démarrage du serveur FastAPI...")
- uvicorn.run(
- app,
- host="0.0.0.0",
- port=8000,
- log_level="info",
- reload=True # Auto-reload en dev
- )
\ No newline at end of file
+async def show_env(): return {"ENV": os.getenv("ENV", "not-set"), "HOSTNAME": os.getenv("HOSTNAME", "not-set")}
\ No newline at end of file
diff --git a/src/app/requirements.txt b/src/app/requirements.txt
index 2b9cb27..2545ee8 100644
--- a/src/app/requirements.txt
+++ b/src/app/requirements.txt
@@ -5,4 +5,6 @@ prometheus-client==0.19.0
python-dotenv==1.0.0
pytest==7.4.3
httpx==0.25.1
-psycopg2==2.9.9
+psycopg2-binary==2.9.9
+markdown==3.6
+jinja2
diff --git a/src/app/templates/index.html b/src/app/templates/index.html
new file mode 100644
index 0000000..bff08a1
--- /dev/null
+++ b/src/app/templates/index.html
@@ -0,0 +1,9 @@
+
+
+
+