]>
git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/StandbyPyModules.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
14 #include "StandbyPyModules.h"
16 #include "common/debug.h"
18 #include "mgr/MgrContext.h"
22 #include <boost/python.hpp>
23 #include "include/assert.h" // boost clobbers this
25 // For ::config_prefix
26 #include "PyModuleRegistry.h"
28 #define dout_context g_ceph_context
29 #define dout_subsys ceph_subsys_mgr
31 #define dout_prefix *_dout << "mgr " << __func__ << " "
33 // Declaration fulfilled by ActivePyModules
34 std::string
handle_pyerror();
37 StandbyPyModules::StandbyPyModules(MonClient
*monc_
, const MgrMap
&mgr_map_
)
38 : monc(monc_
), load_config_thread(monc
, &state
)
40 state
.set_mgr_map(mgr_map_
);
43 // FIXME: completely identical to ActivePyModules
44 void StandbyPyModules::shutdown()
46 Mutex::Locker
locker(lock
);
48 if (!state
.is_config_loaded
&& load_config_thread
.is_started()) {
49 // FIXME: handle cases where initial load races with shutdown
50 // this is actually not super rare because
52 //load_config_thread.kill(SIGKILL);
55 // Signal modules to drop out of serve() and/or tear down resources
56 for (auto &i
: modules
) {
57 auto module
= i
.second
.get();
58 const auto& name
= i
.first
;
59 dout(10) << "waiting for module " << name
<< " to shutdown" << dendl
;
63 dout(10) << "module " << name
<< " shutdown" << dendl
;
66 // For modules implementing serve(), finish the threads where we
68 for (auto &i
: modules
) {
70 dout(10) << "joining thread for module " << i
.first
<< dendl
;
71 i
.second
->thread
.join();
72 dout(10) << "joined thread for module " << i
.first
<< dendl
;
79 int StandbyPyModules::start_one(std::string
const &module_name
,
80 PyObject
*pClass
, const SafeThreadState
&pMyThreadState
)
82 Mutex::Locker
l(lock
);
84 assert(modules
.count(module_name
) == 0);
86 modules
[module_name
].reset(new StandbyPyModule(
91 if (modules
.size() == 1) {
92 load_config_thread
.create("LoadConfig");
95 int r
= modules
[module_name
]->load();
97 modules
.erase(module_name
);
100 dout(4) << "Starting thread for " << module_name
<< dendl
;
101 // Giving Thread the module's module_name member as its
102 // char* thread name: thread must not outlive module class lifetime.
103 modules
[module_name
]->thread
.create(
104 modules
[module_name
]->get_name().c_str());
109 int StandbyPyModule::load()
111 Gil
gil(pMyThreadState
, true);
113 // We tell the module how we name it, so that it can be consistent
114 // with us in logging etc.
115 auto pThisPtr
= PyCapsule_New(this, nullptr, nullptr);
116 assert(pThisPtr
!= nullptr);
117 auto pModuleName
= PyString_FromString(module_name
.c_str());
118 assert(pModuleName
!= nullptr);
119 auto pArgs
= PyTuple_Pack(2, pModuleName
, pThisPtr
);
121 Py_DECREF(pModuleName
);
123 pClassInstance
= PyObject_CallObject(pClass
, pArgs
);
125 if (pClassInstance
== nullptr) {
126 derr
<< "Failed to construct class in '" << module_name
<< "'" << dendl
;
127 derr
<< handle_pyerror() << dendl
;
130 dout(1) << "Constructed class from module: " << module_name
<< dendl
;
135 void *StandbyPyModules::LoadConfigThread::entry()
137 dout(10) << "listing keys" << dendl
;
139 cmd
.run(monc
, "{\"prefix\": \"config-key ls\"}");
143 std::map
<std::string
, std::string
> loaded
;
145 for (auto &key_str
: cmd
.json_result
.get_array()) {
146 std::string
const key
= key_str
.get_str();
147 dout(20) << "saw key '" << key
<< "'" << dendl
;
149 const std::string config_prefix
= PyModuleRegistry::config_prefix
;
151 if (key
.substr(0, config_prefix
.size()) == config_prefix
) {
152 dout(20) << "fetching '" << key
<< "'" << dendl
;
154 std::ostringstream cmd_json
;
155 cmd_json
<< "{\"prefix\": \"config-key get\", \"key\": \"" << key
<< "\"}";
156 get_cmd
.run(monc
, cmd_json
.str());
158 assert(get_cmd
.r
== 0);
159 loaded
[key
] = get_cmd
.outbl
.to_str();
162 state
->loaded_config(loaded
);
167 bool StandbyPyModule::get_config(const std::string
&key
,
168 std::string
*value
) const
170 PyThreadState
*tstate
= PyEval_SaveThread();
171 PyEval_RestoreThread(tstate
);
173 const std::string global_key
= PyModuleRegistry::config_prefix
174 + module_name
+ "/" + key
;
176 dout(4) << __func__
<< "key: " << global_key
<< dendl
;
178 return state
.with_config([global_key
, value
](const PyModuleConfig
&config
){
179 if (config
.count(global_key
)) {
180 *value
= config
.at(global_key
);
188 std::string
StandbyPyModule::get_active_uri() const
191 state
.with_mgr_map([&result
, this](const MgrMap
&mgr_map
){
192 auto iter
= mgr_map
.services
.find(module_name
);
193 if (iter
!= mgr_map
.services
.end()) {
194 result
= iter
->second
;