Skip to content

Commit 70edf0c

Browse files
committed
resolve confilict
2 parents 7553aae + 10fdc7f commit 70edf0c

File tree

4 files changed

+182
-110
lines changed

4 files changed

+182
-110
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--------------------------------------------------------------------------------
2+
New
3+
--------------------------------------------------------------------------------
4+
* IOSXE
5+
* Modified ShowRunningConfigAAAUsernameSchema(MetaParser):
6+
* added: optional 'autocommand'
7+
* added: optional 'nopassword'
8+
9+
* IOSXE
10+
* Modified ShowRunningConfigAAAUsername(ShowRunningConfigAAAUsernameSchema)
11+
* Added support for 'autocommand'
12+
* Added support for 'nopassword'
13+
* Added support for multiline usernames
14+
* Added logging (warning) for unsupported options
15+
16+
--------------------------------------------------------------------------------
17+
Fix
18+
--------------------------------------------------------------------------------
19+
* IOSXE
20+
* Modified ShowRunningConfigAAAUsername(ShowRunningConfigAAAUsernameSchema)
21+
* Changed how the cli() function parses arguments and parameters.
22+

src/genie/libs/parser/iosxe/show_run.py

Lines changed: 111 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
# Python
1616
import re
17+
import logging
1718

1819
# Metaparser
1920
from genie.metaparser import MetaParser
@@ -23,6 +24,8 @@
2324
# import parser utils
2425
from genie.libs.parser.utils.common import Common
2526

