From 7377c00a47ae612e1b1374e8f1828bfcc47bd2d5 Mon Sep 17 00:00:00 2001 From: Waloshi6 Date: Sun, 8 Feb 2026 14:34:23 +0100 Subject: [PATCH] aa --- .gitignore | 3 + TpDevOpsProject.md | 57 ++++++- docs/ProcédureGit.md | 3 + .../indexers/issues.bleve/store/root.bolt | Bin 65536 -> 65536 bytes .../gitea-data/gitea/queues/common/000095.log | 0 gitea/gitea-data/gitea/queues/common/CURRENT | 2 +- .../gitea/queues/common/CURRENT.bak | 2 +- gitea/gitea-data/gitea/queues/common/LOG | 81 +++++++++ .../gitea/queues/common/MANIFEST-000096 | 0 src/app/.dockerignore | 16 ++ src/app/Dockerfile | 60 ++----- src/app/__pycache__/main.cpython-314.pyc | Bin 0 -> 6472 bytes src/app/main.py | 160 +++++------------- src/app/requirements.txt | 4 +- src/app/templates/index.html | 9 + 15 files changed, 229 insertions(+), 168 deletions(-) create mode 100644 .gitignore delete mode 100644 gitea/gitea-data/gitea/queues/common/000095.log delete mode 100644 gitea/gitea-data/gitea/queues/common/MANIFEST-000096 create mode 100644 src/app/.dockerignore create mode 100644 src/app/__pycache__/main.cpython-314.pyc create mode 100644 src/app/templates/index.html 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 5133646e85e8f1c1b53787fa80588c4b1de30169..420632cd653578f5f0f56eacf9ac01a360889536 100644 GIT binary patch delta 111 zcmZo@U}t* delta 111 zcmZo@U}zk(G(5o~41Mk)g4Lg~{d}0UqlC DGngRR 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 0000000000000000000000000000000000000000..27ac07d2108f5d00dea8740caa7a0fd6e4d3dcf7 GIT binary patch literal 6472 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 CG`6b% literal 0 HcmV?d00001 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"

Erreur de lecture du fichier :

{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"

Erreur de template :

{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 @@ + + + +DevOps App + +

{{ header|safe }}

+
{{ content|safe }}
+ + \ No newline at end of file