This source file includes following definitions.
- st_ipc_accept
- st_ipc_dispatch
- st_ipc_closed
- st_ipc_destroy
- stonith_peer_callback
- stonith_peer_ais_callback
- stonith_peer_cs_destroy
- do_local_reply
- get_stonith_flag
- stonith_notify_client
- do_stonith_async_timeout_update
- fenced_send_notification
- fenced_send_config_notification
- node_does_watchdog_fencing
- stonith_shutdown
- stonith_cleanup
- stand_alone_cpg_cb
- st_peer_update_callback
- fencer_metadata
- build_arg_context
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 #include <sys/utsname.h>
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23
24 #include <crm/crm.h>
25 #include <crm/common/cmdline_internal.h>
26 #include <crm/common/ipc.h>
27 #include <crm/common/ipc_internal.h>
28 #include <crm/common/output_internal.h>
29
30 #include <crm/stonith-ng.h>
31 #include <crm/fencing/internal.h>
32 #include <crm/common/xml.h>
33 #include <crm/common/xml_internal.h>
34
35 #include <crm/common/mainloop.h>
36
37 #include <crm/cib/internal.h>
38
39 #include <pacemaker-fenced.h>
40
41 #define SUMMARY "daemon for executing fencing devices in a Pacemaker cluster"
42
43 char *stonith_our_uname = NULL;
44 long long stonith_watchdog_timeout_ms = 0;
45 GList *stonith_watchdog_targets = NULL;
46
47 static GMainLoop *mainloop = NULL;
48
49 gboolean stand_alone = FALSE;
50 gboolean stonith_shutdown_flag = FALSE;
51
52 static qb_ipcs_service_t *ipcs = NULL;
53 static pcmk__output_t *out = NULL;
54
55 pcmk__supported_format_t formats[] = {
56 PCMK__SUPPORTED_FORMAT_NONE,
57 PCMK__SUPPORTED_FORMAT_TEXT,
58 PCMK__SUPPORTED_FORMAT_XML,
59 { NULL, NULL, NULL }
60 };
61
62 static struct {
63 bool no_cib_connect;
64 gchar **log_files;
65 } options;
66
67 crm_exit_t exit_code = CRM_EX_OK;
68
69 static void stonith_cleanup(void);
70
71 static int32_t
72 st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
73 {
74 if (stonith_shutdown_flag) {
75 crm_info("Ignoring new client [%d] during shutdown",
76 pcmk__client_pid(c));
77 return -ECONNREFUSED;
78 }
79
80 if (pcmk__new_client(c, uid, gid) == NULL) {
81 return -ENOMEM;
82 }
83 return 0;
84 }
85
86
87 static int32_t
88 st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
89 {
90 uint32_t id = 0;
91 uint32_t flags = 0;
92 int call_options = 0;
93 xmlNode *request = NULL;
94 pcmk__client_t *c = pcmk__find_client(qbc);
95 const char *op = NULL;
96
97 if (c == NULL) {
98 crm_info("Invalid client: %p", qbc);
99 return 0;
100 }
101
102 request = pcmk__client_data2xml(c, data, &id, &flags);
103 if (request == NULL) {
104 pcmk__ipc_send_ack(c, id, flags, PCMK__XE_NACK, NULL, CRM_EX_PROTOCOL);
105 return 0;
106 }
107
108
109 op = crm_element_value(request, PCMK__XA_CRM_TASK);
110 if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) {
111 crm_xml_add(request, PCMK__XA_T, PCMK__VALUE_STONITH_NG);
112 crm_xml_add(request, PCMK__XA_ST_OP, op);
113 crm_xml_add(request, PCMK__XA_ST_CLIENTID, c->id);
114 crm_xml_add(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c));
115 crm_xml_add(request, PCMK__XA_ST_CLIENTNODE, stonith_our_uname);
116
117 pcmk__cluster_send_message(NULL, crm_msg_stonith_ng, request);
118 free_xml(request);
119 return 0;
120 }
121
122 if (c->name == NULL) {
123 const char *value = crm_element_value(request, PCMK__XA_ST_CLIENTNAME);
124
125 c->name = crm_strdup_printf("%s.%u", pcmk__s(value, "unknown"), c->pid);
126 }
127
128 crm_element_value_int(request, PCMK__XA_ST_CALLOPT, &call_options);
129 crm_trace("Flags %#08" PRIx32 "/%#08x for command %" PRIu32
130 " from client %s", flags, call_options, id, pcmk__client_name(c));
131
132 if (pcmk_is_set(call_options, st_opt_sync_call)) {
133 CRM_ASSERT(flags & crm_ipc_client_response);
134 CRM_LOG_ASSERT(c->request_id == 0);
135 c->request_id = id;
136 }
137
138 crm_xml_add(request, PCMK__XA_ST_CLIENTID, c->id);
139 crm_xml_add(request, PCMK__XA_ST_CLIENTNAME, pcmk__client_name(c));
140 crm_xml_add(request, PCMK__XA_ST_CLIENTNODE, stonith_our_uname);
141
142 crm_log_xml_trace(request, "ipc-received");
143 stonith_command(c, id, flags, request, NULL);
144
145 free_xml(request);
146 return 0;
147 }
148
149
150 static int32_t
151 st_ipc_closed(qb_ipcs_connection_t * c)
152 {
153 pcmk__client_t *client = pcmk__find_client(c);
154
155 if (client == NULL) {
156 return 0;
157 }
158
159 crm_trace("Connection %p closed", c);
160 pcmk__free_client(client);
161
162
163 return 0;
164 }
165
166 static void
167 st_ipc_destroy(qb_ipcs_connection_t * c)
168 {
169 crm_trace("Connection %p destroyed", c);
170 st_ipc_closed(c);
171 }
172
173 static void
174 stonith_peer_callback(xmlNode * msg, void *private_data)
175 {
176 const char *remote_peer = crm_element_value(msg, PCMK__XA_SRC);
177 const char *op = crm_element_value(msg, PCMK__XA_ST_OP);
178
179 if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) {
180 return;
181 }
182
183 crm_log_xml_trace(msg, "Peer[inbound]");
184 stonith_command(NULL, 0, 0, msg, remote_peer);
185 }
186
187 #if SUPPORT_COROSYNC
188 static void
189 stonith_peer_ais_callback(cpg_handle_t handle,
190 const struct cpg_name *groupName,
191 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
192 {
193 uint32_t kind = 0;
194 xmlNode *xml = NULL;
195 const char *from = NULL;
196 char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &kind, &from);
197
198 if(data == NULL) {
199 return;
200 }
201 if (kind == crm_class_cluster) {
202 xml = pcmk__xml_parse(data);
203 if (xml == NULL) {
204 crm_err("Invalid XML: '%.120s'", data);
205 free(data);
206 return;
207 }
208 crm_xml_add(xml, PCMK__XA_SRC, from);
209 stonith_peer_callback(xml, NULL);
210 }
211
212 free_xml(xml);
213 free(data);
214 return;
215 }
216
217 static void
218 stonith_peer_cs_destroy(gpointer user_data)
219 {
220 crm_crit("Lost connection to cluster layer, shutting down");
221 stonith_shutdown(0);
222 }
223 #endif
224
225 void
226 do_local_reply(const xmlNode *notify_src, pcmk__client_t *client,
227 int call_options)
228 {
229
230 int local_rc = pcmk_rc_ok;
231 int rid = 0;
232 uint32_t ipc_flags = crm_ipc_server_event;
233
234 if (pcmk_is_set(call_options, st_opt_sync_call)) {
235 CRM_LOG_ASSERT(client->request_id);
236 rid = client->request_id;
237 client->request_id = 0;
238 ipc_flags = crm_ipc_flags_none;
239 }
240
241 local_rc = pcmk__ipc_send_xml(client, rid, notify_src, ipc_flags);
242 if (local_rc == pcmk_rc_ok) {
243 crm_trace("Sent response %d to client %s",
244 rid, pcmk__client_name(client));
245 } else {
246 crm_warn("%synchronous reply to client %s failed: %s",
247 (pcmk_is_set(call_options, st_opt_sync_call)? "S" : "As"),
248 pcmk__client_name(client), pcmk_rc_str(local_rc));
249 }
250 }
251
252 uint64_t
253 get_stonith_flag(const char *name)
254 {
255 if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_FENCE, pcmk__str_none)) {
256 return st_callback_notify_fence;
257
258 } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_ADD, pcmk__str_casei)) {
259 return st_callback_device_add;
260
261 } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_DEL, pcmk__str_casei)) {
262 return st_callback_device_del;
263
264 } else if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_HISTORY,
265 pcmk__str_none)) {
266 return st_callback_notify_history;
267
268 } else if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_HISTORY_SYNCED,
269 pcmk__str_none)) {
270 return st_callback_notify_history_synced;
271
272 }
273 return st_callback_unknown;
274 }
275
276 static void
277 stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
278 {
279
280 const xmlNode *update_msg = user_data;
281 pcmk__client_t *client = value;
282 const char *type = NULL;
283
284 CRM_CHECK(client != NULL, return);
285 CRM_CHECK(update_msg != NULL, return);
286
287 type = crm_element_value(update_msg, PCMK__XA_SUBT);
288 CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
289
290 if (client->ipcs == NULL) {
291 crm_trace("Skipping client with NULL channel");
292 return;
293 }
294
295 if (pcmk_is_set(client->flags, get_stonith_flag(type))) {
296 int rc = pcmk__ipc_send_xml(client, 0, update_msg,
297 crm_ipc_server_event);
298
299 if (rc != pcmk_rc_ok) {
300 crm_warn("%s notification of client %s failed: %s "
301 CRM_XS " id=%.8s rc=%d", type, pcmk__client_name(client),
302 pcmk_rc_str(rc), client->id, rc);
303 } else {
304 crm_trace("Sent %s notification to client %s",
305 type, pcmk__client_name(client));
306 }
307 }
308 }
309
310 void
311 do_stonith_async_timeout_update(const char *client_id, const char *call_id, int timeout)
312 {
313 pcmk__client_t *client = NULL;
314 xmlNode *notify_data = NULL;
315
316 if (!timeout || !call_id || !client_id) {
317 return;
318 }
319
320 client = pcmk__find_client_by_id(client_id);
321 if (!client) {
322 return;
323 }
324
325 notify_data = pcmk__xe_create(NULL, PCMK__XE_ST_ASYNC_TIMEOUT_VALUE);
326 crm_xml_add(notify_data, PCMK__XA_T, PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE);
327 crm_xml_add(notify_data, PCMK__XA_ST_CALLID, call_id);
328 crm_xml_add_int(notify_data, PCMK__XA_ST_TIMEOUT, timeout);
329
330 crm_trace("timeout update is %d for client %s and call id %s", timeout, client_id, call_id);
331
332 if (client) {
333 pcmk__ipc_send_xml(client, 0, notify_data, crm_ipc_server_event);
334 }
335
336 free_xml(notify_data);
337 }
338
339
340
341
342
343
344
345
346
347 void
348 fenced_send_notification(const char *type, const pcmk__action_result_t *result,
349 xmlNode *data)
350 {
351
352 xmlNode *update_msg = pcmk__xe_create(NULL, PCMK__XE_NOTIFY);
353
354 CRM_LOG_ASSERT(type != NULL);
355
356 crm_xml_add(update_msg, PCMK__XA_T, PCMK__VALUE_ST_NOTIFY);
357 crm_xml_add(update_msg, PCMK__XA_SUBT, type);
358 crm_xml_add(update_msg, PCMK__XA_ST_OP, type);
359 stonith__xe_set_result(update_msg, result);
360
361 if (data != NULL) {
362 xmlNode *wrapper = pcmk__xe_create(update_msg, PCMK__XE_ST_CALLDATA);
363
364 pcmk__xml_copy(wrapper, data);
365 }
366
367 crm_trace("Notifying clients");
368 pcmk__foreach_ipc_client(stonith_notify_client, update_msg);
369 free_xml(update_msg);
370 crm_trace("Notify complete");
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384
385 void
386 fenced_send_config_notification(const char *op,
387 const pcmk__action_result_t *result,
388 const char *desc)
389 {
390 xmlNode *notify_data = pcmk__xe_create(NULL, op);
391
392 crm_xml_add(notify_data, PCMK__XA_ST_DEVICE_ID, desc);
393
394 fenced_send_notification(op, result, notify_data);
395 free_xml(notify_data);
396 }
397
398
399
400
401
402
403
404
405
406
407
408 gboolean
409 node_does_watchdog_fencing(const char *node)
410 {
411 return ((stonith_watchdog_targets == NULL) ||
412 pcmk__str_in_list(node, stonith_watchdog_targets, pcmk__str_casei));
413 }
414
415 void
416 stonith_shutdown(int nsig)
417 {
418 crm_info("Terminating with %d clients", pcmk__ipc_client_count());
419 stonith_shutdown_flag = TRUE;
420 if (mainloop != NULL && g_main_loop_is_running(mainloop)) {
421 g_main_loop_quit(mainloop);
422 }
423 }
424
425 static void
426 stonith_cleanup(void)
427 {
428 fenced_cib_cleanup();
429 if (ipcs) {
430 qb_ipcs_destroy(ipcs);
431 }
432
433 pcmk__cluster_destroy_node_caches();
434 pcmk__client_cleanup();
435 free_stonith_remote_op_list();
436 free_topology_list();
437 free_device_list();
438 free_metadata_cache();
439 fenced_unregister_handlers();
440
441 free(stonith_our_uname);
442 stonith_our_uname = NULL;
443 }
444
445 static gboolean
446 stand_alone_cpg_cb(const gchar *option_name, const gchar *optarg, gpointer data,
447 GError **error)
448 {
449 stand_alone = FALSE;
450 options.no_cib_connect = true;
451 return TRUE;
452 }
453
454 struct qb_ipcs_service_handlers ipc_callbacks = {
455 .connection_accept = st_ipc_accept,
456 .connection_created = NULL,
457 .msg_process = st_ipc_dispatch,
458 .connection_closed = st_ipc_closed,
459 .connection_destroyed = st_ipc_destroy
460 };
461
462
463
464
465
466
467
468
469
470 static void
471 st_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
472 {
473 if ((type != crm_status_processes)
474 && !pcmk_is_set(node->flags, crm_remote_node)) {
475
476
477
478
479 xmlNode *query = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND);
480
481 crm_xml_add(query, PCMK__XA_T, PCMK__VALUE_STONITH_NG);
482 crm_xml_add(query, PCMK__XA_ST_OP, STONITH_OP_POKE);
483
484 crm_debug("Broadcasting our uname because of node %u", node->id);
485 pcmk__cluster_send_message(NULL, crm_msg_stonith_ng, query);
486
487 free_xml(query);
488 }
489 }
490
491
492
493
494 static int
495 fencer_metadata(void)
496 {
497 const char *name = "pacemaker-fenced";
498 const char *desc_short = N_("Instance attributes available for all "
499 "\"stonith\"-class resources");
500 const char *desc_long = N_("Instance attributes available for all "
501 "\"stonith\"-class resources and used by "
502 "Pacemaker's fence daemon, formerly known as "
503 "stonithd");
504
505 return pcmk__daemon_metadata(out, name, desc_short, desc_long,
506 pcmk__opt_fencing);
507 }
508
509 static GOptionEntry entries[] = {
510 { "stand-alone", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &stand_alone,
511 N_("Deprecated (will be removed in a future release)"), NULL },
512
513 { "stand-alone-w-cpg", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
514 stand_alone_cpg_cb, N_("Intended for use in regression testing only"), NULL },
515
516 { "logfile", 'l', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME_ARRAY,
517 &options.log_files, N_("Send logs to the additional named logfile"), NULL },
518
519 { NULL }
520 };
521
522 static GOptionContext *
523 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
524 {
525 GOptionContext *context = NULL;
526
527 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
528 pcmk__add_main_args(context, entries);
529 return context;
530 }
531
532 int
533 main(int argc, char **argv)
534 {
535 int rc = pcmk_rc_ok;
536 pcmk_cluster_t *cluster = NULL;
537 crm_ipc_t *old_instance = NULL;
538
539 GError *error = NULL;
540
541 GOptionGroup *output_group = NULL;
542 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
543 gchar **processed_args = pcmk__cmdline_preproc(argv, "l");
544 GOptionContext *context = build_arg_context(args, &output_group);
545
546 crm_log_preinit(NULL, argc, argv);
547
548 pcmk__register_formats(output_group, formats);
549 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
550 exit_code = CRM_EX_USAGE;
551 goto done;
552 }
553
554 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
555 if (rc != pcmk_rc_ok) {
556 exit_code = CRM_EX_ERROR;
557 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
558 "Error creating output format %s: %s",
559 args->output_ty, pcmk_rc_str(rc));
560 goto done;
561 }
562
563 if (args->version) {
564 out->version(out, false);
565 goto done;
566 }
567
568 if ((g_strv_length(processed_args) >= 2)
569 && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
570
571 rc = fencer_metadata();
572 if (rc != pcmk_rc_ok) {
573 exit_code = CRM_EX_FATAL;
574 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
575 "Unable to display metadata: %s", pcmk_rc_str(rc));
576 }
577 goto done;
578 }
579
580
581 pcmk__add_logfiles(options.log_files, out);
582
583 crm_log_init(NULL, LOG_INFO + args->verbosity, TRUE,
584 (args->verbosity > 0), argc, argv, FALSE);
585
586 crm_notice("Starting Pacemaker fencer");
587
588 old_instance = crm_ipc_new("stonith-ng", 0);
589 if (old_instance == NULL) {
590
591
592
593 exit_code = CRM_EX_FATAL;
594 goto done;
595 }
596
597 if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
598
599 crm_ipc_close(old_instance);
600 crm_ipc_destroy(old_instance);
601 crm_err("pacemaker-fenced is already active, aborting startup");
602 goto done;
603 } else {
604
605 crm_ipc_destroy(old_instance);
606 old_instance = NULL;
607 }
608
609 mainloop_add_signal(SIGTERM, stonith_shutdown);
610
611 pcmk__cluster_init_node_caches();
612
613 rc = fenced_scheduler_init();
614 if (rc != pcmk_rc_ok) {
615 exit_code = CRM_EX_FATAL;
616 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
617 "Error initializing scheduler data: %s", pcmk_rc_str(rc));
618 goto done;
619 }
620
621 cluster = pcmk_cluster_new();
622
623 if (!stand_alone) {
624 #if SUPPORT_COROSYNC
625 if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
626 pcmk_cluster_set_destroy_fn(cluster, stonith_peer_cs_destroy);
627 pcmk_cpg_set_deliver_fn(cluster, stonith_peer_ais_callback);
628 pcmk_cpg_set_confchg_fn(cluster, pcmk__cpg_confchg_cb);
629 }
630 #endif
631
632 pcmk__cluster_set_status_callback(&st_peer_update_callback);
633
634 if (pcmk_cluster_connect(cluster) != pcmk_rc_ok) {
635 exit_code = CRM_EX_FATAL;
636 crm_crit("Cannot sign in to the cluster... terminating");
637 goto done;
638 }
639 pcmk__str_update(&stonith_our_uname, cluster->uname);
640
641 if (!options.no_cib_connect) {
642 setup_cib();
643 }
644
645 } else {
646 pcmk__str_update(&stonith_our_uname, "localhost");
647 crm_warn("Stand-alone mode is deprecated and will be removed "
648 "in a future release");
649 }
650
651 init_device_list();
652 init_topology_list();
653
654 pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks);
655
656
657 mainloop = g_main_loop_new(NULL, FALSE);
658 crm_notice("Pacemaker fencer successfully started and accepting connections");
659 g_main_loop_run(mainloop);
660
661 done:
662 g_strfreev(processed_args);
663 pcmk__free_arg_context(context);
664
665 g_strfreev(options.log_files);
666
667 stonith_cleanup();
668 pcmk_cluster_free(cluster);
669 fenced_scheduler_cleanup();
670
671 pcmk__output_and_clear_error(&error, out);
672
673 if (out != NULL) {
674 out->finish(out, exit_code, true, NULL);
675 pcmk__output_free(out);
676 }
677
678 pcmk__unregister_formats();
679 crm_exit(exit_code);
680 }