diff --git a/show/main.py b/show/main.py index 0a914f7bd1..73798cc0be 100644 --- a/show/main.py +++ b/show/main.py @@ -14,6 +14,7 @@ from tabulate import tabulate from utilities_common.db import Db import utilities_common.constants as constants +from json.decoder import JSONDecodeError from . import acl from . import bgp_common @@ -110,6 +111,10 @@ def run_command(command, display_cmd=False, return_cmd=False): if rc != 0: sys.exit(rc) +def get_cmd_output(cmd): + proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE) + return proc.communicate()[0], proc.returncode + # Global class instance for SONiC interface name to alias conversion iface_alias_converter = clicommon.InterfaceAliasConverter() @@ -1055,8 +1060,25 @@ 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" - run_command(cmd, display_cmd=verbose) + 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 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)) # 'acl' subcommand ("show runningconfiguration acl") diff --git a/tests/show_test.py b/tests/show_test.py index 699d908880..114dbc3c6c 100644 --- a/tests/show_test.py +++ b/tests/show_test.py @@ -1,10 +1,58 @@ +import os +import sys import pytest import show.main as show from click.testing import CliRunner -from unittest.mock import MagicMock, patch +from unittest import mock +from unittest.mock import call, MagicMock, patch EXPECTED_BASE_COMMAND = 'sudo ' +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +sys.path.insert(0, test_path) +sys.path.insert(0, modules_path) + + +class TestShowRunAllCommands(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + def test_show_runningconfiguration_all_json_loads_failure(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 + + def test_show_runningconfiguration_all_get_cmd_ouput_failure(self): + def get_cmd_output_side_effect(*args, **kwargs): + return "{}", 2 + 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 + + def test_show_runningconfiguration_all(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 == 2 + assert mock_get_cmd_output.call_args_list == [ + call(['sonic-cfggen', '-d', '--print-data']), + call(['rvtysh', '-c', 'show running-config'])] + + @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" + @patch('show.main.run_command') @pytest.mark.parametrize( "cli_arguments,expected",