This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
sonic-buildimage/src/sonic-host-services/scripts/aaastatsd
Qi Luo f14430b29b
Replace swsssdk with swsscommon in sonic-host-services (#8034)
#### Why I did it
swsssdk will be deprecated. Use swsscommon instead.

#### How to verify it
Unit test
2021-07-06 02:07:45 -07:00

223 lines
7.2 KiB
Python
Executable File

#!/usr/bin/env python3
#
import os
import syslog
import threading
from swsscommon.swsscommon import ConfigDBConnector
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# FILE
RADIUS_PAM_AUTH_CONF_DIR = "/etc/pam_radius_auth.d/"
RADIUS_PAM_AUTH_CONF_STATS_DIR = "/etc/pam_radius_auth.d/statistics/"
class RadiusCountersDbMon (threading.Thread):
def __init__(self, ID, name, radiusStatsInstance):
threading.Thread.__init__(self)
self.ID = ID
self.name = name
self.radiusStatsInstance = radiusStatsInstance
def handle_CountersDbRadiusClear(self, key, data):
# print("RadiusCountersDbMon.handle_CountersDbRadiusClear()")
if key == 'clear':
self.radiusStatsInstance.handle_clear()
def run(self):
# print("RadiusCountersDbMon.run()")
self.radiusStatsInstance.counters_db.subscribe('RADIUS', lambda table, key, data: self.handle_CountersDbRadiusClear(key, data))
self.radiusStatsInstance.counters_db.listen()
# print("RadiusCountersDbMon.run(): After listen()")
class RadiusStatsFileHandler(FileSystemEventHandler):
def __init__(self, radiusStatsInstance):
self.radiusStatsInstance = radiusStatsInstance
def on_any_event(self, event):
# print("RadiusStatsFileHandler.on_any_event()")
if event.is_directory:
return None
self.radiusStatsInstance.handle_update(os.path.basename(event.src_path))
class RadiusStatsFileMon ():
def __init__(self, radiusStatsInstance):
self.event_handler = RadiusStatsFileHandler(radiusStatsInstance)
self.observer = Observer()
self.observer.schedule(self.event_handler, RADIUS_PAM_AUTH_CONF_STATS_DIR, recursive=False)
self.observer.start()
# print("RadiusStatsFileMon.__init__(): After observer.start()")
def stop(self):
# print("RadiusStatsFileMon.stop()")
self.observer.stop()
# print("RadiusStatsFileMon.stop(): After observer.stop()")
self.observer.join()
# print("RadiusStatsFileMon.stop(): After observer.join()")
class RadiusStatistics:
def __init__(self, cfg_db, rad_global_conf, radius_conf):
self.radius_counter_names = [
"counter_0",
"access_requests",
"access_accepts",
"access_rejects",
"accounting_requests",
"accounting_responses",
"counter_6",
"counter_7",
"counter_8",
"counter_9",
"counter_10",
"access_challenges",
"counter_12",
"counter_13",
"counter_14",
"counter_15",
"counter_16",
"retried_access_requests",
"counter_18",
"counter_19",
"retried_accounting_requests",
"counter_21",
"counter_22",
"counter_23",
"counter_24",
"counter_25",
"counter_26",
"retried_access_challenges",
"counter_28",
"counter_29",
"counter_30",
"counter_31",
"timeouts",
"bad_authenticators",
"invalid_packets",
"counter_35",
]
self.radius_global = {
'statistics': 'False'
}
self.radius_servers = {}
self.config_db = cfg_db
for row in rad_global_conf:
self.radius_global_update(row, rad_global_conf[row])
for row in radius_conf:
self.radius_server_update(row, radius_conf[row])
self.counters_db = ConfigDBConnector()
self.counters_db.db_connect('COUNTERS_DB', wait_for_init=False,
retry_on=True)
syslog.syslog(syslog.LOG_INFO, 'CountersDB connect success')
self.dbmon_thread = RadiusCountersDbMon("RadiusCountersDbMon",
"RadiusCountersDbMon", self)
self.dbmon_thread.daemon = True
self.dbmon_thread.start()
self.filemon = RadiusStatsFileMon(self)
syslog.syslog(syslog.LOG_INFO, 'RADIUS Stats File Monitor started')
def radius_global_update(self, key, data):
if key == 'global':
self.radius_global.update(data)
for addr in self.radius_servers:
self.create_file(addr)
def radius_server_update(self, key, data):
if data == {}:
if key in self.radius_servers:
del self.radius_servers[key]
else:
self.radius_servers[key] = data
self.create_file(key)
def create_file(self, addr):
# print( "RadiusStatistics.create_file({})".format(addr))
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + addr
if self.radius_global['statistics'] == 'False':
if os.path.exists(stats_file):
os.unlink(stats_file)
else:
open(stats_file, 'a').close()
os.chmod(stats_file, 0o666)
self.handle_update(addr)
def handle_clear(self):
# print( "RadiusStatistics.handle_clear()")
for filename in os.listdir(RADIUS_PAM_AUTH_CONF_STATS_DIR):
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + filename
open(stats_file, 'w').close()
def handle_update(self, srv):
# print( "RadiusStatistics.handle_update({})".format(srv))
if self.radius_global['statistics'] == 'False':
return
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + srv
entry = None
if os.path.exists(stats_file):
with open(stats_file, 'r') as f:
lines = f.readlines()
if len(lines) > 0:
radius_counters = lines[0].split(' ')
entry = dict(zip(self.radius_counter_names, radius_counters))
counters_db = ConfigDBConnector()
counters_db.db_connect('COUNTERS_DB', wait_for_init=False,
retry_on=False)
counters_db.set_entry('RADIUS_SERVER_STATS', srv, entry)
counters_db.close(counters_db.COUNTERS_DB)
class AAAStatsDaemon:
def __init__(self):
self.config_db = ConfigDBConnector()
self.config_db.connect(wait_for_init=True, retry_on=True)
syslog.syslog(syslog.LOG_INFO, 'ConfigDB connect success')
radius_global = self.config_db.get_table('RADIUS')
radius_server = self.config_db.get_table('RADIUS_SERVER')
self.radiusstats = RadiusStatistics(self.config_db, radius_global,
radius_server)
def radius_global_handler(self, key, data):
self.radiusstats.radius_global_update(key, data)
def radius_server_handler(self, key, data):
self.radiusstats.radius_server_update(key, data)
def start(self):
self.config_db.subscribe('RADIUS_SERVER',
lambda table, key, data: self.radius_server_handler(key, data))
self.config_db.subscribe('RADIUS',
lambda table, key, data: self.radius_global_handler(key, data))
self.config_db.listen()
# print( "After config_db.listen()")
syslog.syslog(syslog.LOG_INFO, 'Stopping FileMon')
self.radiusstats.filemon.stop()
# print( "Exiting")
syslog.syslog(syslog.LOG_INFO, 'Exiting')
def main():
daemon = AAAStatsDaemon()
daemon.start()
if __name__ == "__main__":
main()