an option named "mgr_disabled_modules" is added in this change to
prevent mgr from loading modules listed in this option. because mgr
loads *all* modules found in the configured path, and per
https://tracker.ceph.com/issues/45147, python subinterpreter could hang
when loading numpy, so this behavior practically creates a deadlock
in mgr.
this issue is found when mgr uses python3.8 runtime. in development
environment, it'd be inconvenient to disable the offending mgr module
without changing the source code, even if we can choose to not install
them, for instance, the enduser can workaround this issue by
uninstalling `ceph-mgr-diskprediction-local`.
an option would be useful in this case, so we can add the module to the
list before mgr tries to load it.
as this issue is found with python3.8 + diskprediction_local (numpy), so
this mgr module is disabled by default if mgr is compiled with python3.8
runtime.
Fixes: https://tracker.ceph.com/issues/45147
Signed-off-by: Kefu Chai <kchai@redhat.com>
(cherry picked from commit
067adbf9a032b5de793fd0b41b071f24f075270a)
set(MGR_PYTHON_LIBRARIES ${Python3_LIBRARIES})
set(MGR_PYTHON_VERSION_MAJOR ${Python3_VERSION_MAJOR})
set(MGR_PYTHON_VERSION_MINOR ${Python3_VERSION_MINOR})
+ # https://tracker.ceph.com/issues/45147
+ if(Python3_VERSION VERSION_GREATER_EQUAL 3.8)
+ set(MGR_DISABLED_MODULES "diskprediction_local")
+ message(STATUS "mgr module disabled for ${Python3_VERSION}: ${MGR_DISABLED_MODULES}")
+ endif()
# Boost dependency check deferred to Boost section
endif(WITH_MGR)
.add_service("mgr")
.set_description("Filesystem path to manager modules."),
+ Option("mgr_disabled_modules", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+#ifdef MGR_DISABLED_MODULES
+ .set_default(MGR_DISABLED_MODULES)
+#endif
+ .set_flag(Option::FLAG_STARTUP)
+ .add_service("mgr")
+ .set_description("List of manager modules never get loaded")
+ .set_long_description("A comma delimited list of module names. This list "
+ "is read by manager when it starts. By default, manager loads all "
+ "modules found in specified 'mgr_module_path', and it starts the "
+ "enabled ones as instructed. The modules in this list will not be "
+ "loaded at all.")
+ .add_see_also("mgr_module_path"),
+
Option("mgr_initial_modules", Option::TYPE_STR, Option::LEVEL_BASIC)
.set_default("restful iostat")
.set_flag(Option::FLAG_NO_MON_UPDATE)
#cmakedefine MGR_PYTHON_EXECUTABLE "@MGR_PYTHON_EXECUTABLE@"
+/* the default value of "mgr_disabled_module" option */
+#cmakedefine MGR_DISABLED_MODULES "@MGR_DISABLED_MODULES@"
+
/* Define to 1 if you have the `getprogname' function. */
#cmakedefine HAVE_GETPROGNAME 1
#include "include/stringify.h"
#include "common/errno.h"
+#include "common/split.h"
#include "BaseMgrModule.h"
#include "PyOSDMap.h"
std::set<std::string> PyModuleRegistry::probe_modules(const std::string &path) const
{
+ const auto opt = g_conf().get_val<std::string>("mgr_disabled_modules");
+ const auto disabled_modules = ceph::split(opt);
+
std::set<std::string> modules;
for (const auto& entry: fs::directory_iterator(path)) {
if (!fs::is_directory(entry)) {
continue;
}
+ const std::string name = entry.path().filename();
+ if (std::count(disabled_modules.begin(), disabled_modules.end(), name)) {
+ dout(10) << "ignoring disabled module " << name << dendl;
+ continue;
+ }
auto module_path = entry.path() / "module.py";
if (fs::exists(module_path)) {
- modules.emplace(entry.path().filename());
+ modules.emplace(name);
}
}
return modules;