27+
log = logging.getLogger(__name__)
28+
2629
# =================================================
2730
# Schema for:
2831
# * 'show run policy-map {name}'
@@ -2751,7 +2754,9 @@ class ShowRunningConfigAAAUsernameSchema(MetaParser):
27512754
Optional('common_criteria_policy'): str,
27522755
Optional('view'): str,
27532756
Optional('type'): str,
2757+
Optional('autocommand'): str,
27542758
Optional('onetime'): bool,
2759+
Optional('nopassword'): bool,
27552760
Optional('secret'): {
27562761
Optional('type'): int,
27572762
Optional('secret'): str,
@@ -2897,139 +2902,135 @@ def cli(self, output=None):
28972902
else:
28982903
out = output
28992904

2900-
# username testuser password 0 lab
2901-
p1 = re.compile(r'^username +(?P<username>\S+) +password +(?P<type>\d) +(?P<password>.*)$')
2905+
# NOTE: All of the following regular expressions should be anchored to
2906+
# the begining of the line ('^'). As each is used the line will be
2907+
# shortened. Think of this as popping arguments (and their parameters)
2908+
# off of a stack (the front of the line).
2909+
#
2910+
# There are some arguments that cannot have any subsequent arguments.
2911+
# These are:
2912+
# 1) password
2913+
# 2) secret
2914+
# 3) autocommand
2915+
# These arguments shall also match the end of the line ('$').
2916+
#
2917+
# All arguments that are not matched to the end of the line shall match
2918+
# an optional trailing space (' ?').
2919+
2920+
# username testuser
2921+
username_cmd = re.compile(r'^username (?P<username>\S+) ?')
29022922

2903-
# username testuser common-criteria-policy Test-CC password 0 password
2904-
p2 = re.compile(
2905-
r'^username +(?P<username>\S+) +common-criteria-policy +(?P<common_criteria_policy>.*) '
2906-
r'+password +(?P<type>\d) +(?P<password>.*)$')
2923+
# common-criteria-policy Test-CC
2924+
common_criteria_policy = re.compile(r'^common-criteria-policy (?P<common_criteria_policy>\S+) ?')
29072925

2908-
# username testuser secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2909-
p3 = re.compile(r'^username +(?P<username>\S+) +secret +(?P<type>\d) +(?P<secret>.*)$')
2926+
# secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2927+
secret = re.compile(r'^secret (?P<type>\d) (?P<secret>.*)$')
29102928

2911-
# username testuser one-time secret 9 $9$AuJ8xgW8aBBuF.$HyAzLk.3ILFsKrEvd4YjaAHbtonVMLikXw2pnrlkYJY
2912-
p4 = re.compile(
2913-
r'^username +(?P<username>\S+) +one-time +(?P<Onetime>)\s*secret +(?P<type>\d+) +(?P<secret>.*)$')
2929+
# privilege 15
2930+
privilege = re.compile(r'^privilege (?P<privilege>\d+) ?')
29142931

2915-
# username testuser privilege 15 password 0 lab
2916-
p5 = re.compile(
2917-
r'^username +(?P<username>\S+) +privilege +(?P<privilege>\d+) +password +(?P<type>\d) +(?P<password>.*)$')
2932+
# one-time
2933+
onetime = re.compile(r'^one-time ?')
29182934

2919-
# username testuser common-criteria-policy Test-CC secret 9 $9$7K9qbCZMJa2Vuk$6bS3.Bv7AkBXhTHpTH9V9fhMnJCQe1a9O7xBWHtOKo.
2920-
p6 = re.compile(
2921-
r'^username +(?P<username>\S+) +common-criteria-policy +(?P<common_criteria_policy>.*) '
2922-
r'+secret +(?P<type>\d) +(?P<secret>.*)$')
2935+
# nopassword
2936+
nopassword = re.compile(r'^nopassword ?')
29232937

2924-
# username testuser one-time password 0 password
2925-
p7 = re.compile(
2926-
r'^username +(?P<username>\S+) +one-time +(?P<Onetime>)\s*password +(?P<type>\d) +(?P<password>.*)$')
2938+
# password 0 lab
2939+
password = re.compile(r'^password (?P<type>\d) (?P<password>.*)$')
29272940

2928-
# username developer privilege 15 secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A
2929-
p8 = re.compile(r'^username +(?P<username>\S+) +privilege +(?P<privilege>\d+) +secret +(?P<secret_type>\d+) +(?P<secret>\S+)$')
2941+
# autocommand show ip bgp summary
2942+
autocommand = re.compile(r'^autocommand (?P<autocommand>.*)$')
29302943

29312944
# Initial return dictionary
29322945
ret_dict = {}
29332946

29342947
for line in out.splitlines():
29352948
line = line.strip()
29362949

2937-
# username testuser password 0 lab
2938-
m = p1.match(line)
2939-
if m:
2940-
group = m.groupdict()
2941-
username = group['username']
2942-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
2943-
pass_dict = users_dict.setdefault('password', {})
2944-
pass_dict['type'] = int(group['type'])
2945-
pass_dict['password'] = group['password']
2950+
# username testuser
2951+
m = username_cmd.match(line)
2952+
if not m:
2953+
# CLAIM: This is not a line with a 'username' command.
29462954
continue
29472955

2948-
# username testuser common-criteria-policy Test-CC password 0 password
2949-
m = p2.match(line)
2950-
if m:
2951-
group = m.groupdict()
2952-
username = group['username']
2953-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
2954-
users_dict['common_criteria_policy'] = group['common_criteria_policy']
2955-
pass_dict = users_dict.setdefault('password', {})
2956-
pass_dict['type'] = int(group['type'])
2957-
pass_dict['password'] = group['password']
2958-
continue
2956+
# CLAIM: this is a username line
2957+
# GOAL: extract the specified username and switch to that
2958+
# sub-dictionary:
2959+
group = m.groupdict()
2960+
username = group['username']
2961+
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
29592962

2960-
# username testuser secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2961-
m = p3.match(line)
2962-
if m:
2963-
group = m.groupdict()
2964-
username = group['username']
2965-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
2966-
secret_dict = users_dict.setdefault('secret', {})
2967-
secret_dict['type'] = int(group['type'])
2968-
secret_dict['secret'] = group['secret']
2969-
continue
2963+
# GOAL: remove the matched portion from the begining of the line
2964+
# so that we can match the subsequent argument (if any):
2965+
line = line[m.end():]
29702966

2971-
# username testuser one-time secret 9 $9$AuJ8xgW8aBBuF.$HyAzLk.3ILFsKrEvd4YjaAHbtonVMLikXw2pnrlkYJY
2972-
m = p4.match(line)
2973-
if m:
2974-
group = m.groupdict()
2975-
username = group['username']
2976-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
2977-
users_dict['onetime'] = True
2978-
secret_dict = users_dict.setdefault('secret', {})
2979-
secret_dict['type'] = int(group['type'])
2980-
secret_dict['secret'] = group['secret']
2981-
continue
2967+
while line:
2968+
# GOAL: parse through the line an argument at a time,
2969+
# shortening the line as we go.
29822970

2983-
# username testuser privilege 15 password 0 lab
2984-
m = p5.match(line)
2985-
if m:
2986-
group = m.groupdict()
2987-
username = group['username']
2988-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
2989-
users_dict['privilege'] = int(group['privilege'])
2990-
pass_dict = users_dict.setdefault('password', {})
2991-
pass_dict['type'] = int(group['type'])
2992-
pass_dict['password'] = group['password']
2993-
continue
2971+
# GOAL: match the 'common-criteria-policy' option and return its parameter
2972+
# Sample: "common-criteria-policy MyPolicy"
2973+
if m := common_criteria_policy.match(line):
2974+
group = m.groupdict()
2975+
users_dict['common_criteria_policy'] = group['common_criteria_policy']
2976+
line = line[m.end():]
2977+
continue
29942978

2995-
# username testuser common-criteria-policy Test-CC secret 9 $9$7K9qbCZMJa2Vuk$6bS3.Bv7AkBXhTHpTH9V9fhMnJCQe1a9O7xBWHtOKo.
2996-
m = p6.match(line)
2997-
if m:
2998-
group = m.groupdict()
2999-
username = group['username']
3000-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
3001-
users_dict['common_criteria_policy'] = group['common_criteria_policy']
3002-
secret_dict = users_dict.setdefault('secret', {})
3003-
secret_dict['type'] = int(group['type'])
3004-
secret_dict['secret'] = group['secret']
3005-
continue
2979+
# GOAL: match the 'privilege' option and return its parameter
2980+
# Sample: "privilege 15"
2981+
if m := privilege.match(line):
2982+
group = m.groupdict()
2983+
users_dict['privilege'] = int(group['privilege'])
2984+
line = line[m.end():]
2985+
continue
30062986

3007-
# username testuser one-time password 0 password
3008-
m = p7.match(line)
3009-
if m:
3010-
group = m.groupdict()
3011-
username = group['username']
3012-
users_dict = ret_dict.setdefault('username', {}).setdefault(username, {})
3013-
users_dict['onetime'] = True
3014-
pass_dict = users_dict.setdefault('password', {})
3015-
pass_dict['type'] = int(group['type'])
3016-
pass_dict['password'] = group['password']
3017-
continue
2987+
# GOAL: match the 'secret' option and return its parameters ('type' and 'secret')
2988+
# Sample: "secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A"
2989+
if m := secret.match(line):
2990+
group = m.groupdict()
2991+
pass_dict = users_dict.setdefault('secret', {})
2992+
pass_dict['type'] = int(group['type'])
2993+
pass_dict['secret'] = group['secret']
2994+
line = line[m.end():]
2995+
continue
30182996

3019-
# username developer privilege 15 secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A
3020-
m = p8.match(line)
3021-
if m:
3022-
group = m.groupdict()
3023-
user_dict = ret_dict.setdefault('username', {}).setdefault(group['username'], {})
3024-
user_dict.update({
3025-
'privilege': int(group['privilege']),
3026-
})
2997+
# GOAL: match the 'onetime' flag
2998+
# Sample: "onetime"
2999+
if m := onetime.match(line):
3000+
group = m.groupdict()
3001+
users_dict['onetime'] = True
3002+
line = line[m.end():]
3003+
continue
30273004

3028-
secret_dict = user_dict.setdefault('secret', {})
3029-
secret_dict.update({
3030-
'type': int(group['secret_type']),
3031-
'secret': group['secret']
3032-
})
3005+
# GOAL: match the 'nopassword' flag
3006+
# Sample: "nopassword"
3007+
if m := nopassword.match(line):
3008+
group = m.groupdict()
3009+
users_dict['nopassword'] = True
3010+
line = line[m.end():]
3011+
continue
3012+
3013+
# GOAL: match the 'autocommand' option and return all subsequent text
3014+
# Sample: "autocommand show ip bgp summary"
3015+
if m := autocommand.match(line):
3016+
group = m.groupdict()
3017+
users_dict['autocommand'] = group['autocommand']
3018+
line = line[m.end():]
3019+
continue
3020+
3021+
# GOAL: match the 'password' option and return its parameters ('type' and 'password')
3022+
# Sample: "password 0 lab"
3023+
if m := password.match(line):
3024+
group = m.groupdict()
3025+
pass_dict = users_dict.setdefault('password', {})
3026+
pass_dict['type'] = int(group['type'])
3027+
pass_dict['password'] = group['password']
3028+
line = line[m.end():]
3029+
continue
3030+
3031+
# CLAIM: There is an unhandled argument.
3032+
log.warning(f"Unhandled argument in parser 'show running-config aaa username': {line}")
3033+
break
30333034

30343035
return ret_dict
30353036

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
expected_output = {
2+
"username": {
3+
"testuser07": {
4+
"nopassword": True,
5+
"privilege": 3
6+
},
7+
"testuser08": {
8+
"common_criteria_policy": "Test-CC",
9+
"privilege": 15,
10+
"secret": {
11+
"secret": "$9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A",
12+
"type": 9
13+
}
14+
},
15+
"testuser09": {
16+
"autocommand": "show ip bgp summary",
17+
"privilege": 15,
18+
"secret": {
19+
"secret": "$9$UuxZCcqGu2IgBU$teHrzSPJK5FgLH0YAnUezoA1JwaqGBcJI4Xb6c3S7tU",
20+
"type": 9
21+
}
22+
},
23+
"testuser10": {
24+
"common_criteria_policy": "Test-CC",
25+
"password": {
26+
"password": "lab",
27+
"type": 0
28+
},
29+
"privilege": 15
30+
},
31+
"testuser11": {
32+
"privilege": 15
33+
}
34+
}
35+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
9400-HA#show running-config aaa username
2+
!
3+
! You may also need to setup a common criteria policy for testing:
4+
! aaa new-model
5+
! aaa common-criteria policy Test-CC
6+
! min-length 1
7+
username testuser07 privilege 3 nopassword
8+
username testuser08 privilege 15 common-criteria-policy Test-CC secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A
9+
! Some usernames can span multiple lines:
10+
username testuser09 privilege 15 secret 9 $9$UuxZCcqGu2IgBU$teHrzSPJK5FgLH0YAnUezoA1JwaqGBcJI4Xb6c3S7tU
11+
username testuser09 autocommand show ip bgp summary
12+
username testuser10 privilege 15 common-criteria-policy Test-CC password 0 lab
13+
! username with privilege and no password can happen if SSH pubkey auth is used:
14+
username testuser11 privilege 15

0 commit comments

Comments
 (0)