Skip to content

Commit 8cd6714

Browse files
hostcfgd: Handle missed tacacs updates between load & listen (#8223)
Why I did it The time gap between last config load & db-listen seem to have increased. Any config updates that occurred in this gap gets missed by db-listen. This could miss updating /etc/pam.d/common-auth-sonic How I did it Add a one shot timer, just before db-listen. The timer will fire after the subscribe is done When the timer fires, reload tacacs & aaa
1 parent d573cd1 commit 8cd6714

File tree

1 file changed

+63
-36
lines changed

1 file changed

+63
-36
lines changed

files/image_config/hostcfgd/hostcfgd

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import ast
55
import os
66
import time
7+
import threading
78
import sys
89
import subprocess
910
import syslog
@@ -25,6 +26,20 @@ TACPLUS_SERVER_PASSKEY_DEFAULT = ""
2526
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
2627
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
2728

29+
global_lock = None
30+
31+
class lock_mgr:
32+
def __init__(self):
33+
self.lock = global_lock
34+
35+
def __enter__( self ):
36+
if self.lock:
37+
self.lock.acquire()
38+
39+
def __exit__( self, exc_type, exc_value, traceback ):
40+
if self.lock:
41+
self.lock.release()
42+
2843

2944
def is_true(val):
3045
if val == 'True' or val == 'true':
@@ -123,7 +138,7 @@ class Iptables(object):
123138
.format(err.cmd, err.returncode, err.output))
124139

125140
class AaaCfg(object):
126-
def __init__(self):
141+
def __init__(self, config_db):
127142
self.auth_default = {
128143
'login': 'local',
129144
}
@@ -136,49 +151,42 @@ class AaaCfg(object):
136151
self.tacplus_global = {}
137152
self.tacplus_servers = {}
138153
self.debug = False
154+
self.config_db = config_db
139155

140156
# Load conf from ConfigDb
141-
def load(self, aaa_conf, tac_global_conf, tacplus_conf):
142-
for row in aaa_conf:
143-
self.aaa_update(row, aaa_conf[row], modify_conf=False)
144-
for row in tac_global_conf:
145-
self.tacacs_global_update(row, tac_global_conf[row], modify_conf=False)
146-
for row in tacplus_conf:
147-
self.tacacs_server_update(row, tacplus_conf[row], modify_conf=False)
157+
def load(self):
148158
self.modify_conf_file()
149159

150-
def aaa_update(self, key, data, modify_conf=True):
160+
def aaa_update(self, key):
151161
if key == 'authentication':
152-
self.auth = data
153-
if 'failthrough' in data:
154-
self.auth['failthrough'] = is_true(data['failthrough'])
155-
if 'debug' in data:
156-
self.debug = is_true(data['debug'])
157-
if modify_conf:
158162
self.modify_conf_file()
159163

160-
def tacacs_global_update(self, key, data, modify_conf=True):
164+
def tacacs_global_update(self, key):
161165
if key == 'global':
162-
self.tacplus_global = data
163-
if modify_conf:
164-
self.modify_conf_file()
165-
166-
def tacacs_server_update(self, key, data, modify_conf=True):
167-
if data == {}:
168-
if key in self.tacplus_servers:
169-
del self.tacplus_servers[key]
170-
else:
171-
self.tacplus_servers[key] = data
172-
173-
if modify_conf:
174166
self.modify_conf_file()
175167

168+
def tacacs_server_update(self, key):
169+
self.modify_conf_file()
170+
176171
def modify_single_file(self, filename, operations=None):
177172
if operations:
178173
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
179174
os.system(cmd)
180175

