mirror_frr/tests/topotests/munet/cleanup.py
Christian Hopps a465000035 tests: munet: update to version 0.14.9
Topotest relevant changes:

    - add support for `timeout` arg to `cmd_*()`
    - handle invalid regexp in CLI commands
    - fix long interface name support

Full munet changelog:

    munet: 0.14.9: add support for `timeout` arg to `cmd_*()`
    munet: 0.14.8: cleanup the cleanup (kill) on launch options
    munet: 0.14.7: allow multiple extra commands for shell console init
    munet: 0.14.6:
      - qemu: gather gcda files where munet can find them
      - handle invalid regexp in CLI commands
    munet: 0.14.5:
      - (podman) pull missing images for containers
      - fix long interface name support
      - add another router example
    munet: 0.14.4: mutest: add color to PASS/FAIL indicators on tty consoles
    munet: 0.14.3: Add hostnet node that runs it's commands in the host network namespace.
    munet: 0.14.2:
      - always fail mutest tests on bad json inputs
      - improve ssh-remote for common use-case of connecting to host connected devices
      - fix ready-cmd for python v3.11+
    munet: 0.14.1: Improved host interface support.

Signed-off-by: Christian Hopps <chopps@labn.net>
2024-06-06 08:50:05 +00:00

127 lines
3.8 KiB
Python

# -*- coding: utf-8 eval: (blacken-mode 1) -*-
# SPDX-License-Identifier: GPL-2.0-or-later
#
# September 30 2021, Christian Hopps <chopps@labn.net>
#
# Copyright 2021, LabN Consulting, L.L.C.
#
"""Provides functionality to cleanup processes on posix systems."""
import glob
import logging
import os
import signal
def get_pids_with_env(has_var, has_val=None):
result = {}
for pidenv in glob.iglob("/proc/*/environ"):
pid = pidenv.split("/")[2]
try:
with open(pidenv, "rb") as rfb:
envlist = [
x.decode("utf-8").split("=", 1) for x in rfb.read().split(b"\0")
]
envlist = [[x[0], ""] if len(x) == 1 else x for x in envlist]
envdict = dict(envlist)
if has_var not in envdict:
continue
if has_val is None:
result[pid] = envdict
elif envdict[has_var] == str(has_val):
result[pid] = envdict
except Exception:
# E.g., process exited and files are gone
pass
return result
def _kill_piddict(pids_by_upid, sig):
ourpid = str(os.getpid())
for upid, pids in pids_by_upid:
logging.info("Sending %s to (%s) of munet pid %s", sig, ", ".join(pids), upid)
for pid in pids:
try:
if pid != ourpid:
cmdline = open(f"/proc/{pid}/cmdline", "r", encoding="ascii").read()
cmdline = cmdline.replace("\x00", " ")
logging.info("killing proc %s (%s)", pid, cmdline)
os.kill(int(pid), sig)
except Exception:
pass
def _get_our_pids():
ourpid = str(os.getpid())
piddict = get_pids_with_env("MUNET_PID", ourpid)
pids = [x for x in piddict if x != ourpid]
if pids:
return {ourpid: pids}
return {}
def _get_other_pids(rundir):
if rundir:
# get only munet pids using the given rundir
piddict = get_pids_with_env("MUNET_RUNDIR", str(rundir))
else:
# Get all munet pids
piddict = get_pids_with_env("MUNET_PID")
unet_pids = {d["MUNET_PID"] for d in piddict.values() if "MUNET_PID" in d}
pids_by_upid = {p: set() for p in unet_pids}
for pid, envdict in piddict.items():
if "MUNET_PID" not in envdict:
continue
unet_pid = envdict["MUNET_PID"]
pids_by_upid[unet_pid].add(pid)
# Filter out any child pid sets whos munet pid is still running
return {x: y for x, y in pids_by_upid.items() if x not in y}
def _get_pids_by_upid(ours, rundir):
if ours:
assert rundir is None
return _get_our_pids()
return _get_other_pids(rundir)
def _cleanup_pids(ours, rundir):
pids_by_upid = _get_pids_by_upid(ours, rundir).items()
if not pids_by_upid:
return
t = "current" if ours else "previous"
logging.info("Reaping %s munet processes", t)
# _kill_piddict(pids_by_upid, signal.SIGTERM)
# # Give them 5 second to exit cleanly
# logging.info("Waiting up to 5s to allow for clean exit of abandon'd pids")
# for _ in range(0, 5):
# pids_by_upid = _get_pids_by_upid(ours).items()
# if not pids_by_upid:
# return
# time.sleep(1)
pids_by_upid = _get_pids_by_upid(ours, rundir).items()
_kill_piddict(pids_by_upid, signal.SIGKILL)
def cleanup_current():
"""Attempt to cleanup preview runs.
Currently this only scans for old processes.
"""
_cleanup_pids(True, None)
def cleanup_previous(rundir=None):
"""Attempt to cleanup preview runs.
Currently this only scans for old processes.
"""
_cleanup_pids(False, rundir)
def is_running_in_rundir(rundir):
return bool(get_pids_with_env("MUNET_RUNDIR", str(rundir)))