#!/usr/bin/env python3 # drive-netup.py — bootea la VM con la NIC conectada al tap del lab (scripts/labnet.sh) y corre `netup` # + chequeos de conectividad real (DHCP de dnsmasq, NAT, DNS). Driver no-interactivo: espera la shell # de arje-zero, manda el test, captura hasta el marcador y emite veredicto. # # Prerequisito: sudo sh scripts/labnet.sh up (bridge hmbr0 + tap hmtap0 + dnsmasq + NAT) # # Variables: KERNEL (def store/*-linux/boot/bzImage) DISK (def work/hammer-disk.img) # TAP (def hmtap0) NICDEV (def e1000) MEM (def 4096) KVM (1 si /dev/kvm) # DEADLINE (def 180s) LOG (def work/netup-run.log) import os, pty, select, subprocess, sys, time, re, glob ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) def absp(p): return p if os.path.isabs(p) else os.path.join(ROOT, p) KERNEL = os.environ.get("KERNEL") or (glob.glob(os.path.join(ROOT, "store/*-linux/boot/bzImage")) + [""])[0] DISK = absp(os.environ.get("DISK", "work/hammer-disk.img")) TAP = os.environ.get("TAP", "hmtap0") NICDEV = os.environ.get("NICDEV", "e1000") MEM = os.environ.get("MEM", "4096") DEADLINE = int(os.environ.get("DEADLINE", "180")) LOG = absp(os.environ.get("LOG", "work/netup-run.log")) WANT_KVM = os.environ.get("KVM", "1") == "1" for p, what in [(KERNEL, "kernel"), (DISK, "imagen de disco")]: if not p or not os.path.exists(p): sys.exit(f"no existe {what}: {p}") accel = ["-cpu", "Broadwell"] if WANT_KVM and os.access("/dev/kvm", os.W_OK): accel = ["-enable-kvm", "-cpu", "host"] # SLIRP=1 ⇒ red user-mode de QEMU (DHCP/DNS/NAT virtuales, cero setup de host). Si no, tap del lab. if os.environ.get("SLIRP", "0") == "1": netdev = ["-netdev", "user,id=n0"] else: netdev = ["-netdev", f"tap,id=n0,ifname={TAP},script=no,downscript=no"] QEMU = (["qemu-system-x86_64", "-m", MEM, "-no-reboot", "-nographic"] + accel + ["-kernel", KERNEL, "-drive", f"file={DISK},if=virtio,format=raw", "-append", "console=ttyS0 root=/dev/vda1 rw rdinit=/sbin/init"] + netdev + ["-device", f"{NICDEV},netdev=n0"]) # El test que corre dentro de la VM: netup (autodetecta la NIC) + conectividad NAT + DNS. # Los marcadores se CONSTRUYEN en runtime (printf '%s') para que NO aparezcan literales en el eco del # comando tecleado — si no, el driver los matchearía en el eco y saldría antes de que el test corra. TEST = os.environ.get("TESTCMD") or ( "netup; " "ping -c2 -W2 8.8.8.8 >/dev/null 2>&1 && printf 'PING_%s\\n' OK || printf 'PING_%s\\n' FAIL; " "nslookup google.com >/dev/null 2>&1 && printf 'DNS_%s\\n' OK || printf 'DNS_%s\\n' FAIL; " "printf 'TEST_%s\\n' DONE" ) TEST = TEST + "\n" print(f"==> kernel {KERNEL}\n==> disco {DISK}\n==> tap {TAP} ({NICDEV}) mem {MEM} kvm {'sí' if accel[0]=='-enable-kvm' else 'no'}") ansi = re.compile(rb'\x1b\[[0-9;?]*[a-zA-Z]') master, slave = pty.openpty() p = subprocess.Popen(QEMU, stdin=slave, stdout=slave, stderr=slave, close_fds=True) os.close(slave) log = open(LOG, "wb") buf = b"" sent = False start = time.time() while True: if time.time() - start > DEADLINE: log.write(b"\n[DRIVER] DEADLINE\n") break r, _, _ = select.select([master], [], [], 5) if r: try: data = os.read(master, 8192) except OSError: break if not data: break log.write(data) log.flush() buf = ansi.sub(b'', buf + data)[-20000:] if not sent and (b"\n~ #" in buf or b"\r~ #" in buf): time.sleep(2) os.write(master, TEST.encode()) sent = True log.write(b"\n[DRIVER] enviado test netup\n") if sent and b"TEST_DONE" in buf: time.sleep(1) try: log.write(os.read(master, 8192)) except Exception: pass break elif p.poll() is not None: break for fn in (p.terminate, p.kill): try: fn(); time.sleep(1) except Exception: pass log.close() blob = ansi.sub(b'', open(LOG, "rb").read()) configured = b"red configurada" in blob # netup imprime esto sólo si todo salió bien ping = b"PING_OK" in blob dns = b"DNS_OK" in blob lease = re.search(rb"netup: lease (\d+\.\d+\.\d+\.\d+)", blob) print(f"\nDRIVER done sent={sent} elapsed={int(time.time()-start)}s") print(f" netup ok : {configured}") print(f" lease : {lease.group(1).decode() if lease else '—'}") print(f" ping NAT : {ping}") print(f" DNS : {dns}") ok = configured and lease and ping and dns print("RESULTADO:", "✓ RED OK (lease + NAT + DNS)" if ok else "✗ revisá el log: " + LOG) sys.exit(0 if ok else 1)