Skip to content

Commit bcce6ec

Browse files
committed
added plugin from internal
1 parent 73f7de8 commit bcce6ec

File tree

6 files changed

+360
-0
lines changed

6 files changed

+360
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
26+
27+
from nodescraper.models import AnalyzerArgs
28+
from nodescraper.plugins.inband.device_enumeration.deviceenumdata import (
29+
DeviceEnumerationDataModel,
30+
)
31+
32+
33+
class DeviceEnumerationAnalyzerArgs(AnalyzerArgs):
34+
cpu_count: list | int = (None,)
35+
gpu_count: list | int = (None,)
36+
vf_count: list | int = (None,)
37+
38+
@classmethod
39+
def build_from_model(
40+
cls, datamodel: DeviceEnumerationDataModel
41+
) -> "DeviceEnumerationAnalyzerArgs":
42+
"""build analyzer args from data model
43+
44+
Args:
45+
datamodel (DeviceEnumerationDataModel): data model for plugin
46+
47+
Returns:
48+
DeviceEnumerationAnalyzerArgs: instance of analyzer args class
49+
"""
50+
return cls(exp_bios_version=datamodel.bios_version)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###########################
26+
27+
from errorscraper.event import EventCategory, EventPriority
28+
29+
from nodescraper.interfaces import DataAnalyzer
30+
from nodescraper.models import TaskResult, TaskStatus
31+
from nodescraper.plugins.inband.deviceenumdata import DeviceEnumerationDataModel
32+
33+
34+
class DeviceEnumerationAnalyzer(
35+
DataAnalyzer[DeviceEnumerationDataModel, DeviceEnumerationAnalyzerArgs]
36+
):
37+
"""Check Device Enumeration matches expected cpu and gpu count
38+
supported by all OSs, SKUs, and platforms."""
39+
40+
DATA_MODEL = DeviceEnumerationDataModel
41+
42+
def analyze_data(
43+
self, data: DeviceEnumerationDataModel, args: Optional[DeviceEnumerationAnalyzerArgs] = None
44+
) -> TaskResult:
45+
46+
if not args:
47+
self.result.message = "Expected Device Enumeration expected data not provided"
48+
self.result.status = TaskStatus.NOT_RAN
49+
return self.result
50+
51+
if isinstance(args.cpu_count, int):
52+
cpu_count = [args.cpu_count]
53+
if isinstance(args.gpu_count, int):
54+
gpu_count = [args.gpu_count]
55+
if isinstance(args.vf_count, int):
56+
vf_count = [args.vf_count]
57+
58+
checks = {}
59+
if cpu_count not in [None, []]:
60+
checks["cpu_count"] = cpu_count
61+
if gpu_count not in [None, []]:
62+
checks["gpu_count"] = gpu_count
63+
if vf_count not in [None, []]:
64+
checks["vf_count"] = vf_count
65+
66+
self.result.message = ""
67+
for check, accepted_counts in checks.items():
68+
actual_count = getattr(data, check)
69+
if actual_count not in accepted_counts:
70+
message = f"Expected {check} in {accepted_counts}, but got {actual_count}. "
71+
self.result.message += message
72+
self.result.status = TaskStatus.ERRORS_DETECTED
73+
self._log_event(
74+
category=EventCategory.PLATFORM,
75+
description=message,
76+
data={check: actual_count},
77+
priority=EventPriority.CRITICAL,
78+
console_log=True,
79+
)
80+
if self.result.message == "":
81+
self.result.status = TaskStatus.OK
82+
self.result.message = f"Device Enumeration validated on {checks.keys()}."
83+
84+
return self.result
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
26+
27+
28+
from nodescraper.base import InBandDataCollector
29+
from nodescraper.connection.inband.inband import CommandArtifact
30+
from nodescraper.enums import EventCategory, EventPriority, OSFamily
31+
from nodescraper.models import TaskResult, TaskStatus
32+
from nodescraper.plugins.inband.devenumdata import DeviceEnumerationDataModel
33+
34+
35+
class DeviceEnumerationCollector(InBandDataCollector[DeviceEnumerationDataModel]):
36+
"""Collect CPU and GPU count"""
37+
38+
DATA_MODEL = DeviceEnumerationDataModel
39+
40+
def _warning(
41+
self,
42+
description: str,
43+
command: CommandArtifact,
44+
category: EventCategory = EventCategory.PLATFORM,
45+
):
46+
self._log_event(
47+
category=category,
48+
description=description,
49+
data={
50+
"command": command.command,
51+
"stdout": command.stdout,
52+
"stderr": command.stderr,
53+
"exit_code": command.exit_code,
54+
},
55+
priority=EventPriority.WARNING,
56+
)
57+
58+
def collect_data(self, args=None) -> tuple[TaskResult, DeviceEnumerationDataModel | None]:
59+
"""
60+
Read CPU and GPU count
61+
On Linux, use lscpu and lspci
62+
On Windows, use WMI and hyper-v cmdlets
63+
"""
64+
device_enum = None
65+
if self.system_info.os_family == OSFamily.LINUX:
66+
baremetal_device_id = self.system_info.devid_ep
67+
sriov_device_id = self.system_info.devid_ep_vf
68+
69+
cpu_count_res = self._run_system_command("lscpu | grep Socket | awk '{ print $2 }'")
70+
gpu_count_res = self._run_system_command(f"lspci -d :{baremetal_device_id} | wc -l")
71+
vf_count_res = self._run_system_command(f"lspci -d :{sriov_device_id} | wc -l")
72+
else:
73+
cpu_count_res = self._run_system_command(
74+
'powershell -Command "(Get-WmiObject -Class Win32_Processor | Measure-Object).Count"'
75+
)
76+
gpu_count_res = self._run_system_command(
77+
'powershell -Command "(wmic path win32_VideoController get name | findstr AMD | Measure-Object).Count"'
78+
)
79+
vf_count_res = self._run_system_command(
80+
'powershell -Command "(Get-VMHostPartitionableGpu | Measure-Object).Count"'
81+
)
82+
cpu_count, gpu_count, vf_count = [None, None, None]
83+
84+
if cpu_count_res.exit_code == 0:
85+
cpu_count = int(cpu_count_res.stdout)
86+
else:
87+
self._warning(description="Cannot determine CPU count", command=cpu_count_res)
88+
89+
if gpu_count_res.exit_code == 0:
90+
gpu_count = int(gpu_count_res.stdout)
91+
else:
92+
self._warning(description="Cannot determine GPU count", command=gpu_count_res)
93+
94+
if vf_count_res.exit_code == 0:
95+
vf_count = int(vf_count_res.stdout)
96+
else:
97+
self._warning(
98+
description="Cannot determine VF count",
99+
command=vf_count_res,
100+
category=EventCategory.SW_DRIVER,
101+
)
102+
103+
if cpu_count or gpu_count or vf_count:
104+
device_enum = DeviceEnumerationDataModel(
105+
cpu_count=cpu_count, gpu_count=gpu_count, vf_count=vf_count
106+
)
107+
self._log_event(
108+
category=EventCategory.PLATFORM,
109+
description=f"Counted {device_enum.cpu_count} CPUs, {device_enum.gpu_count} GPUs, {device_enum.vf_count} VFs",
110+
data=device_enum.model_dump(exclude_none=True),
111+
priority=EventPriority.INFO,
112+
)
113+
self.result.message = f"Device Enumeration: {device_enum.model_dump(exclude_none=True)}"
114+
self.result.status = TaskStatus.OK
115+
else:
116+
self.result.message = "Device Enumeration info not found"
117+
self.result.status = TaskStatus.EXECUTION_FAILURE
118+
self._log_event(
119+
category=EventCategory.SW_DRIVER,
120+
description=self.result.message,
121+
priority=EventPriority.CRITICAL,
122+
)
123+
124+
return self.result, device_enum
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
26+
from nodescraper.base import InBandDataPlugin
27+
28+
from .analyzer_args import DeviceEnumerationAnalyzerArgs
29+
from .device_enumeration_analyzer import DeviceEnumerationAnalyzer
30+
from .device_enumeration_collector import DeviceEnumerationCollector
31+
from .device_enumerationdata import DeviceEnumerationDataModel
32+
33+
34+
class DeviceEnumerationPlugin(
35+
InBandDataPlugin[DeviceEnumerationDataModel, None, DeviceEnumerationAnalyzerArgs]
36+
):
37+
"""Plugin for collection and analysis of BIOS data"""
38+
39+
DATA_MODEL = DeviceEnumerationDataModel
40+
41+
COLLECTOR = DeviceEnumerationCollector
42+
43+
ANALYZER = DeviceEnumerationAnalyzer
44+
45+
ANALYZER_ARGS = DeviceEnumerationAnalyzerArgs
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
26+
from nodescraper.models import DataModel
27+
28+
29+
class DeviceEnumerationDataModel(DataModel):
30+
cpu_count: int | None = None
31+
gpu_count: int | None = None
32+
vf_count: int | None = None

0 commit comments

Comments
 (0)