diff --git a/config/feature.py b/config/feature.py index 8a90ae798d97..6fdc68c02690 100644 --- a/config/feature.py +++ b/config/feature.py @@ -20,17 +20,25 @@ def feature(): @pass_db def feature_state(db, name, state): """Enable/disable a feature""" - entry_data = db.cfgdb.get_entry('FEATURE', name) + entry_data_set = set() - if not entry_data: - click.echo("Feature '{}' doesn't exist".format(name)) + for ns, cfgdb in db.cfgdb_clients.items(): + entry_data = cfgdb.get_entry('FEATURE', name) + if not entry_data: + click.echo("Feature '{}' doesn't exist".format(name)) + sys.exit(1) + entry_data_set.add(entry_data['state']) + + if len(entry_data_set) > 1: + click.echo("Feature '{}' state is not consistent across namespaces".format(name)) sys.exit(1) if entry_data['state'] == "always_enabled": click.echo("Feature '{}' state is always enabled and can not be modified".format(name)) return - db.cfgdb.mod_entry('FEATURE', name, {'state': state}) + for ns, cfgdb in db.cfgdb_clients.items(): + cfgdb.mod_entry('FEATURE', name, {'state': state}) # # 'autorestart' command ('config feature autorestart ...') @@ -41,14 +49,22 @@ def feature_state(db, name, state): @pass_db def feature_autorestart(db, name, autorestart): """Enable/disable autorestart of a feature""" - entry_data = db.cfgdb.get_entry('FEATURE', name) + entry_data_set = set() + + for ns, cfgdb in db.cfgdb_clients.items(): + entry_data = cfgdb.get_entry('FEATURE', name) + if not entry_data: + click.echo("Feature '{}' doesn't exist".format(name)) + sys.exit(1) + entry_data_set.add(entry_data['auto_restart']) - if not entry_data: - click.echo("Feature '{}' doesn't exist".format(name)) + if len(entry_data_set) > 1: + click.echo("Feature '{}' auto-restart is not consistent across namespaces".format(name)) sys.exit(1) if entry_data['auto_restart'] == "always_enabled": click.echo("Feature '{}' auto-restart is always enabled and can not be modified".format(name)) return - db.cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart}) + for ns, cfgdb in db.cfgdb_clients.items(): + cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart}) diff --git a/tests/crm_test.py b/tests/crm_test.py index 2ddb1b21084f..2056b90775e5 100644 --- a/tests/crm_test.py +++ b/tests/crm_test.py @@ -1,5 +1,6 @@ import os import sys +from importlib import reload from click.testing import CliRunner import crm.main as crm @@ -1298,3 +1299,4 @@ def teardown_class(cls): os.environ["UTILITIES_UNIT_TESTING"] = "0" os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" from .mock_tables import mock_single_asic + reload(mock_single_asic) diff --git a/tests/feature_test.py b/tests/feature_test.py index c260a4b5f626..1b5e275a7c34 100644 --- a/tests/feature_test.py +++ b/tests/feature_test.py @@ -1,3 +1,5 @@ +from importlib import reload + from click.testing import CliRunner from utilities_common.db import Db @@ -76,6 +78,12 @@ --------- -------------- database always_enabled """ +config_feature_bgp_inconsistent_state_output="""\ +Feature 'bgp' state is not consistent across namespaces +""" +config_feature_bgp_inconsistent_autorestart_output="""\ +Feature 'bgp' auto-restart is not consistent across namespaces +""" class TestFeature(object): @classmethod @@ -217,3 +225,102 @@ def test_config_unknown_feature(self, get_cmd_module): @classmethod def teardown_class(cls): print("TEARDOWN") + +class TestFeatureMultiAsic(object): + @classmethod + def setup_class(cls): + print("SETUP") + + def test_config_bgp_feature_inconsistent_state(self, get_cmd_module): + from .mock_tables import dbconnector + from .mock_tables import mock_multi_asic_3_asics + reload(mock_multi_asic_3_asics) + dbconnector.load_namespace_config() + (config, show) = get_cmd_module + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == config_feature_bgp_inconsistent_state_output + result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "enabled"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == config_feature_bgp_inconsistent_state_output + + def test_config_bgp_feature_inconsistent_autorestart(self, get_cmd_module): + from .mock_tables import dbconnector + from .mock_tables import mock_multi_asic_3_asics + reload(mock_multi_asic_3_asics) + dbconnector.load_namespace_config() + (config, show) = get_cmd_module + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == config_feature_bgp_inconsistent_autorestart_output + result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "enabled"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == config_feature_bgp_inconsistent_autorestart_output + + def test_config_bgp_feature_consistent_state(self, get_cmd_module): + from .mock_tables import dbconnector + from .mock_tables import mock_multi_asic + reload(mock_multi_asic) + dbconnector.load_namespace_config() + (config, show) = get_cmd_module + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"], obj=db) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_feature_bgp_disabled_status_output + result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "enabled"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"], obj=db) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_feature_bgp_status_output + + def test_config_bgp_feature_consistent_autorestart(self, get_cmd_module): + from .mock_tables import dbconnector + from .mock_tables import mock_multi_asic + reload(mock_multi_asic) + dbconnector.load_namespace_config() + (config, show) = get_cmd_module + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"], obj=db) + print(result.output) + print(result.exit_code) + assert result.exit_code == 0 + assert result.output == show_feature_bgp_disabled_autorestart_output + result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "enabled"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"], obj=db) + print(result.output) + print(result.exit_code) + assert result.exit_code == 0 + assert result.output == show_feature_bgp_autorestart_output + + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + from .mock_tables import mock_single_asic + reload(mock_single_asic) diff --git a/tests/ip_show_routes_multi_asic_test.py b/tests/ip_show_routes_multi_asic_test.py index c889a6543082..384cda4f6b5e 100644 --- a/tests/ip_show_routes_multi_asic_test.py +++ b/tests/ip_show_routes_multi_asic_test.py @@ -1,4 +1,5 @@ import os +from importlib import reload import pytest @@ -16,6 +17,7 @@ def setup_class(cls): os.environ["UTILITIES_UNIT_TESTING"] = "2" os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" from .mock_tables import mock_multi_asic_3_asics + reload(mock_multi_asic_3_asics) from .mock_tables import dbconnector dbconnector.load_namespace_config() @@ -224,7 +226,5 @@ def teardown_class(cls): os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) os.environ["UTILITIES_UNIT_TESTING"] = "0" os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" - import imp - from sonic_py_common import multi_asic - imp.reload(multi_asic) - import mock_tables.dbconnector + from .mock_tables import mock_single_asic + reload(mock_single_asic) diff --git a/tests/mock_tables/asic0/config_db.json b/tests/mock_tables/asic0/config_db.json index 51f61e7fc775..826daf4c6e74 100644 --- a/tests/mock_tables/asic0/config_db.json +++ b/tests/mock_tables/asic0/config_db.json @@ -162,5 +162,10 @@ }, "PEER_SWITCH|sonic" : { "address_ipv4": "10.2.2.2" + }, + "FEATURE|bgp": { + "state": "enabled", + "auto_restart": "enabled", + "high_mem_alert": "disabled" } } diff --git a/tests/mock_tables/asic1/config_db.json b/tests/mock_tables/asic1/config_db.json index 066732e6159d..9bd34c08a1cf 100644 --- a/tests/mock_tables/asic1/config_db.json +++ b/tests/mock_tables/asic1/config_db.json @@ -131,5 +131,10 @@ }, "PEER_SWITCH|sonic" : { "address_ipv4": "10.2.2.2" + }, + "FEATURE|bgp": { + "state": "enabled", + "auto_restart": "enabled", + "high_mem_alert": "disabled" } } diff --git a/tests/mock_tables/asic2/config_db.json b/tests/mock_tables/asic2/config_db.json index be5af80bf4bd..532d85bcbbcb 100644 --- a/tests/mock_tables/asic2/config_db.json +++ b/tests/mock_tables/asic2/config_db.json @@ -119,5 +119,10 @@ "PFC_WD|GLOBAL": { "BIG_RED_SWITCH": "enable", "POLL_INTERVAL": "199" + }, + "FEATURE|bgp": { + "state": "disabled", + "auto_restart": "disabled", + "high_mem_alert": "disabled" } }