@@ -982,84 +982,141 @@ class NtpCfg(object):
982
982
1) ntp-config.service handles the configuration updates and then starts ntp.service
983
983
2) Both of them start after all the feature services start
984
984
3) Purpose of this daemon is to propagate runtime config changes in
985
- NTP, NTP_SERVER and LOOPBACK_INTERFACE
985
+ NTP, NTP_SERVER, NTP_KEY, and LOOPBACK_INTERFACE
986
986
"""
987
+ NTP_CONF_RESTART = ['systemctl' , 'restart' , 'ntp-config' ]
988
+
987
989
def __init__ (self ):
988
- self .ntp_global = {}
989
- self .ntp_servers = set ()
990
+ self .cache = {}
991
+
992
+ def load (self , ntp_global_conf : dict , ntp_server_conf : dict ,
993
+ ntp_key_conf : dict ):
994
+ """Load initial NTP configuration
990
995
991
- def load (self , ntp_global_conf , ntp_server_conf ):
992
- syslog .syslog (syslog .LOG_INFO , "NtpCfg load ..." )
996
+ Force load cache on init. NTP config should be taken at boot-time by
997
+ ntp and ntp-config services. So loading whole config here.
998
+
999
+ Args:
1000
+ ntp_global_conf: Global configuration
1001
+ ntp_server_conf: Servers configuration
1002
+ ntp_key_conf: Keys configuration
1003
+ """
993
1004
994
- for row in ntp_global_conf :
995
- self .ntp_global_update (row , ntp_global_conf [row ], is_load = True )
1005
+ syslog .syslog (syslog .LOG_INFO , "NtpCfg: load initial" )
996
1006
997
- # Force reload on init
998
- self .ntp_server_update (0 , None , is_load = True )
1007
+ if ntp_global_conf is None :
1008
+ ntp_global_conf = {}
1009
+
1010
+ # Force load cache on init.
1011
+ # NTP config should be taken at boot-time by ntp and ntp-config
1012
+ # services.
1013
+ self .cache = {
1014
+ 'global' : ntp_global_conf .get ('global' , {}),
1015
+ 'servers' : ntp_server_conf ,
1016
+ 'keys' : ntp_key_conf
1017
+ }
999
1018
1000
1019
def handle_ntp_source_intf_chg (self , intf_name ):
1001
- # if no ntp server configured, do nothing
1002
- if not self .ntp_servers :
1020
+ # If no ntp server configured, do nothing. Source interface will be
1021
+ # taken once any server will be configured.
1022
+ if not self .cache .get ('servers' ):
1003
1023
return
1004
1024
1005
1025
# check only the intf configured as source interface
1006
- if intf_name not in self .ntp_global .get ('src_intf' , '' ).split (';' ):
1026
+ ifs = self .cache .get ('global' , {}).get ('src_intf' , '' ).split (';' )
1027
+ if intf_name not in ifs :
1028
+ return
1029
+
1030
+ # Just restart ntp config
1031
+ try :
1032
+ run_cmd (self .NTP_CONF_RESTART , True , True )
1033
+ except Exception :
1034
+ syslog .syslog (syslog .LOG_ERR , 'NtpCfg: Failed to restart '
1035
+ 'ntp-config service' )
1036
+ return
1037
+
1038
+ def ntp_global_update (self , key : str , data : dict ):
1039
+ """Update NTP global configuration
1040
+
1041
+ The table holds NTP global configuration. It has some configs that
1042
+ require reloading only but some other require restarting ntp daemon.
1043
+ Handle each of them accordingly.
1044
+
1045
+ Args:
1046
+ key: Triggered table's key. Should be always "global"
1047
+ data: Global configuration data
1048
+ """
1049
+
1050
+ syslog .syslog (syslog .LOG_NOTICE , 'NtpCfg: Global configuration update' )
1051
+ if key != 'global' or self .cache .get ('global' , {}) == data :
1052
+ syslog .syslog (syslog .LOG_NOTICE , 'NtpCfg: Nothing to update' )
1007
1053
return
1008
- else :
1009
- # just restart ntp config
1010
- cmd = ['systemctl' , 'restart' , 'ntp-config' ]
1011
- run_cmd (cmd )
1012
1054
1013
- def ntp_global_update (self , key , data , is_load = False ):
1014
- syslog .syslog (syslog .LOG_INFO , 'NTP GLOBAL Update' )
1015
- orig_src = self .ntp_global .get ('src_intf' , '' )
1016
- orig_src_set = set (orig_src .split (";" ))
1017
- orig_vrf = self .ntp_global .get ('vrf' , '' )
1055
+ syslog .syslog (syslog .LOG_INFO , f'NtpCfg: Set global config: { data } ' )
1018
1056
1019
- new_src = data .get ('src_intf' , '' )
1020
- new_src_set = set (new_src .split (";" ))
1021
- new_vrf = data .get ('vrf' , '' )
1057
+ old_dhcp = self .cache .get (key , {}).get ('dhcp' )
1058
+ old_vrf = self .cache .get (key , {}).get ('vrf' )
1059
+ new_dhcp = data .get ('dhcp' )
1060
+ new_vrf = data .get ('vrf' )
1061
+
1062
+ restart_ntpd = False
1063
+ if new_dhcp != old_dhcp or new_vrf != old_vrf :
1064
+ restart_ntpd = True
1065
+
1066
+ # Restarting the service
1067
+ try :
1068
+ run_cmd (self .NTP_CONF_RESTART , True , True )
1069
+ if restart_ntpd :
1070
+ run_cmd (['systemctl' , 'restart' , 'ntp' ], True , True )
1071
+ except Exception :
1072
+ syslog .syslog (syslog .LOG_ERR , f'NtpCfg: Failed to restart ntp '
1073
+ 'services' )
1074
+ return
1022
1075
1023
1076
# Update the Local Cache
1024
- self .ntp_global = data
1077
+ self .cache [key ] = data
1078
+
1079
+ def ntp_srv_key_update (self , ntp_servers : dict , ntp_keys : dict ):
1080
+ """Update NTP server/key configuration
1025
1081
1026
- # If initial load don't restart daemon
1027
- if is_load : return
1082
+ The tables holds only NTP servers config and/or NTP authentication keys
1083
+ config, so any change to those tables should cause NTP config reload.
1084
+ It does not make sense to handle each of the separately. NTP config
1085
+ reload takes whole configuration, so once got to this handler - cache
1086
+ whole config.
1028
1087
1029
- # check if ntp server configured, if not, do nothing
1030
- if not self .ntp_servers :
1031
- syslog .syslog (syslog .LOG_INFO , "No ntp server when global config change, do nothing" )
1088
+ Args:
1089
+ ntp_servers: Servers config table
1090
+ ntp_keys: Keys config table
1091
+ """
1092
+
1093
+ syslog .syslog (syslog .LOG_NOTICE , 'NtpCfg: Server/key configuration '
1094
+ 'update' )
1095
+
1096
+ if (self .cache .get ('servers' , {}) == ntp_servers and
1097
+ self .cache .get ('keys' , {}) == ntp_keys ):
1098
+ syslog .syslog (syslog .LOG_NOTICE , 'NtpCfg: Nothing to update' )
1032
1099
return
1033
1100
1034
- if orig_src_set != new_src_set :
1035
- syslog .syslog (syslog .LOG_INFO , "ntp global update for source intf old {} new {}, restarting ntp-config"
1036
- .format (orig_src_set , new_src_set ))
1037
- cmd = ['systemctl' , 'restart' , 'ntp-config' ]
1038
- run_cmd (cmd )
1039
- elif new_vrf != orig_vrf :
1040
- syslog .syslog (syslog .LOG_INFO , "ntp global update for vrf old {} new {}, restarting ntp service"
1041
- .format (orig_vrf , new_vrf ))
1042
- cmd = ['service' , 'ntp' , 'restart' ]
1043
- run_cmd (cmd )
1101
+ # Pop keys values to print
1102
+ ntp_keys_print = copy .deepcopy (ntp_keys )
1103
+ for key in ntp_keys_print :
1104
+ ntp_keys_print [key ].pop ('value' , None )
1044
1105
1045
- def ntp_server_update (self , key , op , is_load = False ):
1046
- syslog .syslog (syslog .LOG_INFO , 'ntp server update key {}' .format (key ))
1047
-
1048
- restart_config = False
1049
- if not is_load :
1050
- if op == "SET" and key not in self .ntp_servers :
1051
- restart_config = True
1052
- self .ntp_servers .add (key )
1053
- elif op == "DEL" and key in self .ntp_servers :
1054
- restart_config = True
1055
- self .ntp_servers .remove (key )
1056
- else :
1057
- restart_config = True
1106
+ syslog .syslog (syslog .LOG_INFO , f'NtpCfg: Set servers: { ntp_servers } ' )
1107
+ syslog .syslog (syslog .LOG_INFO , f'NtpCfg: Set keys: { ntp_keys_print } ' )
1058
1108
1059
- if restart_config :
1060
- cmd = ['systemctl' , 'restart' , 'ntp-config' ]
1061
- syslog .syslog (syslog .LOG_INFO , 'ntp server update, restarting ntp-config, ntp servers configured {}' .format (self .ntp_servers ))
1062
- run_cmd (cmd )
1109
+ # Restarting the service
1110
+ try :
1111
+ run_cmd (self .NTP_CONF_RESTART , True , True )
1112
+ except Exception :
1113
+ syslog .syslog (syslog .LOG_ERR , f'NtpCfg: Failed to restart '
1114
+ 'ntp-config service' )
1115
+ return
1116
+
1117
+ # Updating the cache
1118
+ self .cache ['servers' ] = ntp_servers
1119
+ self .cache ['keys' ] = ntp_keys
1063
1120
1064
1121
class PamLimitsCfg (object ):
1065
1122
"""
@@ -1501,8 +1558,6 @@ class HostConfigDaemon:
1501
1558
radius_global = init_data ['RADIUS' ]
1502
1559
radius_server = init_data ['RADIUS_SERVER' ]
1503
1560
lpbk_table = init_data ['LOOPBACK_INTERFACE' ]
1504
- ntp_server = init_data ['NTP_SERVER' ]
1505
- ntp_global = init_data ['NTP' ]
1506
1561
kdump = init_data ['KDUMP' ]
1507
1562
passwh = init_data ['PASSW_HARDENING' ]
1508
1563
ssh_server = init_data ['SSH_SERVER' ]
@@ -1513,10 +1568,12 @@ class HostConfigDaemon:
1513
1568
syslog_srv = init_data .get (swsscommon .CFG_SYSLOG_SERVER_TABLE_NAME , {})
1514
1569
dns = init_data .get ('DNS_NAMESERVER' , {})
1515
1570
fips_cfg = init_data .get ('FIPS' , {})
1571
+ ntp_global = init_data .get (swsscommon .CFG_NTP_GLOBAL_TABLE_NAME )
1572
+ ntp_servers = init_data .get (swsscommon .CFG_NTP_SERVER_TABLE_NAME )
1573
+ ntp_keys = init_data .get (swsscommon .CFG_NTP_KEY_TABLE_NAME )
1516
1574
1517
1575
self .aaacfg .load (aaa , tacacs_global , tacacs_server , radius_global , radius_server )
1518
1576
self .iptables .load (lpbk_table )
1519
- self .ntpcfg .load (ntp_global , ntp_server )
1520
1577
self .kdumpCfg .load (kdump )
1521
1578
self .passwcfg .load (passwh )
1522
1579
self .sshscfg .load (ssh_server )
@@ -1526,6 +1583,7 @@ class HostConfigDaemon:
1526
1583
self .rsyslogcfg .load (syslog_cfg , syslog_srv )
1527
1584
self .dnscfg .load (dns )
1528
1585
self .fipscfg .load (fips_cfg )
1586
+ self .ntpcfg .load (ntp_global , ntp_servers , ntp_keys )
1529
1587
1530
1588
# Update AAA with the hostname
1531
1589
self .aaacfg .hostname_update (self .devmetacfg .hostname )
@@ -1615,12 +1673,16 @@ class HostConfigDaemon:
1615
1673
key = ConfigDBConnector .deserialize_key (key )
1616
1674
self .aaacfg .handle_radius_source_intf_ip_chg (key )
1617
1675
1618
- def ntp_server_handler (self , key , op , data ):
1619
- self .ntpcfg .ntp_server_update (key , op )
1620
-
1621
1676
def ntp_global_handler (self , key , op , data ):
1677
+ syslog .syslog (syslog .LOG_NOTICE , 'Handling NTP global config' )
1622
1678
self .ntpcfg .ntp_global_update (key , data )
1623
1679
1680
+ def ntp_srv_key_handler (self , key , op , data ):
1681
+ syslog .syslog (syslog .LOG_NOTICE , 'Handling NTP server/key config' )
1682
+ self .ntpcfg .ntp_srv_key_update (
1683
+ self .config_db .get_table (swsscommon .CFG_NTP_SERVER_TABLE_NAME ),
1684
+ self .config_db .get_table (swsscommon .CFG_NTP_KEY_TABLE_NAME ))
1685
+
1624
1686
def kdump_handler (self , key , op , data ):
1625
1687
syslog .syslog (syslog .LOG_INFO , 'Kdump handler...' )
1626
1688
self .kdumpCfg .kdump_update (key , data )
@@ -1682,9 +1744,6 @@ class HostConfigDaemon:
1682
1744
self .config_db .subscribe ('SSH_SERVER' , make_callback (self .ssh_handler ))
1683
1745
# Handle IPTables configuration
1684
1746
self .config_db .subscribe ('LOOPBACK_INTERFACE' , make_callback (self .lpbk_handler ))
1685
- # Handle NTP & NTP_SERVER updates
1686
- self .config_db .subscribe ('NTP' , make_callback (self .ntp_global_handler ))
1687
- self .config_db .subscribe ('NTP_SERVER' , make_callback (self .ntp_server_handler ))
1688
1747
# Handle updates to src intf changes in radius
1689
1748
self .config_db .subscribe ('MGMT_INTERFACE' , make_callback (self .mgmt_intf_handler ))
1690
1749
self .config_db .subscribe ('VLAN_INTERFACE' , make_callback (self .vlan_intf_handler ))
@@ -1711,6 +1770,14 @@ class HostConfigDaemon:
1711
1770
# Handle FIPS changes
1712
1771
self .config_db .subscribe ('FIPS' , make_callback (self .fips_config_handler ))
1713
1772
1773
+ # Handle NTP, NTP_SERVER, and NTP_KEY updates
1774
+ self .config_db .subscribe (swsscommon .CFG_NTP_GLOBAL_TABLE_NAME ,
1775
+ make_callback (self .ntp_global_handler ))
1776
+ self .config_db .subscribe (swsscommon .CFG_NTP_SERVER_TABLE_NAME ,
1777
+ make_callback (self .ntp_srv_key_handler ))
1778
+ self .config_db .subscribe (swsscommon .CFG_NTP_KEY_TABLE_NAME ,
1779
+ make_callback (self .ntp_srv_key_handler ))
1780
+
1714
1781
syslog .syslog (syslog .LOG_INFO ,
1715
1782
"Waiting for systemctl to finish initialization" )
1716
1783
self .wait_till_system_init_done ()
0 commit comments