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