Skip to content

Commit fd3e017

Browse files
committed
[Multi-asic] Enhanced Feature Table configuration for multi-asic platforms (#1152)
Enhanced Feature Table configuration for multi-asic platforms to programmed for all config db's.
1 parent 12f03b1 commit fd3e017

File tree

8 files changed

+174
-20
lines changed

8 files changed

+174
-20
lines changed

config/main.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from sonic_py_common import device_info, multi_asic, logger
1717
from sonic_py_common.interface import get_interface_table_name, get_port_table_name
1818
from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig
19+
from utilities_common.multi_asic import get_multi_asic_cfgdb
1920

2021
import aaa
2122
import mlnx
@@ -44,7 +45,7 @@
4445

4546
asic_type = None
4647
config_db = None
47-
48+
multi_asic_cfgdb = None
4849

4950
class AbbreviationGroup(click.Group):
5051
"""This subclass of click.Group supports abbreviated subgroup/subcommand names
@@ -669,6 +670,11 @@ def config():
669670
config_db = ConfigDBConnector()
670671
config_db.connect()
671672

673+
global multi_asic_cfgdb
674+
675+
multi_asic_cfgdb = get_multi_asic_cfgdb()
676+
677+
672678
config.add_command(aaa.aaa)
673679
config.add_command(aaa.tacacs)
674680
# === Add NAT Configuration ==========
@@ -3294,18 +3300,26 @@ def feature():
32943300
@click.argument('state', metavar='<state>', required=True, type=click.Choice(["enabled", "disabled"]))
32953301
def feature_state(name, state):
32963302
"""Enable/disable a feature"""
3297-
entry_data = config_db.get_entry('FEATURE', name)
3303+
entry_data_set = set()
3304+
cfgdb_clients = multi_asic_cfgdb
3305+
3306+
for ns, cfgdb in cfgdb_clients.items():
3307+
entry_data = cfgdb.get_entry('FEATURE', name)
3308+
if not entry_data:
3309+
click.echo("Feature '{}' doesn't exist".format(name))
3310+
sys.exit(1)
3311+
entry_data_set.add(entry_data['state'])
32983312

3299-
if not entry_data:
3300-
click.echo("Feature '{}' doesn't exist".format(name))
3313+
if len(entry_data_set) > 1:
3314+
click.echo("Feature '{}' state is not consistent across namespaces".format(name))
33013315
sys.exit(1)
33023316

33033317
if entry_data['state'] == "always_enabled":
33043318
click.echo("Feature '{}' state is always enabled and can not be modified".format(name))
33053319
return
3306-
3307-
config_db.mod_entry('FEATURE', name, {'state': state})
33083320

3321+
for ns, cfgdb in cfgdb_clients.items():
3322+
cfgdb.mod_entry('FEATURE', name, {'state': state})
33093323
#
33103324
# 'autorestart' command ('config feature autorestart ...')
33113325
#
@@ -3314,16 +3328,26 @@ def feature_state(name, state):
33143328
@click.argument('autorestart', metavar='<autorestart>', required=True, type=click.Choice(["enabled", "disabled"]))
33153329
def feature_autorestart(name, autorestart):
33163330
"""Enable/disable autorestart of a feature"""
3317-
entry_data = config_db.get_entry('FEATURE', name)
3318-
if not entry_data:
3319-
click.echo("Feature '{}' doesn't exist".format(name))
3331+
entry_data_set = set()
3332+
cfgdb_clients = multi_asic_cfgdb
3333+
3334+
for ns, cfgdb in cfgdb_clients.items():
3335+
entry_data = cfgdb.get_entry('FEATURE', name)
3336+
if not entry_data:
3337+
click.echo("Feature '{}' doesn't exist".format(name))
3338+
sys.exit(1)
3339+
entry_data_set.add(entry_data['auto_restart'])
3340+
3341+
if len(entry_data_set) > 1:
3342+
click.echo("Feature '{}' auto-restart is not consistent across namespaces".format(name))
33203343
sys.exit(1)
33213344

33223345
if entry_data['auto_restart'] == "always_enabled":
33233346
click.echo("Feature '{}' auto-restart is always enabled and can not be modified".format(name))
33243347
return
3325-
3326-
config_db.mod_entry('FEATURE', name, {'auto_restart': autorestart})
3348+
3349+
for ns, cfgdb in cfgdb_clients.items():
3350+
cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart})
33273351

33283352
if __name__ == '__main__':
33293353
config()

sonic-utilities-tests/crm_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import imp
12
import os
23
import sys
34

@@ -1345,3 +1346,4 @@ def teardown_class(cls):
13451346
os.environ["UTILITIES_UNIT_TESTING"] = "0"
13461347
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = ""
13471348
import mock_tables.mock_single_asic
1349+
imp.reload(mock_tables.mock_single_asic)

sonic-utilities-tests/feature_test.py

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import imp
12
import os
23
import sys
34

45
import mock
56
from click.testing import CliRunner
67
from swsssdk import ConfigDBConnector
8+
from utilities_common import constants
9+
from utilities_common.multi_asic import get_multi_asic_cfgdb
710

811
test_path = os.path.dirname(os.path.abspath(__file__))
912
modules_path = os.path.dirname(test_path)
@@ -15,11 +18,9 @@
1518
config.asic_type = mock.MagicMock(return_value = "broadcom")
1619
config._get_device_type = mock.MagicMock(return_value = "ToRRouter")
1720

18-
config_db = ConfigDBConnector()
19-
config_db.connect()
21+
config.multi_asic_cfgdb = get_multi_asic_cfgdb()
22+
show.config_db = config.multi_asic_cfgdb[constants.DEFAULT_NAMESPACE]
2023

21-
show.config_db = config_db
22-
config.config_db = config_db
2324

2425
show_feature_status_output="""\
2526
Feature State AutoRestart
@@ -95,6 +96,12 @@
9596
--------- --------------
9697
database always_enabled
9798
"""
99+
config_feature_bgp_inconsistent_state_output="""\
100+
Feature 'bgp' state is not consistent across namespaces
101+
"""
102+
config_feature_bgp_inconsistent_autorestart_output="""\
103+
Feature 'bgp' auto-restart is not consistent across namespaces
104+
"""
98105

99106
class TestFeature(object):
100107
@classmethod
@@ -212,3 +219,102 @@ def test_config_unknown_feature(self):
212219
@classmethod
213220
def teardown_class(cls):
214221
print("TEARDOWN")
222+
223+
class TestFeatureMultiAsic(object):
224+
@classmethod
225+
def setup_class(cls):
226+
print("SETUP")
227+
228+
def test_config_bgp_feature_inconsistent_state(self):
229+
import mock_tables.dbconnector
230+
import mock_tables.mock_multi_asic_3_asics
231+
imp.reload(mock_tables.mock_multi_asic_3_asics)
232+
mock_tables.dbconnector.load_namespace_config()
233+
config.multi_asic_cfgdb = get_multi_asic_cfgdb()
234+
show.config_db = config.multi_asic_cfgdb[constants.DEFAULT_NAMESPACE]
235+
runner = CliRunner()
236+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"])
237+
print(result.exit_code)
238+
print(result.output)
239+
assert result.exit_code == 1
240+
assert result.output == config_feature_bgp_inconsistent_state_output
241+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "enabled"])
242+
print(result.exit_code)
243+
print(result.output)
244+
assert result.exit_code == 1
245+
assert result.output == config_feature_bgp_inconsistent_state_output
246+
247+
def test_config_bgp_feature_inconsistent_autorestart(self):
248+
import mock_tables.dbconnector
249+
import mock_tables.mock_multi_asic_3_asics
250+
imp.reload(mock_tables.mock_multi_asic_3_asics)
251+
mock_tables.dbconnector.load_namespace_config()
252+
config.multi_asic_cfgdb = get_multi_asic_cfgdb()
253+
show.config_db = config.multi_asic_cfgdb[constants.DEFAULT_NAMESPACE]
254+
runner = CliRunner()
255+
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"])
256+
print(result.exit_code)
257+
print(result.output)
258+
assert result.exit_code == 1
259+
assert result.output == config_feature_bgp_inconsistent_autorestart_output
260+
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "enabled"])
261+
print(result.exit_code)
262+
print(result.output)
263+
assert result.exit_code == 1
264+
assert result.output == config_feature_bgp_inconsistent_autorestart_output
265+
266+
def test_config_bgp_feature_consistent_state(self):
267+
import mock_tables.dbconnector
268+
import mock_tables.mock_multi_asic
269+
imp.reload(mock_tables.mock_multi_asic)
270+
mock_tables.dbconnector.load_namespace_config()
271+
config.multi_asic_cfgdb = get_multi_asic_cfgdb()
272+
show.config_db = config.multi_asic_cfgdb[constants.DEFAULT_NAMESPACE]
273+
runner = CliRunner()
274+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"])
275+
print(result.exit_code)
276+
assert result.exit_code == 0
277+
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"])
278+
print(result.output)
279+
assert result.exit_code == 0
280+
assert result.output == show_feature_bgp_disabled_status_output
281+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "enabled"])
282+
print(result.exit_code)
283+
print(result.output)
284+
assert result.exit_code == 0
285+
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"])
286+
print(result.output)
287+
assert result.exit_code == 0
288+
assert result.output == show_feature_bgp_status_output
289+
290+
def test_config_bgp_feature_consistent_autorestart(self):
291+
import mock_tables.dbconnector
292+
import mock_tables.mock_multi_asic
293+
imp.reload(mock_tables.mock_multi_asic)
294+
mock_tables.dbconnector.load_namespace_config()
295+
config.multi_asic_cfgdb = get_multi_asic_cfgdb()
296+
show.config_db = config.multi_asic_cfgdb[constants.DEFAULT_NAMESPACE]
297+
runner = CliRunner()
298+
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"])
299+
print(result.exit_code)
300+
assert result.exit_code == 0
301+
result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"])
302+
print(result.output)
303+
print(result.exit_code)
304+
assert result.exit_code == 0
305+
assert result.output == show_feature_bgp_disabled_autorestart_output
306+
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "enabled"])
307+
print(result.exit_code)
308+
assert result.exit_code == 0
309+
result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"])
310+
print(result.output)
311+
print(result.exit_code)
312+
assert result.exit_code == 0
313+
assert result.output == show_feature_bgp_autorestart_output
314+
315+
316+
@classmethod
317+
def teardown_class(cls):
318+
print("TEARDOWN")
319+
import mock_tables.mock_single_asic
320+
imp.reload(mock_tables.mock_single_asic)

sonic-utilities-tests/ip_show_routes_multi_asic_test.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import imp
23

34
import pytest
45

@@ -16,6 +17,7 @@ def setup_class(cls):
1617
os.environ["UTILITIES_UNIT_TESTING"] = "2"
1718
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic"
1819
import mock_tables.mock_multi_asic_3_asics
20+
imp.reload(mock_tables.mock_multi_asic_3_asics)
1921
mock_tables.dbconnector.load_namespace_config()
2022

2123
@pytest.mark.parametrize('setup_multi_asic_bgp_instance',
@@ -223,9 +225,5 @@ def teardown_class(cls):
223225
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
224226
os.environ["UTILITIES_UNIT_TESTING"] = "0"
225227
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = ""
226-
import imp
227-
from sonic_py_common import multi_asic
228-
imp.reload(multi_asic)
229228
import mock_tables.mock_single_asic
230-
import mock_tables.dbconnector
231-
mock_tables.dbconnector.load_namespace_config()
229+
imp.reload(mock_tables.mock_single_asic)

sonic-utilities-tests/mock_tables/asic0/config_db.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,10 @@
149149
"acl_entry_high_threshold": "85",
150150
"fdb_entry_low_threshold": "70",
151151
"ipv6_nexthop_high_threshold": "85"
152+
},
153+
"FEATURE|bgp": {
154+
"state": "enabled",
155+
"auto_restart": "enabled",
156+
"high_mem_alert": "disabled"
152157
}
153158
}

sonic-utilities-tests/mock_tables/asic1/config_db.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,5 +118,10 @@
118118
"acl_entry_high_threshold": "85",
119119
"fdb_entry_low_threshold": "70",
120120
"ipv6_nexthop_high_threshold": "85"
121+
},
122+
"FEATURE|bgp": {
123+
"state": "enabled",
124+
"auto_restart": "enabled",
125+
"high_mem_alert": "disabled"
121126
}
122127
}

sonic-utilities-tests/mock_tables/asic2/config_db.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,5 +119,10 @@
119119
"PFC_WD|GLOBAL": {
120120
"BIG_RED_SWITCH": "enable",
121121
"POLL_INTERVAL": "199"
122+
},
123+
"FEATURE|bgp": {
124+
"state": "disabled",
125+
"auto_restart": "disabled",
126+
"high_mem_alert": "disabled"
122127
}
123128
}

utilities_common/multi_asic.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,12 @@ def multi_asic_args(parser=None):
136136
parser.add_argument('-n', '--namespace', default=None,
137137
help='Display interfaces for specific namespace')
138138
return parser
139+
140+
def get_multi_asic_cfgdb():
141+
cfgdb = {}
142+
ns_list = { constants.DEFAULT_NAMESPACE }
143+
ns_list.update(multi_asic.get_namespace_list())
144+
for ns in ns_list:
145+
cfgdb[ns] = multi_asic.connect_config_db_for_ns(ns)
146+
147+
return cfgdb

0 commit comments

Comments
 (0)