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

[DHCP] Add try/exception when using psutil.process_iter #19537

Merged
merged 7 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
2 changes: 1 addition & 1 deletion rules/config
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ INCLUDE_NAT = y
INCLUDE_DHCP_RELAY = y

# INCLUDE_DHCP_SERVER - build and install dhcp-server package
INCLUDE_DHCP_SERVER ?= n
INCLUDE_DHCP_SERVER ?= y

# INCLUDE_P4RT - build docker-p4rt for P4RT support
INCLUDE_P4RT = n
Expand Down
11 changes: 7 additions & 4 deletions src/sonic-dhcp-utilities/dhcp_utilities/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,21 @@ def _parse_table_to_dict(table):
return ret


def get_target_process_cmds(process_name):
def get_target_process(process_name):
yaqiangz marked this conversation as resolved.
Show resolved Hide resolved
"""
Get running process cmds
Args:
process_name: name of process
Returns:
List of cmds list
List of process
"""
res = []
for proc in psutil.process_iter():
if proc.name() == process_name:
res.append(proc.cmdline())
try:
if proc.name() == process_name:
res.append(proc)
except psutil.NoSuchProcess:
continue
return res


Expand Down
30 changes: 18 additions & 12 deletions src/sonic-dhcp-utilities/dhcp_utilities/dhcprelayd/dhcprelayd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import syslog
import time
from swsscommon import swsscommon
from dhcp_utilities.common.utils import DhcpDbConnector, terminate_proc, get_target_process_cmds, is_smart_switch
from dhcp_utilities.common.utils import DhcpDbConnector, terminate_proc, get_target_process, is_smart_switch
from dhcp_utilities.common.dhcp_db_monitor import DhcpRelaydDbMonitor, DhcpServerTableIntfEnablementEventChecker, \
VlanTableEventChecker, VlanIntfTableEventChecker, DhcpServerFeatureStateChecker, MidPlaneTableEventChecker

