1313
1414# Python
1515import re
16+ import logging
1617
1718# Metaparser
1819from genie .metaparser import MetaParser
2223# import parser utils
2324from genie .libs .parser .utils .common import Common
2425
26+ log = logging .getLogger (__name__ )
27+
2528# =================================================
2629# Schema for:
2730# * 'show run policy-map {name}'
@@ -2750,7 +2753,9 @@ class ShowRunningConfigAAAUsernameSchema(MetaParser):
27502753 Optional ('common_criteria_policy' ): str ,
27512754 Optional ('view' ): str ,
27522755 Optional ('type' ): str ,
2756+ Optional ('autocommand' ): str ,
27532757 Optional ('onetime' ): bool ,
2758+ Optional ('nopassword' ): bool ,
27542759 Optional ('secret' ): {
27552760 Optional ('type' ): int ,
27562761 Optional ('secret' ): str ,
@@ -2896,139 +2901,135 @@ def cli(self, output=None):
28962901 else :
28972902 out = output
28982903
2899- # username testuser password 0 lab
2900- p1 = re .compile (r'^username +(?P<username>\S+) +password +(?P<type>\d) +(?P<password>.*)$' )
2904+ # NOTE: All of the following regular expressions should be anchored to
2905+ # the begining of the line ('^'). As each is used the line will be
2906+ # shortened. Think of this as popping arguments (and their parameters)
2907+ # off of a stack (the front of the line).
2908+ #
2909+ # There are some arguments that cannot have any subsequent arguments.
2910+ # These are:
2911+ # 1) password
2912+ # 2) secret
2913+ # 3) autocommand
2914+ # These arguments shall also match the end of the line ('$').
2915+ #
2916+ # All arguments that are not matched to the end of the line shall match
2917+ # an optional trailing space (' ?').
2918+
2919+ # username testuser
2920+ username_cmd = re .compile (r'^username (?P<username>\S+) ?' )
29012921
2902- # username testuser common-criteria-policy Test-CC password 0 password
2903- p2 = re .compile (
2904- r'^username +(?P<username>\S+) +common-criteria-policy +(?P<common_criteria_policy>.*) '
2905- r'+password +(?P<type>\d) +(?P<password>.*)$' )
2922+ # common-criteria-policy Test-CC
2923+ common_criteria_policy = re .compile (r'^common-criteria-policy (?P<common_criteria_policy>\S+) ?' )
29062924
2907- # username testuser secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2908- p3 = re .compile (r'^username +(?P<username>\S+) + secret + (?P<type>\d) + (?P<secret>.*)$' )
2925+ # secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2926+ secret = re .compile (r'^secret (?P<type>\d) (?P<secret>.*)$' )
29092927
2910- # username testuser one-time secret 9 $9$AuJ8xgW8aBBuF.$HyAzLk.3ILFsKrEvd4YjaAHbtonVMLikXw2pnrlkYJY
2911- p4 = re .compile (
2912- r'^username +(?P<username>\S+) +one-time +(?P<Onetime>)\s*secret +(?P<type>\d+) +(?P<secret>.*)$' )
2928+ # privilege 15
2929+ privilege = re .compile (r'^privilege (?P<privilege>\d+) ?' )
29132930
2914- # username testuser privilege 15 password 0 lab
2915- p5 = re .compile (
2916- r'^username +(?P<username>\S+) +privilege +(?P<privilege>\d+) +password +(?P<type>\d) +(?P<password>.*)$' )
2931+ # one-time
2932+ onetime = re .compile (r'^one-time ?' )
29172933
2918- # username testuser common-criteria-policy Test-CC secret 9 $9$7K9qbCZMJa2Vuk$6bS3.Bv7AkBXhTHpTH9V9fhMnJCQe1a9O7xBWHtOKo.
2919- p6 = re .compile (
2920- r'^username +(?P<username>\S+) +common-criteria-policy +(?P<common_criteria_policy>.*) '
2921- r'+secret +(?P<type>\d) +(?P<secret>.*)$' )
2934+ # nopassword
2935+ nopassword = re .compile (r'^nopassword ?' )
29222936
2923- # username testuser one-time password 0 password
2924- p7 = re .compile (
2925- r'^username +(?P<username>\S+) +one-time +(?P<Onetime>)\s*password +(?P<type>\d) +(?P<password>.*)$' )
2937+ # password 0 lab
2938+ password = re .compile (r'^password (?P<type>\d) (?P<password>.*)$' )
29262939
2927- # username developer privilege 15 secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A
2928- p8 = re .compile (r'^username + (?P<username>\S+) +privilege +(?P<privilege>\d+) +secret +(?P<secret_type>\d+) +(?P<secret>\S+ )$' )
2940+ # autocommand show ip bgp summary
2941+ autocommand = re .compile (r'^autocommand (?P<autocommand>.* )$' )
29292942
29302943 # Initial return dictionary
29312944 ret_dict = {}
29322945
29332946 for line in out .splitlines ():
29342947 line = line .strip ()
29352948
2936- # username testuser password 0 lab
2937- m = p1 .match (line )
2938- if m :
2939- group = m .groupdict ()
2940- username = group ['username' ]
2941- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
2942- pass_dict = users_dict .setdefault ('password' , {})
2943- pass_dict ['type' ] = int (group ['type' ])
2944- pass_dict ['password' ] = group ['password' ]
2949+ # username testuser
2950+ m = username_cmd .match (line )
2951+ if not m :
2952+ # CLAIM: This is not a line with a 'username' command.
29452953 continue
29462954
2947- # username testuser common-criteria-policy Test-CC password 0 password
2948- m = p2 .match (line )
2949- if m :
2950- group = m .groupdict ()
2951- username = group ['username' ]
2952- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
2953- users_dict ['common_criteria_policy' ] = group ['common_criteria_policy' ]
2954- pass_dict = users_dict .setdefault ('password' , {})
2955- pass_dict ['type' ] = int (group ['type' ])
2956- pass_dict ['password' ] = group ['password' ]
2957- continue
2955+ # CLAIM: this is a username line
2956+ # GOAL: extract the specified username and switch to that
2957+ # sub-dictionary:
2958+ group = m .groupdict ()
2959+ username = group ['username' ]
2960+ users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
29582961
2959- # username testuser secret 9 $9$A2OfV.30kNlIhE$ZEJQIT6aUj.TfCzqGQr.h4AmjQd/bWikQaGRlaLv0nQ
2960- m = p3 .match (line )
2961- if m :
2962- group = m .groupdict ()
2963- username = group ['username' ]
2964- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
2965- secret_dict = users_dict .setdefault ('secret' , {})
2966- secret_dict ['type' ] = int (group ['type' ])
2967- secret_dict ['secret' ] = group ['secret' ]
2968- continue
2962+ # GOAL: remove the matched portion from the begining of the line
2963+ # so that we can match the subsequent argument (if any):
2964+ line = line [m .end ():]
29692965
2970- # username testuser one-time secret 9 $9$AuJ8xgW8aBBuF.$HyAzLk.3ILFsKrEvd4YjaAHbtonVMLikXw2pnrlkYJY
2971- m = p4 .match (line )
2972- if m :
2973- group = m .groupdict ()
2974- username = group ['username' ]
2975- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
2976- users_dict ['onetime' ] = True
2977- secret_dict = users_dict .setdefault ('secret' , {})
2978- secret_dict ['type' ] = int (group ['type' ])
2979- secret_dict ['secret' ] = group ['secret' ]
2980- continue
2966+ while line :
2967+ # GOAL: parse through the line an argument at a time,
2968+ # shortening the line as we go.
29812969
2982- # username testuser privilege 15 password 0 lab
2983- m = p5 .match (line )
2984- if m :
2985- group = m .groupdict ()
2986- username = group ['username' ]
2987- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
2988- users_dict ['privilege' ] = int (group ['privilege' ])
2989- pass_dict = users_dict .setdefault ('password' , {})
2990- pass_dict ['type' ] = int (group ['type' ])
2991- pass_dict ['password' ] = group ['password' ]
2992- continue
2970+ # GOAL: match the 'common-criteria-policy' option and return its parameter
2971+ # Sample: "common-criteria-policy MyPolicy"
2972+ if m := common_criteria_policy .match (line ):
2973+ group = m .groupdict ()
2974+ users_dict ['common_criteria_policy' ] = group ['common_criteria_policy' ]
2975+ line = line [m .end ():]
2976+ continue
29932977
2994- # username testuser common-criteria-policy Test-CC secret 9 $9$7K9qbCZMJa2Vuk$6bS3.Bv7AkBXhTHpTH9V9fhMnJCQe1a9O7xBWHtOKo.
2995- m = p6 .match (line )
2996- if m :
2997- group = m .groupdict ()
2998- username = group ['username' ]
2999- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
3000- users_dict ['common_criteria_policy' ] = group ['common_criteria_policy' ]
3001- secret_dict = users_dict .setdefault ('secret' , {})
3002- secret_dict ['type' ] = int (group ['type' ])
3003- secret_dict ['secret' ] = group ['secret' ]
3004- continue
2978+ # GOAL: match the 'privilege' option and return its parameter
2979+ # Sample: "privilege 15"
2980+ if m := privilege .match (line ):
2981+ group = m .groupdict ()
2982+ users_dict ['privilege' ] = int (group ['privilege' ])
2983+ line = line [m .end ():]
2984+ continue
30052985
3006- # username testuser one-time password 0 password
3007- m = p7 .match (line )
3008- if m :
3009- group = m .groupdict ()
3010- username = group ['username' ]
3011- users_dict = ret_dict .setdefault ('username' , {}).setdefault (username , {})
3012- users_dict ['onetime' ] = True
3013- pass_dict = users_dict .setdefault ('password' , {})
3014- pass_dict ['type' ] = int (group ['type' ])
3015- pass_dict ['password' ] = group ['password' ]
3016- continue
2986+ # GOAL: match the 'secret' option and return its parameters ('type' and 'secret')
2987+ # Sample: "secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A"
2988+ if m := secret .match (line ):
2989+ group = m .groupdict ()
2990+ pass_dict = users_dict .setdefault ('secret' , {})
2991+ pass_dict ['type' ] = int (group ['type' ])
2992+ pass_dict ['secret' ] = group ['secret' ]
2993+ line = line [m .end ():]
2994+ continue
30172995
3018- # username developer privilege 15 secret 9 $9$oNguEA9um9vRx.$MsDk0DOy1rzBjKAcySWdNjoKcA7GetG9YNnKOs8S67A
3019- m = p8 .match (line )
3020- if m :
3021- group = m .groupdict ()
3022- user_dict = ret_dict .setdefault ('username' , {}).setdefault (group ['username' ], {})
3023- user_dict .update ({
3024- 'privilege' : int (group ['privilege' ]),
3025- })
2996+ # GOAL: match the 'onetime' flag
2997+ # Sample: "onetime"
2998+ if m := onetime .match (line ):
2999+ group = m .groupdict ()
3000+ users_dict ['onetime' ] = True
3001+ line = line [m .end ():]
3002+ continue
30263003
3027- secret_dict = user_dict .setdefault ('secret' , {})
3028- secret_dict .update ({
3029- 'type' : int (group ['secret_type' ]),
3030- 'secret' : group ['secret' ]
3031- })
3004+ # GOAL: match the 'nopassword' flag
3005+ # Sample: "nopassword"
3006+ if m := nopassword .match (line ):
3007+ group = m .groupdict ()
3008+ users_dict ['nopassword' ] = True
3009+ line = line [m .end ():]
3010+ continue
3011+
3012+ # GOAL: match the 'autocommand' option and return all subsequent text
3013+ # Sample: "autocommand show ip bgp summary"
3014+ if m := autocommand .match (line ):
3015+ group = m .groupdict ()
3016+ users_dict ['autocommand' ] = group ['autocommand' ]
3017+ line = line [m .end ():]
3018+ continue
3019+
3020+ # GOAL: match the 'password' option and return its parameters ('type' and 'password')
3021+ # Sample: "password 0 lab"
3022+ if m := password .match (line ):
3023+ group = m .groupdict ()
3024+ pass_dict = users_dict .setdefault ('password' , {})
3025+ pass_dict ['type' ] = int (group ['type' ])
3026+ pass_dict ['password' ] = group ['password' ]
3027+ line = line [m .end ():]
3028+ continue
3029+
3030+ # CLAIM: There is an unhandled argument.
3031+ log .warning (f"Unhandled argument in parser 'show running-config aaa username': { line } " )
3032+ break
30323033
30333034 return ret_dict
30343035
@@ -5009,4 +5010,4 @@ def cli(self, output=None):
50095010 radius_server_dict .update ({'dtls_trustpoint_server' : m .groupdict ()['dtls_trustpoint_server' ]})
50105011 continue
50115012
5012- return ret_dict
5013+ return ret_dict
0 commit comments