Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/debian/sonic-host-services-data.gnoi-shutdown.service
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ After=network-online.target database.service gnmi.service pmon.service
[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/gnoi_shutdown_daemon.py
ExecCondition=/usr/bin/python3 -c "import sys; from sonic_py_common import device_info; sys.exit(0 if (device_info.is_smartswitch() and not device_info.is_dpu()) else 1)"
Restart=on-failure
RestartSec=5

Expand Down
9 changes: 0 additions & 9 deletions scripts/gnoi_shutdown_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,6 @@ def _clear_halt_flag(self, dpu_name: str) -> bool:
# #########

def main():
# Check if this is a SmartSwitch NPU platform - exit gracefully if not
try:
if not (device_info.is_smartswitch() and not is_dpu()):
logger.log_notice("Not a SmartSwitch NPU platform, exiting gracefully")
return
except (ImportError, AttributeError, RuntimeError) as e:
logger.log_notice(f"Platform check failed ({e}), exiting gracefully")
return

# Connect for STATE_DB (for gnoi_halt_in_progress flag) and CONFIG_DB
state_db = daemon_base.db_connect("STATE_DB")
config_db = daemon_base.db_connect("CONFIG_DB")
Expand Down
35 changes: 3 additions & 32 deletions tests/gnoi_shutdown_daemon_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,6 @@ def setUp(self):
# Ensure a clean state for each test
gnoi_shutdown_daemon.main = gnoi_shutdown_daemon.__dict__["main"]

@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', return_value=False)
def test_main_exits_on_non_smartswitch(self, mock_is_smartswitch):
"""Test main() exits gracefully on non-SmartSwitch platforms."""
# Should return without doing anything
result = gnoi_shutdown_daemon.main()
self.assertIsNone(result)
mock_is_smartswitch.assert_called_once()

@patch('gnoi_shutdown_daemon.is_dpu', return_value=True)
@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', return_value=True)
def test_main_exits_on_dpu(self, mock_is_smartswitch, mock_is_dpu):
"""Test main() exits gracefully when running on a DPU (not NPU)."""
result = gnoi_shutdown_daemon.main()
self.assertIsNone(result)
mock_is_smartswitch.assert_called_once()
mock_is_dpu.assert_called_once()

@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', side_effect=ImportError("No module"))
def test_main_exits_on_platform_check_exception(self, mock_is_smartswitch):
"""Test main() exits gracefully when platform check raises exception."""
result = gnoi_shutdown_daemon.main()
self.assertIsNone(result)

def test_execute_command_success(self):
"""Test successful execution of a gNOI command."""
with patch("gnoi_shutdown_daemon.subprocess.run") as mock_run:
Expand Down Expand Up @@ -129,13 +106,11 @@ def test_get_halt_timeout_exception(self):
timeout = gnoi_shutdown_daemon._get_halt_timeout()
self.assertEqual(timeout, gnoi_shutdown_daemon.STATUS_POLL_TIMEOUT_SEC)

@patch('gnoi_shutdown_daemon.is_dpu', return_value=False)
@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', return_value=True)
@patch('gnoi_shutdown_daemon.daemon_base.db_connect')
@patch('gnoi_shutdown_daemon.GnoiRebootHandler')
@patch('gnoi_shutdown_daemon.swsscommon.ConfigDBConnector')
@patch('threading.Thread')
def test_main_loop_flow(self, mock_thread, mock_config_db_connector_class, mock_gnoi_reboot_handler, mock_db_connect, mock_is_smartswitch, mock_is_dpu):
def test_main_loop_flow(self, mock_thread, mock_config_db_connector_class, mock_gnoi_reboot_handler, mock_db_connect):
"""Test the main loop processing of a shutdown event."""
# Mock DB connections
mock_state_db = MagicMock()
Expand Down Expand Up @@ -354,11 +329,9 @@ def test_get_dpu_gnmi_port_variants(self):
self.assertEqual(port, "12345")
self.assertEqual(mock_config.hget.call_count, 3)

@patch('gnoi_shutdown_daemon.is_dpu', return_value=False)
@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', return_value=True)
@patch('gnoi_shutdown_daemon.daemon_base.db_connect')
@patch('gnoi_shutdown_daemon.swsscommon.ConfigDBConnector')
def test_main_loop_no_dpu_name(self, mock_config_db_connector_class, mock_db_connect, mock_is_smartswitch, mock_is_dpu):
def test_main_loop_no_dpu_name(self, mock_config_db_connector_class, mock_db_connect):
"""Test main loop with a malformed key."""
mock_chassis = MagicMock()
mock_platform_instance = MagicMock()
Expand Down Expand Up @@ -398,11 +371,9 @@ def test_main_loop_no_dpu_name(self, mock_config_db_connector_class, mock_db_con
with self.assertRaises(KeyboardInterrupt):
gnoi_shutdown_daemon.main()

@patch('gnoi_shutdown_daemon.is_dpu', return_value=False)
@patch('gnoi_shutdown_daemon.device_info.is_smartswitch', return_value=True)
@patch('gnoi_shutdown_daemon.daemon_base.db_connect')
@patch('gnoi_shutdown_daemon.swsscommon.ConfigDBConnector')
def test_main_loop_get_transition_exception(self, mock_config_db_connector_class, mock_db_connect, mock_is_smartswitch, mock_is_dpu):
def test_main_loop_get_transition_exception(self, mock_config_db_connector_class, mock_db_connect):
"""Test main loop when hget raises an exception."""
mock_chassis = MagicMock()
mock_platform_instance = MagicMock()
Expand Down
Loading