Skip to content

Commit df8c944

Browse files
committed
Add python script to generate test fixtures from real drives
1 parent 1bc5733 commit df8c944

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
import json
3+
import re
4+
from pySMART import DeviceList
5+
6+
SMARTMON_ATTRS = {
7+
"airflow_temperature_cel",
8+
"command_timeout",
9+
"current_pending_sector",
10+
"end_to_end_error",
11+
"erase_fail_count",
12+
"g_sense_error_rate",
13+
"hardware_ecc_recovered",
14+
"host_reads_32mib",
15+
"host_reads_mib",
16+
"host_writes_32mib",
17+
"host_writes_mib",
18+
"load_cycle_count",
19+
"media_wearout_indicator",
20+
"nand_writes_1gib",
21+
"offline_uncorrectable",
22+
"power_cycle_count",
23+
"power_on_hours",
24+
"program_fail_cnt_total",
25+
"program_fail_count",
26+
"raw_read_error_rate",
27+
"reallocated_event_count",
28+
"reallocated_sector_ct",
29+
"reported_uncorrect",
30+
"runtime_bad_block",
31+
"sata_downshift_count",
32+
"seek_error_rate",
33+
"spin_retry_count",
34+
"spin_up_time",
35+
"start_stop_count",
36+
"temperature_case",
37+
"temperature_celsius",
38+
"temperature_internal",
39+
"total_lbas_read",
40+
"total_lbas_written",
41+
"udma_crc_error_count",
42+
"unsafe_shutdown_count",
43+
"unused_rsvd_blk_cnt_tot",
44+
"wear_leveling_count",
45+
"workld_host_reads_perc",
46+
"workld_media_wear_indic",
47+
"workload_minutes",
48+
"critical_warning",
49+
"temperature",
50+
"available_spare",
51+
"available_spare_threshold",
52+
"percentage_used",
53+
"data_units_read",
54+
"data_units_written",
55+
"host_reads",
56+
"host_writes",
57+
"controller_busy_time",
58+
"power_cycles",
59+
"unsafe_shutdowns",
60+
"media_errors",
61+
"num_err_log_entries",
62+
"warning_temp_time",
63+
"critical_comp_time",
64+
}
65+
66+
DISK_INFO = {
67+
"name",
68+
"interface",
69+
"vendor",
70+
"family",
71+
"model",
72+
"serial",
73+
"firmware",
74+
"smart_capable",
75+
"smart_enabled",
76+
"assessment",
77+
}
78+
79+
def camel_to_snake(name):
80+
"""
81+
Convert a CamelCase string to snake_case.
82+
83+
Reference: https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
84+
"""
85+
return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
86+
87+
def attrs_to_dict(obj, allowed_keys):
88+
"""
89+
Build {attr: value} for every public, non-callable attribute whose
90+
snake_case name is in `allowed_keys`.
91+
"""
92+
attributes = {}
93+
for name in dir(obj):
94+
if name.startswith('_'):
95+
continue
96+
try:
97+
value = getattr(obj, name)
98+
except Exception:
99+
continue
100+
if value is None:
101+
continue
102+
if callable(value):
103+
continue
104+
if camel_to_snake(name) in allowed_keys:
105+
attributes[name] = value
106+
return attributes
107+
108+
for disk in DeviceList().devices:
109+
110+
fixtures = {}
111+
disk_info = attrs_to_dict(disk, DISK_INFO)
112+
if_stats = attrs_to_dict(disk.if_attributes, SMARTMON_ATTRS)
113+
114+
fixtures["device_info"] = disk_info
115+
fixtures["if_attributes"] = if_stats
116+
117+
print(f'Disk: {disk.name}: \n')
118+
print(json.dumps(fixtures, indent=2, default=str))

0 commit comments

Comments
 (0)