]> git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/MgrStandby.cc
update sources to v12.1.2
[ceph.git] / ceph / src / mgr / MgrStandby.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
7 *
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.
12 */
13
14 #include <Python.h>
15
16 #include "common/errno.h"
17 #include "common/signal.h"
18 #include "include/compat.h"
19
20 #include "include/stringify.h"
21 #include "global/global_context.h"
22 #include "global/signal_handler.h"
23
24 #include "mgr/MgrContext.h"
25
26 #include "messages/MMgrBeacon.h"
27 #include "messages/MMgrMap.h"
28 #include "Mgr.h"
29
30 #include "MgrStandby.h"
31
32 #define dout_context g_ceph_context
33 #define dout_subsys ceph_subsys_mgr
34 #undef dout_prefix
35 #define dout_prefix *_dout << "mgr " << __func__ << " "
36
37
38 MgrStandby::MgrStandby(int argc, const char **argv) :
39 Dispatcher(g_ceph_context),
40 monc{g_ceph_context},
41 client_messenger(Messenger::create_client_messenger(g_ceph_context, "mgr")),
42 objecter{g_ceph_context, client_messenger.get(), &monc, NULL, 0, 0},
43 client{client_messenger.get(), &monc, &objecter},
44 log_client(g_ceph_context, client_messenger.get(), &monc.monmap, LogClient::NO_FLAGS),
45 clog(log_client.create_channel(CLOG_CHANNEL_CLUSTER)),
46 audit_clog(log_client.create_channel(CLOG_CHANNEL_AUDIT)),
47 lock("MgrStandby::lock"),
48 timer(g_ceph_context, lock),
49 active_mgr(nullptr),
50 orig_argc(argc),
51 orig_argv(argv),
52 available_in_map(false)
53 {
54 }
55
56 MgrStandby::~MgrStandby() = default;
57
58 const char** MgrStandby::get_tracked_conf_keys() const
59 {
60 static const char* KEYS[] = {
61 // clog & admin clog
62 "clog_to_monitors",
63 "clog_to_syslog",
64 "clog_to_syslog_facility",
65 "clog_to_syslog_level",
66 "osd_objectstore_fuse",
67 "clog_to_graylog",
68 "clog_to_graylog_host",
69 "clog_to_graylog_port",
70 "host",
71 "fsid",
72 NULL
73 };
74 return KEYS;
75 }
76
77 void MgrStandby::handle_conf_change(
78 const struct md_config_t *conf,
79 const std::set <std::string> &changed)
80 {
81 if (changed.count("clog_to_monitors") ||
82 changed.count("clog_to_syslog") ||
83 changed.count("clog_to_syslog_level") ||
84 changed.count("clog_to_syslog_facility") ||
85 changed.count("clog_to_graylog") ||
86 changed.count("clog_to_graylog_host") ||
87 changed.count("clog_to_graylog_port") ||
88 changed.count("host") ||
89 changed.count("fsid")) {
90 _update_log_config();
91 }
92 }
93
94 int MgrStandby::init()
95 {
96 Mutex::Locker l(lock);
97
98 // Initialize Messenger
99 client_messenger->add_dispatcher_tail(this);
100 client_messenger->add_dispatcher_head(&objecter);
101 client_messenger->add_dispatcher_tail(&client);
102 client_messenger->start();
103
104 // Initialize MonClient
105 if (monc.build_initial_monmap() < 0) {
106 client_messenger->shutdown();
107 client_messenger->wait();
108 return -1;
109 }
110
111 monc.sub_want("mgrmap", 0, 0);
112
113 monc.set_want_keys(CEPH_ENTITY_TYPE_MON|CEPH_ENTITY_TYPE_OSD
114 |CEPH_ENTITY_TYPE_MDS|CEPH_ENTITY_TYPE_MGR);
115 monc.set_messenger(client_messenger.get());
116 int r = monc.init();
117 if (r < 0) {
118 monc.shutdown();
119 client_messenger->shutdown();
120 client_messenger->wait();
121 return r;
122 }
123 r = monc.authenticate();
124 if (r < 0) {
125 derr << "Authentication failed, did you specify a mgr ID with a valid keyring?" << dendl;
126 monc.shutdown();
127 client_messenger->shutdown();
128 client_messenger->wait();
129 return r;
130 }
131
132 client_t whoami = monc.get_global_id();
133 client_messenger->set_myname(entity_name_t::CLIENT(whoami.v));
134 monc.set_log_client(&log_client);
135 _update_log_config();
136 objecter.set_client_incarnation(0);
137 objecter.init();
138 objecter.start();
139 client.init();
140 timer.init();
141
142 tick();
143
144 dout(4) << "Complete." << dendl;
145 return 0;
146 }
147
148 void MgrStandby::send_beacon()
149 {
150 assert(lock.is_locked_by_me());
151 dout(1) << state_str() << dendl;
152
153 set<string> modules;
154 PyModules::list_modules(&modules);
155
156 // Whether I think I am available (request MgrMonitor to set me
157 // as available in the map)
158 bool available = active_mgr != nullptr && active_mgr->is_initialized();
159
160 auto addr = available ? active_mgr->get_server_addr() : entity_addr_t();
161 dout(10) << "sending beacon as gid " << monc.get_global_id()
162 << " modules " << modules << dendl;
163
164 map<string,string> metadata;
165 collect_sys_info(&metadata, g_ceph_context);
166
167 MMgrBeacon *m = new MMgrBeacon(monc.get_fsid(),
168 monc.get_global_id(),
169 g_conf->name.get_id(),
170 addr,
171 available,
172 modules,
173 std::move(metadata));
174
175 if (available && !available_in_map) {
176 // We are informing the mon that we are done initializing: inform
177 // it of our command set. This has to happen after init() because
178 // it needs the python modules to have loaded.
179 m->set_command_descs(active_mgr->get_command_set());
180 dout(4) << "going active, including " << m->get_command_descs().size()
181 << " commands in beacon" << dendl;
182 }
183
184 monc.send_mon_message(m);
185 }
186
187 void MgrStandby::tick()
188 {
189 dout(10) << __func__ << dendl;
190 send_beacon();
191
192 if (active_mgr) {
193 active_mgr->tick();
194 }
195
196 timer.add_event_after(g_conf->mgr_tick_period, new FunctionContext(
197 [this](int r){
198 tick();
199 }
200 ));
201 }
202
203 void MgrStandby::handle_signal(int signum)
204 {
205 Mutex::Locker l(lock);
206 assert(signum == SIGINT || signum == SIGTERM);
207 derr << "*** Got signal " << sig_str(signum) << " ***" << dendl;
208 shutdown();
209 }
210
211 void MgrStandby::shutdown()
212 {
213 // Expect already to be locked as we're called from signal handler
214 assert(lock.is_locked_by_me());
215
216 // stop sending beacon first, i use monc to talk with monitors
217 timer.shutdown();
218 // client uses monc and objecter
219 client.shutdown();
220 // stop monc, so mon won't be able to instruct me to shutdown/activate after
221 // the active_mgr is stopped
222 monc.shutdown();
223 if (active_mgr) {
224 active_mgr->shutdown();
225 }
226 // objecter is used by monc and active_mgr
227 objecter.shutdown();
228 // client_messenger is used by all of them, so stop it in the end
229 client_messenger->shutdown();
230 }
231
232 void MgrStandby::respawn()
233 {
234 char *new_argv[orig_argc+1];
235 dout(1) << " e: '" << orig_argv[0] << "'" << dendl;
236 for (int i=0; i<orig_argc; i++) {
237 new_argv[i] = (char *)orig_argv[i];
238 dout(1) << " " << i << ": '" << orig_argv[i] << "'" << dendl;
239 }
240 new_argv[orig_argc] = NULL;
241
242 /* Determine the path to our executable, test if Linux /proc/self/exe exists.
243 * This allows us to exec the same executable even if it has since been
244 * unlinked.
245 */
246 char exe_path[PATH_MAX] = "";
247 if (readlink(PROCPREFIX "/proc/self/exe", exe_path, PATH_MAX-1) == -1) {
248 /* Print CWD for the user's interest */
249 char buf[PATH_MAX];
250 char *cwd = getcwd(buf, sizeof(buf));
251 assert(cwd);
252 dout(1) << " cwd " << cwd << dendl;
253
254 /* Fall back to a best-effort: just running in our CWD */
255 strncpy(exe_path, orig_argv[0], PATH_MAX-1);
256 } else {
257 dout(1) << "respawning with exe " << exe_path << dendl;
258 strcpy(exe_path, PROCPREFIX "/proc/self/exe");
259 }
260
261 dout(1) << " exe_path " << exe_path << dendl;
262
263 unblock_all_signals(NULL);
264 execv(exe_path, new_argv);
265
266 derr << "respawn execv " << orig_argv[0]
267 << " failed with " << cpp_strerror(errno) << dendl;
268 ceph_abort();
269 }
270
271 void MgrStandby::_update_log_config()
272 {
273 map<string,string> log_to_monitors;
274 map<string,string> log_to_syslog;
275 map<string,string> log_channel;
276 map<string,string> log_prio;
277 map<string,string> log_to_graylog;
278 map<string,string> log_to_graylog_host;
279 map<string,string> log_to_graylog_port;
280 uuid_d fsid;
281 string host;
282
283 if (parse_log_client_options(cct, log_to_monitors, log_to_syslog,
284 log_channel, log_prio, log_to_graylog,
285 log_to_graylog_host, log_to_graylog_port,
286 fsid, host) == 0) {
287 clog->update_config(log_to_monitors, log_to_syslog,
288 log_channel, log_prio, log_to_graylog,
289 log_to_graylog_host, log_to_graylog_port,
290 fsid, host);
291 audit_clog->update_config(log_to_monitors, log_to_syslog,
292 log_channel, log_prio, log_to_graylog,
293 log_to_graylog_host, log_to_graylog_port,
294 fsid, host);
295 }
296 }
297
298 void MgrStandby::handle_mgr_map(MMgrMap* mmap)
299 {
300 auto &map = mmap->get_map();
301 dout(4) << "received map epoch " << map.get_epoch() << dendl;
302 const bool active_in_map = map.active_gid == monc.get_global_id();
303 dout(4) << "active in map: " << active_in_map
304 << " active is " << map.active_gid << dendl;
305 if (active_in_map) {
306 if (!active_mgr) {
307 dout(1) << "Activating!" << dendl;
308 active_mgr.reset(new Mgr(&monc, map, client_messenger.get(), &objecter,
309 &client, clog, audit_clog));
310 active_mgr->background_init(new FunctionContext(
311 [this](int r){
312 // Advertise our active-ness ASAP instead of waiting for
313 // next tick.
314 Mutex::Locker l(lock);
315 send_beacon();
316 }));
317 dout(1) << "I am now activating" << dendl;
318 } else {
319 dout(10) << "I was already active" << dendl;
320 bool need_respawn = active_mgr->got_mgr_map(map);
321 if (need_respawn) {
322 respawn();
323 }
324 }
325
326 if (!available_in_map && map.get_available()) {
327 dout(4) << "Map now says I am available" << dendl;
328 available_in_map = true;
329 }
330 } else {
331 if (active_mgr != nullptr) {
332 derr << "I was active but no longer am" << dendl;
333 respawn();
334 }
335 }
336
337 mmap->put();
338 }
339
340 bool MgrStandby::ms_dispatch(Message *m)
341 {
342 Mutex::Locker l(lock);
343 dout(4) << state_str() << " " << *m << dendl;
344
345 if (m->get_type() == MSG_MGR_MAP) {
346 handle_mgr_map(static_cast<MMgrMap*>(m));
347 return true;
348 } else if (active_mgr) {
349 auto am = active_mgr;
350 lock.Unlock();
351 bool handled = am->ms_dispatch(m);
352 lock.Lock();
353 return handled;
354 } else {
355 return false;
356 }
357 }
358
359
360 bool MgrStandby::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer,
361 bool force_new)
362 {
363 if (dest_type == CEPH_ENTITY_TYPE_MON)
364 return true;
365
366 if (force_new) {
367 if (monc.wait_auth_rotating(10) < 0)
368 return false;
369 }
370
371 *authorizer = monc.build_authorizer(dest_type);
372 return *authorizer != NULL;
373 }
374
375 bool MgrStandby::ms_handle_refused(Connection *con)
376 {
377 // do nothing for now
378 return false;
379 }
380
381 // A reference for use by the signal handler
382 static MgrStandby *signal_mgr = nullptr;
383
384 static void handle_mgr_signal(int signum)
385 {
386 if (signal_mgr) {
387 signal_mgr->handle_signal(signum);
388 }
389 }
390
391 int MgrStandby::main(vector<const char *> args)
392 {
393 // Enable signal handlers
394 signal_mgr = this;
395 init_async_signal_handler();
396 register_async_signal_handler(SIGHUP, sighup_handler);
397 register_async_signal_handler_oneshot(SIGINT, handle_mgr_signal);
398 register_async_signal_handler_oneshot(SIGTERM, handle_mgr_signal);
399
400 client_messenger->wait();
401
402 // Disable signal handlers
403 unregister_async_signal_handler(SIGHUP, sighup_handler);
404 unregister_async_signal_handler(SIGINT, handle_mgr_signal);
405 unregister_async_signal_handler(SIGTERM, handle_mgr_signal);
406 shutdown_async_signal_handler();
407 signal_mgr = nullptr;
408
409 return 0;
410 }
411
412
413 std::string MgrStandby::state_str()
414 {
415 return active_mgr == nullptr ? "standby" : "active";
416 }
417