From a6f82344abef96c2802840cfd425ae1824df0388 Mon Sep 17 00:00:00 2001 From: Feng Pan Date: Tue, 23 Apr 2024 15:11:09 +0000 Subject: [PATCH 1/4] Add CLI for bmp configdb entity Enable/Disable. --- config/main.py | 161 ++++++++++++++++++++++++++++++ doc/Command-Reference.md | 204 +++++++++++++++++++++++++-------------- tests/config_test.py | 144 +++++++++++++++++++++++++++ 3 files changed, 434 insertions(+), 75 deletions(-) diff --git a/config/main.py b/config/main.py index a068a1b7f4..ef62a0d059 100644 --- a/config/main.py +++ b/config/main.py @@ -3916,6 +3916,167 @@ def del_user(db, user): click.echo("Restart service snmp failed with error {}".format(e)) raise click.Abort() +# +# 'bmp' group ('config bmp ...') +# + +@config.group() +@click.pass_context +def bmp(ctx): + """BMP-related configuration""" + +# +# 'enable' subgroup ('config bmp enable ...') +# +@bmp.group() +@click.pass_context +def enable(ctx): + """Enable BMP table dump """ + +# +# 'bgp-neighbor-table' command ('config bmp enable bgp-neighbor-table') +# +@enable.command('bgp-neighbor-table') +@click.pass_context +def enable_bgp_neighbor_table(ctx): + """enable bgp-neighbor-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + print("'bmp enable bgp-neighbor-table' executing...") + log.log_info("'bmp enable bgp-neighbor-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_neighbor_table': 'true'}} + else: + bmp_table['table']['bgp_neighbor_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + + +# +# 'bgp-rib-out-table' command ('config bmp enable bgp-rib-out-table') +# +@enable.command('bgp-rib-out-table') +@click.pass_context +def enable_bgp_rib_out_table(ctx): + """enable bgp-rib-out-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp enable bgp-rib-out-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_out_table': 'true'}} + else: + bmp_table['table']['bgp_rib_out_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'bgp-rib-in-table' command ('config bmp enable bgp-rib-in-table') +# +@enable.command('bgp-rib-in-table') +@click.pass_context +def enable_bgp_rib_in_table(ctx): + """enable bgp-rib-in-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp enable bgp-rib-in-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_in_table': 'true'}} + else: + bmp_table['table']['bgp_rib_in_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'disable' subgroup ('config bmp disable ...') +# +@bmp.group() +@click.pass_context +def disable(ctx): + """Disable BMP table dump """ + +# +# 'bgp-neighbor-table' command ('config bmp disable bgp-neighbor-table') +# +@disable.command('bgp-neighbor-table') +@click.pass_context +def disable_bgp_neighbor_table(ctx): + """disable bgp-neighbor-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-neighbor-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_neighbor_table': 'false'}} + else: + bmp_table['table']['bgp_neighbor_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'bgp-rib-out-table' command ('config bmp disable bgp-rib-out-table') +# +@disable.command('bgp-rib-out-table') +@click.pass_context +def diable_bgp_rib_out_table(ctx): + """disable bgp-rib-out-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-rib-out-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_out_table': 'false'}} + else: + bmp_table['table']['bgp_rib_out_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +# +# 'bgp-rib-in-table' command ('config bmp disable bgp-rib-in-table') +# +@disable.command('bgp-rib-in-table') +@click.pass_context +def disable_bgp_rib_in_table(ctx): + """disable bgp-rib-in-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-rib-in-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_in_table': 'false'}} + else: + bmp_table['table']['bgp_rib_in_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + # # 'bgp' group ('config bgp ...') # diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index e97922af65..645eb30522 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -83,6 +83,9 @@ * [IP / IPv6](#ip--ipv6) * [IP show commands](#ip-show-commands) * [IPv6 show commands](#ipv6-show-commands) +* [BMP](#bmp) + * [BMP show commands](#bmp-show-commands) + * [BMP config commands](#bmp-config-commands) * [IPv6 Link Local](#ipv6-link-local) * [IPv6 Link Local config commands](#ipv6-link-local-config-commands) * [IPv6 Link Local show commands](#ipv6-link-local-show-commands) @@ -2078,6 +2081,129 @@ This command displays the state and key parameters of all BFD sessions that matc Go Back To [Beginning of the document](#) or [Beginning of this section](#bfd) + +## BMP + +### BMP show commands + +This sub-section explains the list of show options available for BMP module. + +**show bmp bgp-neighbor-table** + + +This command is used to show bgp-neighbor-table population. + +- Usage: + ``` + show bmp bgp-neighbor-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo show bmp bgp-neighbor-table + Neighbor Address Peer Address Peer ASN Peer RD Type Local Addr Local ASN Local Port Advertised Capabilities Received Capabilities + ----------- ----------- ------- ------- ------------ ------------ ------------- ------------- ------------ ---------- + 10.0.0.61 10.0.0.61 64915 64900 ibgp 10.0.0.1 65100 5000 11 true + + ``` + +**show bmp bgp-rib-out-table** + +**show bmp bgp-rib-in-table** + +**show bmp status** + + +### BMP config commands + +This sub-section explains the list of configuration options available for BMP module. + +**config bmp enable bgp-neighbor-table** + +This command is used to enable bgp-neighbor-table population. + +- Usage: + ``` + config bmp enable bgp-neighbor-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-neighbor-table + ``` + + +**config bmp disable bgp-neighbor-table** + +This command is used to disable bgp-neighbor-table population. + +- Usage: + ``` + config bmp disable bgp-neighbor-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-neighbor-table + ``` + +**config bmp enable bgp-rib-out-table** + +This command is used to enable bgp-rib-out-table population. + +- Usage: + ``` + config bmp enable bgp-rib-out-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-rib-out-table + ``` + +**config bmp disable bgp-rib-out-table** + +This command is used to disable bgp-rib-out-table population. + +- Usage: + ``` + config bmp disable bgp-rib-out-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-rib-out-table + ``` + +**config bmp enable bgp-rib-in-table** + +This command is used to enable bgp-rib-in-table population. + +- Usage: + ``` + config bmp enable bgp-rib-in-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-rib-in-table + ``` + +**config bmp disable bgp-rib-in-table** + +This command is used to disable bgp-rib-in-table population. + +- Usage: + ``` + config bmp disable bgp-rib-in-table + ``` + +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-rib-in-table + ``` +Go Back To [Beginning of the document](#) or [Beginning of this section](#bmp) + ## BGP This section explains all the BGP show commands and BGP configuration commands in both "Quagga" and "FRR" routing software that are supported in SONiC. @@ -10149,7 +10275,7 @@ This command displays rate limit configuration for containers. - Usage ``` - show syslog rate-limit-container [] -n [] + show syslog rate-limit-container [] ``` - Example: @@ -10173,37 +10299,6 @@ This command displays rate limit configuration for containers. SERVICE INTERVAL BURST -------------- ---------- ------- bgp 0 0 - - # Multi ASIC - show syslog rate-limit-container - SERVICE INTERVAL BURST - -------- ---------- -------- - bgp 500 N/A - snmp 300 20000 - swss 2000 12000 - Namespace asic0: - SERVICE INTERVAL BURST - -------- ---------- -------- - bgp 500 N/A - snmp 300 20000 - swss 2000 12000 - - # Multi ASIC - show syslog rate-limit-container bgp - SERVICE INTERVAL BURST - -------- ---------- -------- - bgp 500 5000 - Namespace asic0: - SERVICE INTERVAL BURST - -------- ---------- -------- - bgp 500 5000 - - # Multi ASIC - show syslog rate-limit-container bgp -n asic1 - Namespace asic1: - SERVICE INTERVAL BURST - -------- ---------- -------- - bgp 500 5000 ``` ### Syslog Config Commands @@ -10282,19 +10377,10 @@ This command is used to configure syslog rate limit for containers. - Parameters: - _interval_: determines the amount of time that is being measured for rate limiting. - _burst_: defines the amount of messages, that have to occur in the time limit of interval, to trigger rate limiting - - _namespace_: namespace name or all. Value "default" indicates global namespace. - Example: ``` - # Config bgp for all namespaces. For multi ASIC platforms, bgp service in all namespaces will be affected. - # For single ASIC platforms, bgp service in global namespace will be affected. admin@sonic:~$ sudo config syslog rate-limit-container bgp --interval 300 --burst 20000 - - # Config bgp for global namespace only. - config syslog rate-limit-container bgp --interval 300 --burst 20000 -n default - - # Config bgp for asic0 namespace only. - config syslog rate-limit-container bgp --interval 300 --burst 20000 -n asic0 ``` **config syslog rate-limit-feature enable** @@ -10303,28 +10389,12 @@ This command is used to enable syslog rate limit feature. - Usage: ``` - config syslog rate-limit-feature enable [] -n [] + config syslog rate-limit-feature enable ``` - Example: ``` - # Enable syslog rate limit for all services in all namespaces admin@sonic:~$ sudo config syslog rate-limit-feature enable - - # Enable syslog rate limit for all services in global namespace - config syslog rate-limit-feature enable -n default - - # Enable syslog rate limit for all services in asic0 namespace - config syslog rate-limit-feature enable -n asic0 - - # Enable syslog rate limit for database in all namespaces - config syslog rate-limit-feature enable database - - # Enable syslog rate limit for database in default namespace - config syslog rate-limit-feature enable database -n default - - # Enable syslog rate limit for database in asci0 namespace - config syslog rate-limit-feature enable database -n asci0 ``` **config syslog rate-limit-feature disable** @@ -10333,28 +10403,12 @@ This command is used to disable syslog rate limit feature. - Usage: ``` - config syslog rate-limit-feature disable [] -n [] + config syslog rate-limit-feature disable ``` - Example: ``` - # Disable syslog rate limit for all services in all namespaces admin@sonic:~$ sudo config syslog rate-limit-feature disable - - # Disable syslog rate limit for all services in global namespace - config syslog rate-limit-feature disable -n default - - # Disable syslog rate limit for all services in asic0 namespace - config syslog rate-limit-feature disable -n asic0 - - # Disable syslog rate limit for database in all namespaces - config syslog rate-limit-feature disable database - - # Disable syslog rate limit for database in default namespace - config syslog rate-limit-feature disable database -n default - - # Disable syslog rate limit for database in asci0 namespace - config syslog rate-limit-feature disable database -n asci0 ``` Go Back To [Beginning of the document](#) or [Beginning of this section](#syslog) diff --git a/tests/config_test.py b/tests/config_test.py index cc0ac22e98..0499e39f1c 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -37,6 +37,9 @@ # Config Reload input Path mock_db_path = os.path.join(test_path, "config_reload_input") +mock_bmp_db_path = os.path.join(test_path, "bmp_input") + + # Load minigraph input Path load_minigraph_input_path = os.path.join(test_path, "load_minigraph_input") load_minigraph_platform_path = os.path.join(load_minigraph_input_path, "platform") @@ -392,6 +395,147 @@ def teardown_class(cls): dbconnector.load_namespace_config() +class TestBMPConfig(object): + @classmethod + def setup_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "1" + print("SETUP") + import config.main + importlib.reload(config.main) + + def test_enable_bgp_neighbor_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-neighbor-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-neighbor-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_neighbor_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-neighbor-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-neighbor-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_enable_bgp_rib_in_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-rib-in-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-rib-in-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_rib_in_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-rib-in-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-rib-in-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_enable_bgp_rib_out_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-rib-out-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-rib-out-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_rib_out_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-rib-out-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-rib-out-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + from .mock_tables import dbconnector + dbconnector.dedicated_dbs = {} + print("TEARDOWN") + class TestLoadMinigraph(object): @classmethod def setup_class(cls): From 7e2e40a2921512d554145f076cafee25c6ea1732 Mon Sep 17 00:00:00 2001 From: Feng Pan Date: Tue, 23 Apr 2024 15:11:09 +0000 Subject: [PATCH 2/4] Add CLI for bmp configdb entity Enable/Disable. --- config/main.py | 161 +++++++++++++++++++++++++++++++++++++++ doc/Command-Reference.md | 70 ++++++++++++++++- tests/config_test.py | 144 ++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index a068a1b7f4..ef62a0d059 100644 --- a/config/main.py +++ b/config/main.py @@ -3916,6 +3916,167 @@ def del_user(db, user): click.echo("Restart service snmp failed with error {}".format(e)) raise click.Abort() +# +# 'bmp' group ('config bmp ...') +# + +@config.group() +@click.pass_context +def bmp(ctx): + """BMP-related configuration""" + +# +# 'enable' subgroup ('config bmp enable ...') +# +@bmp.group() +@click.pass_context +def enable(ctx): + """Enable BMP table dump """ + +# +# 'bgp-neighbor-table' command ('config bmp enable bgp-neighbor-table') +# +@enable.command('bgp-neighbor-table') +@click.pass_context +def enable_bgp_neighbor_table(ctx): + """enable bgp-neighbor-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + print("'bmp enable bgp-neighbor-table' executing...") + log.log_info("'bmp enable bgp-neighbor-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_neighbor_table': 'true'}} + else: + bmp_table['table']['bgp_neighbor_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + + +# +# 'bgp-rib-out-table' command ('config bmp enable bgp-rib-out-table') +# +@enable.command('bgp-rib-out-table') +@click.pass_context +def enable_bgp_rib_out_table(ctx): + """enable bgp-rib-out-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp enable bgp-rib-out-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_out_table': 'true'}} + else: + bmp_table['table']['bgp_rib_out_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'bgp-rib-in-table' command ('config bmp enable bgp-rib-in-table') +# +@enable.command('bgp-rib-in-table') +@click.pass_context +def enable_bgp_rib_in_table(ctx): + """enable bgp-rib-in-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp enable bgp-rib-in-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_in_table': 'true'}} + else: + bmp_table['table']['bgp_rib_in_table'] = 'true' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'disable' subgroup ('config bmp disable ...') +# +@bmp.group() +@click.pass_context +def disable(ctx): + """Disable BMP table dump """ + +# +# 'bgp-neighbor-table' command ('config bmp disable bgp-neighbor-table') +# +@disable.command('bgp-neighbor-table') +@click.pass_context +def disable_bgp_neighbor_table(ctx): + """disable bgp-neighbor-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-neighbor-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_neighbor_table': 'false'}} + else: + bmp_table['table']['bgp_neighbor_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'bgp-rib-out-table' command ('config bmp disable bgp-rib-out-table') +# +@disable.command('bgp-rib-out-table') +@click.pass_context +def diable_bgp_rib_out_table(ctx): + """disable bgp-rib-out-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-rib-out-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_out_table': 'false'}} + else: + bmp_table['table']['bgp_rib_out_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +# +# 'bgp-rib-in-table' command ('config bmp disable bgp-rib-in-table') +# +@disable.command('bgp-rib-in-table') +@click.pass_context +def disable_bgp_rib_in_table(ctx): + """disable bgp-rib-in-table sessions + In the case of Multi-Asic platform, corresponding database instance of neighbor will be operated. + """ + log.log_info("'bmp disable bgp-rib-in-table' executing...") + config_db = ConfigDBConnector() + config_db.connect() + bmp_table = config_db.get_table('BMP') + if not bmp_table: + bmp_table = {'table': {'bgp_rib_in_table': 'false'}} + else: + bmp_table['table']['bgp_rib_in_table'] = 'false' + try: + config_db.mod_entry('BMP', 'table', bmp_table['table']) + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + # # 'bgp' group ('config bgp ...') # diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index e97922af65..8e442264c5 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -32,7 +32,6 @@ * [BFD](#bfd) * [BFD show commands](#bfd-show-commands) * [BGP](#bgp) - * [BGP show commands](#bgp-show-commands) * [BGP config commands](#bgp-config-commands) * [Console](#console) * [Console show commands](#console-show-commands) @@ -83,6 +82,9 @@ * [IP / IPv6](#ip--ipv6) * [IP show commands](#ip-show-commands) * [IPv6 show commands](#ipv6-show-commands) +* [BMP](#bmp) + * [BMP show commands](#bmp-show-commands) + * [BMP config commands](#bmp-config-commands) * [IPv6 Link Local](#ipv6-link-local) * [IPv6 Link Local config commands](#ipv6-link-local-config-commands) * [IPv6 Link Local show commands](#ipv6-link-local-show-commands) @@ -2078,6 +2080,72 @@ This command displays the state and key parameters of all BFD sessions that matc Go Back To [Beginning of the document](#) or [Beginning of this section](#bfd) +## BMP + +### BMP config commands +This sub-section explains the list of configuration options available for BMP module. +**config bmp enable bgp-neighbor-table** +This command is used to enable bgp-neighbor-table population. +- Usage: + ``` + config bmp enable bgp-neighbor-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-neighbor-table + ``` +**config bmp disable bgp-neighbor-table** +This command is used to disable bgp-neighbor-table population. +- Usage: + ``` + config bmp disable bgp-neighbor-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-neighbor-table + ``` +**config bmp enable bgp-rib-out-table** +This command is used to enable bgp-rib-out-table population. +- Usage: + ``` + config bmp enable bgp-rib-out-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-rib-out-table + ``` +**config bmp disable bgp-rib-out-table** +This command is used to disable bgp-rib-out-table population. +- Usage: + ``` + config bmp disable bgp-rib-out-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-rib-out-table + ``` +**config bmp enable bgp-rib-in-table** +This command is used to enable bgp-rib-in-table population. +- Usage: + ``` + config bmp enable bgp-rib-in-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp enable bgp-rib-in-table + ``` +**config bmp disable bgp-rib-in-table** +This command is used to disable bgp-rib-in-table population. +- Usage: + ``` + config bmp disable bgp-rib-in-table + ``` +- Example: + ``` + admin@sonic:~$ sudo config bmp disable bgp-rib-in-table + ``` +Go Back To [Beginning of the document](#) or [Beginning of this section](#bmp) + ## BGP This section explains all the BGP show commands and BGP configuration commands in both "Quagga" and "FRR" routing software that are supported in SONiC. diff --git a/tests/config_test.py b/tests/config_test.py index cc0ac22e98..0499e39f1c 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -37,6 +37,9 @@ # Config Reload input Path mock_db_path = os.path.join(test_path, "config_reload_input") +mock_bmp_db_path = os.path.join(test_path, "bmp_input") + + # Load minigraph input Path load_minigraph_input_path = os.path.join(test_path, "load_minigraph_input") load_minigraph_platform_path = os.path.join(load_minigraph_input_path, "platform") @@ -392,6 +395,147 @@ def teardown_class(cls): dbconnector.load_namespace_config() +class TestBMPConfig(object): + @classmethod + def setup_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "1" + print("SETUP") + import config.main + importlib.reload(config.main) + + def test_enable_bgp_neighbor_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-neighbor-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-neighbor-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_neighbor_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-neighbor-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-neighbor-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_enable_bgp_rib_in_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-rib-in-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-rib-in-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_rib_in_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-rib-in-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-rib-in-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_enable_bgp_rib_out_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp enable bgp-rib-out-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["enable", "bgp-rib-out-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_disable_bgp_rib_out_table( + self, + get_cmd_module, + setup_single_broadcom_asic): + (config, show) = get_cmd_module + jsonfile_config = os.path.join(mock_bmp_db_path, "config_db.json") + from .mock_tables import dbconnector + dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config + + runner = CliRunner() + db = Db() + obj = {'config_db': db.cfgdb} + + # bmp disable bgp-rib-out-table + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["bmp"], + ["disable", "bgp-rib-out-table"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + from .mock_tables import dbconnector + dbconnector.dedicated_dbs = {} + print("TEARDOWN") + class TestLoadMinigraph(object): @classmethod def setup_class(cls): From aad6646a9feb042f089e005e12854e367fbab9fe Mon Sep 17 00:00:00 2001 From: Feng Pan Date: Fri, 25 Oct 2024 04:19:39 +0000 Subject: [PATCH 3/4] Use pytest.mark.parametrize to reduce duplicated code --- tests/config_test.py | 187 +++++-------------------------------------- 1 file changed, 19 insertions(+), 168 deletions(-) diff --git a/tests/config_test.py b/tests/config_test.py index 0cfe216df4..d19115355c 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -714,190 +714,41 @@ def setup_class(cls): print("TEARDOWN") os.environ["UTILITIES_UNIT_TESTING"] = "0" - def test_disable_bgp_neighbor_table( + @pytest.mark.parametrize("table_name",[ + "bgp-neighbor-table", + "bgp-rib-in-table", + "bgp-rib-out-table" + ]) + @pytest.mark.parametrize("enabled", ["true", "false"]) + @pytest.mark.parametrize("filename", ["bmp_invalid.json", "bmp.json"]) + def test_enable_disable_table( self, get_cmd_module, - setup_single_broadcom_asic): + setup_single_broadcom_asic, + table_name, + enabled, + filename): (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") + jsonfile_config = os.path.join(mock_bmp_db_path, filename) config.DEFAULT_CONFIG_DB_FILE = jsonfile_config runner = CliRunner() db = Db() - # bmp disable bgp-neighbor-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_disable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp disable bgp-rib-in-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_disable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp disable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-out-table"], obj=db) - - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_bgp_neighbor_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-neighbor-table - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-in-table + # Enable table result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) + [table_name], obj=db) assert result.exit_code == 0 - def test_enable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_disable_bgp_neighbor_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-neighbor-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-neighbor-table + # Disable table result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) + [table_name], obj=db) assert result.exit_code == 0 - # bmp enable bgp-neighbor-table + # Enable table again result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) + [table_name], obj=db) assert result.exit_code == 0 - def test_enable_disable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-in-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-rib-in-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - # bmp enable bgp-rib-in-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - assert result.exit_code == 0 - - def test_enable_disable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-out-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-out-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - # bmp enable bgp-rib-out-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - assert result.exit_code == 0 class TestConfigReloadMasic(object): @classmethod From 1469779304d0474a16233cc958a1fbd89c012b59 Mon Sep 17 00:00:00 2001 From: Feng Pan Date: Fri, 25 Oct 2024 04:19:39 +0000 Subject: [PATCH 4/4] Use pytest.mark.parametrize to reduce duplicated code --- tests/config_test.py | 187 +++++-------------------------------------- 1 file changed, 19 insertions(+), 168 deletions(-) diff --git a/tests/config_test.py b/tests/config_test.py index 0cfe216df4..4406a10a5c 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -714,190 +714,41 @@ def setup_class(cls): print("TEARDOWN") os.environ["UTILITIES_UNIT_TESTING"] = "0" - def test_disable_bgp_neighbor_table( + @pytest.mark.parametrize("table_name", [ + "bgp-neighbor-table", + "bgp-rib-in-table", + "bgp-rib-out-table" + ]) + @pytest.mark.parametrize("enabled", ["true", "false"]) + @pytest.mark.parametrize("filename", ["bmp_invalid.json", "bmp.json"]) + def test_enable_disable_table( self, get_cmd_module, - setup_single_broadcom_asic): + setup_single_broadcom_asic, + table_name, + enabled, + filename): (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") + jsonfile_config = os.path.join(mock_bmp_db_path, filename) config.DEFAULT_CONFIG_DB_FILE = jsonfile_config runner = CliRunner() db = Db() - # bmp disable bgp-neighbor-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_disable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp disable bgp-rib-in-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_disable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp disable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-out-table"], obj=db) - - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_bgp_neighbor_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-neighbor-table - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-in-table + # Enable table result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) + [table_name], obj=db) assert result.exit_code == 0 - def test_enable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp_invalid.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - def test_enable_disable_bgp_neighbor_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-neighbor-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-neighbor-table + # Disable table result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-neighbor-table"], obj=db) - print(result.exit_code) - print(result.output) + [table_name], obj=db) assert result.exit_code == 0 - # bmp enable bgp-neighbor-table + # Enable table again result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-neighbor-table"], obj=db) + [table_name], obj=db) assert result.exit_code == 0 - def test_enable_disable_bgp_rib_in_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-in-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-rib-in-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-in-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - # bmp enable bgp-rib-in-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-in-table"], obj=db) - assert result.exit_code == 0 - - def test_enable_disable_bgp_rib_out_table( - self, - get_cmd_module, - setup_single_broadcom_asic): - (config, show) = get_cmd_module - jsonfile_config = os.path.join(mock_bmp_db_path, "bmp.json") - config.DEFAULT_CONFIG_DB_FILE = jsonfile_config - runner = CliRunner() - db = Db() - - # bmp enable bgp-rib-out-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - assert result.exit_code == 0 - - # bmp disable bgp-rib-out-table - result = runner.invoke(config.config.commands["bmp"].commands["disable"], - ["bgp-rib-out-table"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - - # bmp enable bgp-rib-out-table first - result = runner.invoke(config.config.commands["bmp"].commands["enable"], - ["bgp-rib-out-table"], obj=db) - assert result.exit_code == 0 class TestConfigReloadMasic(object): @classmethod