fix drive name normalization (#74)

This commit is contained in:
Gustavo de Andrade Rosa
2026-07-21 13:43:59 -04:00
committed by GitHub
parent 9d1bce45af
commit 27eb24bd4b
6 changed files with 29 additions and 16 deletions
+13 -3
View File
@@ -118,6 +118,11 @@ local function smartDeviceFor(path)
return controller ~= nil and "/dev/" .. controller or tostring(path) return controller ~= nil and "/dev/" .. controller or tostring(path)
end end
local function deviceBasename(value)
local normalized = tostring(value or ""):gsub("/+$", "")
return normalized:match("([^/]+)$") or ""
end
local function listDirectory(path) local function listDirectory(path)
local entries = noctalia.listDir(path) local entries = noctalia.listDir(path)
return type(entries) == "table" and entries or {} return type(entries) == "table" and entries or {}
@@ -765,8 +770,13 @@ local function normalizeRaw(raw, source)
local disks = {} local disks = {}
for _, block in ipairs(lsblk.blockdevices or {}) do for _, block in ipairs(lsblk.blockdevices or {}) do
local device = tostring(block.path or ("/dev/" .. tostring(block.name or ""))) local device = tostring(block.path or "")
local name = tostring(block.name or "") local name = deviceBasename(block.name)
if name == "" then name = deviceBasename(block.kname) end
if name == "" then name = deviceBasename(device) end
if not device:match("^/dev/") and name ~= "" then device = "/dev/" .. name end
local kernelName = deviceBasename(block.kname)
if kernelName == "" then kernelName = name end
local virtual = name:match("^zram") or name:match("^loop") or name:match("^ram") or name:match("^sr") local virtual = name:match("^zram") or name:match("^loop") or name:match("^ram") or name:match("^sr")
if block.type == "disk" and device:match("^/dev/") and not virtual then if block.type == "disk" and device:match("^/dev/") and not virtual then
local smartDevice = smartDeviceFor(device) local smartDevice = smartDeviceFor(device)
@@ -789,7 +799,7 @@ local function normalizeRaw(raw, source)
local model = noctalia.string.trim(tostring(block.model or "")) local model = noctalia.string.trim(tostring(block.model or ""))
local namespace = name:match("^nvme%d+(n%d+)$") local namespace = name:match("^nvme%d+(n%d+)$")
local id = serial ~= "" and serial .. (namespace ~= nil and ":" .. namespace or "") local id = serial ~= "" and serial .. (namespace ~= nil and ":" .. namespace or "")
or tostring(block.kname or device) or (kernelName ~= "" and kernelName or device)
local preferences = preferenceFor(id) local preferences = preferenceFor(id)
local removable = block.rm == true or tonumber(block.rm) == 1 or block.hotplug == true or tonumber(block.hotplug) == 1 local removable = block.rm == true or tonumber(block.rm) == 1 or block.hotplug == true or tonumber(block.hotplug) == 1
local transport = tostring(block.tran or "unknown") local transport = tostring(block.tran or "unknown")
+1 -1
View File
@@ -1,6 +1,6 @@
id = "gustav0ar/drive-health" id = "gustav0ar/drive-health"
name = "Drive Health" name = "Drive Health"
version = "1.2.0" version = "1.2.1"
plugin_api = 3 plugin_api = 3
author = "Drive Health contributors" author = "Drive Health contributors"
license = "MIT" license = "MIT"
+1 -1
View File
@@ -59,7 +59,7 @@ lsblk --nodeps --noheadings --paths --output PATH,TYPE,ROTA >"$devices_tmp"
{ {
printf '{"schema":2,"collector_version":"%s","collection_id":"%s","generated_at_epoch":%s,"lsblk":' \ printf '{"schema":2,"collector_version":"%s","collection_id":"%s","generated_at_epoch":%s,"lsblk":' \
"$collector_version" "$collection_id" "$generated_at_epoch" "$collector_version" "$collection_id" "$generated_at_epoch"
lsblk --json --bytes --output \ lsblk --json --bytes --paths --output \
NAME,KNAME,PATH,PKNAME,TYPE,TRAN,ROTA,RM,HOTPLUG,SIZE,LOG-SEC,PHY-SEC,MODEL,SERIAL,FSTYPE,FSSIZE,FSUSED,FSAVAIL,MOUNTPOINTS NAME,KNAME,PATH,PKNAME,TYPE,TRAN,ROTA,RM,HOTPLUG,SIZE,LOG-SEC,PHY-SEC,MODEL,SERIAL,FSTYPE,FSSIZE,FSUSED,FSAVAIL,MOUNTPOINTS
printf ',"smart":[' printf ',"smart":['
+9 -7
View File
@@ -392,10 +392,10 @@ local normalized, normalizeError = normalizeRaw({
generated_at_epoch = 1700000000, generated_at_epoch = 1700000000,
lsblk = { blockdevices = { lsblk = { blockdevices = {
{ {
name = "nvme9n1", kname = "nvme9n1", path = "/dev/nvme9n1", type = "disk", name = "/dev/nvme9n1", kname = "/dev/nvme9n1", path = "/dev/nvme9n1", type = "disk",
tran = "nvme", rota = false, size = 2000000000, model = "Fixture NVMe", serial = "FIXTURE1", tran = "nvme", rota = false, size = 2000000000, model = "Fixture NVMe", serial = "FIXTURE1",
mountpoints = {}, children = { mountpoints = {}, children = {
{ name = "nvme9n1p1", kname = "nvme9n1p1", path = "/dev/nvme9n1p1", type = "part", { name = "/dev/nvme9n1p1", kname = "/dev/nvme9n1p1", path = "/dev/nvme9n1p1", type = "part",
mountpoints = { "/mnt/work" }, fsused = 250, fsavail = 750 }, mountpoints = { "/mnt/work" }, fsused = 250, fsavail = 750 },
}, },
}, },
@@ -485,15 +485,17 @@ assert(sleeping.summary.sleeping_count == 1 and sleeping.summary.smart_unavailab
local namespaces = assert(normalizeRaw({ local namespaces = assert(normalizeRaw({
schema = 2, generated_at_epoch = 1700000000, schema = 2, generated_at_epoch = 1700000000,
lsblk = { blockdevices = { lsblk = { blockdevices = {
{ name = "nvme0n1", kname = "nvme0n1", path = "/dev/nvme0n1", type = "disk", { name = "/dev/nvme0n1", kname = "/dev/nvme0n1", path = "/dev/nvme0n1", type = "disk",
tran = "nvme", rota = false, serial = "SHARED", children = {} }, tran = "nvme", rota = false, serial = "SHARED", children = {} },
{ name = "nvme0n2", kname = "nvme0n2", path = "/dev/nvme0n2", type = "disk", { name = "/dev/nvme0n2", kname = "/dev/nvme0n2", path = "/dev/nvme0n2", type = "disk",
tran = "nvme", rota = false, serial = "SHARED", children = {} }, tran = "nvme", rota = false, serial = "SHARED", children = {} },
{ name = "/dev/zram0", kname = "/dev/zram0", path = "/dev/zram0", type = "disk",
rota = false, serial = "VIRTUAL", children = {} },
} }, smart = {}, } }, smart = {},
}, "test")) }, "test"))
assert(namespaces.disks[1].id ~= namespaces.disks[2].id assert(#namespaces.disks == 2, "absolute zram name was not excluded from physical drive inventory")
and namespaces.disks[1].id:match(":n%d+$") and namespaces.disks[2].id:match(":n%d+$"), assert(namespaces.disks[1].id == "SHARED:n1" and namespaces.disks[2].id == "SHARED:n2",
"NVMe namespaces sharing a controller serial did not receive unique IDs") "absolute NVMe names did not receive stable namespace-qualified IDs")
local empty = assert(normalizeRaw({ local empty = assert(normalizeRaw({
schema = 2, collection_id = " ", generated_at_epoch = 1700000000, schema = 2, collection_id = " ", generated_at_epoch = 1700000000,
+4 -3
View File
@@ -3,12 +3,13 @@ set -eu
case " $* " in case " $* " in
*" --nodeps "*) *" --nodeps "*)
printf '%s\n' "/dev/sda disk 1" "/dev/nvme0n1 disk 0" printf '%s\n' "/dev/sda disk 1" "/dev/nvme0n1 disk 0" "/dev/zram0 disk 0"
;; ;;
*" --json "*) *" --json "*)
printf '%s\n' '{"blockdevices":[' \ printf '%s\n' '{"blockdevices":[' \
'{"name":"sda","kname":"sda","path":"/dev/sda","type":"disk","tran":"sata","rota":true,"size":1000000000,"model":"Fixture SATA","serial":"SATA1","mountpoints":[]},' \ '{"name":"/dev/sda","kname":"/dev/sda","path":"/dev/sda","type":"disk","tran":"sata","rota":true,"size":1000000000,"model":"Fixture SATA","serial":"SATA1","mountpoints":[]},' \
'{"name":"nvme0n1","kname":"nvme0n1","path":"/dev/nvme0n1","type":"disk","tran":"nvme","rota":false,"size":2000000000,"model":"Fixture NVMe","serial":"NVME1","mountpoints":[]}' \ '{"name":"/dev/nvme0n1","kname":"/dev/nvme0n1","path":"/dev/nvme0n1","type":"disk","tran":"nvme","rota":false,"size":2000000000,"model":"Fixture NVMe","serial":"NVME1","mountpoints":[]},' \
'{"name":"/dev/zram0","kname":"/dev/zram0","path":"/dev/zram0","type":"disk","rota":false,"size":4294967296,"mountpoints":[]}' \
']}' ']}'
;; ;;
*) *)
+1 -1
View File
@@ -9,7 +9,7 @@ printf '%s\n' "$payload" | jq -e '
.schema == 2 .schema == 2
and .collector_version == "2.0.0" and .collector_version == "2.0.0"
and (.collection_id | type == "string" and length > 0) and (.collection_id | type == "string" and length > 0)
and (.lsblk.blockdevices | length) == 2 and ([.lsblk.blockdevices[].name] | sort) == ["/dev/nvme0n1", "/dev/sda", "/dev/zram0"]
and (.smart | length) == 2 and (.smart | length) == 2
and ([.smart[].requested_device] | sort) == ["/dev/nvme0", "/dev/sda"] and ([.smart[].requested_device] | sort) == ["/dev/nvme0", "/dev/sda"]
and (.smart[] | select(.requested_device == "/dev/sda") | .payload.test_standby) == true and (.smart[] | select(.requested_device == "/dev/sda") | .payload.test_standby) == true