Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added memory_statistics cfg #144

Draft
wants to merge 51 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4e16175
Added memory_statistics cfg
KanzaLatif Aug 8, 2024
d0b3fe0
Added the test_event file for memory_statistics
kanza-latif Aug 8, 2024
e2f619f
Add MemoryStatsCfg class to manage memory statistics configuration
Arham-Nasir Aug 14, 2024
017b959
madified memory statistics class
kanza-latif Aug 30, 2024
4dac17f
added apply_configurations function
kanza-latif Sep 5, 2024
f581541
updated test case file and the memory_statistics class
kanza-latif Sep 9, 2024
0dc74c8
resolved all the errors
kanza-latif Sep 10, 2024
dcf37a3
resolved function error
kanza-latif Sep 10, 2024
6c5964b
updated hostcfgd
kanza-latif Sep 10, 2024
c7fd2e6
resolving errors
kanza-latif Sep 10, 2024
c1740b0
resolved testing error
kanza-latif Sep 10, 2024
a45a57a
resolved error
kanza-latif Sep 11, 2024
77120ce
resolving errors
kanza-latif Sep 11, 2024
da59394
errors resolving
kanza-latif Sep 11, 2024
c8aa989
error
kanza-latif Sep 11, 2024
3fb4958
resolved error
kanza-latif Sep 11, 2024
4e25cfb
resolving erors
kanza-latif Sep 11, 2024
3ef484c
errors
kanza-latif Sep 12, 2024
3f8d9de
resolved errors
kanza-latif Sep 12, 2024
febf2a0
resolving errors in the test file
kanza-latif Sep 12, 2024
7e76786
taking it a few commits back to resolve errors
kanza-latif Sep 13, 2024
beac5a5
removed pycairofile
kanza-latif Sep 13, 2024
bbdfee9
chaged hostcfgd
kanza-latif Sep 13, 2024
2c1f0cf
errors resolving
kanza-latif Sep 13, 2024
b887226
errors
kanza-latif Sep 16, 2024
fc7645a
Merge branch 'master' into memory_statistics
kanza-latif Sep 16, 2024
f42d768
resolves type errors and key errors
Arham-Nasir Sep 17, 2024
78ed39c
modified the hostcfgd
kanza-latif Sep 18, 2024
ce3f215
added the test_vectors file
kanza-latif Sep 18, 2024
efcae92
resolved errors
kanza-latif Sep 19, 2024
db735d5
errors
kanza-latif Sep 19, 2024
1d403ac
changed the name of db table
kanza-latif Sep 20, 2024
0b9698c
added swss common attributes
kanza-latif Sep 20, 2024
a447a1b
added swss common attribute
kanza-latif Sep 24, 2024
7d61447
added swss common attribute
kanza-latif Sep 24, 2024
d3c0ee0
changed swss common
kanza-latif Sep 24, 2024
82aca30
added sighup and sigterm signals
kanza-latif Sep 24, 2024
dc3939d
added pid
kanza-latif Sep 24, 2024
de9c607
changes made
kanza-latif Sep 24, 2024
7251ad8
imported the swss common again
kanza-latif Sep 24, 2024
5a92cc3
Updated the hostcfgd code
Arham-Nasir Sep 24, 2024
fd20479
corrected import
kanza-latif Sep 25, 2024
1bcc1ef
updated the init_data
kanza-latif Sep 25, 2024
7d4834c
printing the swsscommon file
kanza-latif Sep 25, 2024
8287519
updated hostcfgd
kanza-latif Sep 25, 2024
a20427f
updated hostcfgd
kanza-latif Sep 25, 2024
a5182b1
upodated the code
kanza-latif Sep 25, 2024
15a5c6e
upodated the code
kanza-latif Sep 25, 2024
158b103
updated the hostcfgd class
kanza-latif Sep 25, 2024
c740c82
updated vector.py file and hostcfgd
kanza-latif Sep 25, 2024
9c080dc
updated the test file
kanza-latif Sep 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion scripts/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ import syslog
import signal
import re
import jinja2
import time
import json
import importlib
from shutil import copy2
from datetime import datetime
from sonic_py_common import device_info
from sonic_py_common.general import check_output_pipe
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table
from swsscommon import swsscommon
import swsscommon
from sonic_installer import bootloader
hostcfg_file_path = os.path.abspath(__file__)
hostcfg_dir_path = os.path.dirname(hostcfg_file_path)
sys.path.append(hostcfg_dir_path)
import ldap
importlib.reload(swsscommon)

# FILE
PAM_AUTH_CONF = "/etc/pam.d/common-auth-sonic"
Expand Down Expand Up @@ -1716,6 +1719,99 @@ class FipsCfg(object):
syslog.syslog(syslog.LOG_INFO, f'FipsCfg: update the FIPS enforce option {self.enforce}.')
loader.set_fips(image, self.enforce)

print(swsscommon.__file__)

