diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index d259862c5..e2f252941 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -387,6 +387,23 @@ def test_is_cmis_api(self, mock_class, expected_return_value): mock_xcvr_api.__class__ = mock_class assert is_cmis_api(mock_xcvr_api) == expected_return_value + @patch('swsscommon.swsscommon.SonicV2Connector') + def test_notify_system_ready(self, mock_dbconn): + mock_db = MagicMock() + mock_db.connect = MagicMock() + mock_db.delete = MagicMock() + mock_db.hmset = MagicMock() + mock_dbconn.return_value = mock_db + + # Case 1: Report ready status + notify_system_ready() + mock_db.hmset.assert_called_once() + + # Case 2: Should not report status again + mock_db.hmset.reset_mock() + notify_system_ready() + mock_db.hmset.assert_not_called() + def test_get_state_db_port_table_val_by_key(self): xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) port_mapping = PortMapping() diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index fbb31269f..34af43b33 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -244,6 +244,37 @@ def strip_unit_and_beautify(value, unit): return str(value) +def notify_system_ready(fail_status=False, fail_reason='-'): + key = 'FEATURE|pmon' + statusvalue = {} + + try: + state_db = swsscommon.SonicV2Connector() + state_db.connect(state_db.STATE_DB) + except Exception: + helper_logger.log_error('Failed to connect STATE_DB to report ' + f'{SYSLOG_IDENTIFIER} ready status') + return + + if fail_status: + statusvalue['up_status'] = 'false' + statusvalue['fail_reason'] = fail_reason + else: + statusvalue['up_status'] = 'true' + + if getattr(notify_system_ready, 'reported', False): + helper_logger.log_debug( + f'{SYSLOG_IDENTIFIER} ready status already reported. Tried to ' + f'report status: {statusvalue}') + return + + state_db.delete(state_db.STATE_DB, key) + state_db.hmset(state_db.STATE_DB, key, statusvalue) + helper_logger.log_info(f'Report {SYSLOG_IDENTIFIER} ready status: ' + f'{statusvalue}') + notify_system_ready.reported = True + + def _wrapper_get_presence(physical_port): if platform_chassis is not None: try: @@ -2594,6 +2625,7 @@ def run(self): for thread in self.threads: self.log_notice("Started thread {}".format(thread.getName())) + notify_system_ready() self.stop_event.wait() self.log_info("Stop daemon main loop") @@ -2609,6 +2641,8 @@ def run(self): generate_sigkill = True if generate_sigkill is True: + # Notify system not ready + notify_system_ready(False, "Exception occured in xcvrd daemon") self.log_error("Exiting main loop as child thread raised exception!") os.kill(os.getpid(), signal.SIGKILL) @@ -2637,6 +2671,8 @@ def run(self): self.log_info("Shutting down...") if self.sfp_error_event.is_set(): + # Notify system not ready + notify_system_ready(False, "SFP system error") sys.exit(SFP_SYSTEM_ERROR)