Skip to content

Commit 1a05bbb

Browse files
committed
Improving the CLI and adding a couple of host specific tests.
Signed-off-by: Rob Dobson <rob.dobson@citrix.com>
1 parent 0c1e4be commit 1a05bbb

6 files changed

Lines changed: 193 additions & 24 deletions

File tree

hwinfo/pci/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,17 @@ def get_info(self):
6868
return "%s %s (%s %s)" % (self.get_subvendor_name(), self.get_subdevice_name(), self.get_vendor_name(), self.get_device_name())
6969
else:
7070
return "%s %s" % (self.get_vendor_name(), self.get_device_name())
71+
72+
def get_rec(self):
73+
rec = {}
74+
rec['vendor_name'] = self.get_vendor_name()
75+
rec['device_name'] = self.get_device_name()
76+
rec['vendor_id'] = self.get_vendor_id()
77+
rec['device_id'] = self.get_device_id()
78+
rec['class'] = self.get_pci_class()
79+
rec['subvendor_name'] = self.get_subvendor_name()
80+
rec['subdevice_name'] = self.get_subdevice_name()
81+
rec['subvendor_id'] = self.get_subvendor_id()
82+
rec['subdevice_id'] = self.get_subdevice_id()
83+
84+
return rec

hwinfo/pci/lspci.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class LspciNParser(CommandParser):
4040
]
4141

4242

43-
LABEL_REGEX = r'[\w+\ \.\-\/]+'
43+
LABEL_REGEX = r'[\w+\ \.\-\/\[\]\(\)]+'
4444
CODE_REGEX = r'[0-9a-fA-F]{4}'
4545

4646
class LspciNNMMParser(CommandParser):
@@ -51,7 +51,7 @@ class LspciNNMMParser(CommandParser):
5151
ITEM_REGEXS = [
5252
r'(?P<pci_device_bus_id>([0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F]))\ "(?P<pci_device_class_name>' + LABEL_REGEX + r')\ \[(?P<pci_device_class>' + CODE_REGEX + r')\]"' \
5353
+ r'\ "(?P<pci_vendor_name>' + LABEL_REGEX + r')\ \[(?P<pci_vendor_id>' + CODE_REGEX + r')\]"\ "(?P<pci_device_name>' + LABEL_REGEX + r')\ \[(?P<pci_device_id>' + CODE_REGEX + r')\]"' \
54-
+ r'\ .*\ "((?P<pci_subvendor_name>' + LABEL_REGEX + r')\ \[(?P<pci_subvendor_id>' + CODE_REGEX + r')\])*"\ "((?P<pci_subdevice_name>' + LABEL_REGEX + r')\ \[(?P<pci_subdevice_id>' + CODE_REGEX + r')\])*',
54+
+ r'\ .*\"((?P<pci_subvendor_name>' + LABEL_REGEX + r')\ \[(?P<pci_subvendor_id>' + CODE_REGEX + r')\])*"\ "((?P<pci_subdevice_name>' + LABEL_REGEX + r')\ \[(?P<pci_subdevice_id>' + CODE_REGEX + r')\])*',
5555
]
5656

5757
ITEM_SEPERATOR = "\n"

hwinfo/pci/tests/test_lspci.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,61 @@ class IntelUSBControllerDeviceParse(TestSingleDeviceNNMMParse):
200200
'pci_subdevice_id': '02a3',
201201
}
202202

