Beryl::CLI::Scan
Sous-commande beryl scan <host> : se connecte au rescue Linux,
détecte les disques, propose un YAML pour le fichier host.
Forme typique : beryl scan ns3156789.ip-51-83-6.eu --domain=example.net --apply
Après l'écriture de la fiche, PROPOSE de poser les records DNS (forward
via le dns_provider de la zone) + le reverse IPv4/IPv6 (question, oui par
défaut), pour ne pas l'oublier (idempotent : un nouveau scan d'un host en
place ne change rien).
--no-dns s'en passe ; --dns reste accepté.
Défaut : dry-run (affiche le YAML sans rien écrire). Avec --apply :
écrit ~/.config/beryl/<domaine>/<nom>.yml (nom court
demandé interactivement ou via --hostname).
Constants
Noms courts qui, s'ils étaient acceptés, produiraient un pool
z<nom> monté sur /<nom> — lequel écraserait un dossier
système FreeBSD de premier niveau et casserait l'OS
(bootloader, configuration, binaires, runtime).
Liste dérivée d'un ls -l / sur FreeBSD 15 après install
fraîche. Ajouter ici tout nouveau top-level qui apparaîtrait
dans une version future.
root figure à part (refusé avec un message dédié « réservé
au pool boot zroot ») par ask_pool_short_name et
parse_pool_spec.
Blocs provider connus : retirés de l'existant si le provider a changé
(sinon un ancien bloc scaleway: resterait après bascule vers ovh).
Regex des noms de pool ZFS autorisés : commence par une lettre minuscule, suivie de lettres/chiffres/underscore. Convention standard ZFS — évite les caractères qui poseraient problème en shell ou dans un YAML (espaces, tirets, majuscules…).
Prompt du niveau RAID sous forme numérique pour un pool donné. Convention parlante beryl : 0, 1, 5, 6, 7, 10 plutôt que stripe/mirror/raidz…
Format cohérent avec pick_disks_for : options entre (…),
défaut entre […] avec espaces français autour des :.
Stripe (0) : seul niveau possible sur un disque.
Class methods
Niveau RAID proposé par défaut, jamais un stripe quand une redondance simple existe (un stripe de N disques multiplie par N le risque de tout perdre) : miroir (1) sur deux disques, RAID 10 (miroirs agrégés, paires formées au bootstrap) sur un nombre PAIR de disques à partir de 4 ; stripe (0) sinon — un nombre impair de 3 et plus appelle un raidz, dont le niveau dépend de l'usage et se donne explicitement. Pur.
Suite à donner après --discover, avec les VRAIS noms de hosts (pas de
<host> générique). En dry-run : d'abord relancer avec --apply. Le
scan des disques exige le rescue : beryl rescue vient AVANT scan.
Nom court d'un serveur découvert : le displayName OVH nettoyé s'il
existe, sinon un placeholder new-<id> (partie ns du serviceName) à
renommer par l'opérateur.
Un displayName qui est déjà le FQDN du domaine cible (web1.example.net
pour le domaine example.net) donne son nom court (web1) : sinon le
host deviendrait web1-example-net.example.net.
Exemples de réponse construits sur les VRAIS disques (pas sda,sdb en
dur) : 1,2 | nvme0n1,nvme1n1 | all. Appelé avec au moins 2 disques.
Croise l'inventaire disques DÉCLARÉ par le provider (API matériel) avec les disques réellement vus par l'OS. Retourne un message d'alerte si l'OS en voit MOINS (cas typique : disque défaillant non énuméré, qui fait stagner le firmware au boot), sinon nil. Pur → testable.
Fusionne le YAML généré par scan dans un host.yml EXISTANT, en
PRÉSERVANT toutes les clés que scan ne gère pas (apply_recipes,
proxy_jump, ssh_host, user, port, freebsd.users…). scan possède :
provider, le bloc du provider, et freebsd.{hostname,zfs}.
Les COMMENTAIRES de l'ancien fichier sont perdus (round-trip YAML) — seules les DONNÉES sont préservées. Lève si l'existant n'est pas un mapping YAML (le caller retombe alors sur l'écrasement explicite).
Partenaire de miroir possible : même taille et même type (SSD ou disque dur) — un NVMe n'est pas une alternative pour un miroir de disques durs. Pur.
Avertissements des miroirs d'un seul modèle (RAID 1 : le pool entier ; RAID 10 : chaque paire), seulement si un autre modèle compatible existe. Pur.
Deux disques du même modèle viennent souvent du même lot, avec le même
firmware : ils tendent à tomber en panne ensemble. Un miroir ZFS doit
donc réunir deux modèles différents quand le serveur en a (ADV-3 : 2 ×
Micron + 2 × Samsung). Pour un RAID 10, beryl forme les miroirs avec des
paires CONSÉCUTIVES : l'ordre de lsblk (nvme0n1, nvme1n1…) donnerait
Micron + Micron et Samsung + Samsung. La fiche est triée (beryl fmt) et
ne garde pas d'ordre : c'est beryl bootstrap qui forme les paires
(raid10_order sur les disques du rescue). mix_models annonce ces
paires pour chaque pool RAID 10 et avertit de tout miroir resté d'un seul modèle
alors qu'un disque d'un autre modèle, de même taille et même type, aurait
pu l'accompagner (all : tous les disques détectés).
Le serveur a-t-il un disque d'un AUTRE modèle qui pourrait être le
partenaire de disk ? Pur.
Parse une spec --pool=SHORTNAME:DISKS:RAID et retourne un
PoolSpec data (pool z<SHORTNAME> + mountpoint /<SHORTNAME>,
boot: false).
- SHORTNAME : nom court sans préfixe
z(ex:data,cache). Refuseroot(réservé au pool bootzroot). - DISKS :
sda,sdbouall(tous les disques restants). - RAID : 0|1|5|6|7|10.
Toutes les validations lèvent ArgumentError pour remonter un
message clair à l'opérateur.
Ordre RAID 10 : paires consécutives de deux modèles différents tant que possible (on puise d'abord dans le modèle le plus nombreux) ; à égalité, l'ordre de détection est gardé. Pur.
Rend le YAML d'un host. Le fichier ne contient QUE ce qui est spécifique (provider/service_name/hostname/disques/raid). Le reste vient du merge (_default.yml, <domaine>.yml).
Niveau RAID en notation numérique (0=stripe, 1=mirror, 5=raidz,
6=raidz2, 7=raidz3, 10=mirror_stripe) — traduit en mode ZFS par
Beryl::Config::Zpool.zfs_mode au moment du bootstrap.
Construit la commande à proposer quand beryl scan affiche un YAML
en mode suggestion (dry-run) : même args, mais en ajoutant
--apply et, si l'opérateur n'a pas passé --hostname, le short
résolu interactivement pour éviter le re-prompt.
Résout une IPv4 depuis un host : déjà une IP → tel quel ; sinon DNS (A).
Résout une IPv6 depuis un host : déjà une IPv6 (contient :) → tel quel ;
sinon DNS (AAAA). nil si aucune (host sans IPv6 publique).
existing : fiche ACTUELLE du serveur (même nom court), là où elle est —
y compris dans un groupe (<domaine>/<groupe>/) : réécrite sur place,
jamais doublée à la racine du domaine.
Variante Dedibox du flux --dns. Différences :
- IPs + current_hostname viennent de l'API Dedibox
(
GET /server/{id}), pas OVH. - records A/AAAA posés via le dns_provider RÉEL de la zone
(OVH, Gandi… selon
host.dns_provider), viaDnsApply.forward_via_dns_provider. - rename console :
DediboxApi::Client.servers.update_hostname(API validée live 24 avril 2026). - reverse DNS : skip, l'API Dedibox ne l'expose pas. Warning explicite pour que l'opérateur le pose manuellement dans https://console.online.net.
Variante Scaleway de run_dns_setup. Différences vs Dedibox :
- IPs + current_name viennent de l'API Scaleway
(
client.baremetal.servers.get(uuid, zone)). Si la zone n'est pas fournie explicitement (cas d'un UUID brut venu du shortcut), on la retrouve viafind_any_zone. - Records A/AAAA posés via le dns_provider RÉEL de la zone
(OVH, Gandi…). Même code que Dedibox (
forward_via_dns_provider). - Rename console :
client.baremetal.servers.update(name:). Scaleway n'a pas de séparation « nom système / nom console » comme Dedibox : lenamesert de nom d'affichage dans la console et dans les logs d'install. - Reverse DNS : EXPOSÉ par l'API Scaleway,
client.baremetal.servers.update(reverse:). Contrairement à Dedibox (qui force l'opérateur à passer par la console web), on peut le poser automatiquement.
Garde-fou : un zroot en stripe (RAID 0) sur plusieurs disques n'a AUCUNE redondance — un seul disque perdu = système perdu. Piège vu in vivo après un passage JBOD → ZFS : le défaut 0 accepté d'un [Entrée] a donné un zroot de 4 disques sans redondance, annulant l'intérêt du JBOD. Le défaut reste 0 (convention beryl) ; on exige seulement une confirmation explicite en interactif. Limité au zroot : un pool de données en stripe (cache…) peut être voulu. Renvoie le message d'avertissement, ou nil si rien à signaler.
Valide le nom court d'un pool ZFS (sans préfixe z). Lève
ArgumentError avec un message explicite sur quoi l'opérateur
aurait dû taper. Utilisé à la fois côté interactif
(ask_pool_short_name) et côté CLI (parse_pool_spec).
Deux checks :
- Format regex (lettre minuscule + [a-z0-9_]*).
- Noms réservés qui écraseraient un dossier système FreeBSD de premier niveau (/bin, /etc, /usr, /var, /tmp, /boot…) et casseraient l'OS. Sécurité : mieux vaut refuser que laisser l'opérateur saboter son FreeBSD au prochain boot.
Valide une chaîne RAID. Lève ArgumentError sur entrée non-numérique
ou niveau inconnu.