Skip to content

Commit 7355016

Browse files
authored
[minigraph][port_config] Use imported config.main and add conditional patch (#1728)
* [minigraph][port_config] Consume port_config.json while reloading minigraph (#1705) * [minigraph][port_config] Use imported config.main and add conditional patch Signed-off-by: Jing Kan [email protected]
1 parent cc1d6e4 commit 7355016

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

config/main.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,12 @@ def load_minigraph(db, no_service_restart):
13051305
if os.path.isfile('/etc/sonic/acl.json'):
13061306
clicommon.run_command("acl-loader update full /etc/sonic/acl.json", display_cmd=True)
13071307

1308+
# Load port_config.json
1309+
try:
1310+
load_port_config(db.cfgdb, '/etc/sonic/port_config.json')
1311+
except Exception as e:
1312+
click.secho("Failed to load port_config.json, Error: {}".format(str(e)), fg='magenta')
1313+
13081314
# generate QoS and Buffer configs
13091315
clicommon.run_command("config qos reload --no-dynamic-buffer", display_cmd=True)
13101316

@@ -1327,6 +1333,44 @@ def load_minigraph(db, no_service_restart):
13271333
_restart_services()
13281334
click.echo("Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.")
13291335

1336+
def load_port_config(config_db, port_config_path):
1337+
if not os.path.isfile(port_config_path):
1338+
return
1339+
1340+
try:
1341+
# Load port_config.json
1342+
port_config_input = read_json_file(port_config_path)
1343+
except Exception:
1344+
raise Exception("Bad format: json file broken")
1345+
1346+
# Validate if the input is an array
1347+
if not isinstance(port_config_input, list):
1348+
raise Exception("Bad format: port_config is not an array")
1349+
1350+
if len(port_config_input) == 0 or 'PORT' not in port_config_input[0]:
1351+
raise Exception("Bad format: PORT table not exists")
1352+
1353+
port_config = port_config_input[0]['PORT']
1354+
1355+
# Ensure all ports are exist
1356+
port_table = {}
1357+
for port_name in port_config.keys():
1358+
port_entry = config_db.get_entry('PORT', port_name)
1359+
if not port_entry:
1360+
raise Exception("Port {} is not defined in current device".format(port_name))
1361+
port_table[port_name] = port_entry
1362+
1363+
# Update port state
1364+
for port_name in port_config.keys():
1365+
if 'admin_status' not in port_config[port_name]:
1366+
continue
1367+
if 'admin_status' in port_table[port_name]:
1368+
if port_table[port_name]['admin_status'] == port_config[port_name]['admin_status']:
1369+
continue
1370+
clicommon.run_command('config interface {} {}'.format(
1371+
'startup' if port_config[port_name]['admin_status'] == 'up' else 'shutdown',
1372+
port_name), display_cmd=True)
1373+
return
13301374

13311375
#
13321376
# 'hostname' command

tests/config_test.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def mock_run_command_side_effect(*args, **kwargs):
3030
if kwargs.get('return_cmd'):
3131
return ''
3232

33-
3433
class TestLoadMinigraph(object):
3534
@classmethod
3635
def setup_class(cls):
@@ -51,6 +50,62 @@ def test_load_minigraph(self, get_cmd_module, setup_single_broadcom_asic):
5150
assert "\n".join([l.rstrip() for l in result.output.split('\n')]) == load_minigraph_command_output
5251
assert mock_run_command.call_count == 7
5352

53+
def test_load_minigraph_with_port_config_bad_format(self, get_cmd_module, setup_single_broadcom_asic):
54+
with mock.patch(
55+
"utilities_common.cli.run_command",
56+
mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
57+
(config, show) = get_cmd_module
58+
59+
# Not in an array
60+
port_config = {"PORT": {"Ethernet0": {"admin_status": "up"}}}
61+
self.check_port_config(None, config, port_config, "Failed to load port_config.json, Error: Bad format: port_config is not an array")
62+
63+
# No PORT table
64+
port_config = [{}]
65+
self.check_port_config(None, config, port_config, "Failed to load port_config.json, Error: Bad format: PORT table not exists")
66+
67+
def test_load_minigraph_with_port_config_inconsistent_port(self, get_cmd_module, setup_single_broadcom_asic):
68+
with mock.patch(
69+
"utilities_common.cli.run_command",
70+
mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
71+
(config, show) = get_cmd_module
72+
73+
db = Db()
74+
db.cfgdb.set_entry("PORT", "Ethernet1", {"admin_status": "up"})
75+
port_config = [{"PORT": {"Eth1": {"admin_status": "up"}}}]
76+
self.check_port_config(db, config, port_config, "Failed to load port_config.json, Error: Port Eth1 is not defined in current device")
77+
78+
def test_load_minigraph_with_port_config(self, get_cmd_module, setup_single_broadcom_asic):
79+
with mock.patch(
80+
"utilities_common.cli.run_command",
81+
mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
82+
(config, show) = get_cmd_module
83+
db = Db()
84+
85+
# From up to down
86+
db.cfgdb.set_entry("PORT", "Ethernet0", {"admin_status": "up"})
87+
port_config = [{"PORT": {"Ethernet0": {"admin_status": "down"}}}]
88+
self.check_port_config(db, config, port_config, "config interface shutdown Ethernet0")
89+
90+
# From down to up
91+
db.cfgdb.set_entry("PORT", "Ethernet0", {"admin_status": "down"})
92+
port_config = [{"PORT": {"Ethernet0": {"admin_status": "up"}}}]
93+
self.check_port_config(db, config, port_config, "config interface startup Ethernet0")
94+
95+
def check_port_config(self, db, config, port_config, expected_output):
96+
def read_json_file_side_effect(filename):
97+
return port_config
98+
with mock.patch('config.main.read_json_file', mock.MagicMock(side_effect=read_json_file_side_effect)):
99+
def is_file_side_effect(filename):
100+
return True if 'port_config' in filename else False
101+
with mock.patch('os.path.isfile', mock.MagicMock(side_effect=is_file_side_effect)):
102+
runner = CliRunner()
103+
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"], obj=db)
104+
print(result.exit_code)
105+
print(result.output)
106+
assert result.exit_code == 0
107+
assert expected_output in result.output
108+
54109
@classmethod
55110
def teardown_class(cls):
56111
os.environ['UTILITIES_UNIT_TESTING'] = "0"

0 commit comments

Comments
 (0)