203+
class EmulexNicDeviceParse(TestSingleDeviceNNMMParse):
204+
205+
SAMPLE_DATA = '0c:00.0 "Ethernet controller [0200]" "Emulex Corporation [19a2]" "OneConnect 10Gb NIC (be3) [0710]" -r02 "Emulex Corporation [10df]" "Device [e70b]"'
206+
207+
DEVICE_REC = {
208+
'pci_device_bus_id': '0c:00.0',
209+
'pci_device_class': '0200',
210+
'pci_device_class_name': 'Ethernet controller',
211+
'pci_vendor_name': 'Emulex Corporation',
212+
'pci_vendor_id': '19a2',
213+
'pci_device_id': '0710',
214+
'pci_device_name': 'OneConnect 10Gb NIC (be3)',
215+
'pci_subvendor_name': 'Emulex Corporation',
216+
'pci_subvendor_id': '10df',
217+
'pci_subdevice_name': 'Device',
218+
'pci_subdevice_id': 'e70b',
219+
}
220+
221+
class LsiSASDeviceParse(TestSingleDeviceNNMMParse):
222+
223+
SAMPLE_DATA = '06:00.0 "Serial Attached SCSI controller [0107]" "LSI Logic / Symbios Logic [1000]" "SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire] [0070]" -r03 "IBM [1014]" "Device [03f8]"'
224+
225+
DEVICE_REC = {
226+
'pci_device_bus_id': '06:00.0',
227+
'pci_device_class': '0107',
228+
'pci_device_class_name': 'Serial Attached SCSI controller',
229+
'pci_vendor_name': 'LSI Logic / Symbios Logic',
230+
'pci_vendor_id': '1000',
231+
'pci_device_id': '0070',
232+
'pci_device_name': 'SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire]',
233+
'pci_subvendor_name': 'IBM',
234+
'pci_subvendor_id': '1014',
235+
'pci_subdevice_name': 'Device',
236+
'pci_subdevice_id': '03f8',
237+
}
238+
239+
class BroadcomNetDeviceParse(TestSingleDeviceNNMMParse):
240+
241+
SAMPLE_DATA = '01:00.0 "Ethernet controller [0200]" "Broadcom Corporation [14e4]" "NetXtreme BCM5720 Gigabit Ethernet PCIe [165f]" "Dell [1028]" "Device [1f5b]"'
242+
243+
DEVICE_REC = {
244+
'pci_device_bus_id': '01:00.0',
245+
'pci_device_class': '0200',
246+
'pci_device_class_name': 'Ethernet controller',
247+
'pci_vendor_name': 'Broadcom Corporation',
248+
'pci_vendor_id': '14e4',
249+
'pci_device_id': '165f',
250+
'pci_device_name': 'NetXtreme BCM5720 Gigabit Ethernet PCIe',
251+
'pci_subvendor_name': 'Dell',
252+
'pci_subvendor_id': '1028',
253+
'pci_subdevice_name': 'Device',
254+
'pci_subdevice_id': '1f5b',
255+
}
256+
257+
203258
class TestMultiDeviceNNMMParse(unittest.TestCase):
204259

205260
SAMPLE_FILE = '%s/lspci-nnmm' % DATA_DIR

hwinfo/tools/inspector.py

Lines changed: 116 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
#!/usr/bin/env python
22

33
from argparse import ArgumentParser
4+
from prettytable import PrettyTable
45
import paramiko
56

67
from hwinfo.pci import PCIDevice
78
from hwinfo.pci.lspci import *
9+
from hwinfo.host.dmidecode import *
810

911
def remote_command(host, username, password, cmd):
1012
client = paramiko.SSHClient()
1113
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
1214
client.connect(host, username=username, password=password, timeout=10)
1315
cmdstr = ' '.join(cmd)
14-
print "Executing '%s' on host '%s'" % (cmdstr, host)
16+
#print "Executing '%s' on host '%s'" % (cmdstr, host)
1517
_, stdout, stderr = client.exec_command(cmdstr)
1618
output = stdout.readlines()
1719
error = stderr.readlines()
@@ -25,43 +27,136 @@ def local_command(cmd):
2527

2628
class Host(object):
2729

28-
def __init__(self, host, username, password):
30+
def __init__(self, host='localhost', username=None, password=None):
2931
self.host = host
3032
self.username = username
3133
self.password = password
3234

3335
def exec_command(self, cmd):
34-
assert not self.host
35-
return local_command(cmd)
36+
if self.host == 'localhost':
37+
return local_command(cmd)
38+
else:
39+
return remote_command(self.host, self.username, self.password, cmd)
3640

3741
def get_pci_devices(self):
3842
data = self.exec_command(['lspci', '-nnmm'])
3943
parser = LspciNNMMParser(data)
4044
devices = parser.parse_items()
4145
return [PCIDevice(device) for device in devices]
4246

