Merge lp:~nelson-chu/opencompute/add-ocp-certified-jobs into lp:opencompute/checkbox
- add-ocp-certified-jobs
- Merge into checkbox
Proposed by
Nelson Chu
Status: | Rejected |
---|---|
Rejected by: | Jeff Lane |
Proposed branch: | lp:~nelson-chu/opencompute/add-ocp-certified-jobs |
Merge into: | lp:opencompute/checkbox |
Diff against target: |
1510 lines (+1391/-0) 24 files modified
data/whitelists/opencompute-certify-local.whitelist (+100/-0) jobs/TC-001-0001-CPU_Memory.txt (+25/-0) jobs/TC-001-0002-Platform_Controller_Hub.txt (+11/-0) jobs/TC-001-0003-BIOS_setup_menu.txt (+5/-0) jobs/TC-001-0004-BIOS_remote_update.txt (+17/-0) jobs/TC-001-0005-BIOS_event_log.txt (+5/-0) jobs/TC-002-0001-Initial_machine_provisioning.txt (+17/-0) jobs/TC-002-0004-Boot_order_PXE.txt (+5/-0) jobs/TC-002-0005-Remote_serial_console.txt (+14/-0) jobs/TC-003-0001-Hardware_information.txt (+54/-0) jobs/TC-003-0002-Idle_test.txt (+5/-0) jobs/TC-003-0003-Network_performance.txt (+5/-0) jobs/TC-003-0004-Disk_performance.txt (+6/-0) jobs/TC-004-0001-Knox_testing.txt (+45/-0) scripts/bios_info (+63/-0) scripts/cpu_info (+77/-0) scripts/create_raid6 (+121/-0) scripts/disk_info (+66/-0) scripts/memory_info (+65/-0) scripts/processor_topology (+123/-0) scripts/raid_hdd_info (+59/-0) scripts/raid_info (+49/-0) scripts/read_write_file (+177/-0) scripts/rebulid_raid (+277/-0) |
To merge this branch: | bzr merge lp:~nelson-chu/opencompute/add-ocp-certified-jobs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeff Lane | Disapprove | ||
Review via email: mp+196476@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 2169. By Nelson Chu
-
Add OCP certified jobs
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'data/whitelists/opencompute-certify-local.whitelist' |
2 | --- data/whitelists/opencompute-certify-local.whitelist 1970-01-01 00:00:00 +0000 |
3 | +++ data/whitelists/opencompute-certify-local.whitelist 2013-11-25 07:01:57 +0000 |
4 | @@ -0,0 +1,100 @@ |
5 | +# Resource Jobs |
6 | +block_device |
7 | +cdimage |
8 | +cpuinfo |
9 | +device |
10 | +dmi |
11 | +dpkg |
12 | +efi |
13 | +environment |
14 | +gconf |
15 | +lsb |
16 | +meminfo |
17 | +module |
18 | +optical_drive |
19 | +package |
20 | +sleep |
21 | +uname |
22 | +#Info attachment jobs |
23 | +__info__ |
24 | +cpuinfo_attachment |
25 | +dmesg_attachment |
26 | +dmi_attachment |
27 | +dmidecode_attachment |
28 | +efi_attachment |
29 | +lspci_attachment |
30 | +lshw_attachment |
31 | +mcelog_attachment |
32 | +meminfo_attachment |
33 | +modprobe_attachment |
34 | +modules_attachment |
35 | +sysctl_attachment |
36 | +sysfs_attachment |
37 | +udev_attachment |
38 | +lsmod_attachment |
39 | +acpi_sleep_attachment |
40 | +info/hdparm |
41 | +info/hdparm_.*.txt |
42 | +installer_debug.gz |
43 | +info/disk_partitions |
44 | +# Actual test cases |
45 | +__TC-001-0001-CPU_Memory__ |
46 | +TC-001-0001-001 CPU information |
47 | +TC-001-0001-002 CPU topology |
48 | +TC-001-0001-003 Single Processor Mode |
49 | +TC-001-0001-004 Intel QPI |
50 | +TC-001-0001-005 Memory Information |
51 | + |
52 | +__TC-001-0002-Platform_Controller_Hub__ |
53 | +TC-001-0002-001 SATA port |
54 | +TC-001-0002-002 USB 2.0 |
55 | +TC-001-0002-003 Mini-SAS port |
56 | + |
57 | +__TC-001-0003-BIOS_setup_menu__ |
58 | +TC-001-0003-001 BIOS setup menu |
59 | + |
60 | +__TC-001-0004-BIOS_remote_update__ |
61 | +TC-001-0004-001 Scenario 1 |
62 | +TC-001-0004-002 Scenario 2 |
63 | +TC-001-0004-003 Scenario 3 |
64 | + |
65 | +__TC-001-0005-BIOS_event_log__ |
66 | +TC-001-0005-001 BIOS event log |
67 | + |
68 | +__TC-002-0001-Initial_machine_provisioning__ |
69 | +TC-002-0001-001 Inventory information |
70 | +TC-002-0001-002 IP lease information |
71 | +TC-002-0001-003 Monitor attachment |
72 | + |
73 | +__TC-002-0004-Boot_order_PXE__ |
74 | +TC-002-0004-001 Boot Order / PXE |
75 | + |
76 | +__TC-002-0005-Remote_serial_console__ |
77 | +TC-002-0005-001 Enable SOL |
78 | +TC-002-0005-002 SOL operation |
79 | + |
80 | +__TC-003-0001-Hardware_information__ |
81 | +TC-003-0001-001 CPU information |
82 | +TC-003-0001-002 Memory information |
83 | +TC-003-0001-003 Disk information |
84 | +TC-003-0001-004 BIOS information |
85 | +TC-003-0001-005 ME information |
86 | +TC-003-0001-006 NIC information |
87 | +TC-003-0001-007 RAID information |
88 | +TC-003-0001-008 HBA information |
89 | + |
90 | +___TC-003-0002-Idle_test__ |
91 | +TC-003-0002-001 12 hours idle |
92 | + |
93 | +__TC-003-0003-Network_performance__ |
94 | +TC-003-0003-001 Network performance |
95 | + |
96 | +__TC-003-0004-Disk_performance__ |
97 | +TC-003-0004-001 Disk performance |
98 | + |
99 | +__TC-004-0001-Knox_testing__ |
100 | +TC-004-0001-001-RAID_card_information |
101 | +TC-004-0002-001-Get_all_HDD |
102 | +TC-004-0003-001-Build_raid_6 |
103 | +TC-004-0004-001-Read/Write_file |
104 | +TC-004-0005-001-Rebuild_Raid |
105 | |
106 | === added file 'jobs/TC-001-0001-CPU_Memory.txt' |
107 | --- jobs/TC-001-0001-CPU_Memory.txt 1970-01-01 00:00:00 +0000 |
108 | +++ jobs/TC-001-0001-CPU_Memory.txt 2013-11-25 07:01:57 +0000 |
109 | @@ -0,0 +1,25 @@ |
110 | +plugin: shell |
111 | +name: TC-001-0001-001 CPU information |
112 | +requires: package.name == 'lshw' |
113 | +command: cpu_info |
114 | +description: |
115 | + 1. Gathering CPU information by using lshw command. |
116 | + 2. Output CPU model and L1, L2, L3 cache size. |
117 | + 3. Pass criteria: CPU model should belong to Intel Xeon processor E5-2600 product family and Last Level Cache (LLC) should be larger than 20MB |
118 | + |
119 | +plugin: shell |
120 | +name: TC-001-0001-002 CPU topology |
121 | +command: processor_topology |
122 | +description: |
123 | + 1. Gathering CPU information by using lscpu command. |
124 | + 2. Output the total number of CPU, the number of Thread per core, the number of Core per Socket, and the number of Socket. |
125 | + 3. Pass criteria: It should be 8 cores per CPU and 2 Threads per core (that is, up to 16 threads with Hyper-Threading Technology per CPU). |
126 | + |
127 | +plugin: shell |
128 | +name: TC-001-0001-003 Memory Information |
129 | +requires: package.name == 'lshw' |
130 | +command: memory_info |
131 | +description: |
132 | + 1. Gathering memory information by using lshw command. |
133 | + 2. Output memory module, vendor, size and slot. |
134 | + 3. Pass criteria: 2 DDR3 slots per channel per processor (total of 16 DIMMs on the motherboard). |
135 | |
136 | === added file 'jobs/TC-001-0002-Platform_Controller_Hub.txt' |
137 | --- jobs/TC-001-0002-Platform_Controller_Hub.txt 1970-01-01 00:00:00 +0000 |
138 | +++ jobs/TC-001-0002-Platform_Controller_Hub.txt 2013-11-25 07:01:57 +0000 |
139 | @@ -0,0 +1,11 @@ |
140 | +plugin: shell |
141 | +name: TC-001-0002-001 SATA port |
142 | +command: echo "manual"; exit 1 |
143 | +description: |
144 | + individual SATA 6Gps ports from SATA port 0/1. |
145 | + |
146 | +plugin: shell |
147 | +name: TC-001-0002-002 USB 2.0 |
148 | +command: echo "manual"; exit 1 |
149 | +description: |
150 | + USB 2.0 ports (2 designed in this board: one front connector, one vertical onboard) |
151 | |
152 | === added file 'jobs/TC-001-0003-BIOS_setup_menu.txt' |
153 | --- jobs/TC-001-0003-BIOS_setup_menu.txt 1970-01-01 00:00:00 +0000 |
154 | +++ jobs/TC-001-0003-BIOS_setup_menu.txt 2013-11-25 07:01:57 +0000 |
155 | @@ -0,0 +1,5 @@ |
156 | +plugin: shell |
157 | +name: TC-001-0003-001 BIOS setup menu |
158 | +command: echo "manual"; exit 1 |
159 | +description: |
160 | + BIOS setup menu. |
161 | |
162 | === added file 'jobs/TC-001-0004-BIOS_remote_update.txt' |
163 | --- jobs/TC-001-0004-BIOS_remote_update.txt 1970-01-01 00:00:00 +0000 |
164 | +++ jobs/TC-001-0004-BIOS_remote_update.txt 2013-11-25 07:01:57 +0000 |
165 | @@ -0,0 +1,17 @@ |
166 | +plugin: shell |
167 | +name: TC-001-0004-001 Scenario 1 |
168 | +command: echo "Scenario 1: Sample/Audit BIOS settings."; echo "Not implemented yet"; exit 1 |
169 | +description: |
170 | + Scenario 1: Sample/Audit BIOS settings. |
171 | + |
172 | +plugin: shell |
173 | +name: TC-001-0004-002 Scenario 2 |
174 | +command: echo "Scenario 2: Update BIOS with pre-configured set of BIOS settings."; echo "Not implemented yet";exit 1 |
175 | +description: |
176 | + Scenario 2: Update BIOS with pre-configured set of BIOS settings. |
177 | + |
178 | +plugin: shell |
179 | +name: TC-001-0004-003 Scenario 3 |
180 | +command: echo "Scenario 3: BIOS/firmware update with a new revision."; echo "Not implemented yet"; exit 1 |
181 | +description: |
182 | + Scenario 1: BIOS/firmware update with a new revision. |
183 | |
184 | === added file 'jobs/TC-001-0005-BIOS_event_log.txt' |
185 | --- jobs/TC-001-0005-BIOS_event_log.txt 1970-01-01 00:00:00 +0000 |
186 | +++ jobs/TC-001-0005-BIOS_event_log.txt 2013-11-25 07:01:57 +0000 |
187 | @@ -0,0 +1,5 @@ |
188 | +plugin: shell |
189 | +name: TC-001-0005-001 BIOS event log |
190 | +command: echo "manual"; exit 1 |
191 | +description: |
192 | + BIOS event log. Logged errors and error threshold setting. |
193 | |
194 | === added file 'jobs/TC-002-0001-Initial_machine_provisioning.txt' |
195 | --- jobs/TC-002-0001-Initial_machine_provisioning.txt 1970-01-01 00:00:00 +0000 |
196 | +++ jobs/TC-002-0001-Initial_machine_provisioning.txt 2013-11-25 07:01:57 +0000 |
197 | @@ -0,0 +1,17 @@ |
198 | +plugin: shell |
199 | +name: TC-002-0001-001 Inventory information |
200 | +command: echo "MAC address and/or other inventory information feeds/bar codes from the machine's manufacturer."; echo "Not implemented yet"; exit 1 |
201 | +description: |
202 | + MAC address and/or other inventory information feeds/bar codes from the machine's manufacturer. |
203 | + |
204 | +plugin: shell |
205 | +name: TC-002-0001-002 IP lease information |
206 | +command: echo "Searching through IP lease information to find machines that have gotten a DHCP leases for their management interfaces."; echo "Not implemented yet"; exit 1 |
207 | +description: |
208 | + Searching through IP lease information to find machines that have gotten a DHCP leases for their management interfaces. |
209 | + |
210 | +plugin: shell |
211 | +name: TC-002-0001-003 Monitor attachment |
212 | +command: echo "manual"; exit 1 |
213 | +description: |
214 | + Attach KVM to setup machine. |
215 | |
216 | === added file 'jobs/TC-002-0004-Boot_order_PXE.txt' |
217 | --- jobs/TC-002-0004-Boot_order_PXE.txt 1970-01-01 00:00:00 +0000 |
218 | +++ jobs/TC-002-0004-Boot_order_PXE.txt 2013-11-25 07:01:57 +0000 |
219 | @@ -0,0 +1,5 @@ |
220 | +plugin: shell |
221 | +name: TC-002-0004-001 Boot Order / PXE |
222 | +command: echo "Not implemented yet"; exit 1 |
223 | +description: |
224 | + Boot form PXE. |
225 | |
226 | === added file 'jobs/TC-002-0005-Remote_serial_console.txt' |
227 | --- jobs/TC-002-0005-Remote_serial_console.txt 1970-01-01 00:00:00 +0000 |
228 | +++ jobs/TC-002-0005-Remote_serial_console.txt 2013-11-25 07:01:57 +0000 |
229 | @@ -0,0 +1,14 @@ |
230 | +plugin: shell |
231 | +name: TC-002-0005-001 Enable SOL |
232 | +command: echo "manual"; exit 1 |
233 | +description: |
234 | + SOL BIOS setup. |
235 | + |
236 | +plugin: shell |
237 | +name: TC-002-0005-002 SOL operation |
238 | +command: echo "manual"; exit 1 |
239 | +description: |
240 | + 1. Remote control the SUT by using IPMI SOL. |
241 | + 2. SOL that will allow to operate the SUT on: pre-boot process, BIOS setup, boot process, access to the installed OS |
242 | + 3. Pass criteria: Successfully operate the SUT in the scenarios listed above. |
243 | + |
244 | |
245 | === added file 'jobs/TC-003-0001-Hardware_information.txt' |
246 | --- jobs/TC-003-0001-Hardware_information.txt 1970-01-01 00:00:00 +0000 |
247 | +++ jobs/TC-003-0001-Hardware_information.txt 2013-11-25 07:01:57 +0000 |
248 | @@ -0,0 +1,54 @@ |
249 | +plugin: shell |
250 | +name: TC-003-0001-001 CPU information |
251 | +command: echo "refer to TC-001-0001-001" |
252 | +description: |
253 | + To verify CPU information with specification. Show CPU type and speed. |
254 | + |
255 | +plugin: shell |
256 | +name: TC-003-0001-002 Memory information |
257 | +command: echo "refer to TC-001-0001-003" |
258 | +description: |
259 | + To verify memory information with specification. Show memory vendor, location and size. |
260 | + |
261 | +plugin: shell |
262 | +name: TC-003-0001-003 Disk information |
263 | +requires: package.name == 'lshw' |
264 | +command: disk_info |
265 | +description: |
266 | + 1. Gathering disk information by using lshw command. |
267 | + 2. Output Disk type, vendor, product, capacity. |
268 | + 3. Pass criteria: If catch the information then pass. |
269 | + |
270 | +plugin: shell |
271 | +name: TC-003-0001-004 BIOS information |
272 | +requires: package.name == 'lshw' |
273 | +command: bios_info |
274 | +description: |
275 | + 1. Gathering BIOS information by using lshw command. |
276 | + 2. Output BIOS vendor, version and release date. |
277 | + 3. Pass criteria: If catch the information then pass. |
278 | + |
279 | +plugin: shell |
280 | +name: TC-003-0001-005 ME information |
281 | +command: echo "Show Intel ME information."; echo "Refer to DCMI job." |
282 | +description: |
283 | + Show Intel ME information. |
284 | + |
285 | +plugin: shell |
286 | +name: TC-003-0001-006 NIC information |
287 | +command: network_device_info |
288 | +description: |
289 | + 1. Gathering NIC information by using udevadm command. |
290 | + 2. Output Interface, product, vendor, driver, device path. |
291 | + 3. Pass criteria: If catch the information then pass. |
292 | + |
293 | +plugin: shell |
294 | +name: TC-003-0001-007 RAID card information |
295 | +requires: |
296 | + package.name == 'megacli' |
297 | + package.name == 'megactl' |
298 | +command: raid_info |
299 | +description: |
300 | + 1. Gathering LSI RAID card information by using megasasctl command. |
301 | + 2. Show adapter, product name, memory, BBU, serial no. |
302 | + 3. Pass criteria: If catch the information then pass. |
303 | |
304 | === added file 'jobs/TC-003-0002-Idle_test.txt' |
305 | --- jobs/TC-003-0002-Idle_test.txt 1970-01-01 00:00:00 +0000 |
306 | +++ jobs/TC-003-0002-Idle_test.txt 2013-11-25 07:01:57 +0000 |
307 | @@ -0,0 +1,5 @@ |
308 | +plugin: shell |
309 | +name: TC-003-0002-001 12 hours idle |
310 | +command: echo "Leave server sitting idle for 12 hours. Verify after 12 hours that the system is still stable."; echo "Not implemented yet"; exit 1 |
311 | +description: |
312 | + Leave server sitting idle for 12 hours. Verify after 12 hours that the system is still stable. |
313 | |
314 | === added file 'jobs/TC-003-0003-Network_performance.txt' |
315 | --- jobs/TC-003-0003-Network_performance.txt 1970-01-01 00:00:00 +0000 |
316 | +++ jobs/TC-003-0003-Network_performance.txt 2013-11-25 07:01:57 +0000 |
317 | @@ -0,0 +1,5 @@ |
318 | +plugin: shell |
319 | +name: TC-003-0003-001 Network performance |
320 | +command: echo "Tx/Rx Gbps for 10G NIC spec. >9.5 Gbps"; echo "Not implemented yet"; exit 1 |
321 | +description: |
322 | + Tx/Rx Gbps for 10G NIC spec. > 9.5 Gbps |
323 | |
324 | === added file 'jobs/TC-003-0004-Disk_performance.txt' |
325 | --- jobs/TC-003-0004-Disk_performance.txt 1970-01-01 00:00:00 +0000 |
326 | +++ jobs/TC-003-0004-Disk_performance.txt 2013-11-25 07:01:57 +0000 |
327 | @@ -0,0 +1,6 @@ |
328 | +plugin: shell |
329 | +name: TC-003-0004-001 Disk performance |
330 | +command: echo "SMART threshold, grown defect list glist = reallocated sectors = 200 for 4TB, glist = 100 for 2TB for all vendors. |
331 | +SMART HDD temp = 60C."; echo "Not implemented yet"; exit 1 |
332 | +description: |
333 | + Test disk performance. |
334 | |
335 | === added file 'jobs/TC-004-0001-Knox_testing.txt' |
336 | --- jobs/TC-004-0001-Knox_testing.txt 1970-01-01 00:00:00 +0000 |
337 | +++ jobs/TC-004-0001-Knox_testing.txt 2013-11-25 07:01:57 +0000 |
338 | @@ -0,0 +1,45 @@ |
339 | +plugin: shell |
340 | +name: TC-004-0001-001-RAID_card_information |
341 | +command: echo "refer to TC-003-0001-007" |
342 | +description: |
343 | + RAID card information |
344 | + |
345 | +plugin: shell |
346 | +name: TC-004-0002-001-Get_all_HDD |
347 | +requires: |
348 | + package.name == 'megacli' |
349 | + package.name == 'megactl' |
350 | +depends: TC-004-0001-001 RAID card information |
351 | +command: raid_hdd_info |
352 | +description: |
353 | + Get knox all HDD. |
354 | + |
355 | +plugin: shell |
356 | +name: TC-004-0003-001-Build_raid_6 |
357 | +requires: |
358 | + package.name == 'megacli' |
359 | + package.name == 'megactl' |
360 | +depends: TC-004-0002-001-Get_all_HDD |
361 | +command: create_raid6 |
362 | +description: |
363 | + Build Raid 6 |
364 | + |
365 | +plugin: shell |
366 | +name: TC-004-0004-001-Read/Write_file |
367 | +depends: TC-004-0003-001-Build_raid_6 |
368 | +description: Test RAID Read/Write file |
369 | +user: root |
370 | +command: |
371 | + exit 1 |
372 | + |
373 | +plugin: shell |
374 | +name: TC-004-0005-001-Rebuild_Raid |
375 | +requires: |
376 | + package.name == 'megacli' |
377 | + package.name == 'megactl' |
378 | +depends: TC-004-0004-001-Read/Write_file |
379 | +environ: CHECKBOX_DATA |
380 | +user: root |
381 | +command: rebulid_raid -l $CHECKBOX_DATA/rebulid_raid.log |
382 | +description: |
383 | + Re-build Raid |
384 | |
385 | === added file 'scripts/bios_info' |
386 | --- scripts/bios_info 1970-01-01 00:00:00 +0000 |
387 | +++ scripts/bios_info 2013-11-25 07:01:57 +0000 |
388 | @@ -0,0 +1,63 @@ |
389 | +#!/usr/bin/env python3 |
390 | +""" |
391 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
392 | +Industrial Technology Research Institute |
393 | + |
394 | +bios_info |
395 | + Gathering BIOS information by using lshw command. |
396 | + And output BIOS vendor, version and release date. |
397 | + |
398 | +Authors |
399 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
400 | + |
401 | +This program is free software: you can redistribute it and/or modify |
402 | +it under the terms of the GNU General Public License version 3, |
403 | +as published by the Free Software Foundation. |
404 | + |
405 | +This program is distributed in the hope that it will be useful, |
406 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
407 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
408 | +GNU General Public License for more details. |
409 | + |
410 | +You should have received a copy of the GNU General Public License |
411 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
412 | + |
413 | +""" |
414 | + |
415 | +import os |
416 | +import sys |
417 | +import xml.etree.ElementTree as ET |
418 | +from subprocess import check_output |
419 | + |
420 | + |
421 | +def main(): |
422 | + attribute = ['vendor', 'version', 'date'] |
423 | + command = 'lshw -xml' |
424 | + with open(os.devnull, "w") as NULL: |
425 | + hwinfo_xml = check_output(command, stderr=NULL, shell=True) |
426 | + root = ET.fromstring(hwinfo_xml) |
427 | + |
428 | + # Parser lshw XML for gather BIOS information. |
429 | + bios_info = root.findall(".//node[@id='firmware']") |
430 | + |
431 | + if not bios_info: |
432 | + print("Can not parser any BIOS information.") |
433 | + return 10 |
434 | + |
435 | + for bios in bios_info: |
436 | + for attr in attribute: |
437 | + if bios.find(attr) is None: |
438 | + print(("Can not found BIOS %s") %attr) |
439 | + return 20 |
440 | + |
441 | + for attr in attribute: |
442 | + if attr == 'date': |
443 | + print(('release date=%s.') %(bios.find(attr).text)), |
444 | + continue |
445 | + print(('%s=%s,') %(attr, bios.find(attr).text)), |
446 | + print() |
447 | + |
448 | + return 0 |
449 | + |
450 | +if __name__ == '__main__': |
451 | + sys.exit(main()) |
452 | |
453 | === added file 'scripts/cpu_info' |
454 | --- scripts/cpu_info 1970-01-01 00:00:00 +0000 |
455 | +++ scripts/cpu_info 2013-11-25 07:01:57 +0000 |
456 | @@ -0,0 +1,77 @@ |
457 | +#!/usr/bin/env python3 |
458 | +""" |
459 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
460 | +Industrial Technology Research Institute |
461 | + |
462 | +cpu_info |
463 | + Gathering CPU information by using lshw command. |
464 | + And output CPU model and L1, L2, L3 cache size. |
465 | + L3 Cache should be larger than 20MB. |
466 | + |
467 | +Authors |
468 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
469 | + |
470 | +This program is free software: you can redistribute it and/or modify |
471 | +it under the terms of the GNU General Public License version 3, |
472 | +as published by the Free Software Foundation. |
473 | + |
474 | +This program is distributed in the hope that it will be useful, |
475 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
476 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
477 | +GNU General Public License for more details. |
478 | + |
479 | +You should have received a copy of the GNU General Public License |
480 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
481 | + |
482 | +""" |
483 | + |
484 | +import os |
485 | +import re |
486 | +import sys |
487 | +import xml.etree.ElementTree as ET |
488 | +from subprocess import check_output |
489 | + |
490 | +def main(): |
491 | + command = 'lshw -xml' |
492 | + with open(os.devnull, "w") as NULL: |
493 | + hwinfo_xml = check_output(command, stderr=NULL, shell=True) |
494 | + root = ET.fromstring(hwinfo_xml) |
495 | + |
496 | + # Parser lshw XML for gather processor information. |
497 | + processor = root.findall(".//product/..[@class='processor']") |
498 | + |
499 | + if not processor: |
500 | + print("Can not parser any processor information.") |
501 | + return 10 |
502 | + |
503 | + for cpu in processor: |
504 | + if cpu.find('product') is None: |
505 | + print("Can not found processor product.") |
506 | + return 20 |
507 | + print(cpu.find('product').text) |
508 | + |
509 | + cache_list = cpu.findall(".//size/..[@class='memory']") |
510 | + if not cache_list: |
511 | + print("Can not found any CPU cache.") |
512 | + return 30 |
513 | + |
514 | + for cache in cache_list: |
515 | + if cache.find('size') is None or cache.find('slot') is None: |
516 | + print("Can not access Last Level Cache (LLC).") |
517 | + return 40 |
518 | + |
519 | + cache_size = int(cache.find('size').text) / 1024 |
520 | + if cache_size > 1024: |
521 | + cache_size = cache_size / 1024 |
522 | + print(('%s %d MB') %(cache.find('slot').text, cache_size)) |
523 | + if re.search('L3', cache.find('slot').text): |
524 | + if cache_size < 20: |
525 | + print('L3 cache size less than 20MB.') |
526 | + return 50 |
527 | + else: |
528 | + print(('%s %d KB') %(cache.find('slot').text, cache_size)) |
529 | + |
530 | + return 0 |
531 | + |
532 | +if __name__ == '__main__': |
533 | + sys.exit(main()) |
534 | |
535 | === added file 'scripts/create_raid6' |
536 | --- scripts/create_raid6 1970-01-01 00:00:00 +0000 |
537 | +++ scripts/create_raid6 2013-11-25 07:01:57 +0000 |
538 | @@ -0,0 +1,121 @@ |
539 | +#!/usr/bin/env python3 |
540 | +""" |
541 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
542 | +Industrial Technology Research Institute |
543 | + |
544 | +create_raid6 |
545 | + Using megacli command build RAID 6 on knox. |
546 | + |
547 | + Warning: Make sure there is no RAID configuration in LSI RAID card |
548 | + before this program is executed. |
549 | + |
550 | +Authors |
551 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
552 | + |
553 | +This program is free software: you can redistribute it and/or modify |
554 | +it under the terms of the GNU General Public License version 3, |
555 | +as published by the Free Software Foundation. |
556 | + |
557 | +This program is distributed in the hope that it will be useful, |
558 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
559 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
560 | +GNU General Public License for more details. |
561 | + |
562 | +You should have received a copy of the GNU General Public License |
563 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
564 | + |
565 | +""" |
566 | + |
567 | +import os |
568 | +import re |
569 | +import sys |
570 | +from subprocess import check_output, check_call |
571 | + |
572 | + |
573 | +def get_adapter(): |
574 | + """ |
575 | + Gather all adapter number if there are multiple RAID card. |
576 | + """ |
577 | + |
578 | + command = 'megacli -CfgDsply -Aall|grep Adapter' |
579 | + adapter_list = [] |
580 | + |
581 | + adapter_info = check_output(command, shell=True) |
582 | + adapter_info = adapter_info.decode('utf-8') |
583 | + |
584 | + for adapter in adapter_info.strip().split('\n'): |
585 | + adapter_list.append(adapter.strip().split(' ')[-1]) |
586 | + return adapter_list |
587 | + |
588 | + |
589 | +def get_all_disk(adapter): |
590 | + """ |
591 | + Gather all disks Enclosure and Slot number, and make a |
592 | + Enclosure:Slot pair list. |
593 | + """ |
594 | + |
595 | + command = 'megacli -PDList -A{0}'.format(adapter) \ |
596 | + + '|grep -E "Enclosure Device ID|Slot Number"' |
597 | + |
598 | + disk_list = [] |
599 | + disk_info = check_output(command, shell=True) |
600 | + disk_info = disk_info.decode('utf-8') |
601 | + |
602 | + for line in disk_info.strip().split('\n'): |
603 | + if line.startswith('Enclosure'): |
604 | + match = re.search(r'\d+', line) |
605 | + disk_list.append(match.group(0)) |
606 | + if line.startswith('Slot'): |
607 | + match = re.search(r'\d+', line) |
608 | + enclosure = disk_list.pop() |
609 | + E_S = '%s:%s' %(enclosure, match.group(0)) |
610 | + disk_list.append(E_S) |
611 | + return disk_list |
612 | + |
613 | + |
614 | +def build_raid(adapter, disk_list): |
615 | + """ |
616 | + Use all disk creatd RAID 6 and set last disk as hot spare. |
617 | + """ |
618 | + |
619 | + # use the last disk as hot spare |
620 | + spare = disk_list.pop() |
621 | + |
622 | + disk = ','.join(disk_list) |
623 | + command = 'megacli -CfgLDadd -r6 [{0}] WB Direct -Hsp[{1}] -a{2}'.format( |
624 | + disk, spare, adapter) |
625 | + |
626 | + check_call(command, shell=True) |
627 | + |
628 | + |
629 | +def main(): |
630 | + knox_dict = {} |
631 | + |
632 | + # get RAID card adapter number |
633 | + try: |
634 | + adapter_list = get_adapter() |
635 | + except Exception as e: |
636 | + print('Error: %s' %e) |
637 | + return 10 |
638 | + |
639 | + # get all disk in RAID card |
640 | + try: |
641 | + for adapter in adapter_list: |
642 | + knox_dict[adapter] = get_all_disk(adapter) |
643 | + except Exception as e: |
644 | + print('Error: %s' %e) |
645 | + return 20 |
646 | + |
647 | + # use all HDD build RAID |
648 | + try: |
649 | + for adapter, disk_list in knox_dict.items(): |
650 | + build_raid(adapter, disk_list) |
651 | + except Exception as e: |
652 | + print('Error: Knox build raid 6 failed.') |
653 | + return 30 |
654 | + |
655 | + return 0 |
656 | + |
657 | + |
658 | +if __name__ == '__main__': |
659 | + sys.exit(main()) |
660 | |
661 | === added file 'scripts/disk_info' |
662 | --- scripts/disk_info 1970-01-01 00:00:00 +0000 |
663 | +++ scripts/disk_info 2013-11-25 07:01:57 +0000 |
664 | @@ -0,0 +1,66 @@ |
665 | +#!/usr/bin/env python3 |
666 | +""" |
667 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
668 | +Industrial Technology Research Institute |
669 | + |
670 | +disk_info |
671 | + Gathering disk information by using lshw command. |
672 | + And output disk type, vendor, product, capacity. |
673 | + |
674 | +Authors |
675 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
676 | + |
677 | +This program is free software: you can redistribute it and/or modify |
678 | +it under the terms of the GNU General Public License version 3, |
679 | +as published by the Free Software Foundation. |
680 | + |
681 | +This program is distributed in the hope that it will be useful, |
682 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
683 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
684 | +GNU General Public License for more details. |
685 | + |
686 | +You should have received a copy of the GNU General Public License |
687 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
688 | + |
689 | +""" |
690 | + |
691 | +import sys |
692 | +import xml.etree.ElementTree as ET |
693 | +from subprocess import Popen, PIPE |
694 | + |
695 | +def main(): |
696 | + attribute = ['description', 'vendor', 'product', 'size'] |
697 | + command = 'lshw -xml' |
698 | + hwinfo_xml = Popen(command, stdout=PIPE, stderr=PIPE, |
699 | + shell=True).communicate()[0] |
700 | + root = ET.fromstring(hwinfo_xml) |
701 | + |
702 | + # Parser lshw XML for gather disk information. |
703 | + disk_list = root.findall(".//node[@class='disk']") |
704 | + |
705 | + if not disk_list: |
706 | + print("Can not parser any disk information.") |
707 | + return 10 |
708 | + |
709 | + for disk in disk_list: |
710 | + for attr in attribute: |
711 | + if disk.find(attr) is None: |
712 | + print(("Can not found disk %s") %attr) |
713 | + return 20 |
714 | + |
715 | + disk_size = int(disk.find('size').text) / (1000**3) |
716 | + for attr in attribute: |
717 | + if attr == 'description': |
718 | + print(('Type=%s,') %disk.find(attr).text), |
719 | + continue |
720 | + elif attr == 'size': |
721 | + print(('%s=%dGB.') %(attr, disk_size)), |
722 | + continue |
723 | + else: |
724 | + print(('%s=%s,') %(attr, disk.find(attr).text)), |
725 | + print() |
726 | + |
727 | + return 0 |
728 | + |
729 | +if __name__ == '__main__': |
730 | + sys.exit(main()) |
731 | |
732 | === added file 'scripts/memory_info' |
733 | --- scripts/memory_info 1970-01-01 00:00:00 +0000 |
734 | +++ scripts/memory_info 2013-11-25 07:01:57 +0000 |
735 | @@ -0,0 +1,65 @@ |
736 | +#!/usr/bin/env python3 |
737 | +""" |
738 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
739 | +Industrial Technology Research Institute |
740 | + |
741 | +memory_info |
742 | + Gathering memory information by using lshw command. |
743 | + And output memory module, vendor, size and slot. |
744 | + |
745 | +Authors |
746 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
747 | + |
748 | +This program is free software: you can redistribute it and/or modify |
749 | +it under the terms of the GNU General Public License version 3, |
750 | +as published by the Free Software Foundation. |
751 | + |
752 | +This program is distributed in the hope that it will be useful, |
753 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
754 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
755 | +GNU General Public License for more details. |
756 | + |
757 | +You should have received a copy of the GNU General Public License |
758 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
759 | + |
760 | +""" |
761 | + |
762 | +import sys |
763 | +import xml.etree.ElementTree as ET |
764 | +from subprocess import Popen, PIPE |
765 | + |
766 | +def main(): |
767 | + attribute = ['description', 'vendor', 'slot', 'size'] |
768 | + command = 'lshw -xml' |
769 | + hwinfo_xml = Popen(command, stdout=PIPE, stderr=PIPE, |
770 | + shell=True).communicate()[0] |
771 | + root = ET.fromstring(hwinfo_xml) |
772 | + |
773 | + # Parser lshw XML for gather memory information. |
774 | + memory_list = root.findall(".//clock/..[@class='memory']") |
775 | + |
776 | + if not memory_list: |
777 | + print("Can not parser any memory information.") |
778 | + return 10 |
779 | + |
780 | + for dimm in memory_list: |
781 | + for attr in attribute: |
782 | + if dimm.find(attr) is None: |
783 | + print(("Can not found memory %s") %attr) |
784 | + return 20 |
785 | + |
786 | + memory_size = int(dimm.find('size').text) / (1024**3) |
787 | + for attr in attribute: |
788 | + if attr == 'description': |
789 | + print(('%s,') %(dimm.find(attr).text)), |
790 | + continue |
791 | + elif attr == 'size': |
792 | + print(('%s=%dGB.') %(attr, memory_size)), |
793 | + continue |
794 | + print(('%s=%s,') %(attr, dimm.find(attr).text)), |
795 | + print() |
796 | + |
797 | + return 0 |
798 | + |
799 | +if __name__ == '__main__': |
800 | + sys.exit(main()) |
801 | |
802 | === added file 'scripts/processor_topology' |
803 | --- scripts/processor_topology 1970-01-01 00:00:00 +0000 |
804 | +++ scripts/processor_topology 2013-11-25 07:01:57 +0000 |
805 | @@ -0,0 +1,123 @@ |
806 | +#!/usr/bin/env python3 |
807 | +''' |
808 | +cpu_topology |
809 | +Written by Jeffrey Lane <jeffrey.lane@canonical.com> |
810 | +''' |
811 | +import sys |
812 | +import os |
813 | +from subprocess import check_output |
814 | + |
815 | +class proc_cpuinfo(): |
816 | + ''' |
817 | + Class to get and handle information from /proc/cpuinfo |
818 | + Creates a dictionary of data gleaned from that file. |
819 | + ''' |
820 | + def __init__(self): |
821 | + self.cpuinfo = {} |
822 | + cpu_fh = open('/proc/cpuinfo', 'r') |
823 | + try: |
824 | + temp = cpu_fh.readlines() |
825 | + finally: |
826 | + cpu_fh.close() |
827 | + |
828 | + for i in temp: |
829 | + if i.startswith('processor'): |
830 | + key = 'cpu' + (i.split(':')[1].strip()) |
831 | + self.cpuinfo[key] = {'core_id':'', 'physical_package_id':''} |
832 | + elif i.startswith('core id'): |
833 | + self.cpuinfo[key].update({'core_id': i.split(':')[1].strip()}) |
834 | + elif i.startswith('physical id'): |
835 | + self.cpuinfo[key].update({'physical_package_id': |
836 | + i.split(':')[1].strip()}) |
837 | + else: |
838 | + continue |
839 | + |
840 | + |
841 | +class sysfs_cpu(): |
842 | + ''' |
843 | + Class to get and handle information from sysfs as relates to CPU topology |
844 | + Creates an informational class to present information on various CPUs |
845 | + ''' |
846 | + |
847 | + def __init__(self, proc): |
848 | + self.syscpu = {} |
849 | + self.path = '/sys/devices/system/cpu/' + proc + '/topology' |
850 | + items = ['core_id', 'physical_package_id'] |
851 | + for i in items: |
852 | + syscpu_fh = open(os.path.join(self.path, i), 'r') |
853 | + try: |
854 | + self.syscpu[i] = syscpu_fh.readline().strip() |
855 | + finally: |
856 | + syscpu_fh.close() |
857 | + |
858 | + |
859 | +def compare(proc_cpu, sys_cpu): |
860 | + cpu_map = {} |
861 | + ''' |
862 | + If there is only 1 CPU the test don't look for core_id |
863 | + and physical_package_id because those information are absent in |
864 | + /proc/cpuinfo on singlecore system |
865 | + ''' |
866 | + for key in proc_cpu.keys(): |
867 | + if 'cpu1' not in proc_cpu: |
868 | + cpu_map[key] = True |
869 | + else: |
870 | + for subkey in proc_cpu[key].keys(): |
871 | + if proc_cpu[key][subkey] == sys_cpu[key][subkey]: |
872 | + cpu_map[key] = True |
873 | + else: |
874 | + cpu_map[key] = False |
875 | + return cpu_map |
876 | + |
877 | + |
878 | +def main(): |
879 | + cpuinfo = proc_cpuinfo() |
880 | + sys_cpu = {} |
881 | + keys = cpuinfo.cpuinfo.keys() |
882 | + for k in keys: |
883 | + sys_cpu[k] = sysfs_cpu(k).syscpu |
884 | + cpu_map = compare(cpuinfo.cpuinfo, sys_cpu) |
885 | + if False in cpu_map.values() or len(cpu_map) < 1: |
886 | + print("FAIL: CPU Topology is incorrect", file=sys.stderr) |
887 | + print("-" * 52, file=sys.stderr) |
888 | + print("{0}{1}".format("/proc/cpuinfo".center(30), "sysfs".center(25)), |
889 | + file=sys.stderr) |
890 | + print("{0}{1}{2}{3}{1}{2}".format( |
891 | + "CPU".center(6), |
892 | + "Physical ID".center(13), |
893 | + "Core ID".center(9), |
894 | + "|".center(3)), file=sys.stderr) |
895 | + for key in sorted(sys_cpu.keys()): |
896 | + print("{0}{1}{2}{3}{4}{5}".format( |
897 | + key.center(6), |
898 | + cpuinfo.cpuinfo[key]['physical_package_id'].center(13), |
899 | + cpuinfo.cpuinfo[key]['core_id'].center(9), |
900 | + "|".center(3), |
901 | + sys_cpu[key]['physical_package_id'].center(13), |
902 | + sys_cpu[key]['core_id'].center(9)), file=sys.stderr) |
903 | + return 1 |
904 | + else: |
905 | + # Output the total number of CPU, the number of Thread per core, |
906 | + # the number of Core per Socket, and the number of Socket. |
907 | + # Revised by Nelson Chu <nelson.chu@itri.org.tw> |
908 | + command = 'lscpu' |
909 | + |
910 | + with open(os.devnull, "w") as NULL: |
911 | + cpu_info = check_output(command, stderr=NULL, shell=True) |
912 | + |
913 | + cpu_info = cpu_info.decode() |
914 | + |
915 | + for cpu in cpu_info.split('\n'): |
916 | + if cpu.startswith("CPU(s)"): |
917 | + print(cpu + ',') |
918 | + if cpu.startswith("Thread(s) per core"): |
919 | + print(cpu + ',') |
920 | + if cpu.startswith("Core(s) per socket"): |
921 | + print(cpu + ',') |
922 | + if cpu.startswith("Socket(s)"): |
923 | + print(cpu + '.') |
924 | + |
925 | + return 0 |
926 | + |
927 | +if __name__ == '__main__': |
928 | + sys.exit(main()) |
929 | |
930 | === added file 'scripts/raid_hdd_info' |
931 | --- scripts/raid_hdd_info 1970-01-01 00:00:00 +0000 |
932 | +++ scripts/raid_hdd_info 2013-11-25 07:01:57 +0000 |
933 | @@ -0,0 +1,59 @@ |
934 | +#!/usr/bin/env python3 |
935 | +""" |
936 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
937 | +Industrial Technology Research Institute |
938 | + |
939 | +raid_hdd_info |
940 | + Get all knox HDD information by using megasasctl command. |
941 | + Show total HDD number in knox and check these disks status is ready or not. |
942 | + Pass criteria: All knox disks information and status are correct. |
943 | + |
944 | +Authors |
945 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
946 | + |
947 | +This program is free software: you can redistribute it and/or modify |
948 | +it under the terms of the GNU General Public License version 3, |
949 | +as published by the Free Software Foundation. |
950 | + |
951 | +This program is distributed in the hope that it will be useful, |
952 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
953 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
954 | +GNU General Public License for more details. |
955 | + |
956 | +You should have received a copy of the GNU General Public License |
957 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
958 | + |
959 | +""" |
960 | + |
961 | +import sys |
962 | +from subprocess import Popen, PIPE |
963 | + |
964 | +def main(): |
965 | + command = 'megasasctl |grep -E "a[0-9]+e[0-9]+s[0-9]+ +[0-9]+GiB"' |
966 | + hdd_info = Popen(command, stdout=PIPE, stderr=PIPE, |
967 | + shell=True).communicate()[0] |
968 | + hdd_info = hdd_info.decode('utf-8') |
969 | + disk_number = 0 |
970 | + fail = 0 |
971 | + |
972 | + # Check is there has any disk. |
973 | + if not hdd_info: |
974 | + print('There is no disk in knox.') |
975 | + return 10 |
976 | + |
977 | + for disk in hdd_info.strip().split('\n'): |
978 | + disk_number = disk_number+1 |
979 | + # Check disk status is ready or not |
980 | + if disk.strip().split(' ')[-1] != 'ready': |
981 | + fail = fail+1 |
982 | + |
983 | + print(('Total %d HDDs in knox.') %disk_number) |
984 | + |
985 | + if fail: |
986 | + print(('There are %d disk status not in ready!') %fail) |
987 | + return 20 |
988 | + |
989 | + return 0 |
990 | + |
991 | +if __name__ == '__main__': |
992 | + sys.exit(main()) |
993 | |
994 | === added file 'scripts/raid_info' |
995 | --- scripts/raid_info 1970-01-01 00:00:00 +0000 |
996 | +++ scripts/raid_info 2013-11-25 07:01:57 +0000 |
997 | @@ -0,0 +1,49 @@ |
998 | +#!/bin/bash |
999 | +# |
1000 | +# Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
1001 | +# Industrial Technology Research Institute |
1002 | +# |
1003 | +# raid_info |
1004 | +# Gathering LSI RAID card information by using megasasctl command. |
1005 | +# Show adapter, product name, memory, BBU, serial no. |
1006 | +# |
1007 | +# Authors |
1008 | +# Nelson Chu <Nelson.Chu@itri.org.tw> |
1009 | +# |
1010 | +# This program is free software: you can redistribute it and/or modify |
1011 | +# it under the terms of the GNU General Public License version 3, |
1012 | +# as published by the Free Software Foundation. |
1013 | +# |
1014 | +# This program is distributed in the hope that it will be useful, |
1015 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1016 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1017 | +# GNU General Public License for more details. |
1018 | +# |
1019 | +# You should have received a copy of the GNU General Public License |
1020 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1021 | +# |
1022 | + |
1023 | +check_return_code() { |
1024 | + if [ "${1}" -ne "0" ]; then |
1025 | + echo "ERROR: ${2}" >&2 |
1026 | + exit ${1} |
1027 | + fi |
1028 | +} |
1029 | + |
1030 | +show=`megacli -CfgDsply -Aall|grep -E \ |
1031 | + 'Adapter:|Product Name:|Memory:|BBU:|Serial No:'` |
1032 | +check_return_code $? "There is no LSI MegaRAID SAS cards found." |
1033 | + |
1034 | +n=0 |
1035 | +echo "$show" | { |
1036 | + while IFS= read -r line; do |
1037 | + echo $line"." |
1038 | + n=$(($n + 1)) |
1039 | + done |
1040 | + |
1041 | + if [ $n -ne "5" ]; then |
1042 | + check_return_code 10 "LSI RAID attributes are not correct." |
1043 | + fi |
1044 | + |
1045 | + exit 0 |
1046 | +} |
1047 | |
1048 | === added file 'scripts/read_write_file' |
1049 | --- scripts/read_write_file 1970-01-01 00:00:00 +0000 |
1050 | +++ scripts/read_write_file 2013-11-25 07:01:57 +0000 |
1051 | @@ -0,0 +1,177 @@ |
1052 | +#!/usr/bin/env python3 |
1053 | +""" |
1054 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
1055 | +Industrial Technology Research Institute |
1056 | + |
1057 | +read_write_file |
1058 | + Create one partition and format on device then test disk I/O. |
1059 | + |
1060 | +Authors |
1061 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
1062 | + |
1063 | +This program is free software: you can redistribute it and/or modify |
1064 | +it under the terms of the GNU General Public License version 3, |
1065 | +as published by the Free Software Foundation. |
1066 | + |
1067 | +This program is distributed in the hope that it will be useful, |
1068 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
1069 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1070 | +GNU General Public License for more details. |
1071 | + |
1072 | +You should have received a copy of the GNU General Public License |
1073 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
1074 | +""" |
1075 | + |
1076 | +import os |
1077 | +import re |
1078 | +import sys |
1079 | +import logging |
1080 | +from subprocess import check_output, check_call, STDOUT |
1081 | +from argparse import ArgumentParser, RawTextHelpFormatter |
1082 | + |
1083 | +log_formatter = '%(asctime)s [%(levelname)-4s] %(funcName)s: %(message)s' |
1084 | +logging.basicConfig(level=logging.DEBUG, |
1085 | + format=log_formatter, |
1086 | + datefmt='%Y-%m-%d %H:%M:%S') |
1087 | + |
1088 | + |
1089 | +def read_file_test(mount_point, file_size): |
1090 | + command = "dd if={0}/test_file of=/dev/null ".format(mount_point) \ |
1091 | + + "bs=1M count={0} iflag=direct".format(file_size) |
1092 | + |
1093 | + output = check_output(command, stderr=STDOUT, shell=True) |
1094 | + output = output.decode("utf-8") |
1095 | + |
1096 | + match = re.search(r'\((.*)\)\D*(\d+\.\d+)\D*(\d+.*)', output) |
1097 | + if not match: |
1098 | + logging.error('Does not match patterns of read file test.') |
1099 | + return False |
1100 | + |
1101 | + logging.info('Read file successful: %s in %s seconds, speed= %s.' |
1102 | + %match.group(1,2,3)) |
1103 | + return True |
1104 | + |
1105 | + |
1106 | +def write_file_test(mount_point, file_size): |
1107 | + command = "dd if=/dev/zero of={0}/test_file ".format(mount_point) \ |
1108 | + + "bs=1M count={0} oflag=direct".format(file_size) |
1109 | + |
1110 | + output = check_output(command, stderr=STDOUT, shell=True) |
1111 | + output = output.decode("utf-8") |
1112 | + |
1113 | + match = re.search(r'\((.*)\)\D*(\d+\.\d+)\D*(\d+.*)', output) |
1114 | + if not match: |
1115 | + logging.error('Does not match patterns of write file test.') |
1116 | + return False |
1117 | + |
1118 | + logging.info('Write file successful: %s in %s seconds, speed= %s.' |
1119 | + %match.group(1,2,3)) |
1120 | + return True |
1121 | + |
1122 | + |
1123 | +def umount_filesystem(mount_point): |
1124 | + umount_cmd = "umount {0}".format(mount_point) |
1125 | + with open(os.devnull, "w") as NULL: |
1126 | + check_call(umount_cmd, stdout=NULL, stderr=NULL, shell=True) |
1127 | + logging.debug('Umount %s directory successful.' %mount_point) |
1128 | + |
1129 | + |
1130 | +def mount_filesystem(device): |
1131 | + mount_point = '/mnt/' + os.path.basename(device) |
1132 | + if not os.path.exists(mount_point): |
1133 | + os.mkdir(mount_point) |
1134 | + logging.debug('Create %s directory successful!' %mount_point) |
1135 | + else: |
1136 | + if os.path.ismount(mount_point): |
1137 | + logging.debug('The %s directory is already mounted.' %mount_point) |
1138 | + umount_filesystem(mount_point) |
1139 | + |
1140 | + mount_cmd = "mount {0} {1}".format(device, mount_point) |
1141 | + with open(os.devnull, "w") as NULL: |
1142 | + check_call(mount_cmd, stdout=NULL, stderr=NULL, shell=True) |
1143 | + logging.debug('Mount %s on %s directory successful.' |
1144 | + %(device, mount_point)) |
1145 | + return mount_point |
1146 | + |
1147 | + |
1148 | +def format_device(device): |
1149 | + command = "mkfs.ext4 -F {0}".format(device) |
1150 | + logging.debug('Format %s device beginning.' %device) |
1151 | + with open(os.devnull, "w") as NULL: |
1152 | + check_call(command, stdout=NULL, stderr=NULL, shell=True) |
1153 | + logging.debug('Format %s completed successfully.' %device) |
1154 | + |
1155 | + |
1156 | +def run(device, file_size): |
1157 | + |
1158 | + # format device |
1159 | + try: |
1160 | + format_device(device) |
1161 | + except Exception as e: |
1162 | + logging.error('%s' %e) |
1163 | + return 20 |
1164 | + |
1165 | + # mount device on system |
1166 | + try: |
1167 | + mount_point = mount_filesystem(device) |
1168 | + except Exception as e: |
1169 | + logging.error('%s' %e) |
1170 | + return 30 |
1171 | + |
1172 | + # write file test |
1173 | + try: |
1174 | + if not write_file_test(mount_point, file_size): |
1175 | + return 35 |
1176 | + except Exception as e: |
1177 | + logging.error('%s' %e) |
1178 | + return 40 |
1179 | + |
1180 | + # read file test |
1181 | + try: |
1182 | + if not read_file_test(mount_point, file_size): |
1183 | + return 45 |
1184 | + except Exception as e: |
1185 | + logging.error('%s' %e) |
1186 | + return 50 |
1187 | + |
1188 | + # umount device |
1189 | + try: |
1190 | + umount_filesystem(mount_point) |
1191 | + except Exception as e: |
1192 | + logging.error('%s' %e) |
1193 | + return 60 |
1194 | + |
1195 | + return 0 |
1196 | + |
1197 | + |
1198 | +def main(): |
1199 | + description_text = 'read_write_file\n\tTest the device read/write file ' \ |
1200 | + + 'correctly.\n\n\n\tWarning: This program will create one partition' \ |
1201 | + + ' on device and format it.\n\t\t Please make sure what you are ' \ |
1202 | + + 'doing!\n\n\n\tRequirement: Give a device name on the system.' |
1203 | + |
1204 | + parser = ArgumentParser(description=description_text, |
1205 | + formatter_class=RawTextHelpFormatter) |
1206 | + |
1207 | + parser.add_argument('-d', '--device', type=str, required=True, |
1208 | + help=('The device name which used to read write test.\n' |
1209 | + '[Example: sda]')) |
1210 | + parser.add_argument('-m', '--megabyte', type=int, |
1211 | + default=5000, |
1212 | + help=('The test file size. [Default: 5GB]')) |
1213 | + |
1214 | + args = parser.parse_args() |
1215 | + |
1216 | + device = args.device |
1217 | + if not device.startswith('/dev/'): |
1218 | + device = '/dev/' + device |
1219 | + |
1220 | + if not os.path.exists(device): |
1221 | + parser.print_help() |
1222 | + return 10 |
1223 | + |
1224 | + return run(device, args.megabyte) |
1225 | + |
1226 | + |
1227 | +if __name__ == '__main__': |
1228 | + sys.exit(main()) |
1229 | |
1230 | === added file 'scripts/rebulid_raid' |
1231 | --- scripts/rebulid_raid 1970-01-01 00:00:00 +0000 |
1232 | +++ scripts/rebulid_raid 2013-11-25 07:01:57 +0000 |
1233 | @@ -0,0 +1,277 @@ |
1234 | +#!/usr/bin/env python3 |
1235 | +""" |
1236 | +Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications |
1237 | +Industrial Technology Research Institute |
1238 | + |
1239 | +rebulid_raid |
1240 | + Test RAID 6 auto rebuild feature in hot spare mode. |
1241 | + |
1242 | +Authors |
1243 | + Nelson Chu <Nelson.Chu@itri.org.tw> |
1244 | + |
1245 | +This program is free software: you can redistribute it and/or modify |
1246 | +it under the terms of the GNU General Public License version 3, |
1247 | +as published by the Free Software Foundation. |
1248 | + |
1249 | +This program is distributed in the hope that it will be useful, |
1250 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
1251 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1252 | +GNU General Public License for more details. |
1253 | + |
1254 | +You should have received a copy of the GNU General Public License |
1255 | +along with this program. If not, see <http://www.gnu.org/licenses/>. |
1256 | + |
1257 | +""" |
1258 | + |
1259 | +import os |
1260 | +import re |
1261 | +import sys |
1262 | +import time |
1263 | +import random |
1264 | +import logging |
1265 | +from subprocess import check_output, check_call |
1266 | +from argparse import ArgumentParser, RawTextHelpFormatter |
1267 | + |
1268 | +logFormatter = logging.Formatter( |
1269 | + "%(asctime)s [%(levelname)-5.5s] %(funcName)s: %(message)s", |
1270 | + datefmt='%Y-%m-%d %H:%M:%S') |
1271 | +logger = logging.getLogger() |
1272 | +logger.setLevel(logging.DEBUG) |
1273 | + |
1274 | + |
1275 | +def get_adapter(): |
1276 | + """ |
1277 | + Gather all adapter number if there are multiple RAID card. |
1278 | + """ |
1279 | + |
1280 | + command = 'megacli -CfgDsply -Aall|grep Adapter' |
1281 | + adapter_list = [] |
1282 | + |
1283 | + adapter_info = check_output(command, shell=True) |
1284 | + adapter_info = adapter_info.decode('utf-8') |
1285 | + |
1286 | + for adapter in adapter_info.strip().split('\n'): |
1287 | + adapter_list.append(adapter.strip().split(' ')[-1]) |
1288 | + logger.debug('adapter_list: %s' %adapter_list) |
1289 | + return adapter_list |
1290 | + |
1291 | + |
1292 | +def get_all_disk(adapter): |
1293 | + """ |
1294 | + Gather all disks Enclosure and Slot number, and make a |
1295 | + Enclosure:Slot pair list. |
1296 | + """ |
1297 | + |
1298 | + command = ('megacli -PDList -A%s|grep -E "Enclosure Device ID|Slot Numbe"' |
1299 | + %adapter) |
1300 | + disk_list = [] |
1301 | + disk_info = check_output(command, shell=True) |
1302 | + disk_info = disk_info.decode('utf-8') |
1303 | + |
1304 | + for line in disk_info.strip().split('\n'): |
1305 | + if line.startswith('Enclosure'): |
1306 | + match = re.search(r'\d+', line) |
1307 | + disk_list.append(match.group(0)) |
1308 | + if line.startswith('Slot'): |
1309 | + match = re.search(r'\d+', line) |
1310 | + enclosure = disk_list.pop() |
1311 | + E_S = '%s:%s' %(enclosure, match.group(0)) |
1312 | + disk_list.append(E_S) |
1313 | + |
1314 | + logger.debug('adapter: %s, disk_list: %s' %(adapter, disk_list)) |
1315 | + return disk_list |
1316 | + |
1317 | + |
1318 | +def set_disk_offline(adapter, disk_list): |
1319 | + """ |
1320 | + Use all disk creatd RAID 6 and set last disk as hot spare. |
1321 | + """ |
1322 | + |
1323 | + # Random offline one disk in disk list. |
1324 | + disk = disk_list[random.randint(0, len(disk_list)-1)] |
1325 | + command = ('megacli -PDOffline -PhysDrv [%s] -a%s' %(disk, adapter)) |
1326 | + with open(os.devnull, "w") as NULL: |
1327 | + check_call(command, stdout=NULL, stderr=NULL, shell=True) |
1328 | + logger.info('Random offline one disk in disk list, Enclosure: %s, Slot: %s' |
1329 | + %(disk.split(':')[0], disk.split(':')[1])) |
1330 | + |
1331 | + |
1332 | +def find_hotspare_disk(adapter): |
1333 | + """ |
1334 | + Find hotspare disk in adapter |
1335 | + """ |
1336 | + command = "megasasctl |grep -E '^a%s.*hotspare'" %adapter |
1337 | + output = check_output(command, shell=True) |
1338 | + output = output.decode('utf-8') |
1339 | + hotspare = output.strip() |
1340 | + |
1341 | + if len(hotspare.split('\n')) != 1: |
1342 | + logger.error('Hotspare disk number is not correct.' \ |
1343 | + + 'It can be only one hotspare in a ' \ |
1344 | + + 'adapter.') |
1345 | + return False |
1346 | + |
1347 | + match = re.match(r'a(\d+)e(\d+)s(\d+)',hotspare) |
1348 | + if not match: |
1349 | + logger.error('Can not found enclosure and slot number of hotspare.') |
1350 | + return False |
1351 | + |
1352 | + hotspare_E_S = "%s:%s" %(match.group(2), match.group(3)) |
1353 | + logger.info('Found hotspare, Enclosure: %s, Slot: %s' |
1354 | + %(match.group(2), match.group(3))) |
1355 | + return hotspare_E_S |
1356 | + |
1357 | + |
1358 | +def check_rebuild_status(adapter, spare): |
1359 | + command = 'megacli -PDRbld -ShowProg -PhysDrv [%s] -A%s|grep -i rebuild' \ |
1360 | + %(spare, adapter) |
1361 | + output = check_output(command, shell=True) |
1362 | + output = output.decode('utf-8') |
1363 | + logger.debug('%s' %output.strip()) |
1364 | + |
1365 | + match = re.search(r'Completed (\d+)% in (\d+) Minutes', output) |
1366 | + if not match: |
1367 | + return True |
1368 | + return False |
1369 | + |
1370 | + |
1371 | +def all_rebuild_status(adapter_list, spare_dict): |
1372 | + for adapter in adapter_list: |
1373 | + if not check_rebuild_status(adapter, spare_dict[adapter]): |
1374 | + return False |
1375 | + return True |
1376 | + |
1377 | + |
1378 | +def confirm_rebuild_status(adapter, spare): |
1379 | + enclosure, slot = spare.split(':') |
1380 | + command = ("megasasctl|grep -E '^a%se%ss%s'" %(adapter, enclosure, slot)) |
1381 | + output = check_output(command, shell=True) |
1382 | + output = output.decode('utf-8') |
1383 | + |
1384 | + match = re.search(r'online', output) |
1385 | + if not match: |
1386 | + logger.error('Hotspare status did not change to online. Adapter: %s, ' \ |
1387 | + +'Hotspare: [$s:$s]' %(adapter, enclosure, slot)) |
1388 | + return False |
1389 | + return True |
1390 | + |
1391 | + |
1392 | +def run(Adapter= None, Hsp=None, disk_list=None): |
1393 | + disk_dict = {} |
1394 | + spare_dict = {} |
1395 | + adapter_list = [] |
1396 | + rebuild_status = {} |
1397 | + |
1398 | + try: |
1399 | + if Adapter: |
1400 | + adapter_list.append(Adapter) |
1401 | + else: |
1402 | + adapter_list = get_adapter() |
1403 | + except Exception as e: |
1404 | + logger.error('%s' %e) |
1405 | + return 10 |
1406 | + |
1407 | + try: |
1408 | + if Adapter and disk_list: |
1409 | + disk_dict[Adapter] = disk_list |
1410 | + else: |
1411 | + for adapter in adapter_list: |
1412 | + disk_dict[adapter] = get_all_disk(adapter) |
1413 | + except Exception as e: |
1414 | + logger.error('%s' %e) |
1415 | + return 20 |
1416 | + |
1417 | + try: |
1418 | + if Adapter and Hsp: |
1419 | + spare_dict[Adapter] = Hsp |
1420 | + else: |
1421 | + for adapter in adapter_list: |
1422 | + spare_dict[adapter] = find_hotspare_disk(adapter) |
1423 | + if not spare_dict[adapter]: |
1424 | + return 30 |
1425 | + except Exception as e: |
1426 | + logger.error('%s' %e) |
1427 | + return 40 |
1428 | + |
1429 | + try: |
1430 | + for adapter in adapter_list: |
1431 | + # Remove hotspare disk from disk dict. |
1432 | + if spare_dict[adapter] in disk_dict[adapter]: |
1433 | + disk_dict[adapter].remove(spare_dict[adapter]) |
1434 | + set_disk_offline(adapter, disk_dict[adapter]) |
1435 | + except Exception as e: |
1436 | + logger.error('%s' %e) |
1437 | + return 50 |
1438 | + |
1439 | + # Wait for rebuild process |
1440 | + time.sleep(5) |
1441 | + |
1442 | + try: |
1443 | + while(True): |
1444 | + if not all_rebuild_status(adapter_list, spare_dict): |
1445 | + # Check rebuild RAID status every 15 min. |
1446 | + time.sleep(900) |
1447 | + continue |
1448 | + break |
1449 | + except Exception as e: |
1450 | + logger.error('%s' %e) |
1451 | + return 60 |
1452 | + |
1453 | + check = 0 |
1454 | + try: |
1455 | + for adapter in adapter_list: |
1456 | + if not confirm_rebuild_status(adapter, spare_dict[adapter]): |
1457 | + logger.error('Rebuild RAID failed, Adapter: %s, Hotspare: %s' |
1458 | + %(adapter, spare_dict[adapter])) |
1459 | + check = 1 |
1460 | + if check != 0: |
1461 | + return 70 |
1462 | + except Exception as e: |
1463 | + logger.error('%s' %e) |
1464 | + return 80 |
1465 | + |
1466 | + logger.info('All adapter rebuild RAID successful!') |
1467 | + return 0 |
1468 | + |
1469 | + |
1470 | +def main(): |
1471 | + description_text = 'rebulit_raid\n\tTests LSI RAID card auto rebuild ' \ |
1472 | + + 'function.\n\n\n\tWarning: This program will rebuild RAID ' \ |
1473 | + + 'automaticity.\n\t\t Please make sure what you are doing!\n\n\n' \ |
1474 | + + '\tRequirement: It can be only one hotspare in a adapter.' |
1475 | + |
1476 | + parser = ArgumentParser(description=description_text, |
1477 | + formatter_class=RawTextHelpFormatter) |
1478 | + |
1479 | + parser.add_argument('-l', '--log', type=str, |
1480 | + default='/tmp/rebulid_raid.log', |
1481 | + help=('Specify the location and name of the log file.\n' |
1482 | + '[Default: %(default)s]')) |
1483 | + parser.add_argument('-P', '--PhysDrv', type=str, |
1484 | + help=('The physical drive enclosure and slot of RAID.' |
1485 | + '\n[Example: --PhysDrv E0:S0,E1:S1,...] ')) |
1486 | + parser.add_argument('-H', '--Hsp', type=str, |
1487 | + help=('The hotspare\'s enclosure and slot of RAID.' |
1488 | + '\n[Example: --Hsp E0:S0] ')) |
1489 | + parser.add_argument('-A', '--Adapter', type=str, |
1490 | + help=('The adapter number of RAID card.' |
1491 | + '\n[Example: 0')) |
1492 | + args = parser.parse_args() |
1493 | + |
1494 | + file_handler = logging.FileHandler(args.log) |
1495 | + file_handler.setFormatter(logFormatter) |
1496 | + console_handler = logging.StreamHandler() |
1497 | + console_handler.setFormatter(logFormatter) |
1498 | + console_handler.setLevel(logging.INFO) |
1499 | + logger.addHandler(file_handler) |
1500 | + logger.addHandler(console_handler) |
1501 | + |
1502 | + disk_list = None |
1503 | + if args.PhysDrv: |
1504 | + disk_list = args.PhysDrv.split(',') |
1505 | + |
1506 | + logger.info('Rebuild process beginning.') |
1507 | + return run(args.Adapter, args.Hsp, disk_list) |
1508 | + |
1509 | +if __name__ == '__main__': |
1510 | + sys.exit(main()) |
Hi Nelson...
I really hate to do this, but I'm going to reject this Merge Proposal. Here's why:
Please, PLEASE make several, smaller, targeted merge requests rather than one large 1500 line merge. The only time a merge should have that many lines of changed code is if it adds or changes a very large chunk of code, not adding so many small, individual files.
Smaller merge requests make it a lot easier to review, make suggestions and get things merged in a more timely fashion.
I would suggest breaking this merge request up into smaller chunks divided based on testing topic. So, for example submit one merge request with your proposed changes for: 0001-CPU_ Memory
TC-001-
whcih should include the whitelist changes, the added scripts, added/modified job files, etc.
Then do the same in different merge requests for: 0002-Platform_ Controller_ Hub 0003-BIOS_ setup_menu 0004-BIOS_ remote_ update 0005-BIOS_ event_log
TC-001-
TC-001-
TC-001-
TC-001-
and so on.
Now, a word about job naming and whitelists that apply across all these changes:
1: Dont put whitespace (space, tab) in the job name.
TC-001- 0001-001- CPU_information
TC-001- 0001/001_ CPU_information
Rather than TC-001-0001-001 CPU information, you should use something like these:
2: I don't know that it will hurt, but try to remove any blank lines in the whitelist file, the sections are identifiable by the __SUITENAME__ items on the list, so blank lines are not necessary.
3: You CAN, however, add comments preceding them with the # character
4: remember that every job called __SUITENAME__ must exist in the local.txt.in file (see that file for examples)
That job is a special job that causes the suitename.txt.in file to be read in when checkbox launches.
Beyond those suggestions, We'll deal with individual problems in the smaller merge requests I've asked for.
Also, given that you are new to this process, using smaller merge requests will make it a LOT easier for me to help show you through the process as well as acquaint you with the way checkbox works and how the code needs to look.