Skip to content

Commit 13c3e16

Browse files
author
Gerlof Fokkema
committed
Zabbix mode is of yet untested, and the error faking mechanism is gone.
Despite that this should already be a nice improvement :)
1 parent 5514c50 commit 13c3e16

1 file changed

Lines changed: 150 additions & 142 deletions

File tree

wrapper-scripts/3ware-status

Lines changed: 150 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,165 @@
11
#!/usr/bin/python
22

3+
import json
34
import os
45
import re
56
import sys
67

7-
binarypath = "/usr/sbin/tw-cli"
8-
9-
if len(sys.argv) > 2:
10-
print 'Usage: 3ware-status [--nagios]'
11-
sys.exit(1)
12-
13-
nagiosmode=False
14-
nagiosoutput=''
15-
nagiosgoodarray=0
16-
nagiosbadarray=0
17-
nagiosgooddisk=0
18-
nagiosbaddisk=0
8+
from subprocess import check_output
199

20-
if len(sys.argv) > 1:
21-
if sys.argv[1] == '--nagios':
22-
nagiosmode=True
10+
binarypath = "/usr/sbin/tw-cli"
11+
normalmode = False
12+
nagiosmode = False
13+
zabbixmode = False
14+
argv = list()
15+
16+
if len(sys.argv) > 1 and sys.argv[1][:2] == '--':
17+
if len(sys.argv) == 2 and sys.argv[1] == '--nagios':
18+
nagiosmode = True
19+
elif len(sys.argv) > 2 and sys.argv[1] == '--zabbix':
20+
zabbixmode = True
21+
argv = sys.argv[2:]
2322
else:
24-
print 'Usage: 3ware-status [--nagios]'
23+
print 'Usage: 3ware-status [--nagios|[[--zabbix] <prop> [<key>]]]'
2524
sys.exit(1)
26-
27-
# Check binary exists (and +x), if not print an error message
28-
# or return UNKNOWN nagios error code
29-
if os.path.exists(binarypath) and os.access(binarypath, os.X_OK):
30-
pass
3125
else:
32-
if nagiosmode:
33-
print 'UNKNOWN - Cannot find '+binarypath
34-
else:
35-
print 'Cannot find '+binarypath+'. Please install it.'
36-
sys.exit(3)
26+
normalmode = True
27+
argv = sys.argv[1:]
3728

29+
# Check binary exists (and +x), if not print an error message
30+
if not (os.path.exists(binarypath) and os.access(binarypath, os.X_OK)):
31+
if nagiosmode:
32+
print 'UNKNOWN - Cannot find %s' % binarypath
33+
else:
34+
print 'Cannot find %s. Please install it.' % binarypath
35+
sys.exit(3)
3836

3937
# Get command output
40-
def getOutput(cmd):
41-
output = os.popen(cmd)
42-
lines = []
43-
for line in output:
44-
if not re.match(r'^$',line.strip()):
45-
lines.append(line.strip())
46-
return lines
38+
def getOutput(args = ''):
39+
output = check_output([binarypath] + args.split())
40+
return [line for line in output.splitlines() if not re.match(r'^$', line.strip())]
41+
42+
def getProperty(args):
43+
try:
44+
return getOutput('info %s' % args)[0].split(' = ')[1].strip()
45+
except IndexError:
46+
return 'N/A'
4747

