--- name: wg_client_install kind: function lang: bash domain: infra version: "1.0.0" purity: impure signature: "wg_client_install(config_path_or_stdin, [interface_name]) -> json" description: "Device-side: instala wg0.conf en /etc/wireguard/, habilita systemd wg-quick@wg0, verifica handshake con hub. Idempotente. Acepta config por path o stdin (para pipes desde wg_client_config)." tags: [wireguard, client, install, mesh, systemd] uses_functions: [wg_install_bash_infra] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [] params: - name: config_path_or_stdin desc: "path al archivo .conf existente, o '-' para leer de stdin (compatible con pipe desde wg_client_config)" - name: interface_name desc: "nombre de la interfaz WireGuard (default: wg0). Determina /etc/wireguard/.conf y la unit systemd wg-quick@" output: "JSON {status, interface, hub_endpoint, handshake_seen}. status: installed | already-configured | installed-no-handshake | installed-no-systemd" tested: false tests: [] test_file_path: "" file_path: "bash/functions/infra/wg_client_install.sh" --- ## Ejemplo ```bash source bash/functions/infra/wg_client_install.sh # Desde pipe (caso más común en flow 0009): wg_client_config_go_infra | jq -r '.INI' | wg_client_install - # {"status":"installed","interface":"wg0","hub_endpoint":"203.0.113.1:51820","handshake_seen":true} # Desde archivo .conf generado previamente: wg_client_install /tmp/peer_laptop.conf # {"status":"installed","interface":"wg0","hub_endpoint":"203.0.113.1:51820","handshake_seen":true} # Con interfaz personalizada: wg_client_install /tmp/peer_laptop.conf wg1 # {"status":"installed","interface":"wg1","hub_endpoint":"203.0.113.1:51820","handshake_seen":true} # Segunda ejecución con misma config (idempotente): wg_client_install /tmp/peer_laptop.conf # {"status":"already-configured","interface":"wg0","hub_endpoint":"203.0.113.1:51820","handshake_seen":false} ``` ## Cuando usarla Cuando necesites conectar un nuevo peer al mesh WireGuard en el flow 0009. Úsala justo después de `wg_client_config` (que genera el .conf) para instalarlo en el device peer. Es el paso final del onboarding de un nodo: config generada → instalada → verificada con handshake. ## Gotchas - **Requiere root/sudo** para escribir en `/etc/wireguard/`, hacer `chmod 600`, y ejecutar `systemctl`. El operador debe tener `sudo` sin password para estos comandos, o ejecutar la función como root. - **Idempotente por contenido**: si `/etc/wireguard/.conf` ya existe con el mismo contenido, retorna `status=already-configured` sin tocar nada. Si el contenido difiere, hace backup automático con timestamp antes de sobreescribir. - **NetworkManager**: si NM gestiona la interfaz wg0, `wg-quick` puede fallar con conflicto. Solución: crear `/etc/NetworkManager/conf.d/99-wg.conf` con `[keyfile]\nunmanaged-devices=interface-name:wg0` y reiniciar NM antes de ejecutar esta función. - **WSL2 sin systemd** (variantes antiguas o sin `/etc/wsl.conf` con `[boot] systemd=true`): `systemctl` no está disponible. La función detecta esto, emite `status=installed-no-systemd` con instrucciones en stderr para levantar la interfaz manualmente con `sudo wg-quick up wg0`. Para autostart en WSL2 sin systemd: añadir `sudo wg-quick up wg0` al final de `~/.bashrc`. - **WSL2 con systemd**: kernel WSL2 >= 5.6 (default en distros recientes) incluye WireGuard built-in. Habilitar systemd en WSL2 con `[boot]\nsystemd=true` en `/etc/wsl.conf` y reiniciar WSL. Luego esta función funciona igual que en Linux nativo. - **Android / Termux**: NO usar esta función. Termux no tiene systemd ni `/etc/wireguard/`. En Android usar la app WireGuard oficial (F-Droid / Play Store) e importar el .conf generado por `wg_client_config` directamente desde la app. - **handshake_seen=false con status=installed-no-handshake**: la interfaz está activa pero el hub no ha respondido en 10s. No es un error fatal — puede tardar más si el hub está ocupado o hay NAT traversal pendiente. Verificar: endpoint accesible por UDP, hub corriendo con `wg show`, claves public/preshared coincidentes. - Los logs van siempre a stderr con prefijo `[wg_client_install]`; stdout es exclusivamente el JSON de resultado. ## Capability growth log