KPIs applicatifs: Oracle, PostgreSQL, MariaDB, HANA, httpd, nginx, HAProxy, Tomcat, Java, Node.js, Redis, MongoDB, Elastic, Docker/Podman — cliquables avec filtre

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalid MOUTAOUAKIL 2026-04-06 17:08:25 +02:00
parent 38b27beb9d
commit cdd550c84b
2 changed files with 59 additions and 1 deletions

View File

@ -48,7 +48,21 @@ async def audit_full_list(request: Request, db=Depends(get_db)):
OR (uptime LIKE '%week%' AND (
CASE WHEN uptime ~ '(\d+) week' THEN (substring(uptime from '(\d+) week'))::int ELSE 0 END >= 17
))
) as uptime_long
) as uptime_long,
COUNT(*) FILTER (WHERE services::text ~* 'postgres') as app_postgres,
COUNT(*) FILTER (WHERE services::text ~* 'mariadb|mysqld') as app_mariadb,
COUNT(*) FILTER (WHERE services::text ~* 'hdb|sapstart|HANA') as app_hana,
COUNT(*) FILTER (WHERE services::text ~* 'oracle|ora_pmon' OR processes::text ~* 'ora_pmon|oracle') as app_oracle,
COUNT(*) FILTER (WHERE services::text ~* '"httpd"' OR listen_ports::text ~* '"httpd"') as app_httpd,
COUNT(*) FILTER (WHERE services::text ~* '"nginx"' OR listen_ports::text ~* '"nginx"') as app_nginx,
COUNT(*) FILTER (WHERE services::text ~* 'haproxy') as app_haproxy,
COUNT(*) FILTER (WHERE services::text ~* 'tomcat' OR processes::text ~* 'tomcat|catalina') as app_tomcat,
COUNT(*) FILTER (WHERE listen_ports::text ~* '"node"' OR processes::text ~* '/applis.*node') as app_nodejs,
COUNT(*) FILTER (WHERE services::text ~* 'redis') as app_redis,
COUNT(*) FILTER (WHERE services::text ~* 'mongod') as app_mongodb,
COUNT(*) FILTER (WHERE services::text ~* 'elasticsearch|opensearch') as app_elastic,
COUNT(*) FILTER (WHERE services::text ~* 'docker|podman' OR processes::text ~* 'dockerd|podman') as app_container,
COUNT(*) FILTER (WHERE listen_ports::text ~* '"java"' OR processes::text ~* '\.jar') as app_java
FROM server_audit_full
WHERE status = 'ok'
AND id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC)
@ -86,6 +100,33 @@ async def audit_full_list(request: Request, db=Depends(get_db)):
audits = [a for a in audits if a.id in ids]
elif filtre == "uptime":
audits = [a for a in audits if a.uptime and ("month" in a.uptime or "year" in a.uptime)]
elif filtre and filtre.startswith("app_"):
# Filtre applicatif generique
app_patterns = {
"app_postgres": "postgres",
"app_mariadb": "mariadb|mysqld",
"app_hana": "hdb|sapstart|HANA",
"app_oracle": "ora_pmon|oracle",
"app_httpd": "httpd",
"app_nginx": "nginx",
"app_haproxy": "haproxy",
"app_tomcat": "tomcat|catalina",
"app_nodejs": "node",
"app_redis": "redis",
"app_mongodb": "mongod",
"app_elastic": "elasticsearch|opensearch",
"app_container": "docker|podman",
"app_java": "java|\\.jar",
}
pattern = app_patterns.get(filtre, "")
if pattern:
ids = {r.id for r in db.execute(text("""
SELECT id FROM server_audit_full
WHERE status = 'ok'
AND (services::text ~* :pat OR listen_ports::text ~* :pat OR processes::text ~* :pat)
AND id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC)
"""), {"pat": pattern}).fetchall()}
audits = [a for a in audits if a.id in ids]
# Filtre domaine ou zone
if domain:

View File

@ -47,6 +47,23 @@
<div class="text-xs text-gray-500">Uptime > 4m</div>
</a>
</div>
<!-- KPIs applicatifs -->
<div style="display:flex;flex-wrap:nowrap;gap:4px;margin-bottom:12px;">
{% for key, label, icon in [
('app_oracle','Oracle','db'),('app_postgres','PostgreSQL','db'),('app_mariadb','MariaDB/MySQL','db'),('app_hana','SAP HANA','db'),
('app_httpd','Apache','web'),('app_nginx','Nginx','web'),('app_haproxy','HAProxy','web'),
('app_tomcat','Tomcat','app'),('app_java','Java','app'),('app_nodejs','Node.js','app'),
('app_redis','Redis','db'),('app_mongodb','MongoDB','db'),('app_elastic','Elastic','db'),('app_container','Docker/Podman','app')
] %}
{% set val = kpis[key]|default(0) %}
{% if val > 0 %}
<a href="/audit-full?filter={{ key }}" class="card px-2 py-1 text-center hover:bg-cyber-hover {% if filter == key %}ring-1 ring-cyber-accent{% endif %}" style="min-width:0;flex:0 1 auto;">
<div class="text-sm font-bold {% if icon == 'db' %}text-blue-400{% elif icon == 'web' %}text-green-400{% else %}text-purple-400{% endif %}">{{ val }}</div>
<div style="font-size:10px;" class="text-gray-500 whitespace-nowrap">{{ label }}</div>
</a>
{% endif %}
{% endfor %}
</div>
{% if filter %}
<div class="mb-3 text-xs text-gray-400">Filtre actif : <span class="text-cyber-accent">{{ filter }}</span><a href="/audit-full" class="text-cyber-accent underline">Tout voir</a></div>
{% endif %}