From da9340007167b217539a53667059aa89933b88e2 Mon Sep 17 00:00:00 2001 From: liora Date: Tue, 22 Nov 2022 20:21:30 +0000 Subject: [PATCH 1/4] Add CLI command for ECMP calculator --- show/main.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/show/main.py b/show/main.py index 0fce8037ea..7fce2e2e48 100755 --- a/show/main.py +++ b/show/main.py @@ -66,6 +66,8 @@ PLATFORM_JSON = 'platform.json' HWSKU_JSON = 'hwsku.json' PORT_STR = "Ethernet" +ECMP_CALC = '/usr/bin/ecmp_calc.py' +CONTAINER_NAME = 'syncd' VLAN_SUB_INTERFACE_SEPARATOR = '.' @@ -1034,6 +1036,29 @@ def fib(ipaddress, verbose): run_command(cmd, display_cmd=verbose) +# +# 'ecmp-egress-port' subcommand ("show ip ecmp-egress-port...") +# + +@ip.command() +@click.option('--packet', '-p', required=True, help="Json file describing a packet") +@click.option('--ingress-port', '-i', required=True, help="Ingress port") +@click.option('--vrf', '-v', required=False, help="VRF name") +@click.option('--debug', '-d', required=False, is_flag=True, help="Run in debug mode") +def ecmp_egress_port(packet, ingress_port, vrf, debug): + """Show egress port for given packet""" + cmd = "docker cp {} {}:/".format(packet, CONTAINER_NAME) + run_command(cmd) + + packet = os.path.basename(packet) + cmd = "docker exec {} {} --packet {} --interface {}".format(CONTAINER_NAME, ECMP_CALC, packet, ingress_port) + if vrf is not None: + cmd += " --vrf {}".format(vrf) + if debug is True: + cmd += " --debug" + run_command(cmd, display_cmd=debug) + + # # 'ipv6' group ("show ipv6 ...") # From 18c0b0bc06d3842e82b80455148825681d630c25 Mon Sep 17 00:00:00 2001 From: liora Date: Sun, 4 Dec 2022 09:43:58 +0000 Subject: [PATCH 2/4] Add check if ECMP calculator is implemented --- show/main.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/show/main.py b/show/main.py index 7fce2e2e48..108187d94f 100755 --- a/show/main.py +++ b/show/main.py @@ -1035,7 +1035,6 @@ def fib(ipaddress, verbose): cmd += " -ip {}".format(ipaddress) run_command(cmd, display_cmd=verbose) - # # 'ecmp-egress-port' subcommand ("show ip ecmp-egress-port...") # @@ -1047,9 +1046,18 @@ def fib(ipaddress, verbose): @click.option('--debug', '-d', required=False, is_flag=True, help="Run in debug mode") def ecmp_egress_port(packet, ingress_port, vrf, debug): """Show egress port for given packet""" + + # Check if ECMP calculaor is implemented + proc = subprocess.run(['docker', 'exec', '-it', CONTAINER_NAME, 'test', '-f', ECMP_CALC]) + if proc.returncode != 0: + click.echo("ECMP calculator is not available in this image") + return + + # Copy packet JSON to syncd cmd = "docker cp {} {}:/".format(packet, CONTAINER_NAME) run_command(cmd) + # Call ECMP calculaor packet = os.path.basename(packet) cmd = "docker exec {} {} --packet {} --interface {}".format(CONTAINER_NAME, ECMP_CALC, packet, ingress_port) if vrf is not None: From 123486b70b7e7d121c4e91eb691470c8f63a704e Mon Sep 17 00:00:00 2001 From: liora Date: Mon, 12 Dec 2022 14:32:53 +0000 Subject: [PATCH 3/4] Remove short prefix for command options --- show/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/show/main.py b/show/main.py index 108187d94f..209c6af3b3 100755 --- a/show/main.py +++ b/show/main.py @@ -1040,10 +1040,10 @@ def fib(ipaddress, verbose): # @ip.command() -@click.option('--packet', '-p', required=True, help="Json file describing a packet") -@click.option('--ingress-port', '-i', required=True, help="Ingress port") -@click.option('--vrf', '-v', required=False, help="VRF name") -@click.option('--debug', '-d', required=False, is_flag=True, help="Run in debug mode") +@click.option('--packet', required=True, help="Json file describing a packet") +@click.option('--ingress-port', required=True, help="Ingress port") +@click.option('--vrf', required=False, help="VRF name") +@click.option('--debug', required=False, is_flag=True, help="Run in debug mode") def ecmp_egress_port(packet, ingress_port, vrf, debug): """Show egress port for given packet""" From f5c5ef3f68d108baafd07ebcfbb6e7acdb2726da Mon Sep 17 00:00:00 2001 From: liora Date: Tue, 13 Dec 2022 11:02:41 +0000 Subject: [PATCH 4/4] Add unittest for ECMP calculator CLI command --- tests/ecmp_calc_test.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/ecmp_calc_test.py diff --git a/tests/ecmp_calc_test.py b/tests/ecmp_calc_test.py new file mode 100644 index 0000000000..f0b447e154 --- /dev/null +++ b/tests/ecmp_calc_test.py @@ -0,0 +1,39 @@ +import os +import subprocess +import show.main as show +from unittest import mock +from click.testing import CliRunner + +FILE_FOUND_RC = 0 +FILE_NOT_FOUND_RC= 1 +CONTAINER_NAME = 'syncd' +ECMP_CALC = '/usr/bin/ecmp_calc.py' +SHOW_CMD_ARGS = '--ingress-port Ethernet0 --packet /packet.json --vrf Vrf_red --debug' + +class TestShowIpEcmpEgressPort(object): + @classmethod + def setup_class(cls): + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + @mock.patch('subprocess.run', mock.MagicMock(return_value = subprocess.CompletedProcess('', FILE_FOUND_RC, None, None))) + def test_valid_flow(self): + with mock.patch("show.main.run_command", mock.MagicMock()) as mock_run_command: + runner = CliRunner() + result = runner.invoke(show.cli.commands["ip"].commands["ecmp-egress-port"], SHOW_CMD_ARGS.split()) + assert result.exit_code == 0 + assert mock_run_command.call_count == 2 + + ecmp_calc_cmd = "docker exec {} {} --packet packet.json --interface Ethernet0 --vrf Vrf_red --debug".format(CONTAINER_NAME, ECMP_CALC) + mock_run_command.assert_called_with(ecmp_calc_cmd, display_cmd=True) + + @mock.patch('subprocess.run', mock.MagicMock(return_value = subprocess.CompletedProcess('', FILE_NOT_FOUND_RC, None, None))) + def test_binary_not_found(self): + with mock.patch("show.main.run_command", mock.MagicMock()) as mock_run_command: + runner = CliRunner() + result = runner.invoke(show.cli.commands["ip"].commands["ecmp-egress-port"], SHOW_CMD_ARGS.split()) + assert result.exit_code == 0 + assert mock_run_command.call_count == 0 + + @classmethod + def teardown_class(cls): + os.environ["UTILITIES_UNIT_TESTING"] = "0"