Skip to content

Commit b846f29

Browse files
authored
Add new Parser SnmpdConf (#4434)
Signed-off-by: xintli <[email protected]> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent 079bc1d commit b846f29

File tree

4 files changed

+175
-17
lines changed

4 files changed

+175
-17
lines changed

insights/parsers/snmp.py

+75-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"""
2+
snmpd parser
3+
============
4+
Parsers provided by this module are:
5+
26
TcpIpStats - file ``/proc/net/snmp``
3-
====================================
7+
------------------------------------
48
The ``TcpIpStats`` class implements the parsing of ``/proc/net/snmp``
59
file, which contains TCP/IP stats of individual layer.
610
@@ -9,9 +13,17 @@
913
The ``TcpIpStatsIPV6`` class implements the parsing of ``/proc/net/snmp6``
1014
file, which contains TCP/IP stats of individual layer.
1115
16+
17+
SnmpdConf - file ``/etc/snmp/snmpd.conf``
18+
-----------------------------------------
19+
The ``SnmpdConf`` class implements the parsing of ``/etc/snmp/snmpd.conf``
20+
file, which is the configuration file for the Net-SNMP SNMP agent.
1221
"""
1322

14-
from .. import Parser, parser, LegacyItemAccess
23+
from insights.core import LegacyItemAccess, Parser
24+
from insights.core.exceptions import ParseException
25+
from insights.core.plugins import parser
26+
from insights.parsers import get_active_lines
1527
from insights.specs import Specs
1628

1729

@@ -38,14 +50,13 @@ class TcpIpStats(Parser, LegacyItemAccess):
3850
... UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
3951
... UdpLite: 0 0 0 0 0 0 0 0
4052
... '''.strip()
41-
>>> from insights.tests import context_wrap
42-
>>> shared = {TcpIpStats: TcpIpStats(context_wrap(SNMP_CONTENT))}
43-
>>> stats = shared[TcpIpStats]
44-
>>> snmp_stats = stats.get("Ip")
45-
>>> print snmp_stats["DefaultTTL"]
53+
>>> type(proc_snmp_ipv4)
54+
<class 'insights.parsers.snmp.TcpIpStats'>
55+
>>> snmp_stats = proc_snmp_ipv4.get("Ip")
56+
>>> snmp_stats["DefaultTTL"]
4657
64
47-
>>> snmp_stats = stats.get("Udp")
48-
>>> print snmp_stats["InDatagrams"]
58+
>>> snmp_stats = proc_snmp_ipv4.get("Udp")
59+
>>> snmp_stats["InDatagrams"]
4960
18905
5061
5162
@@ -109,15 +120,14 @@ class TcpIpStatsIPV6(Parser, LegacyItemAccess):
109120
... Ip6InOctets 579410
110121
... Icmp6OutErrors 0
111122
... Icmp6InCsumErrors 0
112-
...'''.strip()
113-
>>> from insights.tests import context_wrap
114-
>>> shared = {TcpIpStatsIPV6: TcpIpStatsIPV6(context_wrap(SNMP_CONTENT))}
115-
>>> stats = shared[TcpIpStatsIPV6]
116-
>>> IP6_RX_stats = stats.get("Ip6InReceives")
117-
>>> print IP6_RX_stats
123+
... '''.strip()
124+
>>> type(proc_snmp_ipv6)
125+
<class 'insights.parsers.snmp.TcpIpStatsIPV6'>
126+
>>> IP6_RX_stats = proc_snmp_ipv6.get("Ip6InReceives")
127+
>>> IP6_RX_stats
118128
757
119-
>>> IP6_In_Disc = stats.get("Ip6InDiscards")
120-
>>> print IP6_In_Disc
129+
>>> IP6_In_Disc = proc_snmp_ipv6.get("Ip6InDiscards")
130+
>>> IP6_In_Disc
121131
10
122132
123133
@@ -141,3 +151,51 @@ def parse_content(self, content):
141151
line_split = line.split()
142152
snmp6_stats[line_split[0]] = int(line_split[1]) if len(line_split) > 1 and line_split[1] else None
143153
self.data = snmp6_stats
154+
155+
156+
@parser(Specs.snmpd_conf)
157+
class SnmpdConf(Parser, dict):
158+
"""
159+
Class for parsing the file ``/etc/snmp/snmpd.conf``
160+
161+
Sample file content::
162+
163+
# sec.name source community
164+
com2sec notConfigUser default public
165+
166+
# groupName securityModel securityName
167+
group notConfigGroup v1 notConfigUser
168+
group notConfigGroup v2c notConfigUser
169+
170+
# Make at least snmpwalk -v 1 localhost -c public system fast again.
171+
# name incl/excl subtree mask(optional)
172+
view systemview included .1.3.6.1.2.1.1
173+
view systemview included .1.3.6.1.2.1.25.1.1
174+
175+
# group context sec.model sec.level prefix read write notif
176+
access notConfigGroup "" any noauth exact systemview none none
177+
178+
dontLogTCPWrappersConnects yes
179+
include_ifmib_iface_prefix eth enp1s0
180+
181+
Examples:
182+
>>> type(snmpd_conf)
183+
<class 'insights.parsers.snmp.SnmpdConf'>
184+
>>> snmpd_conf['dontLogTCPWrappersConnects']
185+
['yes']
186+
>>> snmpd_conf['include_ifmib_iface_prefix']
187+
['eth enp1s0']
188+
"""
189+
190+
def parse_content(self, content):
191+
content = get_active_lines(content)
192+
if not content:
193+
raise ParseException('Empty Content')
194+
195+
for line in content:
196+
parts = line.split(None, 1)
197+
key = parts[0].strip()
198+
self.setdefault(key, [])
199+
if len(parts) > 1:
200+
value = parts[1].strip()
201+
self[key].append(value)

insights/specs/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ class Specs(SpecSet):
754754
smartpdc_settings = RegistryPoint(filterable=True)
755755
smbstatus_S = RegistryPoint()
756756
smbstatus_p = RegistryPoint()
757+
snmpd_conf = RegistryPoint(filterable=True)
757758
sockstat = RegistryPoint(no_obfuscate=['hostname', 'ip', 'ipv6', 'mac'])
758759
softnet_stat = RegistryPoint(no_obfuscate=['hostname', 'ip', 'ipv6', 'mac'])
759760
software_collections_list = RegistryPoint(no_obfuscate=['hostname', 'ip', 'ipv6', 'mac'])

insights/specs/default.py

+1
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ class DefaultSpecs(Specs):
827827
setup_named_chroot = simple_file("/usr/libexec/setup-named-chroot.sh")
828828
smartctl_health = foreach_execute(dev.physical_devices, "/usr/sbin/smartctl -H %s -j")
829829
smbstatus_p = simple_command("/usr/bin/smbstatus -p")
830+
snmpd_conf = simple_file("/etc/snmp/snmpd.conf")
830831
sockstat = simple_file("/proc/net/sockstat")
831832
softnet_stat = simple_file("proc/net/softnet_stat")
832833
software_collections_list = simple_command('/usr/bin/scl --list')

insights/tests/parsers/test_snmp.py

+98
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
import doctest
2+
import pytest
3+
from insights.core.exceptions import ParseException
4+
from insights.parsers import snmp
15
from insights.parsers.snmp import TcpIpStats
26
from insights.parsers.snmp import TcpIpStatsIPV6
7+
from insights.parsers.snmp import SnmpdConf
38
from insights.tests import context_wrap
49

510
PROC_SNMP = """
@@ -121,6 +126,66 @@
121126
Ip6InDiscards
122127
""".strip()
123128

129+
TCP_STATS_DOC = '''
130+
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
131+
Ip: 2 64 43767 0 0 0 0 0 41807 18407 12 73 0 0 0 10 0 0 0
132+
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
133+
Icmp: 34 0 0 34 0 0 0 0 0 0 0 0 0 0 44 0 44 0 0 0 0 0 0 0 0 0 0
134+
IcmpMsg: InType3 OutType3
135+
IcmpMsg: 34 44
136+
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
137+
Tcp: 1 200 120000 -1 444 0 0 6 7 19269 17050 5 4 234 0
138+
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
139+
Udp: 18905 34 0 1348 0 0 0 3565
140+
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
141+
UdpLite: 0 0 0 0 0 0 0 0
142+
'''.strip()
143+
144+
TCP_IP_STATS_IPV6_DOC = '''
145+
Ip6InReceives 757
146+
Ip6InHdrErrors 0
147+
Ip6InTooBigErrors 0
148+
Ip6InNoRoutes 0
149+
Ip6InAddrErrors 0
150+
Ip6InDiscards 10
151+
Ip6OutForwDatagrams 0
152+
Ip6OutDiscards 0
153+
Ip6OutNoRoutes 0
154+
Ip6InOctets 579410
155+
Icmp6OutErrors 0
156+
Icmp6InCsumErrors 0
157+
'''.strip()
158+
159+
SNMPD_CONF = """
160+
# sec.name source community
161+
com2sec notConfigUser default public
162+
163+
# groupName securityModel securityName
164+
group notConfigGroup v1 notConfigUser
165+
group notConfigGroup v2c notConfigUser
166+
167+
# Make at least snmpwalk -v 1 localhost -c public system fast again.
168+
# name incl/excl subtree mask(optional)
169+
view systemview included .1.3.6.1.2.1.1
170+
view systemview included .1.3.6.1.2.1.25.1.1
171+
172+
# group context sec.model sec.level prefix read write notif
173+
access notConfigGroup "" any noauth exact systemview none none
174+
175+
dontLogTCPWrappersConnects yes
176+
include_ifmib_iface_prefix eth enp1s0
177+
leave_pidfile
178+
179+
syscontact Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
180+
""".strip()
181+
182+
SNMPD_CONF_NO_HIT = """
183+
# sec.name source community
184+
""".strip()
185+
186+
SNMPD_CONF_EMPTY = """
187+
""".strip()
188+
124189

125190
def test_snmp():
126191
stats = TcpIpStats(context_wrap(PROC_SNMP))
@@ -165,3 +230,36 @@ def test_snmp6():
165230
snmp6_stats_odd = stats.get("some_unknown")
166231
assert snmp6_stats_disx is None
167232
assert snmp6_stats_odd is None
233+
234+
235+
def test_snmpd_conf():
236+
result = SnmpdConf(context_wrap(SNMPD_CONF))
237+
assert len(result) == 8
238+
assert 'com2sec' in result
239+
assert result['group'][0] == 'notConfigGroup v1 notConfigUser'
240+
assert result['group'][1] == 'notConfigGroup v2c notConfigUser'
241+
assert result['leave_pidfile'] == []
242+
assert result['access'] == ['notConfigGroup "" any noauth exact systemview none none']
243+
assert result['syscontact'] == ['Root <root@localhost> (configure /etc/snmp/snmp.local.conf)']
244+
245+
246+
def test_snmpd_conf_empty():
247+
with pytest.raises(ParseException) as exc:
248+
SnmpdConf(context_wrap(SNMPD_CONF_EMPTY))
249+
assert str(exc.value) == "Empty Content"
250+
251+
252+
def test_snmpd_conf_empty2():
253+
with pytest.raises(ParseException) as exc:
254+
SnmpdConf(context_wrap(SNMPD_CONF_NO_HIT))
255+
assert str(exc.value) == "Empty Content"
256+
257+
258+
def test_doc():
259+
env = {
260+
'proc_snmp_ipv4': TcpIpStats(context_wrap(TCP_STATS_DOC)),
261+
'proc_snmp_ipv6': TcpIpStatsIPV6(context_wrap(TCP_IP_STATS_IPV6_DOC)),
262+
'snmpd_conf': SnmpdConf(context_wrap(SNMPD_CONF)),
263+
}
264+
failed, total = doctest.testmod(snmp, globs=env)
265+
assert failed == 0

0 commit comments

Comments
 (0)