Skip to content

Commit 4cf2a53

Browse files
authored
Merge pull request #957 from bleuzkernel/master
[IOSXR] New `ShowSubscriberSessionAllSummary` Genie parser for IOS XR `show subscriber session all summary`
2 parents 7d8175a + 1ad5d8a commit 4cf2a53

File tree

9 files changed

+513
-0
lines changed

9 files changed

+513
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--------------------------------------------------------------------------------
2+
New
3+
--------------------------------------------------------------------------------
4+
5+
* IOSXR
6+
* Added `ShowSubscriberSessionAllSummary` Parser
7+
* Added schema and parser for `show subscriber session all summary` command.
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
"""
2+
show_subscriber.py
3+
IOSXR parsers for the following show commands:
4+
5+
* `show subscriber session all summary`
6+
"""
7+
8+
# Python
9+
import re
10+
11+
# parser utils
12+
from genie.libs.parser.utils.common import Common
13+
14+
# Metaparser
15+
from genie.metaparser import MetaParser
16+
from genie.metaparser.util.schemaengine import Any, Optional, Or, Schema
17+
18+
19+
# =======================================
20+
# Schema for 'show subscriber session all summary'
21+
# =======================================
22+
class ShowSubscriberSessionAllSummarySchema(MetaParser):
23+
"""Schema for `show subscriber session all summary`"""
24+
25+
schema = {
26+
"subscriber": {
27+
"session_summary": {
28+
"state": {
29+
Or(
30+
"pppoe", "ip_subscriber_dhcp", "ip_subscriber_packet"
31+
): {
32+
Optional("initializing"): int,
33+
Optional("connecting"): int,
34+
Optional("connected"): int,
35+
Optional("activated"): int,
36+
Optional("idle"): int,
37+
Optional("disconnecting"): int,
38+
Optional("end"): int,
39+
Optional("total"): int,
40+
},
41+
},
42+
"address_family": {
43+
Or(
44+
"pppoe", "ip_subscriber_dhcp", "ip_subscriber_packet"
45+
): {
46+
Optional("in_progress"): int,
47+
Optional("ipv4_only"): int,
48+
Optional("ipv6_only"): int,
49+
Optional("dual_partial_up"): int,
50+
Optional("dual_up"): int,
51+
Optional("lac"): int,
52+
Optional("total"): int,
53+
},
54+
},
55+
}
56+
}
57+
}
58+
59+
60+
# =======================================
61+
# Parser for 'show subscriber session all summary'
62+
# =======================================
63+
class ShowSubscriberSessionAllSummary(ShowSubscriberSessionAllSummarySchema):
64+
"""Parser for `show subscriber session all summary`"""
65+
66+
cli_command = "show subscriber session all summary"
67+
68+
# RP/0/RSP0/CPU0:Router#show subscriber session all summary
69+
# Thu Jan 01 00:00:00.000 UTC
70+
71+
# Session Summary Information for all nodes
72+
73+
# Type PPPoE IPSub IPSub
74+
# (DHCP) (PKT)
75+
# ==== ===== ====== =====
76+
77+
# Session Counts by State:
78+
# initializing 0 0 0
79+
# connecting 0 0 0
80+
# connected 0 0 0
81+
# activated 0 0 666
82+
# idle 0 0 0
83+
# disconnecting 0 0 0
84+
# end 0 0 0
85+
# Total: 0 0 666
86+
87+
# Session Counts by Address-Family/LAC:
88+
# in progress 0 0 0
89+
# ipv4-only 0 0 333
90+
# ipv6-only 0 0 333
91+
# dual-partial-up 0 0 0
92+
# dual-up 0 0 0
93+
# lac 0 0 0
94+
# Total: 0 0 666
95+
96+
def cli(self, output=None) -> dict[str, object]:
97+
if output is None:
98+
# Execute command to get the raw output
99+
out = self.device.execute(self.cli_command)
100+
else:
101+
out = output
102+
103+
# initial return dictionary
104+
ret_dict: dict = {}
105+
106+
# Locate sections with regex
107+
108+
# Session Counts by State:
109+
# initializing 0 0 0
110+
# connecting 0 0 0
111+
# connected 0 0 0
112+
# activated 0 0 666
113+
# idle 0 0 0
114+
# disconnecting 0 0 0
115+
# end 0 0 0
116+
# Total: 0 0 666
117+
state_match = re.search(
118+
r"Session Counts by State:\s*(.+?)(?:\n\s*\n|\Z)",
119+
out,
120+
re.DOTALL | re.IGNORECASE,
121+
)
122+
123+
# Session Counts by Address-Family/LAC:
124+
# in progress 0 0 0
125+
# ipv4-only 0 0 333
126+
# ipv6-only 0 0 333
127+
# dual-partial-up 0 0 0
128+
# dual-up 0 0 0
129+
# lac 0 0 0
130+
# Total: 0 0 666
131+
af_match = re.search(
132+
r"Session Counts by Address-Family/LAC:\s*(.+?)(?:\n\s*\n|\Z)",
133+
out,
134+
re.DOTALL | re.IGNORECASE,
135+
)
136+
137+
# The actual section as string, or empty string if not found
138+
state_sec = state_match.group(1) if state_match else ""
139+
af_sec = af_match.group(1) if af_match else ""
140+
141+
if state_sec or af_sec:
142+
# Column-to-key mapping (left-to-right numeric columns)
143+
svc_keys: list[str] = [
144+
"pppoe",
145+
"ip_subscriber_dhcp",
146+
"ip_subscriber_packet",
147+
]
148+
149+
# Build output skeleton
150+
ret_dict = {
151+
"subscriber": {
152+
"session_summary": {
153+
"state": {k: {} for k in svc_keys},
154+
"address_family": {k: {} for k in svc_keys},
155+
}
156+
}
157+
}
158+
159+
# The following regex will match lines like, excluding the colon sign:
160+
# initializing 0 0 0
161+
# connecting 0 0 0
162+
# connected 0 0 0
163+
# activated 0 0 666
164+
# idle 0 0 0
165+
# disconnecting 0 0 0
166+
# end 0 0 0
167+
# Total: 0 0 666
168+
# in progress 0 0 0
169+
# ipv4-only 0 0 333
170+
# ipv6-only 0 0 333
171+
# dual-partial-up 0 0 0
172+
# dual-up 0 0 0
173+
# lac 0 0 0
174+
# Total: 0 0 666
175+
p = re.compile(
176+
r"^(?P<key>[A-Za-z0-9][A-Za-z0-9 \/\-\(\)\.]*?)(?::)?\s+(?P<pppoe>\d+)\s+(?P<dhcp>\d+)\s+(?P<pkt>\d+)$"
177+
)
178+
179+
# State section the rows with regex only (fallback)
180+
for line in state_sec.splitlines():
181+
line = line.strip()
182+
183+
if m := p.match(line):
184+
key = (
185+
m.group("key")
186+
.replace(" ", "_")
187+
.replace("-", "_")
188+
.lower()
189+
)
190+
ret_dict["subscriber"]["session_summary"]["state"][
191+
"pppoe"
192+
][key] = int(m.group("pppoe"))
193+
ret_dict["subscriber"]["session_summary"]["state"][
194+
"ip_subscriber_dhcp"
195+
][key] = int(m.group("dhcp"))
196+
ret_dict["subscriber"]["session_summary"]["state"][
197+
"ip_subscriber_packet"
198+
][key] = int(m.group("pkt"))
199+
200+
# Address-Family section the rows with regex only (fallback)
201+
for line in af_sec.splitlines():
202+
line = line.strip()
203+
204+
if m := p.match(line):
205+
key = (
206+
m.group("key")
207+
.replace(" ", "_")
208+
.replace("-", "_")
209+
.lower()
210+
)
211+
ret_dict["subscriber"]["session_summary"][
212+
"address_family"
213+
]["pppoe"][key] = int(m.group("pppoe"))
214+
ret_dict["subscriber"]["session_summary"][
215+
"address_family"
216+
]["ip_subscriber_dhcp"][key] = int(m.group("dhcp"))
217+
ret_dict["subscriber"]["session_summary"][
218+
"address_family"
219+
]["ip_subscriber_packet"][key] = int(m.group("pkt"))
220+
221+
return ret_dict

