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