[FIX] long_test : bail attendu, rallumage à froid, marge mémoire
Trois mesures faites sur une descente à cinq étages, et une conclusion de ma part corrigée par le contre-essai. Le bail DHCP se fait attendre. L'étage 3 était créé, en type='kvm', et « domifaddr » ne rendait rien : l'invité n'avait pas encore demandé son adresse — 87 s puis 94 s selon les tours, quand deploy_qemu s'accorde 90 s et rend 0 sans l'avoir trouvée. Lu une fois, cela ne prouvait rien. Un redémarrage demandé à l'invité peut le laisser bloqué dans son micrologiciel : RIP immobile 46 minutes, pas un octet lu, trois vCPU à fond. J'ai d'abord conclu que c'était la taille de la mémoire, parce que la même machine à 2 Go démarrait. Le contre-essai à 4 Go l'a réfuté : elle démarre aussi, à froid. La différence est le REDÉMARRAGE, pas la mémoire — à chaud elle reste dans l'UEFI, à froid elle charge son noyau en 60 à 90 s, à 2, 3 et 4 Go. La descente rallume donc une fois par le parent, et une seule : une boucle de rallumage cacherait un vrai échec. La mémoire de la pile QEMU est doublée pour une autre raison, mesurée elle aussi : l'étage 2 avec 5 Go hébergeait un invité de 4 Go et n'avait plus que 127 Mo de libre. Ce n'est pas le plancher qui compte, c'est l'écart. --- EN --- Three measurements from a five-level descent, and a conclusion of mine refuted by the counter-test. The DHCP lease takes its time. Level 3 was created, type='kvm', and "domifaddr" returned nothing: the guest had not yet asked for its address — 87 s then 94 s depending on the run, while deploy_qemu allows itself 90 s and returns 0 without having found it. Read once, that proved nothing. A reboot asked of the guest can leave it stuck in its firmware: static RIP for 46 minutes, not a byte read, three vCPU at full tilt. I first concluded it was the memory size, because the same machine booted at 2 GB. The counter-test at 4 GB refuted it: it boots too, cold. The difference is the REBOOT, not the memory — warm it stays in UEFI, cold it loads its kernel in 60 to 90 s, at 2, 3 and 4 GB. The descent therefore power-cycles once through the parent, and only once: a restart loop would hide a real failure. The QEMU stack's memory is doubled for another, also measured reason: level 2 with 5 GB hosted a 4 GB guest and had 127 MB left. It is not the floor that matters, it is the gap. Assisted-by: claude-opus-5 (cherry picked from commit e3f60e3ddf066eb76d434bbfe6b01f2271fb1874)
This commit is contained in:
parent
5af6c94c0a
commit
6e6e99c304
5 changed files with 193 additions and 22 deletions
|
|
@ -36,6 +36,7 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
RACINE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
RACINE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
sys.path.insert(0, RACINE)
|
sys.path.insert(0, RACINE)
|
||||||
|
|
@ -327,6 +328,31 @@ class Descente(descente.Descente):
|
||||||
)
|
)
|
||||||
return vu["libvirtd"] and vu["reseau"]
|
return vu["libvirtd"] and vu["reseau"]
|
||||||
|
|
||||||
|
def rallumer_a_froid(self, parent, nom):
|
||||||
|
"""« virsh destroy » puis « start » : un processus QEMU neuf.
|
||||||
|
|
||||||
|
Mesuré sur la machine bloquée : à chaud elle restait 46 minutes au
|
||||||
|
même pointeur d'instruction, dans son micrologiciel ; à froid elle a
|
||||||
|
chargé son noyau en 60 à 90 secondes, trois fois de suite, à 2, 3 et
|
||||||
|
4 Go. Ce n'est donc pas la taille de la mémoire — c'est la façon de
|
||||||
|
redémarrer.
|
||||||
|
"""
|
||||||
|
if self.dry_run or not parent:
|
||||||
|
return False
|
||||||
|
self.executer(
|
||||||
|
parent,
|
||||||
|
f"virsh -c qemu:///system destroy {nom} 2>/dev/null; true",
|
||||||
|
self.delai("controle"),
|
||||||
|
"extinction",
|
||||||
|
)
|
||||||
|
code, _o = self.executer(
|
||||||
|
parent,
|
||||||
|
f"virsh -c qemu:///system start {nom}",
|
||||||
|
self.delai("controle"),
|
||||||
|
"rallumage",
|
||||||
|
)
|
||||||
|
return code == 0
|
||||||
|
|
||||||
def controler(self, hote):
|
def controler(self, hote):
|
||||||
"""CET étage peut-il héberger le suivant SANS l'émuler ?
|
"""CET étage peut-il héberger le suivant SANS l'émuler ?
|
||||||
|
|
||||||
|
|
@ -388,6 +414,35 @@ class Descente(descente.Descente):
|
||||||
return None
|
return None
|
||||||
return ("default",)
|
return ("default",)
|
||||||
|
|
||||||
|
def attendre_adresse(self, parent, nom):
|
||||||
|
"""Le bail DHCP de l'enfant, attendu. Rend l'adresse, ou "".
|
||||||
|
|
||||||
|
ATTENDU, et non lu une fois. Constaté au troisième étage : le domaine
|
||||||
|
était créé, en type='kvm', et « domifaddr » ne rendait rien — l'invité
|
||||||
|
n'avait pas encore demandé son bail. Plus l'étage est profond, plus il
|
||||||
|
démarre lentement, et c'est justement ce qu'on mesure.
|
||||||
|
|
||||||
|
`deploy_qemu` attend lui-même l'adresse — 90 secondes par défaut — puis
|
||||||
|
rend 0 quand il ne l'a pas trouvée. Son code de sortie ne prouve donc
|
||||||
|
rien ici non plus.
|
||||||
|
"""
|
||||||
|
debut = time.time()
|
||||||
|
delai = self.delai("ssh")
|
||||||
|
while time.time() - debut < delai:
|
||||||
|
_c, sortie = self.executer(
|
||||||
|
parent,
|
||||||
|
f"virsh -c qemu:///system domifaddr {nom} --source lease",
|
||||||
|
DELAIS["controle"],
|
||||||
|
"domifaddr",
|
||||||
|
)
|
||||||
|
adresse = parse_domifaddr(sortie)
|
||||||
|
if adresse:
|
||||||
|
if time.time() - debut > 20:
|
||||||
|
self.dire(f" bail après {int(time.time() - debut)} s")
|
||||||
|
return adresse
|
||||||
|
time.sleep(15)
|
||||||
|
return ""
|
||||||
|
|
||||||
def creer_enfant(self, parent, niveau, res, prepare, noter=None):
|
def creer_enfant(self, parent, niveau, res, prepare, noter=None):
|
||||||
"""Une VM dans le parent, par NOTRE deploy_qemu.py.
|
"""Une VM dans le parent, par NOTRE deploy_qemu.py.
|
||||||
|
|
||||||
|
|
@ -449,13 +504,7 @@ class Descente(descente.Descente):
|
||||||
)
|
)
|
||||||
return None, None
|
return None, None
|
||||||
self.dire(f" domaine kvm, cpu {vu['cpu'] or '?'}")
|
self.dire(f" domaine kvm, cpu {vu['cpu'] or '?'}")
|
||||||
_c, sortie = self.executer(
|
adresse = self.attendre_adresse(parent, nom)
|
||||||
parent,
|
|
||||||
f"virsh -c qemu:///system domifaddr {nom} --source lease",
|
|
||||||
self.delai("ssh"),
|
|
||||||
"domifaddr",
|
|
||||||
)
|
|
||||||
adresse = parse_domifaddr(sortie)
|
|
||||||
if not adresse:
|
if not adresse:
|
||||||
self.dire(" ✗ créée, mais sans adresse : rien à joindre")
|
self.dire(" ✗ créée, mais sans adresse : rien à joindre")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,22 @@ class Descente:
|
||||||
"""Les services de la pile répondent-ils, une fois redémarrés ?"""
|
"""Les services de la pile répondent-ils, une fois redémarrés ?"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def rallumer_a_froid(self, parent, nom):
|
||||||
|
"""Éteindre puis rallumer la machine DEPUIS SON PARENT. Rend True si
|
||||||
|
la pile sait le faire.
|
||||||
|
|
||||||
|
Un redémarrage demandé à l'invité — « systemctl reboot » — peut le
|
||||||
|
laisser bloqué dans son micrologiciel : constaté une fois au troisième
|
||||||
|
étage, pointeur d'instruction immobile pendant 46 minutes, pas un
|
||||||
|
octet lu. Un démarrage à FROID, lui, repart d'un processus neuf, et
|
||||||
|
les trois essais faits ensuite ont tous abouti.
|
||||||
|
|
||||||
|
La cause du gel n'est pas établie ; le remède ne l'attend pas. Une
|
||||||
|
descente ne doit pas passer six heures à guetter une machine qui ne
|
||||||
|
reviendra jamais, quand son parent peut la rallumer.
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
def controler(self, hote):
|
def controler(self, hote):
|
||||||
"""Cet étage peut-il HÉBERGER le suivant ?
|
"""Cet étage peut-il HÉBERGER le suivant ?
|
||||||
|
|
||||||
|
|
@ -337,7 +353,7 @@ class Descente:
|
||||||
time.sleep(15)
|
time.sleep(15)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def redemarrer_et_verifier(self, hote):
|
def redemarrer_et_verifier(self, hote, parent=None, nom=""):
|
||||||
"""Redémarre, attend le retour, exige le noyau voulu.
|
"""Redémarre, attend le retour, exige le noyau voulu.
|
||||||
|
|
||||||
L'installation pose le noyau sans redémarrer — lancée par ssh, un
|
L'installation pose le noyau sans redémarrer — lancée par ssh, un
|
||||||
|
|
@ -379,6 +395,13 @@ class Descente:
|
||||||
f" noyau {noyau} après {int(time.time() - debut)} s"
|
f" noyau {noyau} après {int(time.time() - debut)} s"
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
# Une seule reprise, et seulement si le parent peut la donner : la
|
||||||
|
# machine est peut-être bloquée dans son micrologiciel, où un
|
||||||
|
# redémarrage demandé à l'invité ne la sortira jamais. Une fois, pas
|
||||||
|
# deux — une boucle de rallumage cacherait un vrai échec.
|
||||||
|
if parent and nom and self.rallumer_a_froid(parent, nom):
|
||||||
|
self.dire(" ↻ rallumée à froid par son parent")
|
||||||
|
return self.redemarrer_et_verifier(hote)
|
||||||
self.dire(" ✗ pas revenue sur le noyau attendu")
|
self.dire(" ✗ pas revenue sur le noyau attendu")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -582,7 +605,12 @@ class Descente:
|
||||||
# terminé sans qu'on sache s'il pouvait héberger le suivant.
|
# terminé sans qu'on sache s'il pouvait héberger le suivant.
|
||||||
for etape, action in (
|
for etape, action in (
|
||||||
("install", lambda: self.installer(cible)),
|
("install", lambda: self.installer(cible)),
|
||||||
("reboot", lambda: self.redemarrer_et_verifier(cible)),
|
(
|
||||||
|
"reboot",
|
||||||
|
lambda: self.redemarrer_et_verifier(
|
||||||
|
cible, parent, etage.get("nom", "")
|
||||||
|
),
|
||||||
|
),
|
||||||
("systeme", lambda: self.preparer_systeme(cible)),
|
("systeme", lambda: self.preparer_systeme(cible)),
|
||||||
("services", lambda: self.remettre_debout(cible)),
|
("services", lambda: self.remettre_debout(cible)),
|
||||||
("controle", lambda: self.controler(cible)),
|
("controle", lambda: self.controler(cible)),
|
||||||
|
|
|
||||||
|
|
@ -183,12 +183,17 @@ COUTS_PVE = Couts(
|
||||||
# Un hôte libvirt nu : libvirtd et qemu-kvm, rien d'autre. Le poste qui domine
|
# Un hôte libvirt nu : libvirtd et qemu-kvm, rien d'autre. Le poste qui domine
|
||||||
# n'est plus le système mais l'IMAGE CLOUD que l'étage télécharge pour créer
|
# n'est plus le système mais l'IMAGE CLOUD que l'étage télécharge pour créer
|
||||||
# son enfant — d'où un disque cible qui n'est pas si petit.
|
# son enfant — d'où un disque cible qui n'est pas si petit.
|
||||||
|
#
|
||||||
|
# La mémoire a été DOUBLÉE après une descente à cinq étages : l'étage 2, avec
|
||||||
|
# 5 Go, hébergeait un invité de 4 Go et il ne lui restait que 127 Mo de libre.
|
||||||
|
# Un parent qui ne garde pas de quoi respirer sert mal son enfant, et deux
|
||||||
|
# gibioctets d'écart plutôt qu'un lui laissent cette marge.
|
||||||
COUTS_QEMU = Couts(
|
COUTS_QEMU = Couts(
|
||||||
ram_par_etage=1024,
|
ram_par_etage=2048,
|
||||||
disque_par_etage=6,
|
disque_par_etage=6,
|
||||||
ram_cible=2048,
|
ram_cible=4096,
|
||||||
disque_cible=20,
|
disque_cible=20,
|
||||||
ram_min=1024,
|
ram_min=2048,
|
||||||
disque_min=12,
|
disque_min=12,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,15 +308,18 @@ class TestUneVmEmuleeNestPasUneMesure(unittest.TestCase):
|
||||||
self.d.niveau_courant = 2
|
self.d.niveau_courant = 2
|
||||||
self.d._envoyer_cli = lambda hote: True
|
self.d._envoyer_cli = lambda hote: True
|
||||||
|
|
||||||
def _machine(self, xml, adresse=" x y ipv4 10.0.0.9/24"):
|
def _machine(self, xml, adresse="10.0.0.9"):
|
||||||
|
"""Chaque test une seule chose : l'attente du bail est bouchonnée ici,
|
||||||
|
elle a sa propre classe. Sans ce bouchon, un enfant sans adresse
|
||||||
|
faisait tourner la vraie boucle d'attente — des heures."""
|
||||||
|
|
||||||
def executer(hote, cmd, delai, etiquette="", **k):
|
def executer(hote, cmd, delai, etiquette="", **k):
|
||||||
if "dumpxml" in cmd:
|
if "dumpxml" in cmd:
|
||||||
return 0, xml
|
return 0, xml
|
||||||
if "domifaddr" in cmd:
|
|
||||||
return 0, adresse
|
|
||||||
return 0, ""
|
return 0, ""
|
||||||
|
|
||||||
self.d.executer = executer
|
self.d.executer = executer
|
||||||
|
self.d.attendre_adresse = lambda parent, nom: adresse
|
||||||
|
|
||||||
def test_an_emulated_child_is_refused(self):
|
def test_an_emulated_child_is_refused(self):
|
||||||
self._machine("<domain type='qemu' id='1'><name>x</name>")
|
self._machine("<domain type='qemu' id='1'><name>x</name>")
|
||||||
|
|
@ -364,7 +367,7 @@ class TestUneVmEmuleeNestPasUneMesure(unittest.TestCase):
|
||||||
self.assertEqual(vus, ["deep-qemu-4"])
|
self.assertEqual(vus, ["deep-qemu-4"])
|
||||||
|
|
||||||
def test_a_child_without_an_address_is_refused(self):
|
def test_a_child_without_an_address_is_refused(self):
|
||||||
self._machine("<domain type='kvm'>", adresse=" x y N/A N/A")
|
self._machine("<domain type='kvm'>", adresse="")
|
||||||
with contextlib.redirect_stdout(io.StringIO()) as sortie:
|
with contextlib.redirect_stdout(io.StringIO()) as sortie:
|
||||||
identite, _a = self.d.creer_enfant(
|
identite, _a = self.d.creer_enfant(
|
||||||
{"target": "p"},
|
{"target": "p"},
|
||||||
|
|
@ -376,6 +379,74 @@ class TestUneVmEmuleeNestPasUneMesure(unittest.TestCase):
|
||||||
self.assertIn("sans adresse", sortie.getvalue())
|
self.assertIn("sans adresse", sortie.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
class TestLeBailSeFaitAttendre(unittest.TestCase):
|
||||||
|
"""Constaté au troisième étage : le domaine était créé, en type='kvm', et
|
||||||
|
« domifaddr » ne rendait rien — l'invité n'avait pas encore demandé son
|
||||||
|
bail. Plus l'étage est profond, plus il démarre lentement, et c'est
|
||||||
|
justement ce qu'on mesure.
|
||||||
|
|
||||||
|
`deploy_qemu` attend lui-même l'adresse puis rend 0 quand il ne l'a pas
|
||||||
|
trouvée : son code de sortie ne prouve rien ici non plus."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.d = deep_qemu.Descente.__new__(deep_qemu.Descente)
|
||||||
|
self.d.dry_run = False
|
||||||
|
self.d.journal = None
|
||||||
|
self.d.niveau_courant = 3
|
||||||
|
self.d.profondeur_racine = 0
|
||||||
|
vrai = deep_qemu.time.sleep
|
||||||
|
deep_qemu.time.sleep = lambda _s: None
|
||||||
|
self.addCleanup(setattr, deep_qemu.time, "sleep", vrai)
|
||||||
|
|
||||||
|
def test_it_retries_until_the_lease_appears(self):
|
||||||
|
tours = {"n": 0}
|
||||||
|
|
||||||
|
def executer(hote, cmd, delai, etiquette="", **k):
|
||||||
|
tours["n"] += 1
|
||||||
|
if tours["n"] < 3:
|
||||||
|
return 0, " x y N/A N/A"
|
||||||
|
return 0, " vnet0 52:54:00:aa:bb:cc ipv4 192.168.133.42/24"
|
||||||
|
|
||||||
|
self.d.executer = executer
|
||||||
|
with contextlib.redirect_stdout(io.StringIO()):
|
||||||
|
self.assertEqual(
|
||||||
|
self.d.attendre_adresse({"target": "p"}, "deep-qemu-3"),
|
||||||
|
"192.168.133.42",
|
||||||
|
)
|
||||||
|
self.assertEqual(tours["n"], 3)
|
||||||
|
|
||||||
|
def test_a_single_probe_would_have_missed_it(self):
|
||||||
|
"""Le contrôle qui dit pourquoi la boucle existe : au premier tour, il
|
||||||
|
n'y a rien à lire.
|
||||||
|
|
||||||
|
Borné DANS la sonde plutôt qu'en détournant l'horloge : détourner
|
||||||
|
time.time détourne aussi celle d'unittest, et le test ne finissait
|
||||||
|
plus. Vécu il y a dix minutes.
|
||||||
|
"""
|
||||||
|
tours = {"n": 0}
|
||||||
|
|
||||||
|
def executer(hote, cmd, delai, etiquette="", **k):
|
||||||
|
tours["n"] += 1
|
||||||
|
if tours["n"] > 4:
|
||||||
|
raise AssertionError("sondé sans fin")
|
||||||
|
return 0, " x y N/A N/A"
|
||||||
|
|
||||||
|
self.d.executer = executer
|
||||||
|
with contextlib.redirect_stdout(io.StringIO()):
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.d.attendre_adresse({"target": "p"}, "deep-qemu-3")
|
||||||
|
# Plusieurs tours, pas un seul : c'est tout l'objet de la boucle.
|
||||||
|
self.assertGreater(tours["n"], 1)
|
||||||
|
|
||||||
|
def test_the_wait_grows_with_the_depth(self):
|
||||||
|
"""Le budget est celui du ssh à cet étage : un invité au quatrième
|
||||||
|
démarre des dizaines de fois plus lentement qu'au premier."""
|
||||||
|
self.d.niveau_courant = 1
|
||||||
|
court = self.d.delai("ssh")
|
||||||
|
self.d.niveau_courant = 4
|
||||||
|
self.assertGreater(self.d.delai("ssh"), court)
|
||||||
|
|
||||||
|
|
||||||
class TestNeDetruireQueLeSien(unittest.TestCase):
|
class TestNeDetruireQueLeSien(unittest.TestCase):
|
||||||
"""« virsh undefine --remove-all-storage » efface un disque pour de bon."""
|
"""« virsh undefine --remove-all-storage » efface un disque pour de bon."""
|
||||||
|
|
||||||
|
|
@ -463,18 +534,36 @@ class TestLesDeuxTestsLongsSeRessemblent(unittest.TestCase):
|
||||||
self.pve.FAMILLE.detruire_une, self.qemu.FAMILLE.detruire_une
|
self.pve.FAMILLE.detruire_une, self.qemu.FAMILLE.detruire_une
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_the_qemu_stack_asks_for_less(self):
|
def test_the_qemu_stack_asks_for_less_disk(self):
|
||||||
"""libvirtd seul tient dans un gibioctet là où cinq démons PVE en
|
"""Une Debian avec qemu-kvm occupe ~3 Go là où un nœud Proxmox en
|
||||||
demandent deux."""
|
prend 5,6 — et l'image cloud que l'étage télécharge pour son enfant
|
||||||
|
pèse plus lourd que son propre système."""
|
||||||
from script.proxmox import nesting
|
from script.proxmox import nesting
|
||||||
|
|
||||||
pve = nesting.nesting_plan(3, 28, 39000, 150)
|
pve = nesting.nesting_plan(3, 28, 39000, 150)
|
||||||
qemu = nesting.nesting_plan(3, 28, 39000, 150, nesting.COUTS_QEMU)
|
qemu = nesting.nesting_plan(3, 28, 39000, 150, nesting.COUTS_QEMU)
|
||||||
self.assertLess(qemu["niveaux"][0]["ram"], pve["niveaux"][0]["ram"])
|
|
||||||
self.assertLess(
|
self.assertLess(
|
||||||
qemu["niveaux"][0]["disque"], pve["niveaux"][0]["disque"]
|
qemu["niveaux"][0]["disque"], pve["niveaux"][0]["disque"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_every_parent_keeps_room_to_breathe(self):
|
||||||
|
"""La mémoire de la pile QEMU a été DOUBLÉE après mesure, et n'est
|
||||||
|
donc plus inférieure à celle de Proxmox : à cinq étages, l'étage 2
|
||||||
|
avait 5 Go, hébergeait un invité de 4 Go, et il ne lui restait que
|
||||||
|
127 Mo de libre. Ce qui compte n'est pas le plancher mais l'ÉCART —
|
||||||
|
un parent qui ne respire pas sert mal son enfant."""
|
||||||
|
from script.proxmox import nesting
|
||||||
|
|
||||||
|
niveaux = nesting.nesting_plan(5, 28, 39000, 200, nesting.COUTS_QEMU)[
|
||||||
|
"niveaux"
|
||||||
|
]
|
||||||
|
for parent, enfant in zip(niveaux, niveaux[1:]):
|
||||||
|
self.assertGreaterEqual(
|
||||||
|
parent["ram"] - enfant["ram"],
|
||||||
|
2048,
|
||||||
|
f"étage {parent['niveau']} n'a pas 2 Go de marge",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -405,7 +405,7 @@ class TestUnRapportQuiSurvitAuProcessus(unittest.TestCase):
|
||||||
d.creer_enfant = creer_enfant
|
d.creer_enfant = creer_enfant
|
||||||
d.ecrire_alias = lambda *a, **k: None
|
d.ecrire_alias = lambda *a, **k: None
|
||||||
d.attendre_ssh = lambda cible, delai, parent=None: 1
|
d.attendre_ssh = lambda cible, delai, parent=None: 1
|
||||||
d.redemarrer_et_verifier = lambda cible: True
|
d.redemarrer_et_verifier = lambda cible, parent=None, nom="": True
|
||||||
d.remettre_debout = lambda cible: True
|
d.remettre_debout = lambda cible: True
|
||||||
d.preparer_systeme = lambda cible: True
|
d.preparer_systeme = lambda cible: True
|
||||||
d.controler = lambda cible: True
|
d.controler = lambda cible: True
|
||||||
|
|
@ -917,7 +917,7 @@ class TestUneVmCreeeEstToujoursNommee(unittest.TestCase):
|
||||||
d.ecrire_alias = lambda *a, **k: None
|
d.ecrire_alias = lambda *a, **k: None
|
||||||
d.attendre_ssh = lambda cible, delai, parent=None: 1
|
d.attendre_ssh = lambda cible, delai, parent=None: 1
|
||||||
d.installer = lambda cible: True
|
d.installer = lambda cible: True
|
||||||
d.redemarrer_et_verifier = lambda cible: True
|
d.redemarrer_et_verifier = lambda cible, parent=None, nom="": True
|
||||||
d.remettre_debout = lambda cible: True
|
d.remettre_debout = lambda cible: True
|
||||||
d.preparer_systeme = lambda cible: True
|
d.preparer_systeme = lambda cible: True
|
||||||
d.controler = lambda cible: True
|
d.controler = lambda cible: True
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue