gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1572Shell 203Rust 109Markdown 993728 Definiciones

⎇ 6b7526cba1c69ecc4966ea57fa1d53a732d34fa4 scripts/drive-netup.py Python · 118 líneas · 4.6 KB Historia Quién tocó qué crudo

crates/netup: red mínima Rust-nativa (Etapa C pieza 5) 6886f810b · sergio ·

1#!/usr/bin/env python3
2# drive-netup.py — bootea la VM con la NIC conectada al tap del lab (scripts/labnet.sh) y corre `netup`
3# + chequeos de conectividad real (DHCP de dnsmasq, NAT, DNS). Driver no-interactivo: espera la shell
4# de arje-zero, manda el test, captura hasta el marcador y emite veredicto.
5#
6# Prerequisito:  sudo sh scripts/labnet.sh up   (bridge hmbr0 + tap hmtap0 + dnsmasq + NAT)
7#
8# Variables: KERNEL (def store/*-linux/boot/bzImage)  DISK (def work/hammer-disk.img)
9#            TAP (def hmtap0)  NICDEV (def e1000)  MEM (def 4096)  KVM (1 si /dev/kvm)
10#            DEADLINE (def 180s)  LOG (def work/netup-run.log)
11import os, pty, select, subprocess, sys, time, re, glob
12
13ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
14
15
16def absp(p):
17    return p if os.path.isabs(p) else os.path.join(ROOT, p)
18
19
20KERNEL = os.environ.get("KERNEL") or (glob.glob(os.path.join(ROOT, "store/*-linux/boot/bzImage")) + [""])[0]
21DISK = absp(os.environ.get("DISK", "work/hammer-disk.img"))
22TAP = os.environ.get("TAP", "hmtap0")
23NICDEV = os.environ.get("NICDEV", "e1000")
24MEM = os.environ.get("MEM", "4096")
25DEADLINE = int(os.environ.get("DEADLINE", "180"))
26LOG = absp(os.environ.get("LOG", "work/netup-run.log"))
27WANT_KVM = os.environ.get("KVM", "1") == "1"
28
29for p, what in [(KERNEL, "kernel"), (DISK, "imagen de disco")]:
30    if not p or not os.path.exists(p):
31        sys.exit(f"no existe {what}: {p}")
32
33accel = ["-cpu", "Broadwell"]
34if WANT_KVM and os.access("/dev/kvm", os.W_OK):
35    accel = ["-enable-kvm", "-cpu", "host"]
36
37# SLIRP=1 ⇒ red user-mode de QEMU (DHCP/DNS/NAT virtuales, cero setup de host). Si no, tap del lab.
38if os.environ.get("SLIRP", "0") == "1":
39    netdev = ["-netdev", "user,id=n0"]
40else:
41    netdev = ["-netdev", f"tap,id=n0,ifname={TAP},script=no,downscript=no"]
42QEMU = (["qemu-system-x86_64", "-m", MEM, "-no-reboot", "-nographic"] + accel +
43        ["-kernel", KERNEL,
44         "-drive", f"file={DISK},if=virtio,format=raw",
45         "-append", "console=ttyS0 root=/dev/vda1 rw rdinit=/sbin/init"] +
46        netdev + ["-device", f"{NICDEV},netdev=n0"])
47
48# El test que corre dentro de la VM: netup (autodetecta la NIC) + conectividad NAT + DNS.
49# Los marcadores se CONSTRUYEN en runtime (printf '%s') para que NO aparezcan literales en el eco del
50# comando tecleado — si no, el driver los matchearía en el eco y saldría antes de que el test corra.
51TEST = os.environ.get("TESTCMD") or (
52    "netup; "
53    "ping -c2 -W2 8.8.8.8 >/dev/null 2>&1 && printf 'PING_%s\\n' OK || printf 'PING_%s\\n' FAIL; "
54    "nslookup google.com >/dev/null 2>&1 && printf 'DNS_%s\\n' OK || printf 'DNS_%s\\n' FAIL; "
55    "printf 'TEST_%s\\n' DONE"
56)
57TEST = TEST + "\n"
58
59print(f"==> kernel {KERNEL}\n==> disco  {DISK}\n==> tap    {TAP} ({NICDEV})   mem {MEM}   kvm {'sí' if accel[0]=='-enable-kvm' else 'no'}")
60ansi = re.compile(rb'\x1b\[[0-9;?]*[a-zA-Z]')
61master, slave = pty.openpty()
62p = subprocess.Popen(QEMU, stdin=slave, stdout=slave, stderr=slave, close_fds=True)
63os.close(slave)
64log = open(LOG, "wb")
65buf = b""
66sent = False
67start = time.time()
68
69while True:
70    if time.time() - start > DEADLINE:
71        log.write(b"\n[DRIVER] DEADLINE\n")
72        break
73    r, _, _ = select.select([master], [], [], 5)
74    if r:
75        try:
76            data = os.read(master, 8192)
77        except OSError:
78            break
79        if not data:
80            break
81        log.write(data)
82        log.flush()
83        buf = ansi.sub(b'', buf + data)[-20000:]
84        if not sent and (b"\n~ #" in buf or b"\r~ #" in buf):
85            time.sleep(2)
86            os.write(master, TEST.encode())
87            sent = True
88            log.write(b"\n[DRIVER] enviado test netup\n")
89        if sent and b"TEST_DONE" in buf:
90            time.sleep(1)
91            try:
92                log.write(os.read(master, 8192))
93            except Exception:
94                pass
95            break
96    elif p.poll() is not None:
97        break
98
99for fn in (p.terminate, p.kill):
100    try:
101        fn(); time.sleep(1)
102    except Exception:
103        pass
104log.close()
105
106blob = ansi.sub(b'', open(LOG, "rb").read())
107configured = b"red configurada" in blob          # netup imprime esto sólo si todo salió bien
108ping = b"PING_OK" in blob
109dns = b"DNS_OK" in blob
110lease = re.search(rb"netup: lease (\d+\.\d+\.\d+\.\d+)", blob)
111print(f"\nDRIVER done sent={sent} elapsed={int(time.time()-start)}s")
112print(f"  netup ok   : {configured}")
113print(f"  lease      : {lease.group(1).decode() if lease else '—'}")
114print(f"  ping NAT   : {ping}")
115print(f"  DNS        : {dns}")
116ok = configured and lease and ping and dns
117print("RESULTADO:", "✓ RED OK (lease + NAT + DNS)" if ok else "✗ revisá el log: " + LOG)
118sys.exit(0 if ok else 1)