48-
def returnControllerList(output):
49-
lines = []
50-
for line in output:
51-
if re.match(r'^c[0-9]+\s.*$',line.strip()):
52-
lines.append(line.split()[0])
53-
return lines
54-
55-
def returnDiskList(output):
56-
lines = []
57-
for line in output:
58-
if re.match(r'^[p][0-9]+\s.*$',line.strip()):
59-
# Shoudl contain something like 'u0'
60-
# '-' means the drive doesn't belong to any array
61-
# If is NOT PRESENT too, it just means this is an empty port
62-
if not line.split()[2].strip() == '-' and not line.split()[1].strip() == 'NOT-PRESENT':
63-
lines.append(line.split())
64-
if fake_failure:
65-
lines[0][1] = 'NOT PRESENT'
66-
return lines
67-
68-
def returnArrayList(output):
69-
lines = []
70-
for line in output:
71-
if re.match(r'^[u][0-9]+\s.*$',line.strip()):
72-
lines.append(line.split())
73-
if fake_failure:
74-
lines[0][2] = 'DEGRADED'
75-
return lines
76-
77-
# A way to force a fake failure
78-
fake_failure = False
79-
if os.path.exists('/root/fake_3ware_failure'):
80-
fake_failure = True
81-
82-
cmd = binarypath+' info'
83-
output = getOutput(cmd)
84-
controllerlist = returnControllerList(output)
85-
86-
bad = False
87-
88-
89-
# List available controller
90-
if not nagiosmode:
91-
print '-- Controller informations --'
92-
print '-- ID | Model'
93-
for controller in controllerlist:
94-
cmd = binarypath+' info '+controller+' model'
95-
# https://github.com/eLvErDe/hwraid/issues/69
96-
try:
97-
model = getOutput(cmd)[0].split(' = ')[1].strip()
98-
except IndexError:
99-
model = 'N/A'
100-
print controller+' | '+model
101-
print ''
102-
103-
# List arrays
104-
if not nagiosmode:
105-
print '-- Arrays informations --'
106-
print '-- ID\tType\tSize\tStatus'
107-
for controller in controllerlist:
108-
cmd = binarypath+' info '+controller
109-
output = getOutput(cmd)
110-
arraylist = returnArrayList(output)
111-
for array in arraylist:
112-
type = array[1].replace('-','')
113-
id = controller+array[0]
114-
size = array[6].split('.')[0]+'G'
115-
status = array[2]
116-
if not status in ['OK','VERIFYING']:
117-
bad = True
118-
nagiosbadarray=nagiosbadarray+1
119-
else:
120-
nagiosgoodarray=nagiosgoodarray+1
121-
if not nagiosmode:
122-
print id+'\t'+type+'\t'+size+'\t'+status
123-
if not nagiosmode:
124-
print ''
125-
126-
# List disks
127-
if not nagiosmode:
128-
print '-- Disks informations'
129-
print '-- ID\tModel\t\t\tStatus'
130-
for controller in controllerlist:
131-
cmd = binarypath+' info '+controller
132-
output = getOutput(cmd)
133-
disklist = returnDiskList(output)
134-
for disk in disklist:
135-
id = controller+disk[2]+disk[0]
136-
cmd = binarypath+' info '+controller+' '+disk[0]+' model'
137-
model = getOutput(cmd)[0].split(' = ')[1].strip()
138-
cmd = binarypath+' info '+controller+' '+disk[0]+' status'
139-
status = getOutput(cmd)[0].split(' = ')[1].strip()
140-
if not status == 'OK':
141-
bad = True
142-
nagiosbaddisk=nagiosbaddisk+1
143-
else:
144-
nagiosgooddisk=nagiosgooddisk+1
145-
if not nagiosmode:
146-
print id+'\t'+model+'\t'+status
147-
148-
if nagiosmode:
149-
if bad:
150-
print 'RAID ERROR - Arrays: OK:'+str(nagiosgoodarray)+' Bad:'+str(nagiosbadarray)+' - Disks: OK:'+str(nagiosgooddisk)+' Bad:'+str(nagiosbaddisk)
151-
sys.exit(2)
48+
def parseControllers():
49+
controllers = dict()
50+
for line in getOutput('info'):
51+
if re.match(r'^c[0-9]+\s.*$', line.strip()):
52+
parts = line.split()
53+
54+
id = parts[0]
55+
model = getProperty('%s model' % id)
56+
57+
controllers[id] = { 'model': model }
58+
return controllers
59+
60+
def parseInfo(controller):
61+
arrays = dict()
62+
disks = dict()
63+
for line in getOutput('info %s' % controller):
64+
if re.match(r'^u[0-9]+\s.*$', line.strip()):
65+
parts = line.split()
66+
67+
id = controller + parts[0]
68+
type = parts[1].replace('-', '')
69+
status = parts[2]
70+
size = '%sG' % parts[6].split('.')[0]
71+
72+
arrays[id] = { 'type': type, 'status': status, 'size': size }
73+
74+
if re.match(r'^p[0-9]+\s.*$', line.strip()):
75+
parts = line.split()
76+
77+
if not parts[2].strip() == '-' and not parts[1].strip() == 'NOT-PRESENT':
78+
array = controller + parts[2]
79+
id = array + parts[0]
80+
model = getProperty('%s %s model' % (controller, parts[0]))
81+
status = getProperty('%s %s status' % (controller, parts[0]))
82+
83+
disks[id] = { 'model': model, 'status': status }
84+
85+
return (arrays, disks)
86+
87+
88+
controllers = dict()
89+
arrays = dict()
90+
disks = dict()
91+
92+
def init():
93+
controllers.update(parseControllers())
94+
for controller in controllers.keys():
95+
a, d = parseInfo(controller)
96+
arrays.update(a)
97+
disks.update(d)
98+
99+
def info(args):
100+
str = '-- Controller informations --\n'
101+
str += '-- ID | Model\n'
102+
for c, v in controllers.items():
103+
str += '%s | %s\n' % (c, v['model'])
104+
str += '\n'
105+
106+
str += '-- Arrays informations --\n'
107+
str += '-- ID\tType\tSize\tStatus\n'
108+
for a, v in arrays.items():
109+
str += '%s\t%s\t%s\t%s\n' % (a, v['type'], v['size'], v['status'])
110+
str += '\n'
111+
112+
str += '-- Disks informations\n'
113+
str += '-- ID\tModel\t\t\tStatus\n'
114+
for d, v in disks.items():
115+
str += '%s\t%s\t%s\n' % (d, v['model'], v['status'])
116+
return str[:-1]
117+
118+
def discover(objs, label):
119+
return lambda args: json.dumps({ 'data': [{label: o} for o in objs.keys()] })
120+
121+
def property(objs, prop):
122+
return lambda args: objs[args[0]][prop]
123+
124+
def execute(command, args = []):
125+
try:
126+
init()
127+
print commands[command](args)
128+
except (KeyError, IndexError):
129+
print 'Usage: 3ware-status [--zabbix][<prop> [<key>]]'
130+
print ''
131+
print 'Where prop is one of:'
132+
print '\n'.join([' %s' % command for command in commands])
133+
print ''
134+
print 'And key is one of the items output by <prop.discover>'
135+
136+
if normalmode or zabbixmode:
137+
commands = dict()
138+
if normalmode:
139+
commands['default'] = info
140+
commands['controller.discover'] = discover(controllers, '{#3WCONT}')
141+
commands['controller.model'] = property(controllers, 'model')
142+
commands['array.discover'] = discover(arrays, '{#3WARRAY}')
143+
commands['array.size'] = property(arrays, 'size')
144+
commands['array.status'] = property(arrays, 'status')
145+
commands['array.type'] = property(arrays, 'type')
146+
commands['disk.discover'] = discover(disks, '{#3WDISK}')
147+
commands['disk.model'] = property(disks, 'model')
148+
commands['disk.status'] = property(disks, 'status')
149+
150+
if len(argv) > 0:
151+
command = argv[0]
152+
args = argv[1:]
153+
execute(command, args)
152154
else:
153-
print 'RAID OK - Arrays: OK:'+str(nagiosgoodarray)+' Bad:'+str(nagiosbadarray)+' - Disks: OK:'+str(nagiosgooddisk)+' Bad:'+str(nagiosbaddisk)
154-
else:
155-
if bad:
156-
print '\nThere is at least one disk/array in a NOT OPTIMAL state.'
157-
sys.exit(1)
155+
execute('default')
156+
elif nagiosmode:
157+
init()
158+
badarray = len([a for a, v in arrays.items() if v['status'] not in ['OK', 'VERIFYING']])
159+
goodarray = len([a for a, v in arrays.items() if v['status'] in ['OK', 'VERIFYING']])
160+
baddisk = len([d for d, v in disks.items() if v['status'] not in ['OK', 'VERIFYING']])
161+
gooddisk = len([d for d, v in disks.items() if v['status'] in ['OK', 'VERIFYING']])
162+
bad = badarray or baddisk
163+
164+
print 'RAID %s - Arrays: OK:%s Bad:%s - Disks: OK:%s Bad:%s' % ('ERROR' if bad else 'OK', goodarray, badarray, gooddisk, baddisk)
165+
sys.exit(bad)

0 commit comments

Comments
 (0)