Migration migrate_patching_notes_20260507.sql: - servers.skip_first_reboot boolean (TPV1: vptraatpf1/2 a true) - servers.patching_notes text (markdown — meme operateur) - server_clusters.reboot_delay_min_minutes int default 0 - Backfill patching_notes pour 22 cas particuliers du wiki SANEF: ASM Oracle (~50 hosts kernel*), TPV1, HAproxy FL, Covoiturage, SI Patrimoine (vrpatbsip1 avant vrpataels1, kibana, certs), Talend, Scoop (Debian apt-mark hold + CentOS containers Docker), DATI (pm2/tomcat post-reboot), COMMVAULT (mode maintenance), Masterparc (kmeihm pm2), Splunk (RPM special), Site institutionnel (HAproxy backend rotation, no *node*), Centreon (1 par 1 + check centengine), Sextan (10min reboot delay), OCTAN, PAIPOR (site maintenance), Gaspar, Postgres, Oracle OEM, SMTP relay - Cluster Sextan cree (10 min entre reboots) + 10 serveurs Sextan rattaches UI iexec: - Banner cumule en haut: '⚠ Particularites pour N serveur(s)' si au moins 1 note - Badges sur la cellule asset_name: ⚠ note (modal markdown au clic), ⏭ skip 1st reboot, ⏱ Xmin (cluster reboot delay) - Modal patching_notes avec rendu pre/markdown, fermeture Escape UI fiche serveur (server_detail.html): - Ligne 'Skip 1er reboot' dans bloc Patching - Bandeau orange particularites avec contenu patching_notes si renseigne Pas encore implemente cote logique d'execution (Phase 2): - skip_first_reboot logic dans le step reboot - enforcement reboot_delay_min_minutes entre membres cluster - Pour l'instant: notes affichees en mode 'memo operateur' uniquement
171 lines
10 KiB
HTML
171 lines
10 KiB
HTML
<div class="p-4">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-bold text-cyber-accent">{{ s.hostname }}</h3>
|
|
<button onclick="closePanel()" class="text-gray-500 hover:text-white text-xl">×</button>
|
|
</div>
|
|
|
|
<!-- Identification -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Identification</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div class="flex justify-between"><span class="text-gray-500">FQDN</span><span>{{ s.fqdn or '-' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Domain.ltd</span><span>{{ s.domain_ltd or '-' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Machine</span><span>{{ s.machine_type }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reseau / IPs -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Reseau</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-500">IP reelle</span>
|
|
<span class="font-mono">{{ ips.ip_reelle or '-' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-500">IP de connexion</span>
|
|
<span class="font-mono text-cyber-green">{{ ips.ip_connexion or '-' }}</span>
|
|
</div>
|
|
{% if ips.autres_ips %}
|
|
<div class="mt-1">
|
|
<span class="text-gray-500 text-xs">Autres IPs</span>
|
|
<div class="mt-1 space-y-0.5">
|
|
{% for a in ips.autres_ips %}
|
|
<div class="flex justify-between text-xs">
|
|
<span class="font-mono text-gray-300">{{ a.ip }}</span>
|
|
<span class="text-gray-500">{{ a.type }}{% if a.interface %} ({{ a.interface }}){% endif %}{% if a.description %} - {{ a.description }}{% endif %}</span>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
<div class="flex justify-between"><span class="text-gray-500">Mode connexion</span><span class="badge {% if 'psmp' in s.ssh_method or 'psm' in s.ssh_method %}badge-yellow{% elif 'rdp' in s.ssh_method %}badge-blue{% else %}badge-green{% endif %}">{{ s.ssh_method }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Classification -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Classification</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div class="flex justify-between"><span class="text-gray-500">Domaine</span><span>{{ s.domaine }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Environnement</span><span class="badge {% if s.environnement == 'Production' %}badge-green{% else %}badge-yellow{% endif %}">{{ s.environnement }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Zone</span><span class="badge {% if s.zone == 'DMZ' %}badge-red{% else %}badge-blue{% endif %}">{{ s.zone or 'LAN' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Tier</span><span class="badge {% if s.tier == 'tier0' %}badge-red{% elif s.tier == 'tier1' %}badge-yellow{% else %}badge-blue{% endif %}">{{ s.tier }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Etat</span><span class="badge {% if s.etat == 'Production' %}badge-green{% elif s.etat in ('Obsolète','EOL') %}badge-red{% else %}badge-yellow{% endif %}">{{ s.etat }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Technique -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Technique</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div class="flex justify-between"><span class="text-gray-500">OS</span><span>{{ s.os_family or '-' }}</span></div>
|
|
<div class="text-xs text-gray-400 mt-1">{{ s.os_version or '' }}</div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Licence</span><span class="badge {% if s.licence_support == 'active' %}badge-green{% elif s.licence_support == 'obsolete' %}badge-red{% else %}badge-yellow{% endif %}">{{ s.licence_support }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patching -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Patching</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div class="flex justify-between"><span class="text-gray-500">Owner OS</span><span>{{ s.patch_os_owner }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Frequence</span><span>{{ s.patch_frequency }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Podman</span><span>{{ 'Oui' if s.is_podman else 'Non' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Prevenance PCT</span><span>{{ 'Oui' if s.pct_required else 'Non' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Skip 1er reboot</span><span>{{ 'Oui' if s.skip_first_reboot else 'Non' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Jour préféré</span><span>{{ s.pref_patch_jour or 'indifférent' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Heure préférée</span><span>{{ s.pref_patch_heure or 'indifférent' }}</span></div>
|
|
<div class="flex justify-between"><span class="text-gray-500">Satellite</span><span>{% if s.satellite_url %}{% if 'sat1' in s.satellite_url %}SAT1 (DMZ){% elif 'sat2' in s.satellite_url %}SAT2 (LAN){% else %}{{ s.satellite_url }}{% endif %}{% else %}N/A{% endif %}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if s.patching_notes %}
|
|
<div class="mb-4 p-3 border-l-4 border-cyber-orange bg-cyber-orange/10 rounded">
|
|
<h4 class="text-xs text-cyber-orange font-bold uppercase mb-2">⚠ Particularités de patching</h4>
|
|
<pre class="text-xs whitespace-pre-wrap font-mono text-gray-200">{{ s.patching_notes }}</pre>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Responsables -->
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Responsables</h4>
|
|
<div class="space-y-1 text-sm">
|
|
<div><span class="text-gray-500">Responsable:</span> <span>{{ s.responsable_nom or '-' }}</span></div>
|
|
<div><span class="text-gray-500">Referent:</span> <span>{{ s.referent_nom or '-' }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Correspondance prod ↔ hors-prod -->
|
|
{% if links and (links.as_prod or links.as_nonprod) %}
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Correspondance Prod ↔ Hors-Prod</h4>
|
|
{% if links.as_prod %}
|
|
<div class="text-xs mb-2">
|
|
<div class="text-cyber-green font-bold mb-1">Ce serveur est un PROD — hors-prod liés :</div>
|
|
<ul class="ml-2 space-y-1">
|
|
{% for l in links.as_prod %}
|
|
<li class="flex gap-2 items-center">
|
|
<span class="font-mono text-cyber-accent">{{ l.hostname }}</span>
|
|
<span class="badge badge-yellow" style="font-size:9px">{{ l.env_name or l.environment_code or '?' }}</span>
|
|
<span class="text-gray-600" style="font-size:9px">{{ l.source }}</span>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
{% if links.as_nonprod %}
|
|
<div class="text-xs mb-2">
|
|
<div class="text-cyber-yellow font-bold mb-1">Ce serveur est un HORS-PROD — prod(s) lié(s) :</div>
|
|
<ul class="ml-2 space-y-1">
|
|
{% for l in links.as_nonprod %}
|
|
<li class="flex gap-2 items-center">
|
|
<span class="font-mono text-cyber-accent">{{ l.hostname }}</span>
|
|
<span class="badge badge-green" style="font-size:9px">{{ l.env_name or 'Production' }}</span>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
<a href="/patching/correspondance?search={{ s.hostname }}" class="text-xs text-cyber-accent hover:underline">Gérer dans le builder →</a>
|
|
</div>
|
|
{% else %}
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Correspondance</h4>
|
|
<p class="text-xs text-gray-500">Aucune correspondance prod ↔ hors-prod définie. <a href="/patching/correspondance?search={{ s.hostname }}" class="text-cyber-accent hover:underline">Créer →</a></p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if s.mode_operatoire %}
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Mode operatoire</h4>
|
|
<p class="text-xs text-gray-400">{{ s.mode_operatoire }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if tags %}
|
|
<div class="mb-4">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2 border-b border-cyber-border pb-1">Tags Qualys</h4>
|
|
<div class="flex flex-wrap gap-1">
|
|
{% for tag in tags %}
|
|
<span class="badge badge-blue">{{ tag }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if sync_msg is defined and sync_msg %}
|
|
<div class="mb-3 p-2 rounded text-xs {% if sync_ok %}bg-green-900/30 text-cyber-green{% else %}bg-red-900/30 text-cyber-red{% endif %}">
|
|
{{ sync_msg }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Actions -->
|
|
<div class="flex gap-2 mt-4">
|
|
<button class="btn-primary px-3 py-1 text-sm flex-1" hx-get="/servers/{{ s.id }}/edit" hx-target="#detail-panel" hx-swap="innerHTML">Editer</button>
|
|
<button class="btn-sm bg-cyber-border text-cyber-accent" hx-post="/servers/{{ s.id }}/sync-qualys" hx-target="#detail-panel" hx-swap="innerHTML" hx-indicator="#sync-spin">Sync Qualys</button>
|
|
<button class="btn-sm bg-cyber-border text-gray-300" onclick="closePanel()">Fermer</button>
|
|
</div>
|
|
<span id="sync-spin" class="htmx-indicator text-xs text-gray-500 mt-1">Synchro en cours...</span>
|
|
</div>
|