#include <Python.h>
#include "common/errno.h"
+#include "common/signal.h"
+#include "include/compat.h"
#include "include/stringify.h"
#include "global/global_context.h"
#define dout_prefix *_dout << "mgr " << __func__ << " "
-MgrStandby::MgrStandby() :
+MgrStandby::MgrStandby(int argc, const char **argv) :
Dispatcher(g_ceph_context),
monc{g_ceph_context},
client_messenger(Messenger::create_client_messenger(g_ceph_context, "mgr")),
audit_clog(log_client.create_channel(CLOG_CHANNEL_AUDIT)),
lock("MgrStandby::lock"),
timer(g_ceph_context, lock),
- active_mgr(nullptr)
+ active_mgr(nullptr),
+ orig_argc(argc),
+ orig_argv(argv),
+ available_in_map(false)
{
}
client.init();
timer.init();
- send_beacon();
+ tick();
dout(4) << "Complete." << dendl;
return 0;
{
assert(lock.is_locked_by_me());
dout(1) << state_str() << dendl;
- dout(10) << "sending beacon as gid " << monc.get_global_id() << dendl;
+ set<string> modules;
+ PyModules::list_modules(&modules);
+
+ // Whether I think I am available (request MgrMonitor to set me
+ // as available in the map)
bool available = active_mgr != nullptr && active_mgr->is_initialized();
+
auto addr = available ? active_mgr->get_server_addr() : entity_addr_t();
+ dout(10) << "sending beacon as gid " << monc.get_global_id()
+ << " modules " << modules << dendl;
+
+ map<string,string> metadata;
+ collect_sys_info(&metadata, g_ceph_context);
+
MMgrBeacon *m = new MMgrBeacon(monc.get_fsid(),
monc.get_global_id(),
g_conf->name.get_id(),
addr,
- available);
+ available,
+ modules,
+ std::move(metadata));
+
+ if (available && !available_in_map) {
+ // We are informing the mon that we are done initializing: inform
+ // it of our command set. This has to happen after init() because
+ // it needs the python modules to have loaded.
+ m->set_command_descs(active_mgr->get_command_set());
+ dout(4) << "going active, including " << m->get_command_descs().size()
+ << " commands in beacon" << dendl;
+ }
monc.send_mon_message(m);
- timer.add_event_after(g_conf->mgr_beacon_period, new FunctionContext(
+}
+
+void MgrStandby::tick()
+{
+ dout(10) << __func__ << dendl;
+ send_beacon();
+
+ if (active_mgr) {
+ active_mgr->tick();
+ }
+
+ timer.add_event_after(g_conf->mgr_tick_period, new FunctionContext(
[this](int r){
- send_beacon();
+ tick();
}
));
}
client_messenger->shutdown();
}
+void MgrStandby::respawn()
+{
+ char *new_argv[orig_argc+1];
+ dout(1) << " e: '" << orig_argv[0] << "'" << dendl;
+ for (int i=0; i<orig_argc; i++) {
+ new_argv[i] = (char *)orig_argv[i];
+ dout(1) << " " << i << ": '" << orig_argv[i] << "'" << dendl;
+ }
+ new_argv[orig_argc] = NULL;
+
+ /* Determine the path to our executable, test if Linux /proc/self/exe exists.
+ * This allows us to exec the same executable even if it has since been
+ * unlinked.
+ */
+ char exe_path[PATH_MAX] = "";
+ if (readlink(PROCPREFIX "/proc/self/exe", exe_path, PATH_MAX-1) == -1) {
+ /* Print CWD for the user's interest */
+ char buf[PATH_MAX];
+ char *cwd = getcwd(buf, sizeof(buf));
+ assert(cwd);
+ dout(1) << " cwd " << cwd << dendl;
+
+ /* Fall back to a best-effort: just running in our CWD */
+ strncpy(exe_path, orig_argv[0], PATH_MAX-1);
+ } else {
+ dout(1) << "respawning with exe " << exe_path << dendl;
+ strcpy(exe_path, PROCPREFIX "/proc/self/exe");
+ }
+
+ dout(1) << " exe_path " << exe_path << dendl;
+
+ unblock_all_signals(NULL);
+ execv(exe_path, new_argv);
+
+ derr << "respawn execv " << orig_argv[0]
+ << " failed with " << cpp_strerror(errno) << dendl;
+ ceph_abort();
+}
+
void MgrStandby::_update_log_config()
{
map<string,string> log_to_monitors;
void MgrStandby::handle_mgr_map(MMgrMap* mmap)
{
- auto map = mmap->get_map();
+ auto &map = mmap->get_map();
dout(4) << "received map epoch " << map.get_epoch() << dendl;
const bool active_in_map = map.active_gid == monc.get_global_id();
dout(4) << "active in map: " << active_in_map
if (active_in_map) {
if (!active_mgr) {
dout(1) << "Activating!" << dendl;
- active_mgr.reset(new Mgr(&monc, client_messenger.get(), &objecter,
+ active_mgr.reset(new Mgr(&monc, map, client_messenger.get(), &objecter,
&client, clog, audit_clog));
- active_mgr->background_init();
- dout(1) << "I am now active" << dendl;
+ active_mgr->background_init(new FunctionContext(
+ [this](int r){
+ // Advertise our active-ness ASAP instead of waiting for
+ // next tick.
+ Mutex::Locker l(lock);
+ send_beacon();
+ }));
+ dout(1) << "I am now activating" << dendl;
} else {
dout(10) << "I was already active" << dendl;
+ bool need_respawn = active_mgr->got_mgr_map(map);
+ if (need_respawn) {
+ respawn();
+ }
+ }
+
+ if (!available_in_map && map.get_available()) {
+ dout(4) << "Map now says I am available" << dendl;
+ available_in_map = true;
}
} else {
if (active_mgr != nullptr) {
derr << "I was active but no longer am" << dendl;
- active_mgr->shutdown();
- active_mgr.reset();
+ respawn();
}
}
Mutex::Locker l(lock);
dout(4) << state_str() << " " << *m << dendl;
- switch (m->get_type()) {
- case MSG_MGR_MAP:
- handle_mgr_map(static_cast<MMgrMap*>(m));
- break;
-
- default:
- if (active_mgr) {
- lock.Unlock();
- active_mgr->ms_dispatch(m);
- lock.Lock();
- } else {
- return false;
- }
+ if (m->get_type() == MSG_MGR_MAP) {
+ handle_mgr_map(static_cast<MMgrMap*>(m));
+ return true;
+ } else if (active_mgr) {
+ auto am = active_mgr;
+ lock.Unlock();
+ bool handled = am->ms_dispatch(m);
+ lock.Lock();
+ return handled;
+ } else {
+ return false;
}
-
- return true;
}