first
This commit is contained in:
commit
6482e77af3
68
db.py
Normal file
68
db.py
Normal file
@ -0,0 +1,68 @@
|
||||
import sqlite3, datetime
|
||||
|
||||
class SQLite():
|
||||
def __init__(self, file='sqlite.db'):
|
||||
self.file=file
|
||||
|
||||
def __enter__(self):
|
||||
self.conn = sqlite3.connect(self.file)
|
||||
self.conn.row_factory = sqlite3.Row
|
||||
return self.conn.cursor()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.conn.commit()
|
||||
self.conn.close()
|
||||
|
||||
|
||||
def create_status_table():
|
||||
with SQLite() as cur:
|
||||
cur.execute("""
|
||||
CREATE TABLE `status` (
|
||||
`ID` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`drive` TEXT,
|
||||
`date` NUMERIC,
|
||||
`type` TEXT,
|
||||
`fast` INTEGER,
|
||||
`delayed` INTEGER,
|
||||
`re` INTEGER,
|
||||
`total_e_cottect` INTEGER,
|
||||
`correction` INTEGER,
|
||||
`proc_gb` INTEGER,
|
||||
`total_u_errors` INTEGER,
|
||||
`Non-medium error count` INTEGER
|
||||
);
|
||||
""")
|
||||
|
||||
def table_exist(name):
|
||||
with SQLite() as cur:
|
||||
cur.execute('''
|
||||
SELECT name FROM sqlite_master WHERE type='table' AND name='{}';
|
||||
'''.format(name))
|
||||
|
||||
return True if cur.fetchone() else False
|
||||
|
||||
def add_status(drive, type, status, NM_count):
|
||||
now = int(datetime.datetime.now().timestamp())
|
||||
with SQLite() as cur:
|
||||
cur.execute(
|
||||
'''
|
||||
INSERT INTO status (drive, date, type, fast, delayed, re, total_e_cottect, correction, proc_gb, total_u_errors, "Non-medium error count") VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
||||
''',(drive, now, type, *status, NM_count)
|
||||
)
|
||||
|
||||
def get_status(drive):
|
||||
with SQLite() as cur:
|
||||
cur.execute('''
|
||||
SELECT * FROM status WHERE drive=(?)
|
||||
''',(drive,))
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not table_exist('status'):
|
||||
print("Creating table")
|
||||
create_status_table()
|
||||
else:
|
||||
print('Table table exist!')
|
||||
test = {'read': ['314277204', '9', '0', '314277213', '9', '229503.982', '0'], 'write': ['0', '0', '0', '0', '0', '47762.811', '0'], 'verify': ['64', '0', '0', '64', '0', '0.000', '0'], 'Non-medium error count': '10'}
|
||||
|
108
parse.py
Normal file
108
parse.py
Normal file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re, os
|
||||
from subprocess import getoutput
|
||||
|
||||
keys = [
|
||||
"ECC corrected fast",
|
||||
"ECC corrected delayed",
|
||||
"ECC reread/rewrites",
|
||||
"Total errors corrected",
|
||||
"Correction algorithm invocations",
|
||||
"Gigabytes processed [10^9 bytes]",
|
||||
"Total uncorrected errors",
|
||||
]
|
||||
|
||||
def log(type, disk, message):
|
||||
print("!!LOG", type, disk, message)
|
||||
|
||||
def get_all_scsi_path():
|
||||
disks = os.listdir('/dev/disk/by-id/')
|
||||
out = []
|
||||
for disk in disks:
|
||||
if disk.startswith('scsi') and 'part' not in disk:
|
||||
out.append('/dev/disk/by-id/'+disk)
|
||||
return out
|
||||
|
||||
def call_smart(disks):
|
||||
out = {}
|
||||
for disk in disks:
|
||||
content = getoutput('smartctl -a {}'.format(disk))
|
||||
content = parse_out(content, disk)
|
||||
out[disk] = content
|
||||
|
||||
return out
|
||||
|
||||
def save_status(stats):
|
||||
for disk in status:
|
||||
for key in ['read', 'write', 'verify']:
|
||||
if len(disk[key]) == 7:
|
||||
db.add_status(disk, key, disk[key], disk['Non-medium error count'])
|
||||
else:
|
||||
log('missing', disk, '{} is missing values'.fotmat(key))
|
||||
|
||||
|
||||
def parse_out(content, disk=''):
|
||||
out = {
|
||||
'read': {},
|
||||
'write': {},
|
||||
'verify': {},
|
||||
'Non-medium error count': 0,
|
||||
'Elements in grown defect list': 0,
|
||||
'SMART Health Status': ''
|
||||
}
|
||||
|
||||
try:
|
||||
out['SMART Health Status'] = re.search(
|
||||
r'SMART Health Status:\s+(?P<status>.+)', content
|
||||
).group('status')
|
||||
except AttributeError as error:
|
||||
log('missing', disk, "SMART Health Status not found")
|
||||
|
||||
try:
|
||||
out['Elements in grown defect list'] = re.search(
|
||||
r'Elements in grown defect list:\s+(?P<number>\d+)', content
|
||||
).group('number')
|
||||
except AttributeError as error:
|
||||
log('missing', disk, "Elements in grown defect list not found")
|
||||
|
||||
try:
|
||||
out['Non-medium error count'] = re.search(
|
||||
r'Non-medium error count:\s+(?P<number>\d+)', content
|
||||
).group('number')
|
||||
except AttributeError as error:
|
||||
log('missing', disk, "Non-medium error count not found")
|
||||
|
||||
try:
|
||||
content = content.split("Error counter log:")[1]
|
||||
except IndexError:
|
||||
log('failed', disk, 'Missing error information section')
|
||||
return {}
|
||||
|
||||
for line in content.split('\n'):
|
||||
if line.startswith('read:'):
|
||||
line = re.sub(r'^[a-z:\s]+', '', line)
|
||||
line = re.split(r'\s+', line)
|
||||
out['read'] = dict(zip(keys, line))
|
||||
continue
|
||||
|
||||
if line.startswith('write:'):
|
||||
line = re.sub(r'^[a-z:\s]+', '', line)
|
||||
line = re.split(r'\s+', line)
|
||||
out['write'] = dict(zip(keys, line))
|
||||
continue
|
||||
|
||||
if line.startswith('verify:'):
|
||||
line = re.sub(r'^[a-z:\s]+', '', line)
|
||||
line = re.split(r'\s+', line)
|
||||
out['verify'] = dict(zip(keys, line))
|
||||
continue
|
||||
|
||||
return out
|
||||
|
||||
if __name__ == "__main__":
|
||||
import json
|
||||
disks = get_all_scsi_path()
|
||||
parsed = call_smart(disks)
|
||||
print(json.dumps(parsed, indent=4, sort_keys=True))
|
||||
print(*[(i,parsed[i].get('SMART Health Status')) for i in parsed], sep='\n')
|
60
smart.txt
Normal file
60
smart.txt
Normal file
@ -0,0 +1,60 @@
|
||||
smartctl 6.5 2016-01-24 r4214 [x86_64-linux-4.4.0-165-generic] (local build)
|
||||
Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org
|
||||
|
||||
=== START OF INFORMATION SECTION ===
|
||||
Vendor: SEAGATE
|
||||
Product: ST6000NM0034
|
||||
Revision: E005
|
||||
Compliance: SPC-4
|
||||
User Capacity: 6,001,175,126,016 bytes [6.00 TB]
|
||||
Logical block size: 512 bytes
|
||||
Physical block size: 4096 bytes
|
||||
Formatted with type 2 protection
|
||||
LB provisioning type: unreported, LBPME=0, LBPRZ=0
|
||||
Rotation Rate: 7200 rpm
|
||||
Form Factor: 3.5 inches
|
||||
Logical Unit id: 0x5000c50062502b8b
|
||||
Serial number: Z4D0C1EV0000S440NQKX
|
||||
Device type: disk
|
||||
Transport protocol: SAS (SPL-3)
|
||||
Local Time is: Tue Nov 5 19:56:43 2019 EST
|
||||
SMART support is: Available - device has SMART capability.
|
||||
SMART support is: Enabled
|
||||
Temperature Warning: Enabled
|
||||
|
||||
=== START OF READ SMART DATA SECTION ===
|
||||
SMART Health Status: OK
|
||||
|
||||
Current Drive Temperature: 50 C
|
||||
Drive Trip Temperature: 60 C
|
||||
|
||||
Manufactured in week 36 of year 2014
|
||||
Specified cycle count over device lifetime: 10000
|
||||
Accumulated start-stop cycles: 46
|
||||
Specified load-unload count over device lifetime: 300000
|
||||
Accumulated load-unload cycles: 5971
|
||||
Elements in grown defect list: 7
|
||||
|
||||
Vendor (Seagate) cache information
|
||||
Blocks sent to initiator = 3267148336
|
||||
Blocks received from initiator = 1629969808
|
||||
Blocks read from cache and sent to initiator = 3854095152
|
||||
Number of read and write commands whose size <= segment size = 300541123
|
||||
Number of read and write commands whose size > segment size = 3892
|
||||
|
||||
Vendor (Seagate/Hitachi) factory information
|
||||
number of hours powered up = 28080.92
|
||||
number of minutes until next internal SMART test = 54
|
||||
|
||||
Error counter log:
|
||||
Errors Corrected by Total Correction Gigabytes Total
|
||||
ECC rereads/ errors algorithm processed uncorrected
|
||||
fast | delayed rewrites corrected invocations [10^9 bytes] errors
|
||||
read: 314277204 9 0 314277213 9 229503.982 0
|
||||
write: 0 0 0 0 0 47762.811 0
|
||||
verify: 64 0 0 64 0 0.000 0
|
||||
|
||||
Non-medium error count: 10
|
||||
|
||||
No self-tests have been logged
|
||||
|
Loading…
x
Reference in New Issue
Block a user