Skip to content

Commit 67005a8

Browse files
author
Evan Fraser
committed
Added HP 3PAR Module
1 parent b406746 commit 67005a8

3 files changed

Lines changed: 345 additions & 0 deletions

File tree

hp_3par/README.mkdn

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
EMC RecoverPoint 4.x
2+
===============
3+
4+
This is a new GMOND Python Module that gets metrics from HP 3PAR arrays via SSH.
5+
6+
Currently gathers per Volume:
7+
* Read/Write IOs
8+
* Read/Write Latency
9+
* Read/Write IO Size
10+
* Read/Write Throughput
11+
12+
13+
## Compatibility
14+
* Compatible with 3PAR 7450C and OS 3.2.1 (tested)
15+
* Other versions of 3PAR / OS may work fine.
16+
17+
## DEPENDS
18+
* Python modules: paramiko ssh module
19+
- install with 'pip3 install paramiko'
20+
21+
## USAGE
22+
* Save the hp3par.pyconf into /etc/ganglia/conf.d directory.
23+
* Save the hp3par.py into your ganglia python module dir eg: /usr/lib/ganglia/python_modules. Update the Array Names, IP's, Usernames and passwords.
24+
* Restart gmond and the Arrays should appear in ganglia.
25+
26+
27+
## AUTHOR
28+
29+
Author: Evan Fraser <[email protected]>

hp_3par/conf.d/hp3par.pyconf

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Name: hp3par.pyconf
2+
# Author: Evan Fraser ([email protected])
3+
# Desc: Config file for the ganglia gmond HP 3PAR module.
4+
# Date: 14/05/2015
5+
# To use: Save this file in /etc/ganglia/conf.d/
6+
7+
modules {
8+
module {
9+
name = "hp3par"
10+
language = "python"
11+
}
12+
}
13+
#/* Collection groups for the
14+
# example python module */
15+
collection_group {
16+
collect_every = 20
17+
time_threshold = 50
18+
metric {
19+
name_match = "(.+)iops"
20+
}
21+
metric {
22+
name_match = "(.+)qlen"
23+
}
24+
metric {
25+
name_match = "(.+)throughput"
26+
}
27+
metric {
28+
name_match = "(.+)latency"
29+
}
30+
metric {
31+
name_match = "(.+)iosize"
32+
}
33+
}
34+

