@@ -125,52 +125,281 @@ def get_devices(self, force_run: bool = False) -> Any:
125125 return nvme_devices ["Devices" ]
126126
127127 def get_disks (self , force_run : bool = False ) -> List [str ]:
128- nvme_devices = self .get_devices (force_run = force_run )
129- return [device ["DevicePath" ] for device in nvme_devices ]
130-
131- # NVME namespace ids are unique for each disk under any NVME controller.
132- # These are useful in detecting the lun id of the remote azure disk disks.
133- # Example output of nvme -list -o json and nvme -list
134- # root@lisa--170-e0-n0:/home/lisa# nvme -list -o json
135- # {
136- # "Devices" : [
137- # {
138- # "NameSpace" : 1,
139- # "DevicePath" : "/dev/nvme0n1",
140- # "Firmware" : "v1.00000",
141- # "Index" : 0,
142- # "ModelNumber" : "MSFT NVMe Accelerator v1.0",
143- # "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
144- # "SerialNumber" : "SN: 000001",
145- # "UsedBytes" : 536870912000,
146- # "MaximumLBA" : 1048576000,
147- # "PhysicalSize" : 536870912000,
148- # "SectorSize" : 512
149- # },
150- # {
151- # "NameSpace" : 2,
152- # "DevicePath" : "/dev/nvme0n2",
153- # "Firmware" : "v1.00000",
154- # "Index" : 0,
155- # "ModelNumber" : "MSFT NVMe Accelerator v1.0",
156- # "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
157- # "SerialNumber" : "SN: 000001",
158- # "UsedBytes" : 4294967296,
159- # "MaximumLBA" : 8388608,
160- # "PhysicalSize" : 4294967296,
161- # "SectorSize" : 512
162- # }
163- # ]
164- # }
165- # root@lisa--170-e0-n0:/home/lisa# nvme -list
166- # Node SN Model Namespace Usage Format FW Rev # noqa: E501
167- # --------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- ------- # noqa: E501
168- # /dev/nvme0n1 SN: 000001 MSFT NVMe Accelerator v1.0 1 536.87 GB / 536.87 GB 512 B + 0 B v1.0000 # noqa: E501
169- # /dev/nvme0n2 SN: 000001 MSFT NVMe Accelerator v1.0 2 4.29 GB / 4.29 GB 512 B + 0 B v1.0000 # noqa: E501
170- # /dev/nvme0n3 SN: 000001 MSFT NVMe Accelerator v1.0 15 44.02 GB / 44.02 GB 512 B + 0 B v1.0000 # noqa: E501
171- # /dev/nvme0n4 SN: 000001 MSFT NVMe Accelerator v1.0 14 6.44 GB / 6.44 GB 512 B + 0 B v1.0000 # noqa: E501
172- # /dev/nvme1n1 68e8d42a7ed4e5f90002 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
173- # /dev/nvme2n1 68e8d42a7ed4e5f90001 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
128+ """
129+ Return NVMe device nodes/paths (`/dev/...`) robustly across nvme-cli schemas.
130+
131+ Upstream change context:
132+ - nvme-cli reworked `nvme list -o json` around v2.11, removing the
133+ legacy top-level `.Devices[].DevicePath` and nesting device info under:
134+ Subsystems → Controllers → Namespaces.
135+ - Reference discussion and breakage report:
136+ https://github.com/linux-nvme/nvme-cli/issues/2749
137+ (thread points to commit 929f461 as the change introducing the new JSON)
138+ - Some distro builds (e.g., certain RHEL package revisions) may still
139+ emit `DevicePath`. This logic supports both.
140+
141+ Returns:
142+ List[str]: device nodes/paths like `/dev/nvme0n1`
143+ """
144+ # NVME namespace ids are unique for each disk under any NVME controller.
145+ # These are useful in detecting the lun id of the remote azure disk disks.
146+ # Example output of nvme -list -o json and nvme -list
147+ # root@lisa--170-e0-n0:/home/lisa# nvme -list -o json
148+ # {
149+ # "Devices" : [
150+ # {
151+ # "NameSpace" : 1,
152+ # "DevicePath" : "/dev/nvme0n1",
153+ # "Firmware" : "v1.00000",
154+ # "Index" : 0,
155+ # "ModelNumber" : "MSFT NVMe Accelerator v1.0",
156+ # "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
157+ # "SerialNumber" : "SN: 000001",
158+ # "UsedBytes" : 536870912000,
159+ # "MaximumLBA" : 1048576000,
160+ # "PhysicalSize" : 536870912000,
161+ # "SectorSize" : 512
162+ # },
163+ # {
164+ # "NameSpace" : 2,
165+ # "DevicePath" : "/dev/nvme0n2",
166+ # "Firmware" : "v1.00000",
167+ # "Index" : 0,
168+ # "ModelNumber" : "MSFT NVMe Accelerator v1.0",
169+ # "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
170+ # "SerialNumber" : "SN: 000001",
171+ # "UsedBytes" : 4294967296,
172+ # "MaximumLBA" : 8388608,
173+ # "PhysicalSize" : 4294967296,
174+ # "SectorSize" : 512
175+ # }
176+ # ]
177+ # }
178+ # root@lisa--170-e0-n0:/home/lisa# nvme -list
179+ # Node SN Model Namespace Usage Format FW Rev # noqa: E501
180+ # --------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- ------- # noqa: E501
181+ # /dev/nvme0n1 SN: 000001 MSFT NVMe Accelerator v1.0 1 536.87 GB / 536.87 GB 512 B + 0 B v1.0000 # noqa: E501
182+ # /dev/nvme0n2 SN: 000001 MSFT NVMe Accelerator v1.0 2 4.29 GB / 4.29 GB 512 B + 0 B v1.0000 # noqa: E501
183+ # /dev/nvme0n3 SN: 000001 MSFT NVMe Accelerator v1.0 15 44.02 GB / 44.02 GB 512 B + 0 B v1.0000 # noqa: E501
184+ # /dev/nvme0n4 SN: 000001 MSFT NVMe Accelerator v1.0 14 6.44 GB / 6.44 GB 512 B + 0 B v1.0000 # noqa: E501
185+ # /dev/nvme1n1 68e8d42a7ed4e5f90002 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
186+ # /dev/nvme2n1 68e8d42a7ed4e5f90001 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
187+ #
188+ # Another example output of nvme -list -o json without DevicePath key
189+ # cmd: ['sudo', 'sh', '-c', 'nvme list -o json 2>/dev/null']
190+ # "Devices":[
191+ # {
192+ # "HostNQN":"nqn.2014-08.org.nvmexpress:uuid:ec2bfbbc-632e-0494-048e-31ebc97bd499",
193+ # "HostID":"ec2bfbbc-632e-0494-048e-31ebc97bd499",
194+ # "Subsystems":[
195+ # {
196+ # "Subsystem":"nvme-subsys0",
197+ # "SubsystemNQN":"nqn.2014-08.org.nvmexpress:uuid:7ad35d50-c05b-47ab-b3a0-56a9a845852b",
198+ # "Controllers":[
199+ # {
200+ # "Controller":"nvme0",
201+ # "Cntlid":"0",
202+ # "SerialNumber":"SN: 00000",
203+ # "ModelNumber":"MSFT NVMe Accelerator v1.0",
204+ # "Firmware":"v1.00000",
205+ # "Transport":"pcie",
206+ # "Address":"c05b:00:00.0",
207+ # "Slot":"2060672336",
208+ # "Namespaces":[
209+ # {
210+ # "NameSpace":"nvme0n1",
211+ # "Generic":"ng0n1",
212+ # "NSID":1,
213+ # "UsedBytes":68719476736,
214+ # "MaximumLBA":134217728,
215+ # "PhysicalSize":68719476736,
216+ # "SectorSize":512
217+ # },
218+ # {
219+ # "NameSpace":"nvme0n10",
220+ # "Generic":"ng0n10",
221+ # "NSID":10,
222+ # "UsedBytes":1099511627776,
223+ # "MaximumLBA":2147483648,
224+ # "PhysicalSize":1099511627776,
225+ # "SectorSize":512
226+ # },
227+ # {
228+ # "NameSpace":"nvme0n11",
229+ # "Generic":"ng0n11",
230+ # "NSID":11,
231+ # "UsedBytes":1099511627776,
232+ # "MaximumLBA":2147483648,
233+ # "PhysicalSize":1099511627776,
234+ # "SectorSize":512
235+ # },
236+ # {
237+ # "NameSpace":"nvme0n12",
238+ # "Generic":"ng0n12",
239+ # "NSID":12,
240+ # "UsedBytes":1099511627776,
241+ # "MaximumLBA":2147483648,
242+ # "PhysicalSize":1099511627776,
243+ # "SectorSize":512
244+ # },
245+ # {
246+ # "NameSpace":"nvme0n13",
247+ # "Generic":"ng0n13",
248+ # "NSID":13,
249+ # "UsedBytes":1099511627776,
250+ # "MaximumLBA":2147483648,
251+ # "PhysicalSize":1099511627776,
252+ # "SectorSize":512
253+ # },
254+ # {
255+ # "NameSpace":"nvme0n14",
256+ # "Generic":"ng0n14",
257+ # "NSID":14,
258+ # "UsedBytes":1099511627776,
259+ # "MaximumLBA":2147483648,
260+ # "PhysicalSize":1099511627776,
261+ # "SectorSize":512
262+ # },
263+ # {
264+ # "NameSpace":"nvme0n15",
265+ # "Generic":"ng0n15",
266+ # "NSID":15,
267+ # "UsedBytes":1099511627776,
268+ # "MaximumLBA":2147483648,
269+ # "PhysicalSize":1099511627776,
270+ # "SectorSize":512
271+ # },
272+ # {
273+ # "NameSpace":"nvme0n16",
274+ # "Generic":"ng0n16",
275+ # "NSID":16,
276+ # "UsedBytes":1099511627776,
277+ # "MaximumLBA":2147483648,
278+ # "PhysicalSize":1099511627776,
279+ # "SectorSize":512
280+ # },
281+ # {
282+ # "NameSpace":"nvme0n17",
283+ # "Generic":"ng0n17",
284+ # "NSID":17,
285+ # "UsedBytes":1099511627776,
286+ # "MaximumLBA":2147483648,
287+ # "PhysicalSize":1099511627776,
288+ # "SectorSize":512
289+ # },
290+ # {
291+ # "NameSpace":"nvme0n2",
292+ # "Generic":"ng0n2",
293+ # "NSID":2,
294+ # "UsedBytes":1099511627776,
295+ # "MaximumLBA":2147483648,
296+ # "PhysicalSize":1099511627776,
297+ # "SectorSize":512
298+ # },
299+ # {
300+ # "NameSpace":"nvme0n3",
301+ # "Generic":"ng0n3",
302+ # "NSID":3,
303+ # "UsedBytes":1099511627776,
304+ # "MaximumLBA":2147483648,
305+ # "PhysicalSize":1099511627776,
306+ # "SectorSize":512
307+ # },
308+ # {
309+ # "NameSpace":"nvme0n4",
310+ # "Generic":"ng0n4",
311+ # "NSID":4,
312+ # "UsedBytes":1099511627776,
313+ # "MaximumLBA":2147483648,
314+ # "PhysicalSize":1099511627776,
315+ # "SectorSize":512
316+ # },
317+ # {
318+ # "NameSpace":"nvme0n5",
319+ # "Generic":"ng0n5",
320+ # "NSID":5,
321+ # "UsedBytes":1099511627776,
322+ # "MaximumLBA":2147483648,
323+ # "PhysicalSize":1099511627776,
324+ # "SectorSize":512
325+ # },
326+ # {
327+ # "NameSpace":"nvme0n6",
328+ # "Generic":"ng0n6",
329+ # "NSID":6,
330+ # "UsedBytes":1099511627776,
331+ # "MaximumLBA":2147483648,
332+ # "PhysicalSize":1099511627776,
333+ # "SectorSize":512
334+ # },
335+ # {
336+ # "NameSpace":"nvme0n7",
337+ # "Generic":"ng0n7",
338+ # "NSID":7,
339+ # "UsedBytes":1099511627776,
340+ # "MaximumLBA":2147483648,
341+ # "PhysicalSize":1099511627776,
342+ # "SectorSize":512
343+ # },
344+ # {
345+ # "NameSpace":"nvme0n8",
346+ # "Generic":"ng0n8",
347+ # "NSID":8,
348+ # "UsedBytes":1099511627776,
349+ # "MaximumLBA":2147483648,
350+ # "PhysicalSize":1099511627776,
351+ # "SectorSize":512
352+ # },
353+ # {
354+ # "NameSpace":"nvme0n9",
355+ # "Generic":"ng0n9",
356+ # "NSID":9,
357+ # "UsedBytes":1099511627776,
358+ # "MaximumLBA":2147483648,
359+ # "PhysicalSize":1099511627776,
360+ # "SectorSize":512
361+ # }
362+ # ],
363+ # "Paths":[
364+ # ]
365+ # }
366+ # ],
367+ # "Namespaces":[
368+ # ]
369+ # }
370+ # ]
371+ # }
372+ # ]
373+ # }
374+ nvme_devices = self .get_devices (force_run = force_run ) # raw ["Devices"]
375+ device_paths = []
376+
377+ def _add (path : str ) -> None :
378+ if isinstance (path , str ) and path .startswith ("/dev/" ) and len (path ) > 5 :
379+ device_paths .append (path )
380+
381+ for nvme_device in nvme_devices or []:
382+ # Legacy schema (flat fields):
383+ _add (nvme_device .get ("DevicePath" ))
384+ # _add(nvme_device.get("GenericPath"))
385+
386+ # New schema: Subsystems → Controllers → Namespaces
387+ for subsystem in nvme_device .get ("Subsystems" ) or []:
388+ for controller in (subsystem or {}).get ("Controllers" ) or []:
389+ for namespace in (controller or {}).get ("Namespaces" ) or []:
390+ namespace_name = namespace .get ("NameSpace" ) # e.g., "nvme0n1"
391+ # generic_name = namespace.get("Generic") # e.g., "ng0n1"
392+ if isinstance (namespace_name , str ) and namespace_name :
393+ _add (f"/dev/{ namespace_name } " )
394+ # if isinstance(generic_name, str) and generic_name:
395+ # _add(f"/dev/{generic_name}")
396+
397+ device_paths = sorted (set (device_paths ))
398+ if not device_paths :
399+ raise LisaException (
400+ "No NVMe device nodes could be derived from 'nvme list -o json'."
401+ )
402+ return device_paths
174403
175404 def get_namespace_ids (self , force_run : bool = False ) -> List [Dict [str , int ]]:
176405 nvme_devices = self .get_devices (force_run = force_run )
0 commit comments