181176
def modify_conf_file(self):
177+
with lock_mgr():
178+
self.auth = self.config_db.get_table('AAA').get("authentication", {})
179+
if 'failthrough' in self.auth:
180+
self.auth['failthrough'] = is_true(self.auth['failthrough'])
181+
if 'debug' in self.auth:
182+
self.debug = is_true(self.auth['debug'])
183+
184+
self.tacplus_global = self.config_db.get_table('TACPLUS').get(
185+
"global", {})
186+
self.tacplus_servers = self.config_db.get_table('TACPLUS_SERVER')
187+
self._modify_conf_file()
188+
189+
def _modify_conf_file(self):
182190
auth = self.auth_default.copy()
183191
auth.update(self.auth)
184192
tacplus_global = self.tacplus_global_default.copy()
@@ -224,6 +232,11 @@ class AaaCfg(object):
224232
with open(NSS_TACPLUS_CONF, 'w') as f:
225233
f.write(nss_tacplus_conf)
226234

235+
if 'passkey' in tacplus_global:
236+
tacplus_global['passkey'] = obfuscate(tacplus_global['passkey'])
237+
syslog.syslog(syslog.LOG_INFO, 'pam.d files updated auth={} global={}'.
238+
format(auth, tacplus_global))
239+
227240
class MultiAsicBgpMonCfg(object):
228241
def __init__(self):
229242
self.ns_for_bgp_mon = 'asic4'
@@ -343,7 +356,7 @@ class HostConfigDaemon:
343356
self.config_db.connect(wait_for_init=True, retry_on=True)
344357
syslog.syslog(syslog.LOG_INFO, 'ConfigDB connect success')
345358

346-
self.aaacfg = AaaCfg()
359+
self.aaacfg = AaaCfg(self.config_db)
347360
self.iptables = Iptables()
348361
# Cache the values of 'state' field in 'FEATURE' table of each container
349362
self.cached_feature_states = {}
@@ -355,11 +368,19 @@ class HostConfigDaemon:
355368
if self.is_multi_npu:
356369
self.masicBgpMonCfg = MultiAsicBgpMonCfg()
357370

371+
372+
def timer_load(self):
373+
global global_lock
374+
375+
syslog.syslog(syslog.LOG_INFO, 'reloading tacacs from timer thread')
376+
self.aaacfg.load()
377+
378+
# Remove lock as timer is one shot
379+
global_lock = None
380+
381+
358382
def load(self):
359-
aaa = self.config_db.get_table('AAA')
360-
tacacs_global = self.config_db.get_table('TACPLUS')
361-
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
362-
self.aaacfg.load(aaa, tacacs_global, tacacs_server)
383+
self.aaacfg.load()
363384

364385
lpbk_table = self.config_db.get_table('LOOPBACK_INTERFACE')
365386
self.iptables.load(lpbk_table)
@@ -468,17 +489,18 @@ class HostConfigDaemon:
468489
self.update_feature_state(feature_name, state, feature_table)
469490

470491
def aaa_handler(self, key, data):
471-
self.aaacfg.aaa_update(key, data)
492+
self.aaacfg.aaa_update(key)
493+
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, data))
472494

473495
def tacacs_server_handler(self, key, data):
474-
self.aaacfg.tacacs_server_update(key, data)
496+
self.aaacfg.tacacs_server_update(key)
475497
log_data = copy.deepcopy(data)
476498
if 'passkey' in log_data:
477499
log_data['passkey'] = obfuscate(log_data['passkey'])
478500
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
479501

480502
def tacacs_global_handler(self, key, data):
481-
self.aaacfg.tacacs_global_update(key, data)
503+
self.aaacfg.tacacs_global_update(key)
482504
log_data = copy.deepcopy(data)
483505
if 'passkey' in log_data:
484506
log_data['passkey'] = obfuscate(log_data['passkey'])
@@ -515,6 +537,7 @@ class HostConfigDaemon:
515537
self.update_feature_state(feature_name, state, feature_table)
516538

517539
def start(self):
540+
global global_lock
518541

519542
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
520543
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
@@ -537,6 +560,10 @@ class HostConfigDaemon:
537560
# Defer load until subscribe
538561
self.load()
539562

563+
global_lock = threading.Lock()
564+
self.tmr_thread = threading.Timer(30, self.timer_load)
565+
self.tmr_thread.start()
566+
540567
self.config_db.listen()
541568

542569

0 commit comments

Comments
 (0)