hp_3par/python_modules/hp3par.py

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
#!/usr/bin/env python3
2+
# Name: gmond_3par.py
3+
# Desc: Ganglia Python module for gathering HP 3PAR storage metrics via ssh
4+
# Author: Evan Fraser ([email protected])
5+
# Date: 07/05/2015
6+
import warnings,time,readline
7+
from pprint import pprint
8+
9+
with warnings.catch_warnings():
10+
warnings.simplefilter("ignore")
11+
import paramiko
12+
13+
14+
array_dict = {}
15+
16+
descriptors = list()
17+
METRICSDICT = {
18+
'time' : 0,
19+
'data' : {}
20+
}
21+
22+
'''This is the minimum interval between querying the RPA for metrics.
23+
Each ssh query takes 1.6s so we limit the interval between getting metrics to this interval.'''
24+
25+
METRICS_CACHE_MAX = 10
26+
27+
28+
def run_ssh_thread(ip,user,passwd,cmd):
29+
30+
sshcon = paramiko.SSHClient()
31+
sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy())
32+
try:
33+
sshcon.connect(ip, username=user,password=passwd,look_for_keys='False')
34+
stdin, stdout, stderr = sshcon.exec_command(cmd)
35+
36+
37+
except paramiko.ssh_exception.AuthenticationException as e:
38+
print('Failed to perform SSH', e)
39+
exit(1)
40+
41+
except:
42+
print('Failed to perform SSH')
43+
exit(1)
44+
45+
output_list = []
46+
for line in stdout:
47+
#print(line)
48+
output_list.append(line)
49+
50+
return output_list
51+
52+
53+
def get_vol_perf_stats(ip, user, passwd):
54+
55+
cmd = 'statvv -iter 1 -rw'
56+
line_list = run_ssh_thread(ip, user, passwd, cmd)
57+
vol_perf_stats = []
58+
line_num = 0
59+
for line in line_list:
60+
line_num += 1
61+
if '---' in line:
62+
break
63+
'''if line_num == 2:
64+
print(line)'''
65+
if line_num >= 4:
66+
67+
#volname, metrictype, iocur, ioavg,iomax,thrcur,thravg,thrmax,latcur,latavg,sizecur,sizeavg,qlen = line.split()
68+
#metric_list = []
69+
#metric_list = line.split()
70+
#print(line)
71+
vol_perf_stats.append(line)
72+
73+
return vol_perf_stats
74+
75+
76+
def get_vol_list(ip, user, passwd):
77+
'''Get a list of volumes to build metric definitions with'''
78+
cmd = 'showvv'
79+
80+
showvv_list = run_ssh_thread(ip, user, passwd, cmd)
81+
82+
vol_list = []
83+
line_num = 0
84+
for line in showvv_list:
85+
86+
line_num += 1
87+
if '-------------------------' in line:
88+
break
89+
if '-----' in line or 'rcpy.' in line or '.srdata' in line or '0 admin' in line:
90+
continue
91+
if line_num >= 4:
92+
vol_stats = line.split()
93+
vol_list.append(vol_stats[1])
94+
95+
return vol_list
96+
97+
98+
def get_metric(name):
99+
"""Callback function to get the metrics"""
100+
101+
global METRICSDICT
102+
103+
metrics = {}
104+
105+
if (time.time() - METRICSDICT['time']) > METRICS_CACHE_MAX:
106+
print('time expired, will get metrics')
107+
for array in array_dict:
108+
arrayname = array_dict[array]
109+
110+
vol_perf_stats = get_vol_perf_stats(array_dict[array]['ipaddr'], array_dict[array]['user'], array_dict[array]['pass'])
111+
112+
for vol in vol_perf_stats:
113+
vol_name, metric_type, iocur, ioavg,iomax,thrcur,thravg,thrmax,latcur,latavg,sizecur,sizeavg,qlen = vol.split()
114+
#print(vol_name)
115+
116+
#don't give metrics on rcopy snapshots
117+
if 'rcpy' in vol_name:
118+
continue
119+
elif 'r' in metric_type:
120+
#print('IOcurr: ',iocur)
121+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_read_iops'] = float(iocur)
122+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_read_latency'] = float(latcur)
123+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_read_throughput'] = float(thrcur)
124+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_read_iosize'] = float(sizecur)
125+
126+
elif 'w' in metric_type:
127+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_write_iops'] = float(iocur)
128+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_write_latency'] = float(latcur)
129+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_write_throughput'] = float(thrcur)
130+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_write_iosize'] = float(sizecur)
131+
elif 't' in metric_type:
132+
metrics[array_dict[array]['array_name'] + '_' + vol_name + '_qlen'] = float(qlen)
133+
134+
METRICSDICT= {
135+
'time': time.time(),
136+
'data': metrics
137+
}
138+
139+
if name in METRICSDICT['data']:
140+
return METRICSDICT['data'][name]
141+
else:
142+
return 0
143+
144+
def create_desc(skel, prop):
145+
d = skel.copy()
146+
147+
for k,v in iter(prop.items()):
148+
d[k] = v
149+
return d
150+
151+
152+
def define_metrics(Desc_Skel, array_name, vols, ip):
153+
'''Volume metrics'''
154+
for vol in vols:
155+
'''Iops'''
156+
descriptors.append(create_desc(Desc_Skel, {
157+
"name": (array_name + '_' + vol + '_read_iops').encode('ascii', 'ignore'),
158+
"units": 'iops',
159+
"description" : "Read IOs per second",
160+
'groups': 'io',
161+
"spoof_host" : str(ip) + ':' + array_name,
162+
}))
163+
descriptors.append(create_desc(Desc_Skel, {
164+
"name": (array_name + '_' + vol + '_write_iops').encode('ascii', 'ignore'),
165+
"units": 'iops',
166+
"description" : "Write IOs per second",
167+
'groups': 'io',
168+
"spoof_host" : str(ip) + ':' + array_name,
169+
}))
170+
descriptors.append(create_desc(Desc_Skel, {
171+
"name": (array_name + '_' + vol + '_qlen').encode('ascii', 'ignore'),
172+
"units": 'ios',
173+
"description" : "Queue Length",
174+
'groups': 'io',
175+
"spoof_host" : str(ip) + ':' + array_name,
176+
}))
177+
'''Latency'''
178+
descriptors.append(create_desc(Desc_Skel, {
179+
"name": (array_name + '_' + vol + '_read_latency').encode('ascii', 'ignore'),
180+
"units": 'ms',
181+
"description" : "Read response time",
182+
'groups': 'latency',
183+
"spoof_host" : str(ip) + ':' + array_name,
184+
}))
185+
descriptors.append(create_desc(Desc_Skel, {
186+
"name": (array_name + '_' + vol + '_write_latency').encode('ascii', 'ignore'),
187+
"units": 'ms',
188+
"description" : "Write response time",
189+
'groups': 'latency',
190+
"spoof_host" : str(ip) + ':' + array_name,
191+
}))
192+
'''Throughput'''
193+
descriptors.append(create_desc(Desc_Skel, {
194+
"name": (array_name + '_' + vol + '_read_throughput').encode('ascii', 'ignore'),
195+
"units": 'KB',
196+
"description" : "Read throughput",
197+
'groups': 'throughput',
198+
"spoof_host" : str(ip) + ':' + array_name,
199+
}))
200+
descriptors.append(create_desc(Desc_Skel, {
201+
"name": (array_name + '_' + vol + '_write_throughput').encode('ascii', 'ignore'),
202+
"units": 'KB',
203+
"description" : "Write throughput",
204+
'groups': 'throughput',
205+
"spoof_host" : str(ip) + ':' + array_name,
206+
}))
207+
'''IOsz'''
208+
descriptors.append(create_desc(Desc_Skel, {
209+
"name": (array_name + '_' + vol + '_read_iosize').encode('ascii', 'ignore'),
210+
"units": 'KB',
211+
"description" : "Read IO Size",
212+
'groups': 'io',
213+
"spoof_host" : str(ip) + ':' + array_name,
214+
}))
215+
descriptors.append(create_desc(Desc_Skel, {
216+
"name": (array_name + '_' + vol + '_write_iosize').encode('ascii', 'ignore'),
217+
"units": 'KB',
218+
"description" : "Write IO Size",
219+
'groups': 'io',
220+
"spoof_host" : str(ip) + ':' + array_name,
221+
}))
222+
pprint(descriptors)
223+
224+
return descriptors
225+
226+
227+
def metric_init(params):
228+
"""metric_init(params) this is called by gmond to initialise the metrics"""
229+
230+
global array_dict
231+
232+
array_dict = {
233+
'array1': {'array_name': 'array1', 'ipaddr': '192.168.1.50', 'user': '3paruser', 'pass': '3parpass'},
234+
'array2': {'array_name': 'array2', 'ipaddr': '192.168.1.51', 'user': '3paruser', 'pass': '3parpass'},
235+
236+
}
237+
238+
Desc_Skel = {
239+
'name' : 'XXX',
240+
'call_back' : get_metric,
241+
'time_max' : 600,
242+
'value_type' : 'double',
243+
'format' : '%0f',
244+
'units' : 'XXX',
245+
'slope' : 'both',
246+
'description' : 'XXX',
247+
'groups' : 'storage',
248+
}
249+
descriptors = []
250+
#pprint(params)
251+
for array in array_dict:
252+
ip = array_dict[array]['ipaddr']
253+
user = array_dict[array]['user']
254+
passwd = array_dict[array]['pass']
255+
256+
vols = get_vol_list(ip, user, passwd)
257+
258+
259+
'''create descriptors for the array'''
260+
array_descriptors = define_metrics(Desc_Skel, array_dict[array]['array_name'], vols, ip)
261+
descriptors = descriptors + array_descriptors
262+
263+
return descriptors
264+
265+
266+
if __name__ == '__main__':
267+
"""Main function, for when executed from CLI"""
268+
params = {
269+
'array1': {'array_name': 'array1', 'ipaddr': '192.168.1.50', 'user': '3paruser', 'pass': '3parpass'},
270+
'array2': {'array_name': 'array2', 'ipaddr': '192.168.1.51', 'user': '3paruser', 'pass': '3parpass'},
271+
272+
}
273+
274+
descriptors = metric_init(params)
275+
pprint(descriptors)
276+
print(len(descriptors))
277+
while True:
278+
for d in descriptors:
279+
v = d['call_back'](d['name'])
280+
print('value for %s is %u' % (d['name'], v))
281+
print('Sleeping 5 seconds')
282+
time.sleep(5)

0 commit comments

Comments
 (0)