Skip to content

Commit

Permalink
Added platform plugin support in load_minigraph (#2808) (#2831)
Browse files Browse the repository at this point in the history
Added platform plugin hook to execute platform script after minigraph config is loaded in config db and before starting the services. Cherry-pick of master PR:#2808
  • Loading branch information
anamehra authored May 8, 2023
1 parent f6359bc commit 8adaa02
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 0 deletions.
11 changes: 11 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1683,6 +1683,17 @@ def load_minigraph(db, no_service_restart, traffic_shift_away, override_config,
raise click.Abort()
override_config_by(golden_config_path)

# Invoke platform script if available before starting the services
platform_path, _ = device_info.get_paths_to_platform_and_hwsku_dirs()
platform_mg_plugin = platform_path + '/plugins/platform_mg_post_check'
if os.path.isfile(platform_mg_plugin):
click.echo("Running Platform plugin ............!")
proc = subprocess.Popen([platform_mg_plugin], text=True, stdout=subprocess.PIPE)
proc.communicate()
if proc.returncode != 0:
click.echo("Platform plugin failed! retruncode {}".format(proc.returncode))
raise click.Abort()

# We first run "systemctl reset-failed" to remove the "failed"
# status from all services before we attempt to restart them
if not no_service_restart:
Expand Down
53 changes: 53 additions & 0 deletions tests/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
# Config Reload input Path
mock_db_path = os.path.join(test_path, "config_reload_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")
load_minigraph_platform_false_path = os.path.join(load_minigraph_input_path, "platform_false")

load_minigraph_command_output="""\
Stopping SONiC target ...
Expand All @@ -43,6 +47,17 @@
Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.
"""

load_minigraph_platform_plugin_command_output="""\
Stopping SONiC target ...
Running command: /usr/local/bin/sonic-cfggen -H -m --write-to-db
Running command: config qos reload --no-dynamic-buffer --no-delay
Running command: pfcwd start_default
Running Platform plugin ............!
Restarting SONiC target ...
Reloading Monit configuration ...
Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.
"""

load_mgmt_config_command_ipv4_only_output="""\
Running command: /usr/local/bin/sonic-cfggen -M device_desc.xml --write-to-db
parse dummy device_desc.xml
Expand Down Expand Up @@ -261,6 +276,7 @@ def setup_class(cls):
import config.main
importlib.reload(config.main)

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph(self, get_cmd_module, setup_single_broadcom_asic):
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
(config, show) = get_cmd_module
Expand All @@ -277,6 +293,35 @@ def test_load_minigraph(self, get_cmd_module, setup_single_broadcom_asic):
mock_run_command.assert_any_call('systemctl reset-failed snmp')
assert mock_run_command.call_count == 11

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=(load_minigraph_platform_path, None)))
def test_load_minigraph_platform_plugin(self, get_cmd_module, setup_single_broadcom_asic):
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
(config, show) = get_cmd_module
runner = CliRunner()
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"])
print(result.exit_code)
print(result.output)
traceback.print_tb(result.exc_info[2])
assert result.exit_code == 0
assert "\n".join([l.rstrip() for l in result.output.split('\n')]) == load_minigraph_platform_plugin_command_output
# Verify "systemctl reset-failed" is called for services under sonic.target
mock_run_command.assert_any_call('systemctl reset-failed swss')
assert mock_run_command.call_count == 11

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=(load_minigraph_platform_false_path, None)))
def test_load_minigraph_platform_plugin_fail(self, get_cmd_module, setup_single_broadcom_asic):
print(load_minigraph_platform_false_path)
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
(config, show) = get_cmd_module
runner = CliRunner()
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"])
print(result.exit_code)
print(result.output)
traceback.print_tb(result.exc_info[2])
assert result.exit_code != 0
assert "Platform plugin failed" in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_port_config_bad_format(self, get_cmd_module, setup_single_broadcom_asic):
with mock.patch(
"utilities_common.cli.run_command",
Expand All @@ -291,6 +336,7 @@ def test_load_minigraph_with_port_config_bad_format(self, get_cmd_module, setup_
port_config = [{}]
self.check_port_config(None, config, port_config, "Failed to load port_config.json, Error: Bad format: PORT table not exists")

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_port_config_inconsistent_port(self, get_cmd_module, setup_single_broadcom_asic):
with mock.patch(
"utilities_common.cli.run_command",
Expand All @@ -302,6 +348,7 @@ def test_load_minigraph_with_port_config_inconsistent_port(self, get_cmd_module,
port_config = [{"PORT": {"Eth1": {"admin_status": "up"}}}]
self.check_port_config(db, config, port_config, "Failed to load port_config.json, Error: Port Eth1 is not defined in current device")

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_port_config(self, get_cmd_module, setup_single_broadcom_asic):
with mock.patch(
"utilities_common.cli.run_command",
Expand All @@ -319,6 +366,7 @@ def test_load_minigraph_with_port_config(self, get_cmd_module, setup_single_broa
port_config = [{"PORT": {"Ethernet0": {"admin_status": "up"}}}]
self.check_port_config(db, config, port_config, "config interface startup Ethernet0")

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def check_port_config(self, db, config, port_config, expected_output):
def read_json_file_side_effect(filename):
return port_config
Expand All @@ -333,6 +381,7 @@ def is_file_side_effect(filename):
assert result.exit_code == 0
assert expected_output in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_non_exist_golden_config_path(self, get_cmd_module):
def is_file_side_effect(filename):
return True if 'golden_config' in filename else False
Expand All @@ -344,6 +393,7 @@ def is_file_side_effect(filename):
assert result.exit_code != 0
assert "Cannot find 'non_exist.json'" in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_specified_golden_config_path(self, get_cmd_module):
def is_file_side_effect(filename):
return True if 'golden_config' in filename else False
Expand All @@ -355,6 +405,7 @@ def is_file_side_effect(filename):
assert result.exit_code == 0
assert "config override-config-table golden_config.json" in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_default_golden_config_path(self, get_cmd_module):
def is_file_side_effect(filename):
return True if 'golden_config' in filename else False
Expand All @@ -366,6 +417,7 @@ def is_file_side_effect(filename):
assert result.exit_code == 0
assert "config override-config-table /etc/sonic/golden_config_db.json" in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_traffic_shift_away(self, get_cmd_module):
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
(config, show) = get_cmd_module
Expand All @@ -377,6 +429,7 @@ def test_load_minigraph_with_traffic_shift_away(self, get_cmd_module):
assert result.exit_code == 0
assert "TSA" in result.output

@mock.patch('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs', mock.MagicMock(return_value=("dummy_path", None)))
def test_load_minigraph_with_traffic_shift_away_with_golden_config(self, get_cmd_module):
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
def is_file_side_effect(filename):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

echo "Do Nothing!"
exit 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

echo "Do Nothing!"
exit 1

0 comments on commit 8adaa02

Please sign in to comment.