Expand Down Expand Up @@ -224,7 +224,10 @@ def _check_dhcp_relay_processes(self):
"""
Check whether dhcrelay running as expected, if not, dhcprelayd will exit with code 1
"""
running_cmds = get_target_process_cmds("dhcrelay")
try:
running_cmds = [proc.cmdline() for proc in get_target_process("dhcrelay")]
except psutil.NoSuchProcess:
running_cmds = []
running_cmds.sort()
expected_cmds = [value for key, value in self.dhcp_relay_supervisor_config.items() if "isc-dhcpv4-relay" in key]
expected_cmds.sort()
Expand Down Expand Up @@ -318,17 +321,20 @@ def _kill_exist_relay_releated_process(self, new_dhcp_interfaces, process_name,
target_procs = []

# Get old dhcrelay process and get old dhcp interfaces
for proc in psutil.process_iter():
if proc.name() == process_name:
for proc in get_target_process(process_name):
try:
cmds = proc.cmdline()
index = 0
target_procs.append(proc)
while index < len(cmds):
if cmds[index] == "-id":
old_dhcp_interfaces.add(cmds[index + 1])
index += 2
else:
index += 1
except psutil.NoSuchProcess:
continue

index = 0
target_procs.append(proc)
while index < len(cmds):
if cmds[index] == "-id":
old_dhcp_interfaces.add(cmds[index + 1])
index += 2
else:
index += 1
if len(target_procs) == 0:
return NOT_FOUND_PROC

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ def _notify_kea_dhcp4_proc(self):
Send SIGHUP signal to kea-dhcp4 process
"""
for proc in psutil.process_iter():
if KEA_DHCP4_PROC_NAME in proc.name():
proc.send_signal(signal.SIGHUP)
break
try:
if KEA_DHCP4_PROC_NAME in proc.name():
proc.send_signal(signal.SIGHUP)
break
except psutil.NoSuchProcess:
continue

def dump_dhcp4_config(self):
"""
Expand Down
7 changes: 6 additions & 1 deletion src/sonic-dhcp-utilities/tests/common_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,22 @@ def mock_get_config_db_table(table_name):


class MockProc(object):
def __init__(self, name, pid=None, status=psutil.STATUS_RUNNING):
def __init__(self, name, pid=1, exited=False):
self.proc_name = name
self.pid = pid
self.exited = exited

def name(self):
if self.exited:
raise psutil.NoSuchProcess(self.pid)
return self.proc_name

def send_signal(self, sig_num):
pass

def cmdline(self):
if self.exited:
raise psutil.NoSuchProcess(self.pid)
if self.proc_name == "dhcrelay":
return ["/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file",
"/tmp/port-name-alias-map.txt", "-id", "Vlan1000", "-iu", "docker0", "240.127.1.2"]
Expand Down
21 changes: 13 additions & 8 deletions src/sonic-dhcp-utilities/tests/test_dhcprelayd.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def test_kill_exist_relay_releated_process(mock_swsscommon_dbconnector_init, new
process_iter_ret = []
for running_proc in running_procs:
process_iter_ret.append(MockProc(running_proc))
process_iter_ret.append(MockProc("exited_proc", exited=True))
with patch.object(psutil, "process_iter", return_value=process_iter_ret), \
patch.object(ConfigDbEventChecker, "enable"):
dhcp_db_connector = DhcpDbConnector()
Expand Down Expand Up @@ -194,23 +195,27 @@ def test_execute_supervisor_dhcp_relay_process(mock_swsscommon_dbconnector_init,
mock_run.assert_called_once_with(["supervisorctl", op, "dhcpmon-Vlan1000"], check=True)


@pytest.mark.parametrize("target_cmds", [[["/usr/bin/dhcrelay"]], [["/usr/bin/dhcpmon"]]])
def test_check_dhcp_relay_process(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init, target_cmds):
exp_config = {"isc-dhcpv4-relay-Vlan1000": ["/usr/bin/dhcrelay"]}
with patch("dhcp_utilities.dhcprelayd.dhcprelayd.get_target_process_cmds", return_value=target_cmds), \
@pytest.mark.parametrize("target_procs", [[MockProc("dhcrelay")], [MockProc("dhcrelay", exited=True)],
[MockProc("dhcpmon")]])
def test_check_dhcp_relay_process(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init, target_procs):
exp_config = {
"isc-dhcpv4-relay-Vlan1000": [
"/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file",
"/tmp/port-name-alias-map.txt", "-id", "Vlan1000", "-iu", "docker0", "240.127.1.2"
]
}
with patch("dhcp_utilities.dhcprelayd.dhcprelayd.get_target_process", return_value=target_procs), \
patch.object(DhcpRelayd, "dhcp_relay_supervisor_config",
return_value=exp_config, new_callable=PropertyMock), \
patch.object(sys, "exit", mock_exit_func):
dhcp_db_connector = DhcpDbConnector()
dhcprelayd = DhcpRelayd(dhcp_db_connector, None)
exp_cmds = [value for key, value in exp_config.items() if "isc-dhcpv4-relay" in key]
exp_cmds.sort()
try:
dhcprelayd._check_dhcp_relay_processes()
except SystemExit:
assert exp_cmds != target_cmds
assert target_procs[0].exited or target_procs[0].name() != "dhcrelay"
else:
assert exp_cmds == target_cmds
assert not target_procs[0].exited and target_procs[0].name() == "dhcrelay"


def test_get_dhcp_relay_config(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init):
Expand Down
1 change: 1 addition & 0 deletions src/sonic-dhcp-utilities/tests/test_dhcpservd.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def test_dump_dhcp4_config(mock_swsscommon_dbconnector_init, enabled_checker):
def test_notify_kea_dhcp4_proc(process_list, mock_swsscommon_dbconnector_init, mock_get_render_template,
mock_parse_port_map_alias):
proc_list = [MockProc(process_name) for process_name in process_list]
proc_list.append(MockProc("exited_proc", exited=True))
with patch.object(psutil, "process_iter", return_value=proc_list), \
patch.object(MockProc, "send_signal", MagicMock()) as mock_send_signal:
dhcp_db_connector = DhcpDbConnector()
Expand Down
17 changes: 6 additions & 11 deletions src/sonic-dhcp-utilities/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,12 @@ def test_validate_ttr_type(test_data):
assert res == test_data[2]


def test_get_target_process_cmds():
with patch.object(psutil, "process_iter", return_value=[MockProc("dhcrelay", 1), MockProc("dhcpmon", 2)],
new_callable=PropertyMock):
res = utils.get_target_process_cmds("dhcrelay")
expected_res = [
[
"/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file",
"/tmp/port-name-alias-map.txt", "-id", "Vlan1000", "-iu", "docker0", "240.127.1.2"
]
]
assert res == expected_res
def test_get_target_process():
proc_list = [MockProc("dhcrelay", 1), MockProc("dhcpmon", 2),
MockProc("exited_proc", 3, exited=True)]
with patch.object(psutil, "process_iter", return_value=proc_list, new_callable=PropertyMock):
res = utils.get_target_process("dhcrelay")
assert res == [proc_list[0]]


@pytest.mark.parametrize("is_smart_switch", [True, False])
Expand Down
Loading