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