diff --git a/clear/main.py b/clear/main.py index d09153533b..5ffcd2dba4 100755 --- a/clear/main.py +++ b/clear/main.py @@ -5,6 +5,7 @@ import click import utilities_common.cli as clicommon import utilities_common.multi_asic as multi_asic_util +from sonic_py_common import multi_asic from sonic_py_common.general import getstatusoutput_noshell_pipe from flow_counter_util.route import exit_if_route_flow_counter_not_support from utilities_common import util_base @@ -12,7 +13,6 @@ from config.plugins.pbh import serialize_pbh_counters from . import plugins - # This is from the aliases example: # https://github.com/pallets/click/blob/57c6f09611fc47ca80db0bd010f05998b3c0aa95/examples/aliases/aliases.py class Config(object): @@ -550,6 +550,28 @@ def route(prefix, vrf, namespace): helper = util_base.UtilHelper() helper.load_and_register_plugins(plugins, cli) +# ("sonic-clear asic-sdk-health-event") +@cli.command() +@click.option('--namespace', '-n', 'namespace', required=False, default=None, show_default=False, + help='Option needed for multi-asic only: provide namespace name', + type=click.Choice(multi_asic_util.multi_asic_ns_choices())) +@clicommon.pass_db +def asic_sdk_health_event(db, namespace): + """Clear received ASIC/SDK health events""" + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() + else: + namespace_list = [multi_asic.DEFAULT_NAMESPACE] + + for ns in namespace_list: + if namespace and namespace != ns: + continue + + state_db = db.db_clients[ns] + keys = state_db.keys(db.db.STATE_DB, "ASIC_SDK_HEALTH_EVENT_TABLE*") + for key in keys: + state_db.delete(state_db.STATE_DB, key); + if __name__ == '__main__': cli() diff --git a/config/main.py b/config/main.py index b039c56929..f343299501 100644 --- a/config/main.py +++ b/config/main.py @@ -7372,5 +7372,124 @@ def date(date, time): clicommon.run_command(['timedatectl', 'set-time', date_time]) +# +# 'asic-sdk-health-event' group ('config asic-sdk-health-event ...') +# +@config.group() +def asic_sdk_health_event(): + """Configuring asic-sdk-health-event""" + pass + + +@asic_sdk_health_event.group() +def suppress(): + """Suppress ASIC/SDK health event""" + pass + + +def handle_asic_sdk_health_suppress(db, severity, category_list, max_events, namespace): + ctx = click.get_current_context() + + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() + else: + namespace_list = [DEFAULT_NAMESPACE] + + severityCapabilities = { + "fatal": "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY", + "warning": "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY", + "notice": "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY" + } + + if category_list: + categories = {"software", "firmware", "cpu_hw", "asic_hw"} + + if category_list == 'none': + suppressedCategoriesList = [] + elif category_list == 'all': + suppressedCategoriesList = list(categories) + else: + suppressedCategoriesList = category_list.split(',') + + unsupportCategories = set(suppressedCategoriesList) - categories + if unsupportCategories: + ctx.fail("Invalid category(ies): {}".format(unsupportCategories)) + + for ns in namespace_list: + if namespace and namespace != ns: + continue + + config_db = db.cfgdb_clients[ns] + state_db = db.db_clients[ns] + + entry_name = "SWITCH_CAPABILITY|switch" + if "true" != state_db.get(state_db.STATE_DB, entry_name, "ASIC_SDK_HEALTH_EVENT"): + ctx.fail("ASIC/SDK health event is not supported on the platform") + + if "true" != state_db.get(state_db.STATE_DB, entry_name, severityCapabilities[severity]): + ctx.fail("Suppressing ASIC/SDK health {} event is not supported on the platform".format(severity)) + + entry = config_db.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity) + need_remove = False + noarg = True + + if category_list: + noarg = False + if suppressedCategoriesList: + entry["categories"] = suppressedCategoriesList + elif entry.get("categories"): + entry.pop("categories") + need_remove = True + + if max_events is not None: + noarg = False + if max_events > 0: + entry["max_events"] = max_events + elif entry.get("max_events"): + entry.pop("max_events") + need_remove = True + + if noarg: + ctx.fail("At least one argument should be provided!") + + if entry: + config_db.set_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity, entry) + elif need_remove: + config_db.set_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity, None) + + +@suppress.command() +@click.option('--category-list', metavar='', type=str, help="Categories to be suppressed") +@click.option('--max-events', metavar='', type=click.IntRange(0), help="Maximum number of received events") +@click.option('--namespace', '-n', 'namespace', required=False, default=None, show_default=False, + help='Option needed for multi-asic only: provide namespace name', + type=click.Choice(multi_asic_util.multi_asic_ns_choices())) +@clicommon.pass_db +def fatal(db, category_list, max_events, namespace): + handle_asic_sdk_health_suppress(db, 'fatal', category_list, max_events, namespace) + + +@suppress.command() +@click.option('--category-list', metavar='', type=str, help="Categories to be suppressed") +@click.option('--max-events', metavar='', type=click.IntRange(0), help="Maximum number of received events") +@click.option('--namespace', '-n', 'namespace', required=False, default=None, show_default=False, + help='Option needed for multi-asic only: provide namespace name', + type=click.Choice(multi_asic_util.multi_asic_ns_choices())) +@clicommon.pass_db +def warning(db, category_list, max_events, namespace): + handle_asic_sdk_health_suppress(db, 'warning', category_list, max_events, namespace) + + +@suppress.command() +@click.option('--category-list', metavar='', type=str, help="Categories to be suppressed") +@click.option('--max-events', metavar='', type=click.IntRange(0), help="Maximum number of received events") +@click.option('--namespace', '-n', 'namespace', required=False, default=None, show_default=False, + help='Option needed for multi-asic only: provide namespace name', + type=click.Choice(multi_asic_util.multi_asic_ns_choices())) +@clicommon.pass_db +def notice(db, category_list, max_events, namespace): + handle_asic_sdk_health_suppress(db, 'notice', category_list, max_events, namespace) + + if __name__ == '__main__': config() diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index fb0c94aead..e2578bd697 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -29,6 +29,10 @@ * [ARP & NDP](#arp--ndp) * [ARP show commands](#arp-show-commands) * [NDP show commands](#ndp-show-commands) +* [ASIC SDK health event](#asic-sdk-health-event) + * [ASIC SDK health event config commands](#asic-sdk-health-event-config-commands) + * [ASIC SDK health event show commands](#asic-sdk-health-event-show-commands) + * [ASIC SDK health event clear commands](#asic-sdk-health-event-clear-commands) * [BFD](#bfd) * [BFD show commands](#bfd-show-commands) * [BGP](#bgp) @@ -1928,6 +1932,158 @@ This command is used to display: ACL rules, tables and their priority, ACL packe If the `PACKETS COUNT` and `BYTES COUNT` fields have some numeric value it means that it is a SONiC ACL's and those counters are created in SONiC `COUNTERS_DB`. +## ASIC SDK health event + +### ASIC SDK health event config commands + +**config asic-sdk-health-event suppress ** + +This command is for a customer to configure the categories that he/she wants to suppress for a certain severity. + +- Usage: + ``` + config config asic-sdk-health-event suppress [--category-list ||] [--max-events ] + ``` + + - Parameters: + - severity: Specify the severity whose ASIC/SDK health events to be suppressed. It can be one of `fatal`, `warning`, and `notice`. + - category-list: Specify the categories from which the ASIC/SDK health events to be suppressed. It is a list whose element is one of `software`, `firmware`, `cpu_hw`, `asic_hw` separated by a comma. + If the category-list is `none`, none category is suppressed and all the categories will be notified for `severity`. In this case, it will not be stored in the CONFIG_DB. + If the category-list is `all`, all the categories are suppressed and none category will be notified for `severity`. + - max-events: Specify the maximum number of events of the severity to be stored in the STATE_DB. + There is no limitation if the max-events is 0. In this case, it will not be stored in the CONFIG_DB. + +- Examples: + ``` + admin@sonic:~$ sudo config asic-sdk-health-event suppress fatal --category-list cpu_hw,software --max-events 10240 + ``` + + This command will suppress ASIC/SDK health events whose severity is fatal and cagetory is cpu_hw or software. Maximum number of such events in the STATE_DB is 10240. + +### ASIC SDK health event show commands + +**show asic-sdk-health-event received** + +This command displays the received ASIC/SDK health events. + +- Usage: + ``` + show asic-sdk-health-event received [-n ] + ``` + +- Details: + - show asic-sdk-health-event received: Display the ASIC/SDK health events received on all ASICs + - show asic-sdk-health-event received -n asic0: Display all the ASIC/SDK health events received on asic0 + + +- Example: + ``` + admin@sonic:~$ show asic-sdk-health-event received + Time Severity Category Description + ------------------- ----------- --------- ----------------- + 2023-10-20 05:07:34 fatal firmware Command timeout + 2023-10-20 03:06:25 fatal software SDK daemon keep alive failed + 2023-10-20 05:07:34 fatal asic_hw Uncorrectable ECC error + 2023-10-20 01:58:43 notice asic_hw Correctable ECC error + ``` + +- Example on a multi ASIC system: + ``` + admin@sonic:~$ show asic-sdk-health-event received + asic0: + Time Severity Category Description + ------------------- ----------- --------- ----------------- + 2023-10-20 05:07:34 fatal firmware Command timeout + 2023-10-20 03:06:25 fatal software SDK daemon keep alive failed + asic1: + Time Severity Category Description + ------------------- ----------- --------- ----------------- + 2023-10-20 05:07:34 fatal asic_hw Uncorrectable ECC error + 2023-10-20 01:58:43 notice asic_hw Correctable ECC error + ``` + +Optionally, you can specify the asic name in order to display the ASIC/SDK health events received on that particular ASIC on a multi ASIC system + +- Example: + ``` + admin@sonic:~$ show asic-sdk-health-event received -n asic1 + asic1: + Time Severity Category Description + ------------------- ----------- --------- ----------------- + 2023-10-20 05:07:34 fatal firmware Command timeout + ``` + +**show asic-sdk-health-event suppress-configuration** + +This command displays the suppressed category list and maximum number of events of ASIC/SDK health events. + +- Usage: + ``` + show asic-sdk-health-event suppressed-category-list [-n ] + ``` + +- Details: + - show asic-sdk-health-event suppress-configuration: Display the ASIC/SDK health event suppress category list and maximum number of events on all ASICs + - show asic-sdk-health-event suppress-configuration -n asic0: Display all the ASIC/SDK health event suppress category list and maximum number of events on asic0 + + +- Example: + ``` + admin@sonic:~$ show asic-sdk-health-event suppress-configuration + Severity Suppressed category-list Max events + ---------- -------------------------- ------------ + fatal software unlimited + notice none 1024 + warning firmware,asic_hw 10240 + ``` + +- Example on a multi ASIC system: + ``` + admin@sonic:~$ show asic-sdk-health-event suppress-configuration + asic0: + Severity Suppressed category-list Max events + ---------- -------------------------- ------------ + notice none 1024 + warning firmware,asic_hw 10240 + asic1: + Severity Suppressed category-list Max events + ---------- -------------------------- ------------ + fatal software unlimited + ``` + +Optionally, you can specify the asic name in order to display the ASIC/SDK health event suppress category list on that particular ASIC on a multi ASIC system + +- Example: + ``` + admin@sonic:~$ show asic-sdk-health-event suppress-configuration -n asic1 + asic1: + Severity Suppressed category-list Max events + ---------- -------------------------- ------------ + fatal software unlimited + ``` + +### ASIC SDK health event clear commands + +**sonic-clear asic-sdk-health-event** + +This command clears all the received ASIC/SDK health events. + +- Usage: + ``` + sonic-clear asic-sdk-health-event [-n ] + ``` + +- Details: + - sonic-clear asic-sdk-health-event: Clear the ASIC/SDK health events received on all ASICs + - sonic-clear asic-sdk-health-event -n asic0: Display all the ASIC/SDK health events received on asic0 + + +- Example: + ``` + admin@sonic:~$ sonic-clear asic-sdk-health-event + ``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#asic-sdk-health-event) ## ARP & NDP diff --git a/scripts/generate_dump b/scripts/generate_dump index 64a8917252..4aab27cd48 100755 --- a/scripts/generate_dump +++ b/scripts/generate_dump @@ -1919,6 +1919,8 @@ main() { # 1st counter snapshot early. Need 2 snapshots to make sense of counters trend. save_counter_snapshot $asic 1 + save_cmd "show asic-sdk-health-event received" "asic.sdk.health.event" & + save_cmd "systemd-analyze blame" "systemd.analyze.blame" & save_cmd "systemd-analyze dump" "systemd.analyze.dump" & save_cmd "systemd-analyze plot" "systemd.analyze.plot.svg" & diff --git a/show/main.py b/show/main.py index c1995ad27d..54eeded254 100755 --- a/show/main.py +++ b/show/main.py @@ -2156,6 +2156,103 @@ def suppress_pending_fib(db): click.echo(state) +# asic-sdk-health-event subcommand ("show asic-sdk-health-event") +@cli.group(cls=clicommon.AliasedGroup) +def asic_sdk_health_event(): + """""" + pass + + +@asic_sdk_health_event.command() +@clicommon.pass_db +@click.option('--namespace', '-n', 'namespace', default=None, show_default=True, + type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all') +def suppress_configuration(db, namespace): + """ Show the suppress configuration """ + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() + masic = True + else: + namespace_list = [multi_asic.DEFAULT_NAMESPACE] + masic = False + + header = ['Severity', 'Suppressed category-list', "Max events"] + body = [] + + supported = False + + for ns in namespace_list: + if namespace and namespace != ns: + continue + + state_db = db.db_clients[ns] + if "true" != state_db.get(db.db.STATE_DB, "SWITCH_CAPABILITY|switch", "ASIC_SDK_HEALTH_EVENT"): + continue + + supported = True + + if masic: + click.echo("{}:".format(ns)); + + config_db = db.cfgdb_clients[ns] + suppressSeverities = config_db.get_table('SUPPRESS_ASIC_SDK_HEALTH_EVENT') + + for severity in natsorted(suppressSeverities): + body.append([severity, + ','.join(suppressSeverities[severity].get('categories', ['none'])), + suppressSeverities[severity].get('max_events', 'unlimited')]) + + click.echo(tabulate(body, header)) + + if not supported: + ctx = click.get_current_context() + ctx.fail("ASIC/SDK health event is not supported on the platform") + + +@asic_sdk_health_event.command() +@clicommon.pass_db +@click.option('--namespace', '-n', 'namespace', default=None, show_default=True, + type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all') +def received(db, namespace): + """ Show the received ASIC/SDK health event """ + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() + masic = True + else: + namespace_list = [multi_asic.DEFAULT_NAMESPACE] + masic = False + + header = ['Date', 'Severity', 'Category', 'Description'] + body = [] + + supported = False + + for ns in namespace_list: + if namespace and namespace != ns: + continue + + state_db = db.db_clients[ns] + if "true" != state_db.get(db.db.STATE_DB, "SWITCH_CAPABILITY|switch", "ASIC_SDK_HEALTH_EVENT"): + continue + + supported = True + + if masic: + click.echo("{}:".format(ns)); + + event_keys = state_db.keys(db.db.STATE_DB, "ASIC_SDK_HEALTH_EVENT_TABLE|*") + + for key in natsorted(event_keys): + event = state_db.get_all(state_db.STATE_DB, key) + body.append([key.split('|')[1], event.get('severity'), event.get('category'), event.get('description')]) + + click.echo(tabulate(body, header)) + + if not supported: + ctx = click.get_current_context() + ctx.fail("ASIC/SDK health event is not supported on the platform") + + # Load plugins and register them helper = util_base.UtilHelper() helper.load_and_register_plugins(plugins, cli) diff --git a/tests/asic_sdk_health_event_input/config_db.json b/tests/asic_sdk_health_event_input/config_db.json new file mode 100644 index 0000000000..251f443c3d --- /dev/null +++ b/tests/asic_sdk_health_event_input/config_db.json @@ -0,0 +1,12 @@ +{ + "SUPPRESS_ASIC_SDK_HEALTH_EVENT|fatal": { + "categories@": "software" + }, + "SUPPRESS_ASIC_SDK_HEALTH_EVENT|warning": { + "categories@": "firmware,asic_hw", + "max_events": "10240" + }, + "SUPPRESS_ASIC_SDK_HEALTH_EVENT|notice": { + "max_events": "1024" + } +} diff --git a/tests/asic_sdk_health_event_input/state_db.json b/tests/asic_sdk_health_event_input/state_db.json new file mode 100644 index 0000000000..1eb80bcd81 --- /dev/null +++ b/tests/asic_sdk_health_event_input/state_db.json @@ -0,0 +1,19 @@ +{ + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", + "ACL_ACTION|PACKET_ACTION": "FORWARD", + "ASIC_SDK_HEALTH_EVENT": "true", + "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY": "true" + }, + "ASIC_SDK_HEALTH_EVENT_TABLE|2023-11-22 09:18:12": { + "asic_id": "0", + "severity": "fatal", + "description": "ASIC SDK health event", + "category": "firmware" + } +} diff --git a/tests/asic_sdk_health_event_input/state_db_no_event.json b/tests/asic_sdk_health_event_input/state_db_no_event.json new file mode 100644 index 0000000000..9425fce730 --- /dev/null +++ b/tests/asic_sdk_health_event_input/state_db_no_event.json @@ -0,0 +1,9 @@ +{ + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", + "ACL_ACTION|PACKET_ACTION": "FORWARD" + } +} diff --git a/tests/asic_sdk_health_event_input/state_db_no_fatal.json b/tests/asic_sdk_health_event_input/state_db_no_fatal.json new file mode 100644 index 0000000000..540f1f488c --- /dev/null +++ b/tests/asic_sdk_health_event_input/state_db_no_fatal.json @@ -0,0 +1,13 @@ +{ + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", + "ACL_ACTION|PACKET_ACTION": "FORWARD", + "ASIC_SDK_HEALTH_EVENT": "true", + "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY": "false", + "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY": "true" + } +} diff --git a/tests/asic_sdk_health_event_input/state_db_no_notice.json b/tests/asic_sdk_health_event_input/state_db_no_notice.json new file mode 100644 index 0000000000..82a46e4c95 --- /dev/null +++ b/tests/asic_sdk_health_event_input/state_db_no_notice.json @@ -0,0 +1,13 @@ +{ + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", + "ACL_ACTION|PACKET_ACTION": "FORWARD", + "ASIC_SDK_HEALTH_EVENT": "true", + "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY": "unknown" + } +} diff --git a/tests/asic_sdk_health_event_input/state_db_no_warning.json b/tests/asic_sdk_health_event_input/state_db_no_warning.json new file mode 100644 index 0000000000..f654d3f1a6 --- /dev/null +++ b/tests/asic_sdk_health_event_input/state_db_no_warning.json @@ -0,0 +1,12 @@ +{ + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", + "ACL_ACTION|PACKET_ACTION": "FORWARD", + "ASIC_SDK_HEALTH_EVENT": "true", + "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY": "true", + "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY": "true" + } +} diff --git a/tests/asic_sdk_health_event_test.py b/tests/asic_sdk_health_event_test.py new file mode 100644 index 0000000000..d709a693ca --- /dev/null +++ b/tests/asic_sdk_health_event_test.py @@ -0,0 +1,205 @@ +import click +import config.main as config +import show.main as show +import clear.main as clear +import operator +import os +import pytest +import sys + +from click.testing import CliRunner +from .mock_tables import dbconnector +from utilities_common.db import Db + + +test_path = os.path.dirname(os.path.abspath(__file__)) +mock_db_path = os.path.join(test_path, "asic_sdk_health_event_input") +modules_path = os.path.dirname(test_path) +sys.path.insert(0, modules_path) + + +class TestAsicSdkHealthEvent(object): + @classmethod + def setup_class(cls): + print("SETUP") + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + dbconnector.dedicated_dbs['STATE_DB'] = None + dbconnector.dedicated_dbs['CONFIG_DB'] = None + + @pytest.mark.parametrize("severity,categories", [ + ("fatal", "cpu_hw"), + ("warning", "asic_hw,software,firmware"), + ("notice", "cpu_hw,firmware") + ]) + def test_config_suppress_asic_sdk_health_event(self, severity, categories): + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db') + + runner = CliRunner() + db = Db() + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "all"], obj=db) + assert result.exit_code == 0 + output_categories = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['categories'] + assert {'asic_hw', 'firmware', 'cpu_hw', 'software'} == set(output_categories) + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", categories], obj=db) + assert result.exit_code == 0 + output_categories = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['categories'] + assert set(categories.split(',')) == set(output_categories) + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "none"], obj=db) + assert result.exit_code == 0 + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity) + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "unknown"], obj=db) + assert result.exit_code != 0 + assert "Invalid category(ies): {'unknown'}" in result.output + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity) + + def test_config_suppress_asic_sdk_health_event_mix_category_list_max_events(self): + severity = "fatal" + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db') + + runner = CliRunner() + db = Db() + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "cpu_hw", "--max-events", "10"], obj=db) + assert result.exit_code == 0 + output_categories = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['categories'] + output_max_events = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['max_events'] + assert output_categories == ["cpu_hw"] + assert output_max_events == "10" + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "none", "--max-events", "10"], obj=db) + assert result.exit_code == 0 + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('categories') + output_max_events = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['max_events'] + assert output_max_events == "10" + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "cpu_hw", "--max-events", "0"], obj=db) + assert result.exit_code == 0 + output_categories = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['categories'] + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('max_events') + assert output_categories == ["cpu_hw"] + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--max-events", "10"], obj=db) + assert result.exit_code == 0 + output_categories = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['categories'] + output_max_events = db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity)['max_events'] + assert output_categories == ["cpu_hw"] + assert output_max_events == "10" + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "none", "--max-events", "0"], obj=db) + assert result.exit_code == 0 + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('categories') + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('max_events') + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--max-events", "-50"], obj=db) + assert result.exit_code != 0 + assert "-50 is smaller than the minimum valid value 0" in result.output + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('categories') + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('max_events') + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--max-events", "NaN"], obj=db) + assert result.exit_code != 0 + assert "NaN is not a valid integer" in result.output + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('categories') + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity).get('max_events') + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], severity, obj=db) + assert result.exit_code != 0 + assert "At least one argument should be provided" in result.output + + @pytest.mark.parametrize("severity", ["fatal", "warning", "notice"]) + def test_config_suppress_asic_sdk_health_event_unsupported_severity(self, severity): + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db_no_' + severity) + + runner = CliRunner() + db = Db() + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + [severity, "--category-list", "all"], obj=db) + assert result.exit_code != 0 + assert "Suppressing ASIC/SDK health {} event is not supported on the platform".format(severity) in result.output + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", severity) + + def test_config_suppress_asic_sdk_health_event_unsupported_event(self): + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db_no_event') + + runner = CliRunner() + db = Db() + + result = runner.invoke( + config.config.commands["asic-sdk-health-event"].commands["suppress"], + ["fatal", "--category-list", "all"], obj=db) + assert result.exit_code != 0 + assert "ASIC/SDK health event is not supported on the platform" in result.output + assert not db.cfgdb.get_entry("SUPPRESS_ASIC_SDK_HEALTH_EVENT", "fatal") + + def test_show_asic_sdk_health_event_received(self): + expected_output = \ + "Date Severity Category Description\n" + "------------------- ---------- ---------- ---------------------\n" + "2023-11-22 09:18:12 fatal firmware ASIC SDK health event\n" + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db') + + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["asic-sdk-health-event"].commands["received"], [], obj=db) + assert result.exit_code == 0 + assert expected_output in result.output + + def test_show_asic_sdk_health_event_suppressed_category_list(self): + expected_output = \ + "Severity Suppressed category-list Max events\n" + "---------- -------------------------- ------------\n" + "fatal software unlimited\n" + "notice none 1024\n" + "warning firmware,asic_hw 10240\n" + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'config_db') + + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["asic-sdk-health-event"].commands["suppress-configuration"], [], obj=db) + assert result.exit_code == 0 + assert expected_output in result.output + + def test_clear_suppress_asic_sdk_health_event(self): + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db') + + runner = CliRunner() + db = Db() + + result = runner.invoke(clear.cli.commands["asic-sdk-health-event"], [], obj=db) + assert result.exit_code == 0 + assert not db.db.keys(db.db.STATE_DB, "ASIC_SDK_HEALTH_EVENT_TABLE*")