]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr: add ceph binding for exit
authorPatrick Donnelly <pdonnell@ibm.com>
Tue, 3 Mar 2026 16:36:12 +0000 (11:36 -0500)
committerPatrick Donnelly <pdonnell@ibm.com>
Thu, 5 Mar 2026 14:10:32 +0000 (09:10 -0500)
So we can work around modules disabling calls to sys._exit

Fixes: https://tracker.ceph.com/issues/74605
Fixes: 78983ad0d0cce422da32dc4876ac186f6d32c3f5
Fixes: ceph/ceph.git#66244
Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
src/mgr/BaseMgrModule.cc
src/pybind/mgr/ceph_module.pyi

index 4de20b9d7e2cfa64e8f54d8b0322a73a76f77c5a..efaba4b37fab3f1ec120f8c4e1adaed35be110f0 100644 (file)
@@ -1491,7 +1491,39 @@ ceph_get_daemon_health_metrics(BaseMgrModule *self, PyObject *args)
   return self->py_modules->get_daemon_health_metrics();
 }
 
+static PyObject*
+ceph_exit(BaseMgrModule *self, PyObject *args, PyObject *kwargs)
+{
+  int status = 0;
+  int hard = 0;
+  static const char *keywords[] = { "status", "hard", nullptr };
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|p:ceph_exit",
+        const_cast<char**>(keywords), &status, &hard)) {
+    return nullptr;
+  }
+
+
+  if (hard) {
+    // Immediate OS-level termination via syscall exit_group or similar.
+    // XXX DO NOT RELEASE THE GIL
+    ::_exit(status);
+  } else {
+    // Standard C library exit (runs atexit handlers, flushes stdio)
+    // It is good practice to release the GIL before abruptly terminating the C process.
+    PyThreadState *tstate = PyEval_SaveThread();
+    std::exit(status);
+    PyEval_RestoreThread(tstate);
+  }
+  ceph_abort();
+
+  Py_RETURN_NONE;
+}
+
 PyMethodDef BaseMgrModule_methods[] = {
+  {"_ceph_exit", (PyCFunction)ceph_exit, METH_VARARGS | METH_KEYWORDS,
+   "Exit the ceph-mgr process directly, bypassing Python's sys/os modules."},
+
   {"_ceph_get", (PyCFunction)ceph_state_get, METH_VARARGS,
    "Get a cluster object"},
 
index 69eb7e863def4357ee1ef8995bd92a458ccdc828..3f37576c4b6f884b4c9cc8e60c842da520df8f33 100644 (file)
@@ -63,6 +63,7 @@ PerfCounterT = Dict[str, Any]
 
 class BaseMgrModule(object):
     def __init__(self, py_modules_ptr: object, this_ptr: object) -> None: pass
+    def _ceph_exit(self, status: int, hard: bool = False) -> None: ...
     def _ceph_get_version(self) -> str: ...
     def _ceph_get_release_name(self) -> str: ...
     def _ceph_lookup_release_name(self, release: int) -> str: ...