Skip to content

Commit

Permalink
NAS-133125 / 25.04 / remove psutil from webshell_app.py (#15224)
Browse files Browse the repository at this point in the history
* remove psutil from webshell_app.py

* address review

* address review
  • Loading branch information
yocalebo authored Dec 17, 2024
1 parent 5d1a781 commit 479c09a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 32 deletions.
28 changes: 3 additions & 25 deletions src/middlewared/middlewared/apps/webshell_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,20 @@
import json
import os
import queue
import signal
import struct
import termios
import threading
import time
import uuid


import psutil

from middlewared.api.base.server.ws_handler.base import BaseWebSocketHandler
from middlewared.service_exception import (
CallError,
ErrnoMixin,
InstanceNotFound,
MatchNotFound,
)
from middlewared.utils.os import close_fds
from middlewared.utils.os import close_fds, terminate_pid

__all__ = ("ShellApplication",)

Expand Down Expand Up @@ -200,7 +196,7 @@ def abort(self):
asyncio.run_coroutine_threadsafe(self.ws.close(), self.loop)

with contextlib.suppress(ProcessLookupError):
os.kill(self.shell_pid, signal.SIGTERM)
terminate_pid(self.shell_pid, timeout=5, use_pgid=True)

self.die()

Expand Down Expand Up @@ -363,22 +359,4 @@ async def run(self, ws, origin, conndata):
return ws

async def worker_kill(self, t_worker):
def worker_kill_impl():
# If connection has been closed lets make sure shell is killed
if t_worker.shell_pid:
with contextlib.suppress(psutil.NoSuchProcess):
shell = psutil.Process(t_worker.shell_pid)
to_terminate = [shell] + shell.children(recursive=True)

for p in to_terminate:
with contextlib.suppress(psutil.NoSuchProcess):
p.terminate()
gone, alive = psutil.wait_procs(to_terminate, timeout=2)

for p in alive:
with contextlib.suppress(psutil.NoSuchProcess):
p.kill()

t_worker.join()

await self.middleware.run_in_thread(worker_kill_impl)
await self.middleware.run_in_thread(t_worker.abort)
31 changes: 24 additions & 7 deletions src/middlewared/middlewared/utils/os.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections.abc import Generator
from dataclasses import dataclass
from functools import cached_property
from os import closerange, kill, scandir
from os import closerange, getpgid, kill, killpg, scandir
from resource import getrlimit, RLIMIT_NOFILE, RLIM_INFINITY
from signal import SIGKILL, SIGTERM
from time import sleep, time
Expand Down Expand Up @@ -42,12 +42,29 @@ def close_fds(low_fd, max_fd=None):
closerange(low_fd, max_fd)


def terminate_pid(pid: int, timeout: int = 10) -> bool:
# Send SIGTERM to request the process to terminate
kill(pid, SIGTERM)
def terminate_pid(pid: int, timeout: int = 10, use_pgid: bool = False) -> bool:
"""
Send SIGTERM to `pid` and wait `timeout` seconds for the process to terminate.
If the process is still alive after `timeout`, proceed to send SIGKILL to the
process.
`pid`: integer represents the PID to terminate.
`timeout`: integer represents the total time (in seconds) to wait
before sending SIGKILL to `pid` if the process doesn't honor
SIGTERM or takes longer than `timeout` seconds to terminate.
`use_pgid`: boolean, if true will lookup the process group id of
`pid` and apply the same logic.
"""
pid_or_pgid, method = pid, kill
if use_pgid:
method = killpg
pid_or_pgid = getpgid(pid)

# Send SIGTERM to request the process (group) to terminate
method(pid_or_pgid, SIGTERM)

try:
kill(pid, ALIVE_SIGNAL)
method(pid_or_pgid, ALIVE_SIGNAL)
except ProcessLookupError:
# SIGTERM was honored
return True
Expand All @@ -56,7 +73,7 @@ def terminate_pid(pid: int, timeout: int = 10) -> bool:
start_time = time()
while True:
try:
kill(pid, ALIVE_SIGNAL)
method(pid_or_pgid, ALIVE_SIGNAL)
except ProcessLookupError:
# SIGTERM was honored (eventually)
return True
Expand All @@ -70,7 +87,7 @@ def terminate_pid(pid: int, timeout: int = 10) -> bool:

try:
# Send SIGKILL to forcefully terminate the process
kill(pid, SIGKILL)
method(pid_or_pgid, SIGKILL)
return False
except ProcessLookupError:
# Process may have terminated between checks
Expand Down

0 comments on commit 479c09a

Please sign in to comment.