3131from nodescraper .enums import EventCategory , EventPriority , ExecutionStatus , OSFamily
3232from nodescraper .models import TaskResult
3333
34- from .kernel_module_data import KernelModuleDataModel
34+ from .kernel_module_data import KernelModuleDataModel , ModuleInfo , ModuleParameter
3535
3636
3737class KernelModuleCollector (InBandDataCollector [KernelModuleDataModel , None ]):
@@ -62,6 +62,77 @@ def parse_proc_modules(self, output: dict) -> dict:
6262 }
6363 return modules
6464
65+ def _parse_modinfo (self , output : str ) -> Optional [ModuleInfo ]:
66+ """Parse modinfo command output into structured ModuleInfo
67+
68+ Args:
69+ output (str): modinfo command output
70+
71+ Returns:
72+ Optional[ModuleInfo]: parsed module information or None if parsing fails
73+ """
74+ if not output or not output .strip ():
75+ return None
76+
77+ module_info = ModuleInfo ()
78+
79+ for line in output .splitlines ():
80+ line = line .strip ()
81+ if not line or ":" not in line :
82+ continue
83+
84+ field , _ , value = line .partition (":" )
85+ field = field .strip ()
86+ value = value .strip ()
87+
88+ if field == "filename" :
89+ module_info .filename = value
90+ elif field == "version" :
91+ module_info .version = value
92+ elif field == "license" :
93+ module_info .license = value
94+ elif field == "description" :
95+ module_info .description = value
96+ elif field == "author" :
97+ module_info .author .append (value )
98+ elif field == "firmware" :
99+ module_info .firmware .append (value )
100+ elif field == "srcversion" :
101+ module_info .srcversion = value
102+ elif field == "depends" :
103+ if value :
104+ module_info .depends = [dep .strip () for dep in value .split ("," ) if dep .strip ()]
105+ elif field == "name" :
106+ module_info .name = value
107+ elif field == "vermagic" :
108+ module_info .vermagic = value
109+ elif field == "sig_id" :
110+ module_info .sig_id = value
111+ elif field == "signer" :
112+ module_info .signer = value
113+ elif field == "sig_key" :
114+ module_info .sig_key = value
115+ elif field == "sig_hashalgo" :
116+ module_info .sig_hashalgo = value
117+ elif field == "parm" :
118+ param_name , param_desc = value .split (":" , 1 ) if ":" in value else (value , "" )
119+ param_name = param_name .strip ()
120+ param_desc = param_desc .strip ()
121+
122+ param_type = None
123+ if param_desc and "(" in param_desc and ")" in param_desc :
124+ type_start = param_desc .rfind ("(" )
125+ type_end = param_desc .rfind (")" )
126+ if type_start < type_end :
127+ param_type = param_desc [type_start + 1 : type_end ].strip ()
128+ param_desc = param_desc [:type_start ].strip ()
129+
130+ module_info .parm .append (
131+ ModuleParameter (name = param_name , type = param_type , description = param_desc )
132+ )
133+
134+ return module_info
135+
65136 def get_module_parameters (self , module_name : str ) -> dict :
66137 """Fetches parameter names and values for a given kernel module using _run_sut_cmd
67138
@@ -145,12 +216,23 @@ def collect_data(self, args=None) -> tuple[TaskResult, Optional[KernelModuleData
145216 else :
146217 kernel_modules = self .collect_all_module_info ()
147218
148- # Collect modinfo amdgpu output as artifact
219+ amdgpu_modinfo = None
220+ if self .system_info .os_family != OSFamily .WINDOWS :
221+ # Collect and parse modinfo amdgpu output
149222 modinfo_res = self ._run_sut_cmd (self .CMD_MODINFO_AMDGPU )
150223 if modinfo_res .exit_code == 0 and modinfo_res .stdout :
151- self .result .artifacts .append (
152- TextFileArtifact (filename = "modinfo_amdgpu.txt" , contents = modinfo_res .stdout )
153- )
224+ amdgpu_modinfo = self ._parse_modinfo (modinfo_res .stdout )
225+ if amdgpu_modinfo :
226+ self .result .artifacts .append (
227+ TextFileArtifact (filename = "modinfo_amdgpu.txt" , contents = modinfo_res .stdout )
228+ )
229+ else :
230+ self ._log_event (
231+ category = EventCategory .OS ,
232+ description = "Could not parse modinfo amdgpu output" ,
233+ data = {"command" : modinfo_res .command },
234+ priority = EventPriority .WARNING ,
235+ )
154236 else :
155237 self ._log_event (
156238 category = EventCategory .OS ,
@@ -164,7 +246,9 @@ def collect_data(self, args=None) -> tuple[TaskResult, Optional[KernelModuleData
164246 )
165247
166248 if kernel_modules :
167- km_data = KernelModuleDataModel (kernel_modules = kernel_modules )
249+ km_data = KernelModuleDataModel (
250+ kernel_modules = kernel_modules , amdgpu_modinfo = amdgpu_modinfo
251+ )
168252 self ._log_event (
169253 category = "KERNEL_READ" ,
170254 description = "Kernel modules read" ,
0 commit comments