#!/usr/bin/env python3
"""Los pasos del ensayo: cargar sus arreglos, cortar enlaces y volverlos a subir.

    python3 ensayo.py arreglos          carga lab/*.conf en los routers
    python3 ensayo.py corta <a> <b>     baja el enlace entre dos nodos
    python3 ensayo.py sube <a> <b>      lo vuelve a subir
    python3 ensayo.py enlaces           lista los enlaces

Cortar con `ip link set down` hace que los dos extremos se enteren al instante: BGP cierra
la sesión sin esperar a su hold timer. Es lo que se ve cuando se desconecta un cable.
"""
import os
import subprocess
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
ANSWERS = os.path.join(HERE, "solution")
if not os.path.isdir(ANSWERS):
    ANSWERS = os.path.join(HERE, "lab")
PREFIX = "clab-w09-ensayo-"
FIXED_ROUTERS = ["e1", "e2", "e3", "t2"]
LINKS = {
    ("t1", "t2"): ("eth1", "eth1"),
    ("t1", "e1"): ("eth2", "eth1"),
    ("t1", "e2"): ("eth3", "eth1"),
    ("t1", "e3"): ("eth4", "eth1"),
    ("t2", "e2"): ("eth2", "eth2"),
    ("t2", "e3"): ("eth3", "eth2"),
    ("t2", "e4"): ("eth4", "eth1"),
    ("e3", "e4"): ("eth3", "eth2"),
}


def run(*args):
    done = subprocess.run(args, capture_output=True, text=True, timeout=60)
    if done.returncode != 0:
        raise SystemExit(f"falló {' '.join(args)}:\n{done.stdout}{done.stderr}")
    return done.stdout


def set_link(a, b, state):
    if (a, b) in LINKS:
        interface_a, interface_b = LINKS[a, b]
    elif (b, a) in LINKS:
        interface_b, interface_a = LINKS[b, a]
    else:
        raise SystemExit(f"no hay un enlace entre {a} y {b}: python3 ensayo.py enlaces")
    run("docker", "exec", PREFIX + a, "ip", "link", "set", interface_a, state)
    run("docker", "exec", PREFIX + b, "ip", "link", "set", interface_b, state)


def answer_is_ready(router):
    with open(os.path.join(ANSWERS, f"{router}.conf"), encoding="utf-8") as file:
        return "TODO" not in file.read()


def load_fixes():
    for router in FIXED_ROUTERS:
        if not answer_is_ready(router):
            print(f"{router}: lab/{router}.conf todavía tiene su TODO, no lo cargo")
            continue
        path = os.path.join(ANSWERS, f"{router}.conf")
        run("docker", "cp", path, f"{PREFIX}{router}:/tmp/arreglo.conf")
        run("docker", "exec", PREFIX + router, "vtysh", "-f", "/tmp/arreglo.conf")
        # Un filtro de entrada cambiado no se aplica solo a lo que ya se recibió.
        run("docker", "exec", PREFIX + router, "vtysh", "-c", "clear bgp ipv4 unicast * soft in")
        print(f"{router}: arreglo cargado")


def main():
    if len(sys.argv) == 2 and sys.argv[1] == "arreglos":
        load_fixes()
    elif len(sys.argv) == 2 and sys.argv[1] == "enlaces":
        for a, b in LINKS:
            print(f"{a} {b}")
    elif len(sys.argv) == 4 and sys.argv[1] in ("corta", "sube"):
        set_link(sys.argv[2], sys.argv[3], "down" if sys.argv[1] == "corta" else "up")
    else:
        print(__doc__)


if __name__ == "__main__":
    main()
