From a9506a5505cb059234f91b9e6fc9bc415651713a Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Sat, 23 May 2026 13:39:13 +0200 Subject: [PATCH] =?UTF-8?q?fix(smart=20v0.1.15):=20contr=C3=B4leur=20NVMe?= =?UTF-8?q?=20+=20r=C3=A8gle=20udev=20disk=20group?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cause racine : smartctl -a -j /dev/nvme0n1 (namespace) retourne exit 4 et omet smart_status car les commandes admin échouent via le namespace. Solution : utiliser /dev/nvme0 (contrôleur) accessible grâce à la règle udev SUBSYSTEM==nvme GROUP=disk. - smart.rs : scan /sys/class/nvme/ pour les contrôleurs (nvme0, nvme1) au lieu de /sys/block/ pour les namespaces (nvme0n1) - deploy/99-nanometrics-smart.rules : udev rule KERNEL==nvme* GROUP=disk - deploy/install.sh : déploie la règle udev + udevadm trigger Co-Authored-By: Claude Sonnet 4.6 --- agent/Cargo.lock | 2 +- agent/Cargo.toml | 2 +- agent/src/metrics/smart.rs | 40 +++++++++++++++++-------------- deploy/99-nanometrics-smart.rules | 4 ++++ deploy/install.sh | 11 +++++++++ 5 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 deploy/99-nanometrics-smart.rules diff --git a/agent/Cargo.lock b/agent/Cargo.lock index eb886d3..5dc1c1d 100644 --- a/agent/Cargo.lock +++ b/agent/Cargo.lock @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "nanometrics-agent" -version = "0.1.14" +version = "0.1.15" dependencies = [ "libc", "rumqttc", diff --git a/agent/Cargo.toml b/agent/Cargo.toml index ce5761d..88dc15c 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nanometrics-agent" -version = "0.1.14" +version = "0.1.15" edition = "2021" [lib] diff --git a/agent/src/metrics/smart.rs b/agent/src/metrics/smart.rs index e116131..b7615e1 100644 --- a/agent/src/metrics/smart.rs +++ b/agent/src/metrics/smart.rs @@ -91,24 +91,28 @@ pub fn collect() -> Option> { eprintln!("[smart] smartctl introuvable dans PATH"); return None; } - let mut devs: Vec = std::fs::read_dir("/sys/block") - .into_iter() - .flatten() - .flatten() - .map(|e| e.file_name().into_string().unwrap_or_default()) - .filter_map(|n| { - if n.starts_with("sd") { - Some(format!("/dev/{}", n)) - } else if n.starts_with("nvme") && n[4..].contains('n') { - // nvme0n1, nvme1n1 — namespace block device ; "nvme0" (contrôleur) ne passerait pas - Some(format!("/dev/{}", n)) - } else { - None - } - }) - .collect::>() - .into_iter() - .collect(); + let mut set = std::collections::HashSet::new(); + + // SATA/SAS : /sys/block/sd* → /dev/sda, /dev/sdb… + for e in std::fs::read_dir("/sys/block").into_iter().flatten().flatten() { + let n = e.file_name().into_string().unwrap_or_default(); + if n.starts_with("sd") { + set.insert(format!("/dev/{}", n)); + } + } + + // NVMe : /sys/class/nvme/nvme* → /dev/nvme0, /dev/nvme1… + // On utilise le contrôleur (char device), pas le namespace (block device), + // car smartctl ne peut exécuter les commandes admin SMART que via le contrôleur. + // La règle udev 99-nanometrics-smart.rules lui donne l'accès groupe disk. + for e in std::fs::read_dir("/sys/class/nvme").into_iter().flatten().flatten() { + let n = e.file_name().into_string().unwrap_or_default(); + if n.starts_with("nvme") { + set.insert(format!("/dev/{}", n)); + } + } + + let mut devs: Vec = set.into_iter().collect(); devs.sort(); eprintln!("[smart] disques détectés: {:?}", devs); diff --git a/deploy/99-nanometrics-smart.rules b/deploy/99-nanometrics-smart.rules new file mode 100644 index 0000000..f0f6739 --- /dev/null +++ b/deploy/99-nanometrics-smart.rules @@ -0,0 +1,4 @@ +# Nanometrics: accès groupe disk aux contrôleurs NVMe pour SMART +# Sans cette règle, /dev/nvme0 est crw------- root root (root only), +# ce qui empêche smartctl d'exécuter les commandes admin et omet smart_status du JSON. +KERNEL=="nvme[0-9]*", SUBSYSTEM=="nvme", GROUP="disk", MODE="0660" diff --git a/deploy/install.sh b/deploy/install.sh index 7df67fb..3c784b1 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -45,6 +45,17 @@ else fi echo "" +# ── 2. Règle udev NVMe (accès SMART pour le groupe disk) ────────────────────── +UDEV_RULE="/etc/udev/rules.d/99-nanometrics-smart.rules" +cat > "$UDEV_RULE" << 'UDEVRULE' +# Nanometrics: accès groupe disk aux contrôleurs NVMe pour SMART +KERNEL=="nvme[0-9]*", SUBSYSTEM=="nvme", GROUP="disk", MODE="0660" +UDEVRULE +udevadm control --reload-rules +udevadm trigger --subsystem-match=nvme 2>/dev/null || true +ok "Règle udev NVMe installée ($UDEV_RULE)" +echo "" + # ── 3. Détection de l'architecture ──────────────────────────────────────────── ARCH="$(uname -m)" case "$ARCH" in