From be7cac59f4f928e7da3a9df7376b8ade16478f53 Mon Sep 17 00:00:00 2001 From: mprabhu-nokia <66807480+mprabhu-nokia@users.noreply.github.com> Date: Tue, 12 Jan 2021 12:23:57 -0500 Subject: [PATCH] [show] Add subcommand to show midplane status for modular chassis (#1267) Add subcommand to show midplane status for modular chassis and related unit tests --- show/chassis_modules.py | 47 +++++++++++++++++++++-- tests/chassis_modules_test.py | 67 +++++++++++++++++++++++++++++++++ tests/mock_tables/state_db.json | 12 ++++++ 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/show/chassis_modules.py b/show/chassis_modules.py index 5a13a32419..8a9d22ae35 100644 --- a/show/chassis_modules.py +++ b/show/chassis_modules.py @@ -1,7 +1,7 @@ import click from natsort import natsorted from tabulate import tabulate -from swsssdk import SonicV2Connector +from swsscommon.swsscommon import SonicV2Connector import utilities_common.cli as clicommon @@ -12,6 +12,10 @@ CHASSIS_MODULE_INFO_OPERSTATUS_FIELD = 'oper_status' CHASSIS_MODULE_INFO_ADMINSTATUS_FIELD = 'admin_status' +CHASSIS_MIDPLANE_INFO_TABLE = 'CHASSIS_MIDPLANE_TABLE' +CHASSIS_MIDPLANE_INFO_IP_FIELD = 'ip_address' +CHASSIS_MIDPLANE_INFO_ACCESS_FIELD = 'access' + @click.group(cls=clicommon.AliasedGroup) def chassis_modules(): """Show chassis-modules information""" @@ -31,7 +35,7 @@ def status(db, chassis_module_name): key_pattern = '*' if chassis_module_name: - key_pattern = '|'+chassis_module_name + key_pattern = '|' + chassis_module_name keys = state_db.keys(state_db.STATE_DB, CHASSIS_MODULE_INFO_TABLE + key_pattern) if not keys: @@ -41,7 +45,7 @@ def status(db, chassis_module_name): table = [] for key in natsorted(keys): key_list = key.split('|') - if len(key_list) != 2: # error data in DB, log it and ignore + if len(key_list) != 2: # error data in DB, log it and ignore print('Warn: Invalid Key {} in {} table'.format(key, CHASSIS_MODULE_INFO_TABLE)) continue @@ -61,3 +65,40 @@ def status(db, chassis_module_name): click.echo(tabulate(table, header, tablefmt='simple', stralign='right')) else: click.echo('No data available in CHASSIS_MODULE_TABLE\n') + +@chassis_modules.command() +@click.argument('chassis_module_name', metavar='', required=False) +def midplane_status(chassis_module_name): + """Show chassis-modules midplane-status""" + + header = ['Name', 'IP-Address', 'Reachability'] + + state_db = SonicV2Connector(host="127.0.0.1") + state_db.connect(state_db.STATE_DB) + + key_pattern = '*' + if chassis_module_name: + key_pattern = '|' + chassis_module_name + + keys = state_db.keys(state_db.STATE_DB, CHASSIS_MIDPLANE_INFO_TABLE + key_pattern) + if not keys: + print('Key {} not found in {} table'.format(key_pattern, CHASSIS_MIDPLANE_INFO_TABLE)) + return + + table = [] + for key in natsorted(keys): + key_list = key.split('|') + if len(key_list) != 2: # error data in DB, log it and ignore + print('Warn: Invalid Key {} in {} table'.format(key, CHASSIS_MIDPLANE_INFO_TABLE)) + continue + + data_dict = state_db.get_all(state_db.STATE_DB, key) + ip = data_dict[CHASSIS_MIDPLANE_INFO_IP_FIELD] + access = data_dict[CHASSIS_MIDPLANE_INFO_ACCESS_FIELD] + + table.append((key_list[1], ip, access)) + + if table: + click.echo(tabulate(table, header, tablefmt='simple', stralign='right')) + else: + click.echo('No data available in CHASSIS_MIDPLANE_TABLE\n') diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 754845eba2..fb63488ecd 100644 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -21,12 +21,36 @@ header_lines = 2 warning_lines = 0 +show_chassis_modules_output="""\ + Name Description Physical-Slot Oper-Status Admin-Status +------------ --------------- --------------- ------------- -------------- +FABRIC-CARD0 fabric-card 17 Online up +FABRIC-CARD1 fabric-card 18 Offline up + LINE-CARD0 line-card 1 Empty up + LINE-CARD1 line-card 2 Online down + SUPERVISOR0 supervisor-card 16 Online up +""" + +show_chassis_midplane_output="""\ + Name IP-Address Reachability +----------- ------------- -------------- + LINE-CARD0 192.168.1.1 True + LINE-CARD1 192.168.1.2 False +SUPERVISOR0 192.168.1.100 True +""" + class TestChassisModules(object): @classmethod def setup_class(cls): print("SETUP") os.environ["UTILITIES_UNIT_TESTING"] = "1" + def test_show_and_verify_output(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], []) + print(result.output) + assert(result.output == show_chassis_modules_output) + def test_show_all_count_lines(self): runner = CliRunner() result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], []) @@ -112,6 +136,49 @@ def test_config_incorrect_module(self): print(result.output) assert result.exit_code != 0 + def test_show_and_verify_midplane_output(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], []) + print(result.output) + assert(result.output == show_chassis_midplane_output) + + def test_midplane_show_all_count_lines(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], []) + print(result.output) + result_lines = result.output.strip('\n').split('\n') + modules = ["LINE-CARD0", "LINE-CARD1", "SUPERVISOR0"] + for i, module in enumerate(modules): + assert module in result_lines[i + warning_lines + header_lines] + assert len(result_lines) == warning_lines + header_lines + len(modules) + + def test_midplane_show_single_count_lines(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["LINE-CARD0"]) + print(result.output) + result_lines = result.output.strip('\n').split('\n') + modules = ["LINE-CARD0"] + for i, module in enumerate(modules): + assert module in result_lines[i+header_lines] + assert len(result_lines) == header_lines + len(modules) + + def test_midplane_show_module_down(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["LINE-CARD1"]) + print(result.output) + result_lines = result.output.strip('\n').split('\n') + assert result.exit_code == 0 + result_out = (result_lines[header_lines]).split() + print(result_out) + assert result_out[2] == 'False' + + def test_midplane_show_incorrect_module(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["TEST-CARD1"]) + print(result.output) + print(result.exit_code) + assert result.exit_code == 0 + @classmethod def teardown_class(cls): print("TEARDOWN") diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 7f563d8842..c7d56da133 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -377,5 +377,17 @@ "xon": "18432", "xoff": "32768", "size": "51200" + }, + "CHASSIS_MIDPLANE_TABLE|SUPERVISOR0": { + "ip_address": "192.168.1.100", + "access": "True" + }, + "CHASSIS_MIDPLANE_TABLE|LINE-CARD0": { + "ip_address": "192.168.1.1", + "access": "True" + }, + "CHASSIS_MIDPLANE_TABLE|LINE-CARD1": { + "ip_address": "192.168.1.2", + "access": "False" } }