src/genie/libs/parser/iosxr/tests/ShowSubscriberSessionAllSummary/cli/empty/empty_output_output.txt

Whitespace-only changes.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
expected_output = {
2+
"subscriber": {
3+
"session_summary": {
4+
"state": {
5+
"pppoe": {
6+
"initializing": 0,
7+
"connecting": 0,
8+
"connected": 0,
9+
"activated": 0,
10+
"idle": 0,
11+
"disconnecting": 0,
12+
"end": 0,
13+
"total": 0,
14+
},
15+
"ip_subscriber_dhcp": {
16+
"initializing": 0,
17+
"connecting": 0,
18+
"connected": 0,
19+
"activated": 0,
20+
"idle": 0,
21+
"disconnecting": 0,
22+
"end": 0,
23+
"total": 0,
24+
},
25+
"ip_subscriber_packet": {
26+
"initializing": 0,
27+
"connecting": 0,
28+
"connected": 0,
29+
"activated": 666,
30+
"idle": 0,
31+
"disconnecting": 0,
32+
"end": 0,
33+
"total": 666,
34+
},
35+
},
36+
"address_family": {
37+
"pppoe": {
38+
"in_progress": 0,
39+
"ipv4_only": 0,
40+
"ipv6_only": 0,
41+
"dual_partial_up": 0,
42+
"dual_up": 0,
43+
"lac": 0,
44+
"total": 0,
45+
},
46+
"ip_subscriber_dhcp": {
47+
"in_progress": 0,
48+
"ipv4_only": 0,
49+
"ipv6_only": 0,
50+
"dual_partial_up": 0,
51+
"dual_up": 0,
52+
"lac": 0,
53+
"total": 0,
54+
},
55+
"ip_subscriber_packet": {
56+
"in_progress": 0,
57+
"ipv4_only": 333,
58+
"ipv6_only": 333,
59+
"dual_partial_up": 0,
60+
"dual_up": 0,
61+
"lac": 0,
62+
"total": 666,
63+
},
64+
},
65+
}
66+
}
67+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
RP/0/RSP0/CPU0:Router#show subscriber session all summary
2+
Thu Jan 01 00:00:00.000 UTC
3+
4+
Session Summary Information for all nodes
5+
6+
Type PPPoE IPSub IPSub
7+
(DHCP) (PKT)
8+
==== ===== ====== =====
9+
10+
Session Counts by State:
11+
initializing 0 0 0
12+
connecting 0 0 0
13+
connected 0 0 0
14+
activated 0 0 666
15+
idle 0 0 0
16+
disconnecting 0 0 0
17+
end 0 0 0
18+
Total: 0 0 666
19+
20+
21+
Session Counts by Address-Family/LAC:
22+
in progress 0 0 0
23+
ipv4-only 0 0 333
24+
ipv6-only 0 0 333
25+
dual-partial-up 0 0 0
26+
dual-up 0 0 0
27+
lac 0 0 0
28+
Total: 0 0 666
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
expected_output = {
2+
"subscriber": {
3+
"session_summary": {
4+
"state": {
5+
"pppoe": {
6+
"initializing": 0,
7+
"connecting": 0,
8+
"connected": 0,
9+
"activated": 666,
10+
"idle": 0,
11+
"disconnecting": 0,
12+
"end": 0,
13+
"total": 666,
14+
},
15+
"ip_subscriber_dhcp": {
16+
"initializing": 0,
17+
"connecting": 0,
18+
"connected": 0,
19+
"activated": 0,
20+
"idle": 0,
21+
"disconnecting": 0,
22+
"end": 0,
23+
"total": 0,
24+
},
25+
"ip_subscriber_packet": {
26+
"initializing": 0,
27+
"connecting": 0,
28+
"connected": 0,
29+
"activated": 0,
30+
"idle": 0,
31+
"disconnecting": 0,
32+
"end": 0,
33+
"total": 0,
34+
},
35+
},
36+
"address_family": {
37+
"pppoe": {
38+
"in_progress": 0,
39+
"ipv4_only": 333,
40+
"ipv6_only": 333,
41+
"dual_partial_up": 0,
42+
"dual_up": 0,
43+
"lac": 0,
44+
"total": 666,
45+
},
46+
"ip_subscriber_dhcp": {
47+
"in_progress": 0,
48+
"ipv4_only": 0,
49+
"ipv6_only": 0,
50+
"dual_partial_up": 0,
51+
"dual_up": 0,
52+
"lac": 0,
53+
"total": 0,
54+
},
55+
"ip_subscriber_packet": {
56+
"in_progress": 0,
57+
"ipv4_only": 0,
58+
"ipv6_only": 0,
59+
"dual_partial_up": 0,
60+
"dual_up": 0,
61+
"lac": 0,
62+
"total": 0,
63+
},
64+
},
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)