class Memory_StatisticsCfg:
"""
Memory_StatisticsCfg class handles the configuration updates for the MemoryStatisticsDaemon.
It listens to ConfigDB changes and applies them by restarting, shutting down, or reloading
the MemoryStatisticsDaemon.
"""

def __init__(self, config_db):
self.cache = {
"enabled": "false",
"retention": "15",
"sampling": "5"
}
self.config_db = config_db # Store config_db instance for further use

def load(self, memory_statistics_config: dict):
"""Load initial memory statistics configuration."""
syslog.syslog(syslog.LOG_INFO, 'Memory_StatisticsCfg: Load initial configuration')

if not memory_statistics_config:
memory_statistics_config = {}

# Call memory_statistics_message to handle the initial config load for each key
self.memory_statistics_message("enabled", memory_statistics_config.get("enabled", "false"))
self.memory_statistics_message("retention", memory_statistics_config.get("retention", "15"))
self.memory_statistics_message("sampling", memory_statistics_config.get("sampling", "5"))

def memory_statistics_update(self, key, data):
"""
Apply memory statistics settings handler.
Args:
key: DB table's key that triggered the change.
data: New table data to process.
"""
# Ensure data is a string or convertible to the required value
if not isinstance(data, str):
data = str(data)

# Check if any value has changed
if data != self.cache.get(key):
syslog.syslog(syslog.LOG_INFO, f"Memory_StatisticsCfg: Detected change in '{key}'")

try:
if key == "enabled":
enabled = data.lower() == "true"
if enabled:
self.restart_memory_statistics() # Start or restart the daemon
else:
self.shutdown_memory_statistics() # Stop the daemon if disabled
else:
# If other keys (like sampling/retention) are changed, just reload the daemon config
self.reload_memory_statistics()

# Update cache with the new value
self.cache[key] = data
except Exception as e:
syslog.syslog(syslog.LOG_ERR, f'Memory_StatisticsCfg: Failed to manage MemoryStatisticsDaemon: {e}')

def restart_memory_statistics(self):
"""Restart the memory statistics daemon."""
self.shutdown_memory_statistics() # Ensure the daemon is stopped before restarting
time.sleep(1) # Brief delay to allow shutdown
syslog.syslog(syslog.LOG_INFO, "Memory_StatisticsCfg: Starting MemoryStatisticsDaemon")
try:
subprocess.Popen(['/usr/bin/memorystatsd'])
except Exception as e:
syslog.syslog(syslog.LOG_ERR, f"Memory_StatisticsCfg: Failed to start MemoryStatisticsDaemon: {e}")

def reload_memory_statistics(self):
"""Send SIGHUP to the MemoryStatisticsDaemon to reload its configuration."""
pid = self.get_memory_statistics_pid()
if pid:
os.kill(pid, signal.SIGHUP) # Notify daemon to reload its configuration
syslog.syslog(syslog.LOG_INFO, "Memory_StatisticsCfg: Sent SIGHUP to reload daemon configuration")

def shutdown_memory_statistics(self):
"""Send SIGTERM to stop the MemoryStatisticsDaemon gracefully."""
pid = self.get_memory_statistics_pid()
if pid:
os.kill(pid, signal.SIGTERM) # Graceful shutdown
syslog.syslog(syslog.LOG_INFO, "Memory_StatisticsCfg: Sent SIGTERM to stop MemoryStatisticsDaemon")

def get_memory_statistics_pid(self):
"""Retrieve the PID of the running MemoryStatisticsDaemon."""
try:
with open('/var/run/memorystatsd.pid', 'r') as pid_file:
pid = int(pid_file.read().strip())
return pid
except Exception as e:
syslog.syslog(syslog.LOG_ERR, f"Memory_StatisticsCfg: Failed to retrieve MemoryStatisticsDaemon PID: {e}")
return None

class SerialConsoleCfg:

Expand Down Expand Up @@ -1749,6 +1845,7 @@ class SerialConsoleCfg:
return



class HostConfigDaemon:
def __init__(self):
self.state_db_conn = DBConnector(STATE_DB, 0)
Expand All @@ -1764,6 +1861,8 @@ class HostConfigDaemon:
# Initialize KDump Config and set the config to default if nothing is provided
self.kdumpCfg = KdumpCfg(self.config_db)

self.memory_statisticsCfg = Memory_StatisticsCfg(self.config_db)

# Initialize IpTables
self.iptables = Iptables()

