From 817b8860bb5930904780b24f7843beeb0527a40e Mon Sep 17 00:00:00 2001 From: jingwenxie Date: Fri, 2 Feb 2024 09:21:54 +0000 Subject: [PATCH 1/2] [show] Update show run all to cover all asic config in masic --- show/main.py | 40 +++++++++++++++++++++++++++++----------- tests/show_test.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/show/main.py b/show/main.py index 725556e6e8..e1bdc7f77a 100755 --- a/show/main.py +++ b/show/main.py @@ -142,6 +142,24 @@ def get_cmd_output(cmd): proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE) return proc.communicate()[0], proc.returncode +def get_config_json_by_namespace(namespace): + cmd = ['sonic-cfggen', '-d', '--print-data'] + if namespace is not None and namespace != multi_asic.DEFAULT_NAMESPACE: + cmd += ['-n', namespace] + + stdout, rc = get_cmd_output(cmd) + if rc: + click.echo("Failed to get cmd output '{}':rc {}".format(cmd, rc)) + raise click.Abort() + + try: + config_json = json.loads(stdout) + except JSONDecodeError as e: + click.echo("Failed to load output '{}':{}".format(cmd, e)) + raise click.Abort() + + return config_json + # Lazy global class instance for SONiC interface name to alias conversion iface_alias_converter = lazy_object_proxy.Proxy(lambda: clicommon.InterfaceAliasConverter()) @@ -1407,24 +1425,24 @@ def runningconfiguration(): @click.option('--verbose', is_flag=True, help="Enable verbose output") def all(verbose): """Show full running configuration""" - cmd = ['sonic-cfggen', '-d', '--print-data'] - stdout, rc = get_cmd_output(cmd) - if rc: - click.echo("Failed to get cmd output '{}':rc {}".format(cmd, rc)) - raise click.Abort() - try: - output = json.loads(stdout) - except JSONDecodeError as e: - click.echo("Failed to load output '{}':{}".format(cmd, e)) - raise click.Abort() + if multi_asic.is_multi_asic(): + output = {} + # In multiaisc, the namespace is changed to localhost by design + output['localhost'] = get_config_json_by_namespace(multi_asic.DEFAULT_NAMESPACE) + + ns_list = multi_asic.get_namespace_list() + for ns in ns_list: + output[ns] = get_config_json_by_namespace(ns) + else: + output = get_config_json_by_namespace(None) - if not multi_asic.is_multi_asic(): bgpraw_cmd = [constants.RVTYSH_COMMAND, '-c', 'show running-config'] bgpraw, rc = get_cmd_output(bgpraw_cmd) if rc: bgpraw = "" output['bgpraw'] = bgpraw + click.echo(json.dumps(output, indent=4)) diff --git a/tests/show_test.py b/tests/show_test.py index 5b55c15896..0cdf49966e 100644 --- a/tests/show_test.py +++ b/tests/show_test.py @@ -2,6 +2,7 @@ import sys import click import pytest +import importlib import subprocess import show.main as show from unittest import mock @@ -66,6 +67,43 @@ def teardown_class(cls): os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) os.environ["UTILITIES_UNIT_TESTING"] = "0" + +class TestShowRunAllCommandsMasic(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ['UTILITIES_UNIT_TESTING'] = "2" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + # change to multi asic config + from .mock_tables import dbconnector + from .mock_tables import mock_multi_asic + importlib.reload(mock_multi_asic) + dbconnector.load_namespace_config() + + def test_show_runningconfiguration_all_masic(self): + def get_cmd_output_side_effect(*args, **kwargs): + return "{}", 0 + with mock.patch('show.main.get_cmd_output', + mock.MagicMock(side_effect=get_cmd_output_side_effect)) as mock_get_cmd_output: + result = CliRunner().invoke(show.cli.commands['runningconfiguration'].commands['all'], []) + assert mock_get_cmd_output.call_count == 3 + assert mock_get_cmd_output.call_args_list == [ + call(['sonic-cfggen', '-d', '--print-data']), + call(['sonic-cfggen', '-d', '--print-data', '-n', 'asic0']), + call(['sonic-cfggen', '-d', '--print-data', '-n', 'asic1'])] + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + # change back to single asic config + from .mock_tables import dbconnector + from .mock_tables import mock_single_asic + importlib.reload(mock_single_asic) + dbconnector.load_namespace_config() + + @patch('show.main.run_command') @pytest.mark.parametrize( "cli_arguments0,expected0", From d0dd490e19f34873666b6650023ddeaf329a61d0 Mon Sep 17 00:00:00 2001 From: jingwenxie Date: Wed, 7 Feb 2024 07:42:15 +0000 Subject: [PATCH 2/2] per comment --- show/main.py | 27 +++++++++++++-------------- tests/show_test.py | 22 +++++++++++++++++++--- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/show/main.py b/show/main.py index e1bdc7f77a..c1995ad27d 100755 --- a/show/main.py +++ b/show/main.py @@ -1425,25 +1425,24 @@ def runningconfiguration(): @click.option('--verbose', is_flag=True, help="Enable verbose output") def all(verbose): """Show full running configuration""" + output = {} + bgpraw_cmd = "show running-config" - if multi_asic.is_multi_asic(): - output = {} - # In multiaisc, the namespace is changed to localhost by design - output['localhost'] = get_config_json_by_namespace(multi_asic.DEFAULT_NAMESPACE) + import utilities_common.bgp_util as bgp_util + # In multiaisc, the namespace is changed to 'localhost' by design + host_config = get_config_json_by_namespace(multi_asic.DEFAULT_NAMESPACE) + output['localhost'] = host_config + if multi_asic.is_multi_asic(): ns_list = multi_asic.get_namespace_list() for ns in ns_list: - output[ns] = get_config_json_by_namespace(ns) + ns_config = get_config_json_by_namespace(ns) + ns_config['bgpraw'] = bgp_util.run_bgp_show_command(bgpraw_cmd, ns) + output[ns] = ns_config + click.echo(json.dumps(output, indent=4)) else: - output = get_config_json_by_namespace(None) - - bgpraw_cmd = [constants.RVTYSH_COMMAND, '-c', 'show running-config'] - bgpraw, rc = get_cmd_output(bgpraw_cmd) - if rc: - bgpraw = "" - output['bgpraw'] = bgpraw - - click.echo(json.dumps(output, indent=4)) + host_config['bgpraw'] = bgp_util.run_bgp_show_command(bgpraw_cmd) + click.echo(json.dumps(output['localhost'], indent=4)) # 'acl' subcommand ("show runningconfiguration acl") diff --git a/tests/show_test.py b/tests/show_test.py index 0cdf49966e..077005b220 100644 --- a/tests/show_test.py +++ b/tests/show_test.py @@ -5,6 +5,7 @@ import importlib import subprocess import show.main as show +import utilities_common.bgp_util as bgp_util from unittest import mock from click.testing import CliRunner from utilities_common import constants @@ -33,6 +34,12 @@ class TestShowRunAllCommands(object): def setup_class(cls): print("SETUP") os.environ["UTILITIES_UNIT_TESTING"] = "1" + cls._old_run_bgp_command = bgp_util.run_bgp_command + bgp_util.run_bgp_command = mock.MagicMock( + return_value=cls.mock_run_bgp_command()) + + def mock_run_bgp_command(): + return "" def test_show_runningconfiguration_all_json_loads_failure(self): def get_cmd_output_side_effect(*args, **kwargs): @@ -56,14 +63,15 @@ def get_cmd_output_side_effect(*args, **kwargs): with mock.patch('show.main.get_cmd_output', mock.MagicMock(side_effect=get_cmd_output_side_effect)) as mock_get_cmd_output: result = CliRunner().invoke(show.cli.commands['runningconfiguration'].commands['all'], []) - assert mock_get_cmd_output.call_count == 2 + assert result.exit_code == 0 + assert mock_get_cmd_output.call_count == 1 assert mock_get_cmd_output.call_args_list == [ - call(['sonic-cfggen', '-d', '--print-data']), - call(['rvtysh', '-c', 'show running-config'])] + call(['sonic-cfggen', '-d', '--print-data'])] @classmethod def teardown_class(cls): print("TEARDOWN") + bgp_util.run_bgp_command = cls._old_run_bgp_command os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) os.environ["UTILITIES_UNIT_TESTING"] = "0" @@ -74,18 +82,25 @@ def setup_class(cls): print("SETUP") os.environ['UTILITIES_UNIT_TESTING'] = "2" os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + cls._old_run_bgp_command = bgp_util.run_bgp_command + bgp_util.run_bgp_command = mock.MagicMock( + return_value=cls.mock_run_bgp_command()) # change to multi asic config from .mock_tables import dbconnector from .mock_tables import mock_multi_asic importlib.reload(mock_multi_asic) dbconnector.load_namespace_config() + def mock_run_bgp_command(): + return "" + def test_show_runningconfiguration_all_masic(self): def get_cmd_output_side_effect(*args, **kwargs): return "{}", 0 with mock.patch('show.main.get_cmd_output', mock.MagicMock(side_effect=get_cmd_output_side_effect)) as mock_get_cmd_output: result = CliRunner().invoke(show.cli.commands['runningconfiguration'].commands['all'], []) + assert result.exit_code == 0 assert mock_get_cmd_output.call_count == 3 assert mock_get_cmd_output.call_args_list == [ call(['sonic-cfggen', '-d', '--print-data']), @@ -95,6 +110,7 @@ def get_cmd_output_side_effect(*args, **kwargs): @classmethod def teardown_class(cls): print("TEARDOWN") + bgp_util.run_bgp_command = cls._old_run_bgp_command os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) os.environ["UTILITIES_UNIT_TESTING"] = "0" # change back to single asic config