Skip to content

Commit 8ace0f8

Browse files
authored
[Smartswitch] Fix time format for dpu states (#583)
* Fix time formatting * Added tests for time format
1 parent 7a0813a commit 8ace0f8

File tree

3 files changed

+90
-31
lines changed

3 files changed

+90
-31
lines changed

sonic-chassisd/scripts/chassisd

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ try:
1717
import time
1818
import json
1919
import glob
20-
from datetime import datetime
20+
from datetime import datetime, timezone
2121

2222
from sonic_py_common import daemon_base, logger, device_info
2323
from sonic_py_common.task_base import ProcessTaskBase
@@ -136,6 +136,16 @@ def get_chassis():
136136
self.log_error("Failed to load chassis due to {}".format(repr(e)))
137137
sys.exit(CHASSIS_LOAD_ERROR)
138138

139+
def get_formatted_time(datetimeobj=None, op_format=None):
140+
"""
141+
Get the current time in specified format
142+
:param datetimeobj: Optional - A datetime object already initialized with a specific time
143+
:param op_format: Optional - Output Format for the time to be displayed
144+
:returns time in string format
145+
"""
146+
date_obj = datetimeobj if datetimeobj else datetime.now(timezone.utc)
147+
return date_obj.strftime(op_format if op_format else "%a %b %d %I:%M:%S %p UTC %Y")
148+
139149
#
140150
# Module Config Updater ========================================================
141151
#
@@ -782,7 +792,7 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
782792
updates = {
783793
"dpu_midplane_link_state": state,
784794
"dpu_midplane_link_reason": "",
785-
"dpu_midplane_link_time": datetime.now().strftime("%a %b %d %I:%M:%S %p UTC %Y"),
795+
"dpu_midplane_link_time": get_formatted_time(),
786796
}
787797
current_data.update(updates)
788798

@@ -818,7 +828,7 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
818828

819829
def _get_current_time_str(self):
820830
"""Returns the current time as a string in 'YYYY_MM_DD_HH_MM_SS' format."""
821-
return datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
831+
return get_formatted_time(op_format="%Y_%m_%d_%H_%M_%S")
822832

823833
def _get_history_path(self, module, file_name):
824834
"""Generates the full path for history files."""
@@ -880,11 +890,9 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
880890

881891
file_path = self._get_history_path(module, file_name)
882892
try:
883-
dt_obj = datetime.strptime(prev_reboot_time, "%Y_%m_%d_%H_%M_%S")
893+
formatted_time = get_formatted_time(datetimeobj=datetime.strptime(prev_reboot_time, "%Y_%m_%d_%H_%M_%S"))
884894
except ValueError:
885-
dt_obj = datetime.now()
886-
887-
formatted_time = dt_obj.strftime("%a %b %d %I:%M:%S %p UTC %Y")
895+
formatted_time = get_formatted_time()
888896

889897
reboot_cause_dict = {
890898
"cause": cause,
@@ -1188,7 +1196,7 @@ class DpuStateUpdater(logger.Logger):
11881196
return True
11891197

11901198
def _time_now(self):
1191-
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1199+
return get_formatted_time()
11921200

11931201
def _update_dp_dpu_state(self, state):
11941202
self.dpu_state_table.hset(self.name, self.DP_STATE, state)

sonic-chassisd/tests/test_chassisd.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,27 @@ def test_chassis_db_bootup_with_empty_slot():
15151515
assert status == fvs[CHASSIS_MODULE_INFO_OPERSTATUS_FIELD]
15161516
assert down_module_lc1_key in sup_module_updater.down_modules.keys()
15171517

1518+
1519+
def test_smartswitch_time_format():
1520+
chassis = MockSmartSwitchChassis()
1521+
chassis_state_db = MagicMock()
1522+
mod_updater = SmartSwitchModuleUpdater(SYSLOG_IDENTIFIER, chassis)
1523+
mod_updater.chassis_state_db = chassis_state_db
1524+
mod_updater.chassis_state_db.hgetall = MagicMock(return_value={})
1525+
mod_updater.chassis_state_db.hset = MagicMock()
1526+
date_format = "%a %b %d %I:%M:%S %p UTC %Y"
1527+
def is_valid_date(date_str):
1528+
try:
1529+
datetime.strptime(date_str, date_format)
1530+
except ValueError:
1531+
# Parsing failed and we are unable to obtain the time
1532+
return False
1533+
return True
1534+
mod_updater.update_dpu_state("DPU1", 'up')
1535+
date_value = None
1536+
for args in (mod_updater.chassis_state_db.hset.call_args_list):
1537+
if args[0][0] == "DPU1" and args[0][1] == "dpu_midplane_link_time":
1538+
date_value = args[0][2]
1539+
if not date_value:
1540+
AssertionError("Date is not set!")
1541+
assert is_valid_date(date_value)

sonic-chassisd/tests/test_dpu_chassisd.py

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import signal
66
import threading
77
from imp import load_source
8+
import re
89

910
from mock import MagicMock
1011
from sonic_py_common import daemon_base
@@ -75,14 +76,14 @@ def test_dpu_state_update_api(state, expected_state):
7576

7677
@pytest.mark.parametrize('dpu_id, dp_state, cp_state, expected_state', [
7778
(0, False, False, {'DPU0':
78-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
79-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
79+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
80+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8081
(0, False, True, {'DPU0':
81-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
82-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
82+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
83+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8384
(0, True, True, {'DPU0':
84-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
85-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
85+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
86+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8687
])
8788
def test_dpu_state_update(dpu_id, dp_state, cp_state, expected_state):
8889
chassis = MockDpuChassis()
@@ -102,7 +103,7 @@ def hset(key, field, value):
102103

103104
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset) as hset_mock:
104105
dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, chassis)
105-
dpu_updater._time_now = MagicMock(return_value='2000-01-01 00:00:00')
106+
dpu_updater._time_now = MagicMock(return_value='Sat Jan 01 12:00:00 AM UTC 2000')
106107

107108
dpu_updater.update_state()
108109

@@ -112,20 +113,20 @@ def hset(key, field, value):
112113

113114
# After the deinit we assume that the DPU state is down.
114115
assert chassis_state_db == {'DPU0':
115-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
116-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
116+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
117+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
117118

118119

119120
@pytest.mark.parametrize('dpu_id, dp_state, cp_state, expected_state', [
120121
(0, False, False, {'DPU0':
121-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
122-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
122+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
123+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
123124
(0, False, True, {'DPU0':
124-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
125-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
125+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
126+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
126127
(0, True, True, {'DPU0':
127-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
128-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
128+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
129+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
129130
])
130131
def test_dpu_state_manager(dpu_id, dp_state, cp_state, expected_state):
131132
chassis = MockDpuChassis()
@@ -146,7 +147,7 @@ def hset(key, field, value):
146147
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset):
147148
with mock.patch.object(swsscommon.Select, 'select', side_effect=((swsscommon.Select.OBJECT, None), (swsscommon.Select.OBJECT, None), KeyboardInterrupt)):
148149
dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, chassis)
149-
dpu_updater._time_now = MagicMock(return_value='2000-01-01 00:00:00')
150+
dpu_updater._time_now = MagicMock(return_value='Sat Jan 01 12:00:00 AM UTC 2000')
150151

151152
dpu_state_mng = DpuStateManagerTask(SYSLOG_IDENTIFIER, dpu_updater)
152153

@@ -158,8 +159,8 @@ def hset(key, field, value):
158159

159160
# After the deinit we assume that the DPU state is down.
160161
assert chassis_state_db == {'DPU0':
161-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
162-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
162+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
163+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
163164

164165

165166
def test_dpu_chassis_daemon():
@@ -180,7 +181,7 @@ def hset(key, field, value):
180181
chassis_state_db[key][field] = value
181182

182183
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset) as hset_mock:
183-
with mock.patch.object(DpuStateUpdater, '_time_now', side_effect=lambda: '2000-01-01 00:00:00') as mock_time_now:
184+
with mock.patch.object(DpuStateUpdater, '_time_now', side_effect=lambda: 'Sat Jan 01 12:00:00 AM UTC 2000') as mock_time_now:
184185

185186
daemon_chassisd = DpuChassisdDaemon(SYSLOG_IDENTIFIER, chassis)
186187
daemon_chassisd.CHASSIS_INFO_UPDATE_PERIOD_SECS = MagicMock(return_value=1)
@@ -195,14 +196,40 @@ def hset(key, field, value):
195196
time.sleep(3)
196197

197198
assert chassis_state_db == {'DPU1':
198-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
199-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
199+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
200+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
200201

201202
daemon_chassisd.signal_handler(signal.SIGINT, None)
202203
daemon_chassisd.stop.wait.return_value = True
203204

204205
thread.join()
205206

206207
assert chassis_state_db == {'DPU1':
207-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
208-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
208+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
209+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
210+
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset):
211+
daemon_chassisd = DpuChassisdDaemon(SYSLOG_IDENTIFIER, chassis)
212+
daemon_chassisd.CHASSIS_INFO_UPDATE_PERIOD_SECS = MagicMock(return_value=1)
213+
214+
daemon_chassisd.stop = MagicMock()
215+
daemon_chassisd.stop.wait.return_value = False
216+
217+
thread = threading.Thread(target=daemon_chassisd.run)
218+
thread.start()
219+
# Wait for thread to start and update DB
220+
time.sleep(3)
221+
date_format = "%a %b %d %I:%M:%S %p UTC %Y"
222+
223+
def is_valid_date(date_str):
224+
try:
225+
datetime.strptime(date_str, date_format)
226+
except ValueError:
227+
# Parsing failed and we are unable to obtain the time
228+
return False
229+
return True
230+
assert is_valid_date(chassis_state_db['DPU1']['dpu_data_plane_time'])
231+
assert is_valid_date(chassis_state_db['DPU1']['dpu_control_plane_time'])
232+
daemon_chassisd.signal_handler(signal.SIGINT, None)
233+
daemon_chassisd.stop.wait.return_value = True
234+
235+
thread.join()

0 commit comments

Comments
 (0)