43-
class RemoteHost(Host):
44-
45-
def exec_command(self, cmd):
46-
return remote_command(self.host, self.username, self.password, cmd)
47-
47+
def get_info(self):
48+
data = self.exec_command(['dmidecode'])
49+
parser = DmidecodeParser(data)
50+
rec = parser.parse()
51+
return rec
52+
53+
def pci_filter(devices, types):
54+
res = []
55+
for device in devices:
56+
for t in types:
57+
if device.get_pci_class().startswith(t):
58+
res.append(device)
59+
break
60+
return res
61+
62+
def pci_filter_for_nics(devices):
63+
nic_types = ['02']
64+
return pci_filter(devices, nic_types)
65+
66+
def pci_filter_for_storage(devices):
67+
storage_types = ['00', '01']
68+
return pci_filter(devices, storage_types)
69+
70+
def pci_filter_for_gpu(devices):
71+
gpu_types = ['03']
72+
return pci_filter(devices, gpu_types)
73+
74+
def print_lines(lines):
75+
max_len = 0
76+
output = []
77+
for line in lines:
78+
output.append(line)
79+
if len(line) > max_len:
80+
max_len = len(line)
81+
print ""
82+
print "-" * max_len
83+
print '\n'.join(output)
84+
print "-" * max_len
85+
print ""
86+
87+
def rec_to_table(rec):
88+
table = PrettyTable(["Key", "Value"])
89+
table.align['Key'] = 'l'
90+
table.align['Value'] = 'l'
91+
for k, v in rec.iteritems():
92+
table.add_row([k, v])
93+
return table
94+
95+
def tabulate_pci_recs(recs):
96+
header = [
97+
'vendor_name',
98+
'vendor_id',
99+
'device_name',
100+
'device_id',
101+
'subvendor_name',
102+
'subvendor_id',
103+
'subdevice_name',
104+
'subdevice_id',
105+
]
106+
table = PrettyTable(header)
107+
for rec in recs:
108+
vls = [rec[k] for k in header]
109+
table.add_row(vls)
110+
return table
48111

49112
def main():
50113
"""Entry Point"""
51114

52115
parser = ArgumentParser(prog="hwinfo")
53-
parser.add_argument("cmd")
54-
parser.add_argument("host")
55-
parser.add_argument("username")
56-
parser.add_argument("password")
57116

58-
args = parser.parse_args()
59-
60-
host = RemoteHost(args.host, args.username, args.password)
61-
62-
if args.cmd == 'list':
63-
devices = host.get_pci_devices()
64-
for device in devices:
65-
print device.get_info()
117+
filter_choices = ['bios', 'nic', 'storage', 'gpu']
118+
parser.add_argument("-f", "--filter", choices=filter_choices)
119+
parser.add_argument("-m", "--machine", default='localhost')
120+
parser.add_argument("-u", "--username")
121+
parser.add_argument("-p", "--password")
66122

123+
args = parser.parse_args()
67124

125+
host = Host(args.machine, args.username, args.password)
126+
127+
options = []
128+
129+
if args.filter:
130+
filter_args = args.filter.split(',')
131+
for arg in filter_args:
132+
options.append(arg.strip())
133+
else:
134+
options = filter_choices
135+
136+
if 'bios' in options:
137+
print "Bios Info:"
138+
print ""
139+
print rec_to_table(host.get_info())
140+
print ""
141+
142+
if 'nic' in options:
143+
devices = pci_filter_for_nics(host.get_pci_devices())
144+
print "Ethernet Controller Info:"
145+
print ""
146+
print tabulate_pci_recs([dev.get_rec() for dev in devices])
147+
print ""
148+
149+
if 'storage' in options:
150+
devices = pci_filter_for_storage(host.get_pci_devices())
151+
print "Storage Controller Info:"
152+
print ""
153+
print tabulate_pci_recs([dev.get_rec() for dev in devices])
154+
print ""
155+
156+
if 'gpu' in options:
157+
devices = pci_filter_for_gpu(host.get_pci_devices())
158+
if devices:
159+
print "GPU Info:"
160+
print ""
161+
print tabulate_pci_recs([dev.get_rec() for dev in devices])
162+
print ""

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
},
1414
install_requires = [
1515
'paramiko',
16+
'prettytable',
1617
],
1718
)

tox.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ deps=
66
nose
77
coverage
88
mock
9+
prettytable
10+
paramiko
911

1012
commands=
1113
coverage
@@ -14,6 +16,8 @@ commands=
1416

1517
[testenv:lint]
1618
basepython=python2.7
17-
deps=pylint
19+
deps=
20+
pylint
21+
prettytable
1822
commands=
1923
pylint -r n --rcfile=.pylint.rc hwinfo

0 commit comments

Comments
 (0)