206 lines
9.2 KiB
Markdown
206 lines
9.2 KiB
Markdown
# Fork personnel — exploitation
|
|
|
|
Ce dossier n'existe pas en amont. Il ne créera donc jamais de conflit lors d'un
|
|
rebase, ce qui est exactement pourquoi les fichiers d'exploitation vivent ici et
|
|
pas dans `scripts/`.
|
|
|
|
## Déployer
|
|
|
|
```bash
|
|
ops/deploy-lxc.sh --dry-run # montre ce qui serait écrit, sans rien toucher
|
|
ops/deploy-lxc.sh
|
|
```
|
|
|
|
Le script exige un arbre propre, construit, compare les migrations et l'ABI Node
|
|
avant de toucher quoi que ce soit, sauvegarde `/opt/homarr` **et** la base, arrête
|
|
le service, synchronise, redémarre, puis affiche les journaux. La commande de
|
|
retour arrière est imprimée à la fin, horodatage compris.
|
|
|
|
Ce qu'il ne remplace jamais : `/etc/homarr/homarr.env`, `run.sh`, `entrypoint.sh`,
|
|
`nginx.conf`, `redis.conf` — ils appartiennent à l'installation du LXC, pas au
|
|
build — ni `/var/lib/homarr/db.sqlite`, qui est sauvegardée mais laissée en place.
|
|
|
|
Après déploiement, le contrôle qui compte n'est pas que le nouveau widget
|
|
s'affiche : c'est que les intégrations **préexistantes** fonctionnent encore.
|
|
C'est la seule preuve que `SECRET_ENCRYPTION_KEY` n'a pas bougé.
|
|
|
|
## Déplacer l'état hors de /appdata
|
|
|
|
`/appdata` vient de l'image Docker, où c'est un point de montage. Sur une
|
|
machine, il ne suit aucune convention : l'état d'un service se range sous
|
|
`/var/lib`. La correction se fait sur l'**instance installée**, jamais dans le
|
|
dépôt — ni le code ni le Dockerfile ne sont touchés, sans quoi chaque rebase sur
|
|
l'amont rouvrirait le sujet.
|
|
|
|
```bash
|
|
sudo ops/use-var-lib-homarr.sh /opt/homarr # ou /opt/homarr-dev
|
|
```
|
|
|
|
Le script réécrit `/appdata` en `/var/lib/homarr` dans le `run.sh` et le
|
|
`redis.conf` de l'instance, sauvegarde chaque fichier avant de le toucher, et
|
|
ajoute `LOCAL_CERTIFICATE_PATH` au démarrage. Cette dernière ligne n'est pas
|
|
cosmétique : le chemin des certificats n'est pas lu par `run.sh` mais par
|
|
l'application, qui retombe sur le dossier de l'image dès qu'il manque — elle
|
|
recréerait donc `/appdata` au premier certificat chargé.
|
|
|
|
Le script ne déplace **pas** les données ; il imprime les commandes à passer une
|
|
fois, service arrêté. Sur cette installation, `/appdata` ne contient qu'un
|
|
fichier : le certificat racine qui valide la console UniFi locale. Le contrôle
|
|
d'après-déplacement est donc tout trouvé — si le widget UniFi OS répond encore,
|
|
le certificat a suivi.
|
|
|
|
À relancer après chaque assemblage : `ops/assemble-standalone.sh` recopie le
|
|
`run.sh` du dépôt quand l'instance n'en a pas, et celui-là parle de `/appdata`.
|
|
|
|
## Suivre les mises à jour d'Homarr
|
|
|
|
Aujourd'hui `origin` pointe sur le dépôt d'Homarr lui-même et **aucune copie
|
|
distante de ce travail n'existe** : une panne de disque effacerait la branche.
|
|
Premier geste, avant tout le reste :
|
|
|
|
```bash
|
|
git remote rename origin upstream
|
|
git remote add origin <url-de-ton-Gitea>/homarr.git
|
|
git push -u origin feat/unifi-os-integration
|
|
```
|
|
|
|
### Le cycle de montée de version
|
|
|
|
Homarr publie souvent. Se caler sur une **étiquette de version** plutôt que sur
|
|
`dev` évite de rebaser sur du code en cours :
|
|
|
|
```bash
|
|
git fetch upstream --tags
|
|
git log --oneline dev..upstream/dev | head # ce qui est arrivé
|
|
git rebase v1.78.0 feat/unifi-os-integration # remplace par la version visée
|
|
```
|
|
|
|
Puis, dans cet ordre — chaque étape a déjà attrapé quelque chose :
|
|
|
|
```bash
|
|
pnpm install # le lockfile bouge presque à chaque version
|
|
pnpm turbo typecheck # les 37 paquets
|
|
pnpm test packages/integrations/ packages/widgets/
|
|
pnpm test packages/widgets/src/manifest.spec.ts # les points d'enregistrement
|
|
ops/deploy-lxc.sh --dry-run
|
|
```
|
|
|
|
`manifest.spec.ts` mérite sa ligne à part : il compare l'icône du catalogue à
|
|
celle de la définition **par identité**, et c'est le seul test qui détecte un
|
|
point d'enregistrement perdu dans un conflit.
|
|
|
|
### Où les conflits vont tomber
|
|
|
|
Le gros du travail vit dans des dossiers neufs — `packages/integrations/src/unifi-os/`,
|
|
`unifi-site-manager/`, `packages/widgets/src/unifi-*/` — qui ne peuvent pas
|
|
entrer en conflit. Les points de friction sont les fichiers partagés où ce fork
|
|
ajoute une ligne dans une liste que l'amont fait vivre aussi :
|
|
|
|
| Fichier | Ce qu'on y ajoute |
|
|
|---|---|
|
|
| `packages/definitions/src/integration.ts` | les deux genres d'intégration |
|
|
| `packages/definitions/src/widget.ts` | les deux genres de widget |
|
|
| `packages/definitions/src/widget-integration-map.ts` | l'association widget ↔ intégration |
|
|
| `packages/definitions/src/docs/integration-doc-slugs.ts` | les slugs de documentation |
|
|
| `packages/definitions/src/docs/widget-doc-slugs.ts` | idem, côté widgets |
|
|
| `packages/integrations/src/base/creator.ts` | la construction des classes |
|
|
| `packages/integrations/src/index.ts` | les exports |
|
|
| `packages/integrations/src/types.ts` | les types réexportés **côté client** |
|
|
| `packages/api/src/router/widgets/index.ts` | les routeurs tRPC |
|
|
| `packages/widgets/src/manifest.ts` | deux cartes distinctes, module et composant |
|
|
| `packages/widgets/src/index.tsx` | l'import et l'entrée |
|
|
| `packages/widgets/src/catalog.ts` | l'icône |
|
|
| `packages/widgets/src/refetch-intervals.ts` | l'intervalle de rafraîchissement |
|
|
| `apps/nextjs/src/components/integration/integration-grid-shared.ts` | le libellé de catégorie |
|
|
| `apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts` | l'icône du secret |
|
|
| `packages/translation/src/lang/en.json` | tous les libellés |
|
|
|
|
Deux de ces lignes ne sont vérifiées par **aucun** compilateur, et les perdre
|
|
dans un conflit passerait tous les tests :
|
|
|
|
- `integration-grid-shared.ts` est typé `Record<string, string>` : une entrée
|
|
manquante affiche `UNIFISITEMANAGER` en majuscules collées au lieu du nom.
|
|
- `en.json` n'est pas typé du tout : une clé perdue affiche son chemin brut.
|
|
|
|
Les deux se voient d'un coup d'œil sur la page « New integration » — c'est le
|
|
contrôle visuel à faire après chaque montée de version.
|
|
|
|
### Rejouer les résolutions de conflit
|
|
|
|
Les mêmes conflits reviendront à chaque version, au même endroit. Git sait les
|
|
rejouer tout seul :
|
|
|
|
```bash
|
|
git config rerere.enabled true
|
|
```
|
|
|
|
À activer **avant** le premier rebase : Git n'enregistre que ce qu'il voit
|
|
résoudre. Une fois qu'une résolution est connue, les suivantes sont
|
|
automatiques — à relire quand même, l'amont peut avoir changé la forme de la
|
|
liste autour.
|
|
|
|
|
|
## Construire ailleurs que sur le poste
|
|
|
|
```bash
|
|
SKIP_ENV_VALIDATION=true CI=true DISABLE_REDIS_LOGS=true \
|
|
pnpm turbo build --concurrency=1 --filter=@homarr/nextjs... --filter=@homarr/cli
|
|
```
|
|
|
|
`SKIP_ENV_VALIDATION` n'est pas optionnel : le build charge `next.config.ts`, qui
|
|
valide les variables d'**exécution** — dont `URL`, qui n'a aucun sens à la
|
|
compilation. Le Dockerfile la pose en `ARG` pour la même raison. Un dépôt qui
|
|
construit sans elle ne le doit qu'à un `.env` traînant à sa racine.
|
|
|
|
Mémoire mesurée sur ce dépôt : **1,8 Go de PSS au pic**, et non les 5 Go que
|
|
donne la somme naïve des RSS, qui recompte la mémoire partagée. Sur une machine
|
|
à 2 Go, c'est jouable service arrêté, mais sans marge.
|
|
|
|
|
|
## Faire tourner une instance sous l'utilisateur `homarr`
|
|
|
|
L'unité `homarr-dev.service` déclare `User=homarr`. Le `run.sh` de l'image ne
|
|
peut pas fonctionner ainsi : il écrit `/etc/nginx/nginx.conf` et écoute le port
|
|
80. `ops/run-rootless.sh` le remplace — migrations, secret d'authentification,
|
|
serveur Next, et rien d'autre.
|
|
|
|
```bash
|
|
sudo install -m 755 ops/run-rootless.sh /opt/homarr-dev/run.sh
|
|
sudo chown -R homarr:homarr /opt/homarr-dev/apps/nextjs/.next
|
|
```
|
|
|
|
Le `chown` n'est pas facultatif : Next écrit son cache d'images sous
|
|
`.next/cache` pendant l'exécution.
|
|
|
|
Trois réglages à corriger dans `/etc/homarr/homarr-dev.env`, chacun pour une
|
|
raison distincte :
|
|
|
|
```ini
|
|
DB_URL='/var/lib/homarr-dev/db.sqlite'
|
|
LOCAL_CERTIFICATE_PATH='/var/lib/homarr-dev/trusted-certificates'
|
|
```
|
|
|
|
`DB_URL` doit quitter `/var/lib/homarr`, qui appartient à root : SQLite écrit
|
|
aussi ses fichiers `-wal` et `-shm`, donc il lui faut le **dossier** en écriture,
|
|
pas seulement le fichier. `/var/lib/homarr-dev` est créé et donné à l'utilisateur
|
|
du service par le `StateDirectory=` de l'unité — rien à chowner.
|
|
|
|
`LOCAL_CERTIFICATE_PATH` doit être posée, sans quoi l'application retombe sur le
|
|
dossier de l'image, tente de le recréer et échoue faute de droits. Le CA qui
|
|
valide la console UniFi doit y être recopié :
|
|
|
|
```bash
|
|
sudo cp /var/lib/homarr/trusted-certificates/*.pem /var/lib/homarr-dev/trusted-certificates/
|
|
sudo chown -R homarr:homarr /var/lib/homarr-dev
|
|
```
|
|
|
|
Reste le proxy, qui ne peut pas tourner sous `homarr` : `ops/homarr-dev-proxy.nginx.conf`
|
|
est à déposer dans `/etc/nginx/sites-available/` et à activer. Il n'est pas
|
|
optionnel — le client appelle `ws://<hôte>:<port>/websockets` sur la même origine
|
|
que la page, alors que le serveur WebSocket écoute sur 3001. Sans lui,
|
|
l'application se charge et perd ses mises à jour en direct, sans rien dire.
|
|
|
|
Enfin : **les deux instances ne peuvent pas tourner en même temps.** Le port du
|
|
serveur WebSocket est écrit en dur dans `apps/websocket/src/main.ts` (3001), donc
|
|
même en déplaçant le port HTTP, la seconde instance échouerait à se lier.
|