From d6c86bc254b81e9aa6fae6dd8085cc6bfea03262 Mon Sep 17 00:00:00 2001 From: "Lu.Mao" Date: Tue, 19 Mar 2024 00:14:08 -0700 Subject: [PATCH] Solve the bugs for SONiC CLI Auto-generation (#3221) 1. Fixed the error description for config update 2. Not displaying the command of not configurable table that defined config false in the yang model. 3. Support showing other db table data defined in sonic yang model, not just config db. --- .../templates/sonic-cli-gen/config.py.j2 | 6 +++- .../templates/sonic-cli-gen/show.py.j2 | 33 +++++++++++++++++-- sonic_cli_gen/yang_parser.py | 14 ++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/sonic-utilities-data/templates/sonic-cli-gen/config.py.j2 b/sonic-utilities-data/templates/sonic-cli-gen/config.py.j2 index 0906d7c99f..fe5d10c738 100644 --- a/sonic-utilities-data/templates/sonic-cli-gen/config.py.j2 +++ b/sonic-utilities-data/templates/sonic-cli-gen/config.py.j2 @@ -467,7 +467,7 @@ E.g: {{ gen_click_options(object.attrs) }} @clicommon.pass_db def {{ group }}_update(db, {{ pythonize(object["keys"] + object.attrs) }}): - """ Add object in {{ table.name }}. """ + """ Update object in {{ table.name }}. """ table = "{{ table.name }}" key = {{ pythonize(object["keys"]) }} @@ -531,6 +531,7 @@ def {{ group }}(): {% for table in tables %} +{% if table.config == 'true' %} @click.group(name="{{ cli_name(table.name) }}", cls=clicommon.AliasedGroup) def {{ table.name }}(): @@ -550,6 +551,7 @@ def {{ table.name }}(): {% endfor %} {% endif %} +{% endif %} {% endfor %} def register(cli): @@ -563,8 +565,10 @@ def register(cli): """ {%- for table in tables %} +{%- if table.config == 'true' %} cli_node = {{ table.name }} if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") cli.add_command({{ table.name }}) +{%- endif %} {%- endfor %} diff --git a/sonic-utilities-data/templates/sonic-cli-gen/show.py.j2 b/sonic-utilities-data/templates/sonic-cli-gen/show.py.j2 index 2a3d065fdf..b717d783d9 100644 --- a/sonic-utilities-data/templates/sonic-cli-gen/show.py.j2 +++ b/sonic-utilities-data/templates/sonic-cli-gen/show.py.j2 @@ -54,6 +54,35 @@ def format_group_value(entry, attrs): return tabulate.tabulate(data, tablefmt="plain") +def get_db_table(db, ytable): + """ Retrieve data table from redis DB, support CONFIG_DB|STATE_DB. + + Args: + db: Db object in utilities_common. + ytable: dict data from yang parser + + Returns: + dict: data table. + """ + + name = ytable['name'] + table = {} + + if ytable['config'] == 'true': + table = db.cfgdb.get_table(name) + else: + db_name = ytable['db-name'] + db.db.connect(db_name) + seps = db.db.get_db_separator(db_name) + keys = db.db.keys(db_name, name + seps + '*') + + for key in keys: + t = db.db.get_all(db_name, key) + table[key[(key.find(seps) + 1):]] = t + + return table + + {# Generates a python list that represents a row in the table view. E.g: Jinja2: @@ -185,7 +214,7 @@ def {{ table.name }}_{{ object.name }}(db): header = {{ gen_header(object.attrs) }} body = [] - table = db.cfgdb.get_table("{{ table.name }}") + table = get_db_table(db, {{ table }}) entry = table.get("{{ object.name }}", {}) row = {{ gen_row("entry", object.attrs) }} body.append(row) @@ -222,7 +251,7 @@ def {{ name }}(db): header = {{ gen_header(object["keys"] + object.attrs) }} body = [] - table = db.cfgdb.get_table("{{ table.name }}") + table = get_db_table(db, {{ table }}) for key in natsort.natsorted(table): entry = table[key] if not isinstance(key, tuple): diff --git a/sonic_cli_gen/yang_parser.py b/sonic_cli_gen/yang_parser.py index cfefd9bc6e..6b2c427388 100644 --- a/sonic_cli_gen/yang_parser.py +++ b/sonic_cli_gen/yang_parser.py @@ -166,6 +166,8 @@ def on_table_container(y_module: OrderedDict, """ y2d_elem = { 'name': tbl_container.get('@name'), + 'config': get_value(tbl_container, 'config', 'true'), + 'db-name': get_value(tbl_container, 'sonic-ext:db-name', 'CONFIG_DB'), 'description': get_description(tbl_container) } @@ -407,6 +409,18 @@ def get_mandatory(y_leaf: OrderedDict) -> bool: return y_leaf.get('mandatory').get('@value') == 'true' +def get_value(node: OrderedDict, key: str, default_value: str) -> str: + """ Parse the specified key entity from any YANG element + + Args: + node: reference to YANG 'container' OR 'list' OR 'leaf' ... + key: string of the query key + default_value: default string to return when query failed + Returns: + value of the specified key + """ + + return node.get(key).get('@value') if node.get(key) is not None else default_value def get_description(y_entity: OrderedDict) -> str: """ Parse the 'description' entity from any YANG element