# 2026-05-10 — dnsmasq, ROCm, LM Studio, NFS, modèles partagés

## Accompli

### Rôle `dnsmasq` (storage-01)
- Résolution `*.lab.local` opérationnelle depuis le LAN cluster
- DNS gpu-01 mis à jour : `8.8.8.8` → `192.168.10.1`

### Rôle `rocm` (gpu-01)
- Repo AMD importé, drivers amdgpu + ROCm installés
- `HSA_OVERRIDE_GFX_VERSION=10.3.0` positionné en system-wide (profile.d + service systemd)
- RX 6700XT (gfx1031) détectée par ROCm

### Rôle `lm_studio` (gpu-01) — avec résolution de blocages multiples

LM Studio installe un module Node natif (`watcher.node`) compilé avec GCC 12 qui
requiert `GLIBCXX_3.4.30`. AlmaLinux 9 / GCC 11 fournit au maximum `GLIBCXX_3.4.29`.
Le symbole concerné (`std::condition_variable::wait`) existe dans la libstdc++ système
mais sous le tag `GLIBCXX_3.4.11`.

**Solution retenue : patch ELF de `watcher.node`**
- `patch-glibcxx-compat.py` : parseur ELF qui réécrit le champ `vna_hash` + la chaîne
  de version dans la section `.gnu.version_r` de `watcher.node`
  (`GLIBCXX_3.4.30` → `GLIBCXX_3.4.11`, même longueur → patch in-place)
- `install-lmstudio-compat.sh` : télécharge le bundle officiel, patche `watcher.node`
  avant le bootstrap, patche aussi la copie installée

**Architecture du service systemd** :
- `lms server start` quitte avec code 0 après avoir démarré le daemon → systemd
  déclenchait un cycle de restart
- Solution : wrapper `run-llmster.sh` — appelle `lms server start` (qui gère le passkey
  et démarre `llmster`), puis reste en vie via `pgrep llmster` en boucle
- Service `active (running)` avec le wrapper comme PID principal et `llmster` tracké
  dans le cgroup systemd
- `Restart=on-failure` relance proprement si `llmster` meurt

**Wrapper `lms` global** :
- `/usr/local/bin/lms` → délègue à `sudo -u lmstudio ... lms "$@"`
- Accessible depuis n'importe quel user sans préfixe

**Validation** :
```
curl http://192.168.10.20:1234/v1/models  # depuis storage-01 → OK
lms ls  # depuis gpu-01 → liste les modèles
```

Détail complet des blocages : `ansible/roles/lm_studio/TROUBLESHOOTING.md`

### Rôle `nfs_server` (storage-01)

Le RAID5 `md127` (4×1 TB, créé sous l'OS précédent) a survécu au changement d'OS —
les superblocs mdadm sont sur les disques, pas sur l'OS. Assemblage automatique au boot.

- `mdadm --detail --scan` → `/etc/mdadm.conf` + rebuild initramfs
- `md127` (ext4) monté sur `/srv/data` via UUID dans `/etc/fstab`
- Exports NFS :
  - `/srv/data/nfs/k8s` → pour le futur NFS provisioner k8s
  - `/srv/data/models` → modèles LM Studio partagés
- Ports NFS (111, 2049) déjà ouverts dans nftables (rôle gateway)
- `nfs-server` actif et enabled

### Rôle `nfs_client` (gpu-01)

- `/mnt/nfs` → `192.168.10.1:/srv/data/nfs/k8s`
- `/mnt/models` → `192.168.10.1:/srv/data/models`
- Options robustes aux extinctions fréquentes :
  - `soft` — échoue proprement (EIO) si serveur injoignable, ne bloque jamais
  - `timeo=30, retrans=3` — 3 s de timeout, 3 tentatives
  - `_netdev` — montage après réseau disponible seulement
  - `nofail` — boot du client non bloqué si storage-01 absent
  - `x-systemd.automount` — montage à la demande (premier accès), pas au boot

### Migration des modèles LM Studio vers NFS

- Modèles téléchargés : `gemma-4-e2b` (4.4 GB), `gemma-4-e4b` (6.3 GB) + embedding nomic
- Rsync `/opt/lmstudio/.lmstudio/models/` → `/srv/data/models/` (~80 MB/s LAN interne)
- Intégrité vérifiée (`diff -rq`) avant suppression locale
- `/opt/lmstudio/.lmstudio/models` remplacé par symlink → `/mnt/models`
- LM Studio voit les modèles sans aucun changement de configuration
- 11 GB libérés sur le disque local de gpu-01

## Problèmes rencontrés / Solutions

| Problème | Solution |
|---|---|
| `GLIBCXX_3.4.30 not found` dans `watcher.node` | Patch ELF `vna_hash` + string → `GLIBCXX_3.4.11` |
| LD_PRELOAD ne satisfait pas DT_VERNEED lié à `libstdc++.so.6` | Abandonné — seul le patch ELF fonctionne |
| Offsets mal calculés dans le parseur ELF (`vn_aux` à +4 au lieu de +8) | Corrigé en tenant compte du champ `vn_file` |
| Patch vers `GLIBCXX_3.4.29` : symbole inexistant sous cette version | Cibler `GLIBCXX_3.4.11` — là où le symbole existe réellement |
| `lms server start` quitte avec 0 → systemd déactivate + tue llmster | Wrapper shell avec boucle `pgrep llmster` comme processus principal |
| `lms server start` via ExecStartPost : `Invalid passkey` | lms doit démarrer llmster lui-même pour créer le passkey |
| Port 1234 inaccessible depuis le réseau | `firewall-cmd --permanent --add-port=1234/tcp` |
| `gcc -lstdc++` introuvable sur AlmaLinux 9 | Chemin complet `/usr/lib64/libstdc++.so.6` |
| Automount NFS inactif après `ansible.posix.mount state: mounted` | Utiliser `state: present` + `systemctl enable/start *.automount` |
| Tâche firewalld dans `nfs_server` échoue sur storage-01 (nftables) | Condition `when: firewalld est running` |

## État en fin de journée

| Composant | État |
|---|---|
| common (storage-01 + gpu-01) | ✅ |
| gateway / nftables / NAT | ✅ |
| dnsmasq | ✅ |
| ROCm (gpu-01) | ✅ |
| LM Studio service systemd (gpu-01) | ✅ active (running) |
| API LM Studio `192.168.10.20:1234` | ✅ accessible depuis storage-01 |
| RAID5 md127 monté `/srv/data` | ✅ 2.7 TB, état clean |
| NFS server + exports | ✅ |
| NFS client gpu-01 (automount) | ✅ |
| Modèles sur NFS | ✅ gemma-4-e2b, gemma-4-e4b, nomic-embed |
| Route statique Freebox | ❌ à faire |
| Premier commit GitHub | ❌ à faire |
| postgresql / qdrant / minio | ❌ stubs vides |
| hermes_agent | ❌ stub vide |
