|
14 | 14 |
|
15 | 15 | # Python |
16 | 16 | import re |
| 17 | +import logging |
17 | 18 |
|
18 | 19 | # Metaparser |
19 | 20 | from genie.metaparser import MetaParser |
|
23 | 24 | # import parser utils |
24 | 25 | from genie.libs.parser.utils.common import Common |
25 | 26 |
|
| 27 | +log = logging.getLogger(__name__) |
| 28 | + |
26 | 29 | # ================================================= |
27 | 30 | # Schema for: |
28 | 31 | # * 'show run policy-map {name}' |
@@ -2751,7 +2754,9 @@ class ShowRunningConfigAAAUsernameSchema(MetaParser): |
2751 | 2754 | Optional('common_criteria_policy'): str, |
2752 | 2755 | Optional('view'): str, |
2753 | 2756 | Optional('type'): str, |
| 2757 | + Optional('autocommand'): str, |
2754 | 2758 | Optional('onetime'): bool, |
| 2759 | + Optional('nopassword'): bool, |
2755 | 2760 | Optional('secret'): { |
2756 | 2761 | Optional('type'): int, |
2757 | 2762 | Optional('secret'): str, |
@@ -2897,139 +2902,135 @@ def cli(self, output=None): |
2897 | 2902 | else: |
2898 | 2903 | out = output |
2899 | 2904 |
|
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+) ?') |
2902 | 2922 |
|
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+) ?') |
2907 | 2925 |
|
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>.*)$') |
2910 | 2928 |
|
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+) ?') |
2914 | 2931 |
|
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 ?') |
2918 | 2934 |
|
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 ?') |
2923 | 2937 |
|
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>.*)$') |
2927 | 2940 |
|
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>.*)$') |
2930 | 2943 |
|
2931 | 2944 | # Initial return dictionary |
2932 | 2945 | ret_dict = {} |
2933 | 2946 |
|
2934 | 2947 | for line in out.splitlines(): |
2935 | 2948 | line = line.strip() |
2936 | 2949 |
|
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. |
2946 | 2954 | continue |
2947 | 2955 |
|
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, {}) |
2959 | 2962 |
|
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():] |
2970 | 2966 |
|
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. |
2982 | 2970 |
|
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 |
2994 | 2978 |
|
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 |
3006 | 2986 |
|
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 |
3018 | 2996 |
|
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 |
3027 | 3004 |
|
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 |
3033 | 3034 |
|
3034 | 3035 | return ret_dict |
3035 | 3036 |
|
|
0 commit comments