Expand Down Expand Up @@ -1816,6 +1915,7 @@ class HostConfigDaemon:
passwh = init_data['PASSW_HARDENING']
ssh_server = init_data['SSH_SERVER']
dev_meta = init_data.get(swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, {})
memory_statistics = init_data.get[swsscommon.CFG_MEMORY_STATISTICS_TABLE_NAME, {}]
mgmt_ifc = init_data.get(swsscommon.CFG_MGMT_INTERFACE_TABLE_NAME, {})
mgmt_vrf = init_data.get(swsscommon.CFG_MGMT_VRF_CONFIG_TABLE_NAME, {})
syslog_cfg = init_data.get(swsscommon.CFG_SYSLOG_CONFIG_TABLE_NAME, {})
Expand All @@ -1830,6 +1930,7 @@ class HostConfigDaemon:
self.aaacfg.load(aaa, tacacs_global, tacacs_server, radius_global, radius_server, ldap_global, ldap_server)
self.iptables.load(lpbk_table)
self.kdumpCfg.load(kdump)
self.memory_statisticsCfg.load(memory_statistics)
self.passwcfg.load(passwh)
self.sshscfg.load(ssh_server)
self.devmetacfg.load(dev_meta)
Expand Down Expand Up @@ -1959,6 +2060,10 @@ class HostConfigDaemon:
syslog.syslog(syslog.LOG_INFO, 'Kdump handler...')
self.kdumpCfg.kdump_update(key, data)

def memory_statistics_handler (self, key, op, data):
syslog.syslog(syslog.LOG_INFO, 'Memory_Statistics handler...')
self.memory_statisticsCfg.memory_statistics_update(key, data)

def device_metadata_handler(self, key, op, data):
syslog.syslog(syslog.LOG_INFO, 'DeviceMeta handler...')
self.devmetacfg.hostname_update(data)
Expand Down Expand Up @@ -2035,6 +2140,9 @@ class HostConfigDaemon:
# Handle DEVICE_MEATADATA changes
self.config_db.subscribe(swsscommon.CFG_DEVICE_METADATA_TABLE_NAME,
make_callback(self.device_metadata_handler))

self.config_db.subscribe(swsscommon.CFG_MEMORY_STATISTICS_TABLE_NAME,
make_callback(self.memory_statistics_handler))

# Handle MGMT_VRF_CONFIG changes
self.config_db.subscribe(swsscommon.CFG_MGMT_VRF_CONFIG_TABLE_NAME,
Expand Down
32 changes: 31 additions & 1 deletion tests/hostcfgd/hostcfgd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ def test_kdump_event(self):
call(['sonic-kdump-config', '--memory', '0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M'])]
mocked_subprocess.check_call.assert_has_calls(expected, any_order=True)


def test_devicemeta_event(self):
"""
Test handling DEVICE_METADATA events.
Expand Down Expand Up @@ -324,6 +325,35 @@ def test_mgmtiface_event(self):
]
mocked_check_output.assert_has_calls(expected)

def test_memory_statistics_event(self, mock_config_db_connector):
# Mock the ConfigDBConnector instance methods
mock_instance = mock_config_db_connector.return_value
# Make sure get_table returns the correct nested structure
mock_instance.get_table.return_value = HOSTCFG_DAEMON_CFG_DB['MEMORY_STATISTICS']['memory_statistics']

# Mock the subprocess module to avoid real process callswith mock.patch('hostcfgd.subprocess') as mocked_subprocess:
daemon = hostcfgd.HostConfigDaemon() # Create the daemon instance# Load config using the correct nested dictionary
daemon.memory_statisticsCfg.load(HOSTCFG_DAEMON_CFG_DB['MEMORY_STATISTICS']['memory_statistics'])

# Mock the subprocess.Popen and check_call
popen_mock = mock.Mock()
attrs = {'communicate.return_value': ('output', 'error')}
popen_mock.configure_mock(**attrs)
mocked_subprocess.Popen.return_value = popen_mock
mocked_subprocess.check_call = mock.Mock()

# Trigger event handler
MockConfigDb.event_queue = [('MEMORY_STATISTICS', 'config')]
daemon.memory_statistics_handler('enabled', 'SET', 'true')

# Define expected subprocess calls
expected_calls = [
mock.call(['/usr/bin/memorystatsd']),
]

# Check if subprocess check_call was made with correct arguments
mocked_subprocess.Popen.assert_has_calls(expected_calls, any_order=True)

def test_dns_events(self):
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
MockConfigDb.event_queue = [('DNS_NAMESERVER', '1.1.1.1')]
Expand Down Expand Up @@ -353,4 +383,4 @@ def test_load(self):

data = {}
dns_cfg.load(data)
dns_cfg.dns_update.assert_called()
dns_cfg.dns_update.assert_called()
8 changes: 8 additions & 0 deletions tests/hostcfgd/test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"PASSW_HARDENING": {},
"SSH_SERVER": {},
"KDUMP": {},
"MEMORY_STATISTICS": {},
"NTP": {},
"NTP_SERVER": {},
"LOOPBACK_INTERFACE": {},
Expand Down Expand Up @@ -79,6 +80,13 @@
"timezone": "Europe/Kyiv"
}
},
"MEMORY_STATISTICS": {
"memory_statistics": {
"enabled": "true",
"retention_time": "15",
"sampling_interval": "5"
}
},
"MGMT_INTERFACE": {
"eth0|1.2.3.4/24": {}
},
Expand Down
Loading