diff --git a/config/main.py b/config/main.py index c8ec8bc86b..3816ea87e4 100644 --- a/config/main.py +++ b/config/main.py @@ -7008,6 +7008,53 @@ def disable_link_local(ctx): # +# 'static-anycast-gateway' group ('config static-anycast-gateway ...') +# +@config.group(cls=clicommon.AbbreviationGroup, name='static-anycast-gateway') +def static_anycast_gateway(): + """sag-related configuration tasks""" + pass + +# +# 'static-anycast-gateway mac_address' group +# +@static_anycast_gateway.group(cls=clicommon.AbbreviationGroup, name='mac_address') +def mac_address(): + """Add/Delete static-anycast-gateway mac address""" + pass + +@mac_address.command('add') +@click.argument('mac_address', metavar='', required=True, type=str) +@clicommon.pass_db +def add_mac(db, mac_address): + """Add static-anycast-gateway mac address command""" + log.log_info(f"'static-anycast-gateway mac_address add {mac_address}' executing...") + + try: + gateway_mac = netaddr.EUI(mac_address) + except Exception as e: + click.get_current_context().fail(f'static-anycast-gateway MAC address {mac_address} format is not valid.') + + if (gateway_mac.words[0] & 0b01): + click.get_current_context().fail(f'static-anycast-gateway MAC address {mac_address} is multicast, only allow unicast.') + + if not db.cfgdb.get_entry('SAG', 'GLOBAL'): + db.cfgdb.set_entry('SAG', 'GLOBAL', {'gateway_mac': mac_address}) + else: + click.get_current_context().fail(f'static-anycast-gateway MAC address {mac_address} is alreday existed. Remove it first') + +@mac_address.command('del') +@clicommon.pass_db +def del_mac(db): + """Del static-anycast-gateway mac address command""" + log.log_info(f"'static-anycast-gateway mac_address del {mac_address}' executing...") + + sag_entry = db.cfgdb.get_entry('SAG', 'GLOBAL') + if sag_entry: + db.cfgdb.mod_entry('SAG', 'GLOBAL', None) + else: + click.get_current_context().fail(f'static-anycast-gateway MAC address {mac_address} not found.') + # 'rate' group ('config rate ...') # @@ -7037,7 +7084,6 @@ def smoothing_interval(interval, rates_type): counters_db.set('COUNTERS_DB', 'RATES:TRAP', 'TRAP_SMOOTH_INTERVAL', interval) counters_db.set('COUNTERS_DB', 'RATES:TRAP', 'TRAP_ALPHA', alpha) - # Load plugins and register them helper = util_base.UtilHelper() helper.load_and_register_plugins(plugins, config) diff --git a/config/vlan.py b/config/vlan.py index 03660ab0af..4b508950a9 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -136,7 +136,6 @@ def del_vlan(db, vid, no_restart_dhcp_relay): clicommon.run_command(docker_exec_cmd.format("rm -f /etc/supervisor/conf.d/ndppd.conf"), ignore_error=True, return_cmd=True) clicommon.run_command(docker_exec_cmd.format("supervisorctl update"), return_cmd=True) - def restart_ndppd(): verify_swss_running_cmd = ['docker', 'container', 'inspect', '-f', '{{.State.Status}}', 'swss'] docker_exec_cmd = ['docker', 'exec', '-i', 'swss'] @@ -282,3 +281,48 @@ def del_vlan_member(db, vid, port): except JsonPatchConflict: ctx.fail("{} invalid or does not exist, or {} is not a member of {}".format(vlan, port, vlan)) +# +# 'static-anycast-gateway' group ('config vlan static-anycast-gateway ...') +# +@vlan.group(cls=clicommon.AbbreviationGroup, name='static-anycast-gateway') +def static_anycast_gateway(): + pass + +@static_anycast_gateway.command('enable') +@click.argument('vid', metavar='', required=True, type=int) +@clicommon.pass_db +def enable_vlan_sag(db, vid): + """Enable static-anycast-gatweay on VLAN interface""" + ctx = click.get_current_context() + + log.log_info(f"'vlan static-anycast-gateway enable {vid}' executing...") + + vlan = f'Vlan{vid}' + if not clicommon.is_valid_vlan_interface(db.cfgdb, vlan): + ctx.fail(f"Interface {vlan} does not exist") + + if db.cfgdb.get_entry('VLAN_INTERFACE', vlan) == 'true': + ctx.fail(f"static-anycast-gateway is already enabled") + + db.cfgdb.mod_entry('VLAN_INTERFACE', vlan, {"static_anycast_gateway": "true"}) + click.echo('static-anycast-gateway setting saved to ConfigDB') + + +@static_anycast_gateway.command('disable') +@click.argument('vid', metavar='', required=True, type=int) +@clicommon.pass_db +def disable_vlan_sag(db, vid): + """Disable static-anycast-gatweay on VLAN interface""" + ctx = click.get_current_context() + + log.log_info(f"'vlan static-anycast-gateway disable {vid}' executing...") + + vlan = f'Vlan{vid}' + if not clicommon.is_valid_vlan_interface(db.cfgdb, vlan): + ctx.fail(f"Interface {vlan} does not exist") + + if db.cfgdb.get_entry('VLAN_INTERFACE', vlan) == 'false': + ctx.fail(f"static-anycast-gateway is already disabled") + + db.cfgdb.mod_entry('VLAN_INTERFACE', vlan, {"static_anycast_gateway": "false"}) + click.echo('static-anycast-gateway setting saved to ConfigDB') diff --git a/show/main.py b/show/main.py index aa1b5257b4..dd669ae1c4 100755 --- a/show/main.py +++ b/show/main.py @@ -2057,6 +2057,30 @@ def ztp(status, verbose): cmd += ["--verbose"] run_command(cmd, display_cmd=verbose) +# +# 'static anycast gateway' command ("show static-anycast-gateway") +# +@cli.command('static-anycast-gateway') +@clicommon.pass_db +def sag(db): + """Show static anycast gateway information""" + header = ['MacAddress', 'Interfaces'] + body = [] + + sag_entry = db.cfgdb.get_entry('SAG', 'GLOBAL') + if sag_entry: + sag_mac = sag_entry.get('gateway_mac') + + intf_dict = db.cfgdb.get_table('VLAN_INTERFACE') + for key, value in intf_dict.items(): + if value.get('static_anycast_gateway') == 'true': + if not body: + body.append([sag_mac, key]) + else: + body.append(['', key]) + + click.echo("Static Anycast Gateway Information") + click.echo(tabulate(body, header, tablefmt='simple')) # # 'bfd' group ("show bfd ...") diff --git a/show/vlan.py b/show/vlan.py index b27f282a49..171f2adcf3 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -89,6 +89,15 @@ def get_proxy_arp(ctx, vlan): return proxy_arp +def get_static_anycast_gateway(ctx, vlan): + cfg, _ = ctx + _, vlan_ip_data, _ = cfg + + if vlan in vlan_ip_data: + if vlan_ip_data[vlan].get("static_anycast_gateway") == "true": + return "enabled" + + return "disabled" class VlanBrief: """ This class is used as a namespace to @@ -103,7 +112,8 @@ class VlanBrief: ("IP Address", get_vlan_ip_address), ("Ports", get_vlan_ports), ("Port Tagging", get_vlan_ports_tagging), - ("Proxy ARP", get_proxy_arp) + ("Proxy ARP", get_proxy_arp), + ("Static Anycast Gateway", get_static_anycast_gateway) ] @classmethod @@ -147,19 +157,19 @@ def config(db): member_data = db.cfgdb.get_table('VLAN_MEMBER') interface_naming_mode = clicommon.get_interface_naming_mode() iface_alias_converter = clicommon.InterfaceAliasConverter(db) - + def get_iface_name_for_display(member): name_for_display = member if interface_naming_mode == "alias" and member: name_for_display = iface_alias_converter.name_to_alias(member) return name_for_display - + def get_tagging_mode(vlan, member): if not member: return '' tagging_mode = db.cfgdb.get_entry('VLAN_MEMBER', (vlan, member)).get('tagging_mode') return '?' if tagging_mode is None else tagging_mode - + def tablelize(keys, data): table = [] @@ -168,7 +178,7 @@ def tablelize(keys, data): # vlan with no members if not members: members = [(k, '')] - + for vlan, member in natsorted(members): r = [vlan, data[vlan]['vlanid'], get_iface_name_for_display(member), get_tagging_mode(vlan, member)] table.append(r) diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 538f81d605..36ecad4e38 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -623,7 +623,8 @@ "vlanid": "4000" }, "VLAN_INTERFACE|Vlan1000": { - "NULL": "NULL" + "NULL": "NULL", + "static_anycast_gateway": "true" }, "VLAN_INTERFACE|Vlan2000": { "proxy_arp": "enabled" @@ -2664,6 +2665,9 @@ "QUEUE|Ethernet96|6": { "scheduler": "[SCHEDULER|scheduler.0]" }, + "SAG|GLOBAL": { + "gateway_mac": "00:11:22:33:44:55" + }, "MIRROR_SESSION|test_session_db1": { "dst_port": "Ethernet44", "src_port": "Ethernet40,Ethernet48", diff --git a/tests/sag_test.py b/tests/sag_test.py new file mode 100644 index 0000000000..dfb304e937 --- /dev/null +++ b/tests/sag_test.py @@ -0,0 +1,89 @@ +import pytest +import os +import logging +from click.testing import CliRunner + +import config.main as config +import show.main as show +from utilities_common.db import Db +from importlib import reload + +show_sag_output="""\ +Static Anycast Gateway Information +MacAddress Interfaces +----------------- ------------ +00:11:22:33:44:55 Vlan1000 +""" + +class TestSag(object): + @classmethod + def setup_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "1" + print("SETUP") + + def test_config_add_sag_with_existed_mac(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["static-anycast-gateway"].commands["mac_address"].commands["add"], + ["00:22:33:44:55:66"], obj=db) + assert result.exit_code != 0, f"sag invalid mac with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert {"gateway_mac": "00:11:22:33:44:55"} == db.cfgdb.get_entry("SAG", "GLOBAL") + + def test_config_del_add_invalid_sag_mac_address(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["static-anycast-gateway"].commands["mac_address"].commands["del"], + obj=db) + assert result.exit_code == 0, f"sag invalid mac with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert not db.cfgdb.get_entry("SAG", "GLOBAL") + + result = runner.invoke(config.config.commands["static-anycast-gateway"].commands["mac_address"].commands["add"], + ["01:22:33:44:55:66"], obj=db) + assert result.exit_code != 0, f"sag invalid mac with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert {"gateway_mac": "01:11:22:33:44:55"} != db.cfgdb.get_entry("SAG", "GLOBAL") + + def test_config_del_add_sag_mac_address(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["static-anycast-gateway"].commands["mac_address"].commands["del"], + obj=db) + assert result.exit_code == 0, f"sag invalid mac with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert not db.cfgdb.get_entry("SAG", "GLOBAL") + + result = runner.invoke(config.config.commands["static-anycast-gateway"].commands["mac_address"].commands["add"], + ["00:22:33:44:55:66"], obj=db) + assert result.exit_code == 0, f"sag invalid mac with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert {"gateway_mac": "00:22:33:44:55:66"} == db.cfgdb.get_entry("SAG", "GLOBAL") + + def test_config_enable_sag_on_vlan_interface(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["vlan"].commands["static-anycast-gateway"].commands["enable"], + ["2000"], obj=db) + assert result.exit_code == 0, f"sag invalid vlan with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert {"static_anycast_gateway": "true"}.items() <= db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan2000").items() + + def test_config_disable_sag_on_vlan_interface(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["vlan"].commands["static-anycast-gateway"].commands["disable"], + ["1000"], obj=db) + assert result.exit_code == 0, f"sag invalid vlan with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert {"static_anycast_gateway": "false"}.items() <= db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000").items() + + def test_show_sag_mac(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["static-anycast-gateway"], []) + assert result.exit_code == 0, f"invalid show sag with code {type(result.exit_code)}:{result.exit_code} Output:{result.output}" + assert result.output == show_sag_output + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + print("TEARDOWN") + diff --git a/tests/vlan_test.py b/tests/vlan_test.py index 13364f76e6..143fabd03f 100644 --- a/tests/vlan_test.py +++ b/tests/vlan_test.py @@ -21,71 +21,71 @@ } show_vlan_brief_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | -| | fc02:1000::1/64 | Ethernet8 | untagged | | -| | | Ethernet12 | untagged | | -| | | Ethernet16 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | -| | fc02:1011::1/64 | Ethernet28 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | enabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | | | +| | | Ethernet12 | untagged | | | +| | | Ethernet16 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | disabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ show_vlan_brief_in_alias_mode_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 1000 | 192.168.0.1/21 | etp2 | untagged | disabled | -| | fc02:1000::1/64 | etp3 | untagged | | -| | | etp4 | untagged | | -| | | etp5 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 2000 | 192.168.0.10/21 | etp7 | untagged | enabled | -| | fc02:1011::1/64 | etp8 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 1000 | 192.168.0.1/21 | etp2 | untagged | disabled | enabled | +| | fc02:1000::1/64 | etp3 | untagged | | | +| | | etp4 | untagged | | | +| | | etp5 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 2000 | 192.168.0.10/21 | etp7 | untagged | enabled | disabled | +| | fc02:1011::1/64 | etp8 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ show_vlan_brief_empty_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | -| | fc02:1011::1/64 | Ethernet28 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | disabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ show_vlan_brief_with_portchannel_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | -| | fc02:1000::1/64 | Ethernet8 | untagged | | -| | | Ethernet12 | untagged | | -| | | Ethernet16 | untagged | | -| | | PortChannel1001 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | -| | fc02:1011::1/64 | Ethernet28 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | enabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | | | +| | | Ethernet12 | untagged | | | +| | | Ethernet16 | untagged | | | +| | | PortChannel1001 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | disabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ show_vlan_config_output="""\ @@ -115,43 +115,43 @@ """ config_add_del_vlan_and_vlan_member_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | -| | fc02:1000::1/64 | Ethernet8 | untagged | | -| | | Ethernet12 | untagged | | -| | | Ethernet16 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 1001 | | Ethernet20 | untagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | -| | fc02:1011::1/64 | Ethernet28 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | disabled | enabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | | | +| | | Ethernet12 | untagged | | | +| | | Ethernet16 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 1001 | | Ethernet20 | untagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | enabled | disabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ config_add_del_vlan_and_vlan_member_in_alias_mode_output="""\ -+-----------+-----------------+-----------------+----------------+-------------+ -| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | -+===========+=================+=================+================+=============+ -| 1000 | 192.168.0.1/21 | etp2 | untagged | disabled | -| | fc02:1000::1/64 | etp3 | untagged | | -| | | etp4 | untagged | | -| | | etp5 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 1001 | | etp6 | untagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 2000 | 192.168.0.10/21 | etp7 | untagged | enabled | -| | fc02:1011::1/64 | etp8 | untagged | | -+-----------+-----------------+-----------------+----------------+-------------+ -| 3000 | | | | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ -| 4000 | | PortChannel1001 | tagged | disabled | -+-----------+-----------------+-----------------+----------------+-------------+ ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| VLAN ID | IP Address | Ports | Port Tagging | Proxy ARP | Static Anycast Gateway | ++===========+=================+=================+================+=============+==========================+ +| 1000 | 192.168.0.1/21 | etp2 | untagged | disabled | enabled | +| | fc02:1000::1/64 | etp3 | untagged | | | +| | | etp4 | untagged | | | +| | | etp5 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 1001 | | etp6 | untagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 2000 | 192.168.0.10/21 | etp7 | untagged | enabled | disabled | +| | fc02:1011::1/64 | etp8 | untagged | | | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 3000 | | | | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ +| 4000 | | PortChannel1001 | tagged | disabled | disabled | ++-----------+-----------------+-----------------+----------------+-------------+--------------------------+ """ @@ -385,7 +385,7 @@ def test_config_vlan_del_vlan(self, mock_restart_dhcp_relay_service): vlan_member = db.cfgdb.get_table('VLAN_MEMBER') keys = [ (k, v) for k, v in vlan_member if k == 'Vlan{}'.format(1000) ] - for k,v in keys: + for k,v in keys: result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["del"], ["1000", v], obj=db) print(result.exit_code) print(result.output) @@ -575,8 +575,9 @@ def test_config_vlan_proxy_arp_enable(self): mock.call(['docker', 'exec', '-i', 'swss', 'supervisorctl', 'restart', 'ndppd'], return_cmd=True)] mock_run_command.assert_has_calls(expected_calls) - assert result.exit_code == 0 - assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000") == {"proxy_arp": "enabled"} + + assert result.exit_code == 0 + assert {"proxy_arp": "enabled"}.items() <= db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000").items() def test_config_vlan_proxy_arp_disable(self): runner = CliRunner() @@ -589,35 +590,35 @@ def test_config_vlan_proxy_arp_disable(self): assert result.exit_code == 0 assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan2000") == {"proxy_arp": "disabled"} - + def test_config_2_untagged_vlan_on_same_interface(self): runner = CliRunner() db = Db() - + # add Ethernet4 to vlan 2000 as untagged - should fail as ethrnet4 is already untagged member in 1000 result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"], ["2000", "Ethernet4", "--untagged"], obj=db) print(result.exit_code) assert result.exit_code != 0 - + # add Ethernet4 to vlan 2000 as tagged - should succeed result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"], ["2000", "Ethernet4" ], obj=db) print(result.exit_code) assert result.exit_code == 0 - - def test_config_set_router_port_on_member_interface(self): + + def test_config_set_router_port_on_member_interface(self): db = Db() runner = CliRunner() obj = {'config_db':db.cfgdb} - + # intf enable result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["add"], - ["Ethernet4", "10.10.10.1/24"], obj=obj) + ["Ethernet4", "10.10.10.1/24"], obj=obj) print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Interface Ethernet4 is a member of vlan' in result.output - + def test_config_vlan_add_member_of_portchannel(self): runner = CliRunner() db = Db()