Semaine 5, jour 3

This commit is contained in:
gauvainboiche
2026-02-11 15:59:52 +01:00
parent 3f609ad139
commit df908f9c5a
21 changed files with 918 additions and 1 deletions

View File

@@ -0,0 +1,533 @@
from datetime import date
from typing import Iterator, Callable
class Service:
"""
Un service deploye.
"""
__slots__ = ('_nom', '_port', '_protocole', '_critique')
def __init__(self, nom: str, port: int, protocole: str, *, critique: bool = False):
self._nom = nom
self._port = port
self._protocole = protocole
self._critique = critique
def est_critique(self) -> bool:
"""Ce service est-il critique pour le SI?"""
return self._critique
def ecoute_sur(self, port: int) -> bool:
"""Ce service ecoute-t-il sur ce port?"""
return self._port == port
def utilise_protocole(self, protocole: str) -> bool:
"""Ce service utilise-t-il ce protocole?"""
return self._protocole.lower() == protocole.lower()
def __eq__(self, autre: object) -> bool:
if not isinstance(autre, Service):
return NotImplemented
return self._nom == autre._nom and self._port == autre._port
def __repr__(self) -> str:
return f"Service({self._nom!r}, {self._port}, {self._protocole!r}, critique={self._critique})"
class Services:
"""
Une collection de services. Encapsule la logique de gestion.
Cet objet sait filtrer, compter, itérer sur ses services.
"""
__slots__ = ('_services',)
def __init__(self, *services: Service):
self._services: tuple[Service, ...] = services
def avec(self, service: Service) -> 'Services':
"""Retourne une nouvelle collection incluant ce service."""
if service in self._services:
return self
return Services(*self._services, service)
def sans(self, service: Service) -> 'Services':
"""Retourne une nouvelle collection sans ce service."""
return Services(*(s for s in self._services if s != service))
def critiques(self) -> 'Services':
"""Retourne uniquement les services critiques."""
return Services(*(s for s in self._services if s.est_critique()))
def sur_port(self, port: int) -> 'Services':
"""Retourne les services écoutant sur ce port."""
return Services(*(s for s in self._services if s.ecoute_sur(port)))
def contient(self, service: Service) -> bool:
"""Cette collection contient-elle ce service?"""
return service in self._services
def est_vide(self) -> bool:
"""Cette collection est-elle vide?"""
return len(self._services) == 0
def __len__(self) -> int:
return len(self._services)
def __iter__(self) -> Iterator[Service]:
return iter(self._services)
def __contains__(self, service: Service) -> bool:
return service in self._services
def __repr__(self) -> str:
return f"Services({', '.join(repr(s) for s in self._services)})"
class Serveur:
"""
Un serveur hebergeant des services.
"""
def __init__(self, nom: str, ip: str, os: str, mise_en_service: date):
self._nom = nom
self._ip = ip
self._os = os
self._mise_en_service = mise_en_service
self._services = Services()
def heberge(self, service: Service) -> None:
"""Ajoute un service a ce serveur."""
self._services = self._services.avec(service)
def retire(self, service: Service) -> None:
"""Retire un service de ce serveur."""
self._services = self._services.sans(service)
def services_critiques(self) -> Services:
"""Retourne les services critiques heberges."""
return self._services.critiques()
def nombre_services(self) -> int:
"""Combien de services ce serveur heberge-t-il?"""
return len(self._services)
def repond_au_nom(self, nom: str) -> bool:
"""Ce serveur repond-il a ce nom?"""
return self._nom == nom
def a_pour_ip(self, ip: str) -> bool:
"""Ce serveur a-t-il cette IP?"""
return self._ip == ip
def fonctionne_sous(self, os: str) -> bool:
"""Ce serveur fonctionne-t-il sous cet OS?"""
return self._os.lower() == os.lower()
def en_service_depuis(self, depuis: date) -> bool:
"""Ce serveur est-il en service depuis au moins cette date?"""
return self._mise_en_service <= depuis
def fiche(self) -> str:
"""Retourne une fiche descriptive complete du serveur."""
lignes = [
f"Serveur: {self._nom}",
f" IP: {self._ip}",
f" OS: {self._os}",
f" En service depuis: {self._mise_en_service}",
f" Services ({len(self._services)}):",
]
for service in self._services:
lignes.append(f" - {service}")
return "\n".join(lignes)
def __eq__(self, autre: object) -> bool:
if not isinstance(autre, Serveur):
return NotImplemented
return self._nom == autre._nom and self._ip == autre._ip
def __len__(self) -> int:
"""Nombre de services heberges."""
return len(self._services)
def __repr__(self) -> str:
return f"Serveur({self._nom!r}, {self._ip!r}, {self._os!r}, {self._mise_en_service!r})"
class ServeurPhysique(Serveur):
"""
Un serveur physique dans un rack.
"""
def __init__(
self,
nom: str,
ip: str,
os: str,
mise_en_service: date,
*,
rack: str,
consommation_kw: float,
sous_garantie: bool = True
):
super().__init__(nom, ip, os, mise_en_service)
self._rack = rack
self._consommation_kw = consommation_kw
self._sous_garantie = sous_garantie
def est_sous_garantie(self) -> bool:
"""Ce serveur est-il encore sous garantie?"""
return self._sous_garantie
def consomme_plus_que(self, seuil_kw: float) -> bool:
"""Ce serveur consomme-t-il plus que le seuil?"""
return self._consommation_kw > seuil_kw
def dans_rack(self, rack: str) -> bool:
"""Ce serveur est-il dans ce rack?"""
return self._rack == rack
def fiche(self) -> str:
"""Retourne une fiche descriptive complete du serveur."""
base = super().fiche()
garantie = "Oui" if self._sous_garantie else "Non"
return "\n".join([
base,
f" Rack: {self._rack}",
f" Consommation: {self._consommation_kw} kW",
f" Sous garantie: {garantie}",
])
def __repr__(self) -> str:
return f"ServeurPhysique({self._nom!r}, rack={self._rack!r})"
class ServeurVirtuel(Serveur):
"""
Un serveur virtuel (VM).
"""
def __init__(
self,
nom: str,
ip: str,
os: str,
mise_en_service: date,
*,
hyperviseur: str,
allocation: str
):
super().__init__(nom, ip, os, mise_en_service)
self._hyperviseur = hyperviseur
self._allocation = allocation
def tourne_sur_hyperviseur(self, hyperviseur: str) -> bool:
"""Cette VM tourne-t-elle sur cet hyperviseur?"""
return self._hyperviseur.lower() == hyperviseur.lower()
def fiche(self) -> str:
"""Retourne une fiche descriptive complete du serveur."""
base = super().fiche()
return "\n".join([
base,
f" Hyperviseur: {self._hyperviseur}",
f" Allocation: {self._allocation}",
])
def __repr__(self) -> str:
return f"ServeurVirtuel({self._nom!r}, hyperviseur={self._hyperviseur!r})"
class Technicien:
"""
Un technicien.
"""
__slots__ = ('_identifiant', '_nom', '_specialite')
def __init__(self, identifiant: str, nom: str, specialite: str):
self._identifiant = identifiant
self._nom = nom
self._specialite = specialite
def est_specialise_en(self, domaine: str) -> bool:
"""Ce technicien est-il specialise dans ce domaine?"""
return self._specialite.lower() == domaine.lower()
def __eq__(self, autre: object) -> bool:
if not isinstance(autre, Technicien):
return NotImplemented
return self._identifiant == autre._identifiant
def __repr__(self) -> str:
return f"Technicien({self._identifiant!r}, {self._nom!r}, {self._specialite!r})"
class Maintenance:
"""
Une intervention de maintenance sur un serveur.
"""
__slots__ = ('_identifiant', '_date', '_type', '_serveur', '_technicien')
PREVENTIVE = "preventive"
CORRECTIVE = "corrective"
def __init__(
self,
identifiant: str,
date_intervention: date,
type_maintenance: str,
serveur: Serveur,
technicien: Technicien
):
if type_maintenance not in (self.PREVENTIVE, self.CORRECTIVE):
raise ValueError(f"Type de maintenance invalide: {type_maintenance}")
self._identifiant = identifiant
self._date = date_intervention
self._type = type_maintenance
self._serveur = serveur
self._technicien = technicien
def concerne_serveur(self, serveur: Serveur) -> bool:
"""Cette maintenance concerne-t-elle ce serveur?"""
return self._serveur == serveur
def effectuee_par(self, technicien: Technicien) -> bool:
"""Cette maintenance a-t-elle ete effectuee par ce technicien?"""
return self._technicien == technicien
def est_preventive(self) -> bool:
"""Est-ce une maintenance preventive?"""
return self._type == self.PREVENTIVE
def est_corrective(self) -> bool:
"""Est-ce une maintenance corrective?"""
return self._type == self.CORRECTIVE
def a_eu_lieu_apres(self, depuis: date) -> bool:
"""Cette maintenance a-t-elle eu lieu après cette date?"""
return self._date >= depuis
def rapport(self) -> str:
"""Retourne un rapport formater de la maintenance."""
sep = "=" * 50
return "\n".join([
sep,
f"MAINTENANCE {self._identifiant}",
sep,
f"Date: {self._date}",
f"Type: {self._type.upper()}",
f"Serveur: {self._serveur}",
f"Technicien: {self._technicien}",
sep,
])
def __eq__(self, autre: object) -> bool:
if not isinstance(autre, Maintenance):
return NotImplemented
return self._identifiant == autre._identifiant
def __repr__(self) -> str:
return f"Maintenance({self._identifiant!r}, {self._date!r}, {self._type!r})"
class Datacenter:
"""
Un datacenter regroupant des serveurs.
"""
def __init__(self, nom: str, localisation: str):
self._nom = nom
self._localisation = localisation
self._serveurs: list[Serveur] = []
self._maintenances: list[Maintenance] = []
def accueille(self, serveur: Serveur) -> None:
"""Accueille un nouveau serveur dans le datacenter."""
if serveur not in self._serveurs:
self._serveurs.append(serveur)
def retire_serveur(self, serveur: Serveur) -> None:
"""Retire un serveur du datacenter."""
if serveur in self._serveurs:
self._serveurs.remove(serveur)
def enregistre(self, maintenance: Maintenance) -> None:
"""Enregistre une maintenance effectuee."""
self._maintenances.append(maintenance)
def services_critiques(self) -> Services:
"""Tous les services critiques heberges dans ce datacenter."""
critiques = []
for serveur in self._serveurs:
for service in serveur.services_critiques():
critiques.append(service)
return Services(*critiques)
def total_services(self) -> int:
"""Nombre total de services heberges."""
return sum(serveur.nombre_services() for serveur in self._serveurs)
def serveurs_maintenus_par(self, technicien: Technicien) -> list[Serveur]:
"""Liste des serveurs ayant ete maintenus par ce technicien."""
serveurs_trouves = []
for maintenance in self._maintenances:
if maintenance.effectuee_par(technicien):
for serveur in self._serveurs:
if maintenance.concerne_serveur(serveur) and serveur not in serveurs_trouves:
serveurs_trouves.append(serveur)
return serveurs_trouves
def pour_chaque_serveur(self, action: Callable[[Serveur], None]) -> None:
"""Applique une action a chaque serveur"""
for serveur in self._serveurs:
action(serveur)
def pour_chaque_serveur_physique(self, action: Callable[[ServeurPhysique], None]) -> None:
"""Applique une action a chaque serveur physique."""
for serveur in self._serveurs:
if isinstance(serveur, ServeurPhysique):
action(serveur)
def inventaire(self) -> str:
"""Retourne l'inventaire complet du datacenter."""
sep = "#" * 60
lignes = [
"",
sep,
f"DATACENTER: {self._nom}",
f"Localisation: {self._localisation}",
sep,
"",
f"Nombre de serveurs: {len(self._serveurs)}",
f"Total services: {self.total_services()}",
f"Services critiques: {len(self.services_critiques())}",
"",
]
for serveur in self._serveurs:
lignes.append(serveur.fiche())
lignes.append("")
return "\n".join(lignes)
def __len__(self) -> int:
"""Nombre de serveurs dans le datacenter."""
return len(self._serveurs)
def __contains__(self, serveur: Serveur) -> bool:
"""Ce serveur est-il dans le datacenter?"""
return serveur in self._serveurs
def __repr__(self) -> str:
return f"Datacenter({self._nom!r}, {self._localisation!r})"
if __name__ == "__main__":
# Creation de services
nginx = Service("nginx", 80, "HTTP", critique=True)
api = Service("api-backend", 8080, "HTTP", critique=True)
ssh = Service("sshd", 22, "TCP")
postgres = Service("postgresql", 5432, "TCP", critique=True)
redis = Service("redis", 6379, "TCP")
# Creation de serveurs
srv_web = ServeurPhysique(
"srv-web-01",
"192.168.1.10",
"Debian 12",
date(2023, 6, 15),
rack="R01-U12",
consommation_kw=0.8,
sous_garantie=True
)
srv_web.heberge(nginx)
srv_web.heberge(ssh)
srv_api = ServeurVirtuel(
"srv-api-01",
"192.168.1.20",
"Ubuntu 22.04",
date(2024, 1, 10),
hyperviseur="Proxmox",
allocation="4 vCPU / 8 Go RAM"
)
srv_api.heberge(api)
srv_api.heberge(redis)
srv_db = ServeurPhysique(
"srv-db-01",
"192.168.1.30",
"Rocky Linux 9",
date(2022, 3, 1),
rack="R02-U08",
consommation_kw=1.2,
sous_garantie=False
)
srv_db.heberge(postgres)
srv_db.heberge(ssh)
# Creation du datacenter
dc_paris = Datacenter("DC-Paris-01", "Paris, France")
dc_paris.accueille(srv_web)
dc_paris.accueille(srv_api)
dc_paris.accueille(srv_db)
# Creation de techniciens
alice = Technicien("T001", "Alice Martin", "Linux")
bob = Technicien("T002", "Bob Dupont", "Virtualisation")
# Creation de maintenances
maint_1 = Maintenance(
"M2024-001",
date(2024, 11, 15),
Maintenance.PREVENTIVE,
srv_web,
alice
)
maint_2 = Maintenance(
"M2024-002",
date(2024, 12, 3),
Maintenance.CORRECTIVE,
srv_db,
alice
)
maint_3 = Maintenance(
"M2025-001",
date(2025, 1, 8),
Maintenance.PREVENTIVE,
srv_api,
bob
)
dc_paris.enregistre(maint_1)
dc_paris.enregistre(maint_2)
dc_paris.enregistre(maint_3)
# Inventaire complet
print(dc_paris.inventaire())
# Services critiques
print("--- SERVICES CRITIQUES ---")
print(dc_paris.services_critiques())
# Serveurs maintenus par Alice
print("\n--- SERVEURS MAINTENUS PAR ALICE ---")
for srv in dc_paris.serveurs_maintenus_par(alice):
print(f" - {srv}")
# Rapport de maintenance
print("\n--- RAPPORT MAINTENANCE ---")
print(maint_1.rapport())
print("\n--- SERVEURS HORS GARANTIE ---")
dc_paris.pour_chaque_serveur_physique(
lambda s: print(f" ! {s}") if not s.est_sous_garantie() else None
)
print("\n--- TEST ÉGALITÉ ---")
nginx_copie = Service("nginx", 80, "HTTPS") # Meme nom/port, protocole different
print(f"nginx == nginx_copie: {nginx == nginx_copie}") # True (egalite sur nom+port)