1 /*
2 * Copyright 2009-2024 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
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/wait.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <sys/utsname.h>
19
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include <regex.h>
25
26 #include <crm/crm.h>
27 #include <crm/common/ipc.h>
28 #include <crm/common/ipc_internal.h>
29 #include <crm/cluster/internal.h>
30
31 #include <crm/stonith-ng.h>
32 #include <crm/fencing/internal.h>
33 #include <crm/common/xml.h>
34 #include <crm/common/xml_internal.h>
35
36 #include <crm/common/util.h>
37 #include <pacemaker-fenced.h>
38
39 #define TIMEOUT_MULTIPLY_FACTOR 1.2
40
41 /* When one fencer queries its peers for devices able to handle a fencing
42 * request, each peer will reply with a list of such devices available to it.
43 * Each reply will be parsed into a peer_device_info_t, with each device's
44 * information kept in a device_properties_t.
45 */
46
47 typedef struct device_properties_s {
48 /* Whether access to this device has been verified */
49 gboolean verified;
50
51 /* The remaining members are indexed by the operation's "phase" */
52
53 /* Whether this device has been executed in each phase */
54 gboolean executed[st_phase_max];
55 /* Whether this device is disallowed from executing in each phase */
56 gboolean disallowed[st_phase_max];
57 /* Action-specific timeout for each phase */
58 int custom_action_timeout[st_phase_max];
59 /* Action-specific maximum random delay for each phase */
60 int delay_max[st_phase_max];
61 /* Action-specific base delay for each phase */
62 int delay_base[st_phase_max];
63 /* Group of enum st_device_flags */
64 uint32_t device_support_flags;
65 } device_properties_t;
66
67 typedef struct {
68 /* Name of peer that sent this result */
69 char *host;
70 /* Only try peers for non-topology based operations once */
71 gboolean tried;
72 /* Number of entries in the devices table */
73 int ndevices;
74 /* Devices available to this host that are capable of fencing the target */
75 GHashTable *devices;
76 } peer_device_info_t;
77
78 GHashTable *stonith_remote_op_list = NULL;
79
80 extern xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
81 int call_options);
82
83 static void request_peer_fencing(remote_fencing_op_t *op,
84 peer_device_info_t *peer);
85 static void finalize_op(remote_fencing_op_t *op, xmlNode *data, bool dup);
86 static void report_timeout_period(remote_fencing_op_t * op, int op_timeout);
87 static int get_op_total_timeout(const remote_fencing_op_t *op,
88 const peer_device_info_t *chosen_peer);
89
90 static gint
91 sort_strings(gconstpointer a, gconstpointer b)
92 {
93 return strcmp(a, b);
94 }
95
96 static void
97 free_remote_query(gpointer data)
98 {
99 if (data != NULL) {
100 peer_device_info_t *peer = data;
101
102 g_hash_table_destroy(peer->devices);
103 free(peer->host);
104 free(peer);
105 }
106 }
107
108 void
109 free_stonith_remote_op_list(void)
110 {
111 if (stonith_remote_op_list != NULL) {
112 g_hash_table_destroy(stonith_remote_op_list);
113 stonith_remote_op_list = NULL;
114 }
115 }
116
117 struct peer_count_data {
118 const remote_fencing_op_t *op;
119 gboolean verified_only;
120 uint32_t support_action_only;
121 int count;
122 };
123
124 /*!
125 * \internal
126 * \brief Increment a counter if a device has not been executed yet
127 *
128 * \param[in] key Device ID (ignored)
129 * \param[in] value Device properties
130 * \param[in,out] user_data Peer count data
131 */
132 static void
133 count_peer_device(gpointer key, gpointer value, gpointer user_data)
134 {
135 device_properties_t *props = (device_properties_t*)value;
136 struct peer_count_data *data = user_data;
137
138 if (!props->executed[data->op->phase]
139 && (!data->verified_only || props->verified)
140 && ((data->support_action_only == st_device_supports_none) || pcmk_is_set(props->device_support_flags, data->support_action_only))) {
141 ++(data->count);
142 }
143 }
144
145 /*!
146 * \internal
147 * \brief Check the number of available devices in a peer's query results
148 *
149 * \param[in] op Operation that results are for
150 * \param[in] peer Peer to count
151 * \param[in] verified_only Whether to count only verified devices
152 * \param[in] support_action_only Whether to count only devices that support action
153 *
154 * \return Number of devices available to peer that were not already executed
155 */
156 static int
157 count_peer_devices(const remote_fencing_op_t *op,
158 const peer_device_info_t *peer, gboolean verified_only, uint32_t support_on_action_only)
159 {
160 struct peer_count_data data;
161
162 data.op = op;
163 data.verified_only = verified_only;
164 data.support_action_only = support_on_action_only;
165 data.count = 0;
166 if (peer) {
167 g_hash_table_foreach(peer->devices, count_peer_device, &data);
168 }
169 return data.count;
170 }
171
172 /*!
173 * \internal
174 * \brief Search for a device in a query result
175 *
176 * \param[in] op Operation that result is for
177 * \param[in] peer Query result for a peer
178 * \param[in] device Device ID to search for
179 *
180 * \return Device properties if found, NULL otherwise
181 */
182 static device_properties_t *
183 find_peer_device(const remote_fencing_op_t *op, const peer_device_info_t *peer,
184 const char *device, uint32_t support_action_only)
185 {
186 device_properties_t *props = g_hash_table_lookup(peer->devices, device);
187
188 if (props && support_action_only != st_device_supports_none && !pcmk_is_set(props->device_support_flags, support_action_only)) {
189 return NULL;
190 }
191 return (props && !props->executed[op->phase]
192 && !props->disallowed[op->phase])? props : NULL;
193 }
194
195 /*!
196 * \internal
197 * \brief Find a device in a peer's device list and mark it as executed
198 *
199 * \param[in] op Operation that peer result is for
200 * \param[in,out] peer Peer with results to search
201 * \param[in] device ID of device to mark as done
202 * \param[in] verified_devices_only Only consider verified devices
203 *
204 * \return TRUE if device was found and marked, FALSE otherwise
205 */
206 static gboolean
207 grab_peer_device(const remote_fencing_op_t *op, peer_device_info_t *peer,
208 const char *device, gboolean verified_devices_only)
209 {
210 device_properties_t *props = find_peer_device(op, peer, device,
211 fenced_support_flag(op->action));
212
213 if ((props == NULL) || (verified_devices_only && !props->verified)) {
214 return FALSE;
215 }
216
217 crm_trace("Removing %s from %s (%d remaining)",
218 device, peer->host, count_peer_devices(op, peer, FALSE, st_device_supports_none));
219 props->executed[op->phase] = TRUE;
220 return TRUE;
221 }
222
223 static void
224 clear_remote_op_timers(remote_fencing_op_t * op)
225 {
226 if (op->query_timer) {
227 g_source_remove(op->query_timer);
228 op->query_timer = 0;
229 }
230 if (op->op_timer_total) {
231 g_source_remove(op->op_timer_total);
232 op->op_timer_total = 0;
233 }
234 if (op->op_timer_one) {
235 g_source_remove(op->op_timer_one);
236 op->op_timer_one = 0;
237 }
238 }
239
240 static void
241 free_remote_op(gpointer data)
242 {
243 remote_fencing_op_t *op = data;
244
245 crm_log_xml_debug(op->request, "Destroying");
246
247 clear_remote_op_timers(op);
248
249 free(op->id);
250 free(op->action);
251 free(op->delegate);
252 free(op->target);
253 free(op->client_id);
254 free(op->client_name);
255 free(op->originator);
256
257 if (op->query_results) {
258 g_list_free_full(op->query_results, free_remote_query);
259 }
260 if (op->request) {
261 pcmk__xml_free(op->request);
262 op->request = NULL;
263 }
264 if (op->devices_list) {
265 g_list_free_full(op->devices_list, free);
266 op->devices_list = NULL;
267 }
268 g_list_free_full(op->automatic_list, free);
269 g_list_free(op->duplicates);
270
271 pcmk__reset_result(&op->result);
272 free(op);
273 }
274
275 void
276 init_stonith_remote_op_hash_table(GHashTable **table)
277 {
278 if (*table == NULL) {
279 *table = pcmk__strkey_table(NULL, free_remote_op);
280 }
281 }
282
283 /*!
284 * \internal
285 * \brief Return an operation's originally requested action (before any remap)
286 *
287 * \param[in] op Operation to check
288 *
289 * \return Operation's original action
290 */
291 static const char *
292 op_requested_action(const remote_fencing_op_t *op)
293 {
294 return ((op->phase > st_phase_requested)? PCMK_ACTION_REBOOT : op->action);
295 }
296
297 /*!
298 * \internal
299 * \brief Remap a "reboot" operation to the "off" phase
300 *
301 * \param[in,out] op Operation to remap
302 */
303 static void
304 op_phase_off(remote_fencing_op_t *op)
305 {
306 crm_info("Remapping multiple-device reboot targeting %s to 'off' "
307 QB_XS " id=%.8s", op->target, op->id);
308 op->phase = st_phase_off;
309
310 /* Happily, "off" and "on" are shorter than "reboot", so we can reuse the
311 * memory allocation at each phase.
312 */
313 strcpy(op->action, PCMK_ACTION_OFF);
314 }
315
316 /*!
317 * \internal
318 * \brief Advance a remapped reboot operation to the "on" phase
319 *
320 * \param[in,out] op Operation to remap
321 */
322 static void
323 op_phase_on(remote_fencing_op_t *op)
324 {
325 GList *iter = NULL;
326
327 crm_info("Remapped 'off' targeting %s complete, "
328 "remapping to 'on' for %s " QB_XS " id=%.8s",
329 op->target, op->client_name, op->id);
330 op->phase = st_phase_on;
331 strcpy(op->action, PCMK_ACTION_ON);
332
333 /* Skip devices with automatic unfencing, because the cluster will handle it
334 * when the node rejoins.
335 */
336 for (iter = op->automatic_list; iter != NULL; iter = iter->next) {
337 GList *match = g_list_find_custom(op->devices_list, iter->data,
338 sort_strings);
339
340 if (match) {
341 op->devices_list = g_list_remove(op->devices_list, match->data);
342 }
343 }
344 g_list_free_full(op->automatic_list, free);
345 op->automatic_list = NULL;
346
347 /* Rewind device list pointer */
348 op->devices = op->devices_list;
349 }
350
351 /*!
352 * \internal
353 * \brief Reset a remapped reboot operation
354 *
355 * \param[in,out] op Operation to reset
356 */
357 static void
358 undo_op_remap(remote_fencing_op_t *op)
359 {
360 if (op->phase > 0) {
361 crm_info("Undoing remap of reboot targeting %s for %s "
362 QB_XS " id=%.8s", op->target, op->client_name, op->id);
363 op->phase = st_phase_requested;
364 strcpy(op->action, PCMK_ACTION_REBOOT);
365 }
366 }
367
368 /*!
369 * \internal
370 * \brief Create notification data XML for a fencing operation result
371 *
372 * \param[in,out] parent Parent XML element for newly created element
373 * \param[in] op Fencer operation that completed
374 *
375 * \return Newly created XML to add as notification data
376 * \note The caller is responsible for freeing the result.
377 */
378 static xmlNode *
379 fencing_result2xml(xmlNode *parent, const remote_fencing_op_t *op)
380 {
381 xmlNode *notify_data = pcmk__xe_create(parent, PCMK__XE_ST_NOTIFY_FENCE);
382
383 crm_xml_add_int(notify_data, PCMK_XA_STATE, op->state);
384 crm_xml_add(notify_data, PCMK__XA_ST_TARGET, op->target);
385 crm_xml_add(notify_data, PCMK__XA_ST_DEVICE_ACTION, op->action);
386 crm_xml_add(notify_data, PCMK__XA_ST_DELEGATE, op->delegate);
387 crm_xml_add(notify_data, PCMK__XA_ST_REMOTE_OP, op->id);
388 crm_xml_add(notify_data, PCMK__XA_ST_ORIGIN, op->originator);
389 crm_xml_add(notify_data, PCMK__XA_ST_CLIENTID, op->client_id);
390 crm_xml_add(notify_data, PCMK__XA_ST_CLIENTNAME, op->client_name);
391
392 return notify_data;
393 }
394
395 /*!
396 * \internal
397 * \brief Broadcast a fence result notification to all CPG peers
398 *
399 * \param[in] op Fencer operation that completed
400 * \param[in] op_merged Whether this operation is a duplicate of another
401 */
402 void
403 fenced_broadcast_op_result(const remote_fencing_op_t *op, bool op_merged)
404 {
405 static int count = 0;
406 xmlNode *bcast = pcmk__xe_create(NULL, PCMK__XE_ST_REPLY);
407 xmlNode *wrapper = NULL;
408 xmlNode *notify_data = NULL;
409
410 count++;
411 crm_trace("Broadcasting result to peers");
412 crm_xml_add(bcast, PCMK__XA_T, PCMK__VALUE_ST_NOTIFY);
413 crm_xml_add(bcast, PCMK__XA_SUBT, PCMK__VALUE_BROADCAST);
414 crm_xml_add(bcast, PCMK__XA_ST_OP, STONITH_OP_NOTIFY);
415 crm_xml_add_int(bcast, PCMK_XA_COUNT, count);
416
417 if (op_merged) {
418 pcmk__xe_set_bool_attr(bcast, PCMK__XA_ST_OP_MERGED, true);
419 }
420
421 wrapper = pcmk__xe_create(bcast, PCMK__XE_ST_CALLDATA);
422 notify_data = fencing_result2xml(wrapper, op);
423 stonith__xe_set_result(notify_data, &op->result);
424
425 pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, bcast);
426 pcmk__xml_free(bcast);
427
428 return;
429 }
430
431 /*!
432 * \internal
433 * \brief Reply to a local request originator and notify all subscribed clients
434 *
435 * \param[in,out] op Fencer operation that completed
436 * \param[in,out] data Top-level XML to add notification to
437 */
438 static void
439 handle_local_reply_and_notify(remote_fencing_op_t *op, xmlNode *data)
440 {
441 xmlNode *notify_data = NULL;
442 xmlNode *reply = NULL;
443 pcmk__client_t *client = NULL;
444
445 if (op->notify_sent == TRUE) {
446 /* nothing to do */
447 return;
448 }
449
450 /* Do notification with a clean data object */
451 crm_xml_add_int(data, PCMK_XA_STATE, op->state);
452 crm_xml_add(data, PCMK__XA_ST_TARGET, op->target);
453 crm_xml_add(data, PCMK__XA_ST_OP, op->action);
454
455 reply = fenced_construct_reply(op->request, data, &op->result);
456 crm_xml_add(reply, PCMK__XA_ST_DELEGATE, op->delegate);
457
458 /* Send fencing OP reply to local client that initiated fencing */
459 client = pcmk__find_client_by_id(op->client_id);
460 if (client == NULL) {
461 crm_trace("Skipping reply to %s: no longer a client", op->client_id);
462 } else {
463 do_local_reply(reply, client, op->call_options);
464 }
465
466 /* bcast to all local clients that the fencing operation happend */
467 notify_data = fencing_result2xml(NULL, op);
468 fenced_send_notification(PCMK__VALUE_ST_NOTIFY_FENCE, &op->result,
469 notify_data);
470 pcmk__xml_free(notify_data);
471 fenced_send_notification(PCMK__VALUE_ST_NOTIFY_HISTORY, NULL, NULL);
472
473 /* mark this op as having notify's already sent */
474 op->notify_sent = TRUE;
475 pcmk__xml_free(reply);
476 }
477
478 /*!
479 * \internal
480 * \brief Finalize all duplicates of a given fencer operation
481 *
482 * \param[in,out] op Fencer operation that completed
483 * \param[in,out] data Top-level XML to add notification to
484 */
485 static void
486 finalize_op_duplicates(remote_fencing_op_t *op, xmlNode *data)
487 {
488 for (GList *iter = op->duplicates; iter != NULL; iter = iter->next) {
489 remote_fencing_op_t *other = iter->data;
490
491 if (other->state == st_duplicate) {
492 other->state = op->state;
493 crm_debug("Performing duplicate notification for %s@%s: %s "
494 QB_XS " id=%.8s",
495 other->client_name, other->originator,
496 pcmk_exec_status_str(op->result.execution_status),
497 other->id);
498 pcmk__copy_result(&op->result, &other->result);
499 finalize_op(other, data, true);
500
501 } else {
502 // Possible if (for example) it timed out already
503 crm_err("Skipping duplicate notification for %s@%s "
504 QB_XS " state=%s id=%.8s",
505 other->client_name, other->originator,
506 stonith_op_state_str(other->state), other->id);
507 }
508 }
509 }
510
511 static char *
512 delegate_from_xml(xmlNode *xml)
513 {
514 xmlNode *match = get_xpath_object("//@" PCMK__XA_ST_DELEGATE, xml,
515 LOG_NEVER);
516
517 if (match == NULL) {
518 return crm_element_value_copy(xml, PCMK__XA_SRC);
519 } else {
520 return crm_element_value_copy(match, PCMK__XA_ST_DELEGATE);
521 }
522 }
523
524 /*!
525 * \internal
526 * \brief Finalize a peer fencing operation
527 *
528 * Clean up after a fencing operation completes. This function has two code
529 * paths: the executioner uses it to broadcast the result to CPG peers, and then
530 * each peer (including the executioner) uses it to process that broadcast and
531 * notify its IPC clients of the result.
532 *
533 * \param[in,out] op Fencer operation that completed
534 * \param[in,out] data If not NULL, XML reply of last delegated operation
535 * \param[in] dup Whether this operation is a duplicate of another
536 * (in which case, do not broadcast the result)
537 *
538 * \note The operation result should be set before calling this function.
539 */
540 static void
541 finalize_op(remote_fencing_op_t *op, xmlNode *data, bool dup)
542 {
543 int level = LOG_ERR;
544 const char *subt = NULL;
545 xmlNode *local_data = NULL;
546 gboolean op_merged = FALSE;
547
548 CRM_CHECK((op != NULL), return);
549
550 // This is a no-op if timers have already been cleared
551 clear_remote_op_timers(op);
552
553 if (op->notify_sent) {
554 // Most likely, this is a timed-out action that eventually completed
555 crm_notice("Operation '%s'%s%s by %s for %s@%s%s: "
556 "Result arrived too late " QB_XS " id=%.8s",
557 op->action, (op->target? " targeting " : ""),
558 (op->target? op->target : ""),
559 (op->delegate? op->delegate : "unknown node"),
560 op->client_name, op->originator,
561 (op_merged? " (merged)" : ""),
562 op->id);
563 return;
564 }
565
566 set_fencing_completed(op);
567 undo_op_remap(op);
568
569 if (data == NULL) {
570 data = pcmk__xe_create(NULL, "remote-op");
571 local_data = data;
572
573 } else if (op->delegate == NULL) {
574 switch (op->result.execution_status) {
575 case PCMK_EXEC_NO_FENCE_DEVICE:
576 break;
577
578 case PCMK_EXEC_INVALID:
579 if (op->result.exit_status != CRM_EX_EXPIRED) {
580 op->delegate = delegate_from_xml(data);
581 }
582 break;
583
584 default:
585 op->delegate = delegate_from_xml(data);
586 break;
587 }
588 }
589
590 if (dup || (crm_element_value(data, PCMK__XA_ST_OP_MERGED) != NULL)) {
591 op_merged = true;
592 }
593
594 /* Tell everyone the operation is done, we will continue
595 * with doing the local notifications once we receive
596 * the broadcast back. */
597 subt = crm_element_value(data, PCMK__XA_SUBT);
598 if (!dup && !pcmk__str_eq(subt, PCMK__VALUE_BROADCAST, pcmk__str_none)) {
599 /* Defer notification until the bcast message arrives */
600 fenced_broadcast_op_result(op, op_merged);
601 pcmk__xml_free(local_data);
602 return;
603 }
604
605 if (pcmk__result_ok(&op->result) || dup
606 || !pcmk__str_eq(op->originator, fenced_get_local_node(),
607 pcmk__str_casei)) {
608 level = LOG_NOTICE;
609 }
610 do_crm_log(level, "Operation '%s'%s%s by %s for %s@%s%s: %s (%s%s%s) "
611 QB_XS " id=%.8s", op->action, (op->target? " targeting " : ""),
612 (op->target? op->target : ""),
613 (op->delegate? op->delegate : "unknown node"),
614 op->client_name, op->originator,
615 (op_merged? " (merged)" : ""),
616 crm_exit_str(op->result.exit_status),
617 pcmk_exec_status_str(op->result.execution_status),
618 ((op->result.exit_reason == NULL)? "" : ": "),
619 ((op->result.exit_reason == NULL)? "" : op->result.exit_reason),
620 op->id);
621
622 handle_local_reply_and_notify(op, data);
623
624 if (!dup) {
625 finalize_op_duplicates(op, data);
626 }
627
628 /* Free non-essential parts of the record
629 * Keep the record around so we can query the history
630 */
631 if (op->query_results) {
632 g_list_free_full(op->query_results, free_remote_query);
633 op->query_results = NULL;
634 }
635 if (op->request) {
636 pcmk__xml_free(op->request);
637 op->request = NULL;
638 }
639
640 pcmk__xml_free(local_data);
641 }
642
643 /*!
644 * \internal
645 * \brief Finalize a watchdog fencer op after the waiting time expires
646 *
647 * \param[in,out] userdata Fencer operation that completed
648 *
649 * \return G_SOURCE_REMOVE (which tells glib not to restart timer)
650 */
651 static gboolean
652 remote_op_watchdog_done(gpointer userdata)
653 {
654 remote_fencing_op_t *op = userdata;
655
656 op->op_timer_one = 0;
657
658 crm_notice("Self-fencing (%s) by %s for %s assumed complete "
659 QB_XS " id=%.8s",
660 op->action, op->target, op->client_name, op->id);
661 op->state = st_done;
662 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
663 finalize_op(op, NULL, false);
664 return G_SOURCE_REMOVE;
665 }
666
667 static gboolean
668 remote_op_timeout_one(gpointer userdata)
669 {
670 remote_fencing_op_t *op = userdata;
671
672 op->op_timer_one = 0;
673
674 crm_notice("Peer's '%s' action targeting %s for client %s timed out " QB_XS
675 " id=%.8s", op->action, op->target, op->client_name, op->id);
676 pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_TIMEOUT,
677 "Peer did not return fence result within timeout");
678
679 // The requested delay has been applied for the first device
680 if (op->client_delay > 0) {
681 op->client_delay = 0;
682 crm_trace("Try another device for '%s' action targeting %s "
683 "for client %s without delay " QB_XS " id=%.8s",
684 op->action, op->target, op->client_name, op->id);
685 }
686
687 // Try another device, if appropriate
688 request_peer_fencing(op, NULL);
689 return G_SOURCE_REMOVE;
690 }
691
692 /*!
693 * \internal
694 * \brief Finalize a remote fencer operation that timed out
695 *
696 * \param[in,out] op Fencer operation that timed out
697 * \param[in] reason Readable description of what step timed out
698 */
699 static void
700 finalize_timed_out_op(remote_fencing_op_t *op, const char *reason)
701 {
702 crm_debug("Action '%s' targeting %s for client %s timed out "
703 QB_XS " id=%.8s",
704 op->action, op->target, op->client_name, op->id);
705
706 if (op->phase == st_phase_on) {
707 /* A remapped reboot operation timed out in the "on" phase, but the
708 * "off" phase completed successfully, so quit trying any further
709 * devices, and return success.
710 */
711 op->state = st_done;
712 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
713 } else {
714 op->state = st_failed;
715 pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_TIMEOUT, reason);
716 }
717 finalize_op(op, NULL, false);
718 }
719
720 /*!
721 * \internal
722 * \brief Finalize a remote fencer operation that timed out
723 *
724 * \param[in,out] userdata Fencer operation that timed out
725 *
726 * \return G_SOURCE_REMOVE (which tells glib not to restart timer)
727 */
728 static gboolean
729 remote_op_timeout(gpointer userdata)
730 {
731 remote_fencing_op_t *op = userdata;
732
733 op->op_timer_total = 0;
734
735 if (op->state == st_done) {
736 crm_debug("Action '%s' targeting %s for client %s already completed "
737 QB_XS " id=%.8s",
738 op->action, op->target, op->client_name, op->id);
739 } else {
740 finalize_timed_out_op(userdata, "Fencing did not complete within a "
741 "total timeout based on the "
742 "configured timeout and retries for "
743 "any devices attempted");
744 }
745 return G_SOURCE_REMOVE;
746 }
747
748 static gboolean
749 remote_op_query_timeout(gpointer data)
750 {
751 remote_fencing_op_t *op = data;
752
753 op->query_timer = 0;
754
755 if (op->state == st_done) {
756 crm_debug("Operation %.8s targeting %s already completed",
757 op->id, op->target);
758 } else if (op->state == st_exec) {
759 crm_debug("Operation %.8s targeting %s already in progress",
760 op->id, op->target);
761 } else if (op->query_results) {
762 // Query succeeded, so attempt the actual fencing
763 crm_debug("Query %.8s targeting %s complete (state=%s)",
764 op->id, op->target, stonith_op_state_str(op->state));
765 request_peer_fencing(op, NULL);
766 } else {
767 crm_debug("Query %.8s targeting %s timed out (state=%s)",
768 op->id, op->target, stonith_op_state_str(op->state));
769 finalize_timed_out_op(op, "No capable peers replied to device query "
770 "within timeout");
771 }
772
773 return G_SOURCE_REMOVE;
774 }
775
776 static gboolean
777 topology_is_empty(stonith_topology_t *tp)
778 {
779 int i;
780
781 if (tp == NULL) {
782 return TRUE;
783 }
784
785 for (i = 0; i < ST__LEVEL_COUNT; i++) {
786 if (tp->levels[i] != NULL) {
787 return FALSE;
788 }
789 }
790 return TRUE;
791 }
792
793 /*!
794 * \internal
795 * \brief Add a device to an operation's automatic unfencing list
796 *
797 * \param[in,out] op Operation to modify
798 * \param[in] device Device ID to add
799 */
800 static void
801 add_required_device(remote_fencing_op_t *op, const char *device)
802 {
803 GList *match = g_list_find_custom(op->automatic_list, device,
804 sort_strings);
805
806 if (!match) {
807 op->automatic_list = g_list_prepend(op->automatic_list,
808 pcmk__str_copy(device));
809 }
810 }
811
812 /*!
813 * \internal
814 * \brief Remove a device from the automatic unfencing list
815 *
816 * \param[in,out] op Operation to modify
817 * \param[in] device Device ID to remove
818 */
819 static void
820 remove_required_device(remote_fencing_op_t *op, const char *device)
821 {
822 GList *match = g_list_find_custom(op->automatic_list, device,
823 sort_strings);
824
825 if (match) {
826 op->automatic_list = g_list_remove(op->automatic_list, match->data);
827 }
828 }
829
830 /* deep copy the device list */
831 static void
832 set_op_device_list(remote_fencing_op_t * op, GList *devices)
833 {
834 GList *lpc = NULL;
835
836 if (op->devices_list) {
837 g_list_free_full(op->devices_list, free);
838 op->devices_list = NULL;
839 }
840 for (lpc = devices; lpc != NULL; lpc = lpc->next) {
841 const char *device = lpc->data;
842
843 op->devices_list = g_list_append(op->devices_list,
844 pcmk__str_copy(device));
845 }
846 op->devices = op->devices_list;
847 }
848
849 /*!
850 * \internal
851 * \brief Check whether a node matches a topology target
852 *
853 * \param[in] tp Topology table entry to check
854 * \param[in] node Name of node to check
855 *
856 * \return TRUE if node matches topology target
857 */
858 static gboolean
859 topology_matches(const stonith_topology_t *tp, const char *node)
860 {
861 regex_t r_patt;
862
863 CRM_CHECK(node && tp && tp->target, return FALSE);
864 switch (tp->kind) {
865 case fenced_target_by_attribute:
866 /* This level targets by attribute, so tp->target is a NAME=VALUE pair
867 * of a permanent attribute applied to targeted nodes. The test below
868 * relies on the locally cached copy of the CIB, so if fencing needs to
869 * be done before the initial CIB is received or after a malformed CIB
870 * is received, then the topology will be unable to be used.
871 */
872 if (node_has_attr(node, tp->target_attribute, tp->target_value)) {
873 crm_notice("Matched %s with %s by attribute", node, tp->target);
874 return TRUE;
875 }
876 break;
877
878 case fenced_target_by_pattern:
879 /* This level targets node names matching a pattern, so tp->target
880 * (and tp->target_pattern) is a regular expression.
881 */
882 if (regcomp(&r_patt, tp->target_pattern, REG_EXTENDED|REG_NOSUB)) {
883 crm_info("Bad regex '%s' for fencing level", tp->target);
884 } else {
885 int status = regexec(&r_patt, node, 0, NULL, 0);
886
887 regfree(&r_patt);
888 if (status == 0) {
889 crm_notice("Matched %s with %s by name", node, tp->target);
890 return TRUE;
891 }
892 }
893 break;
894
895 case fenced_target_by_name:
896 crm_trace("Testing %s against %s", node, tp->target);
897 return pcmk__str_eq(tp->target, node, pcmk__str_casei);
898
899 default:
900 break;
901 }
902 crm_trace("No match for %s with %s", node, tp->target);
903 return FALSE;
904 }
905
906 stonith_topology_t *
907 find_topology_for_host(const char *host)
908 {
909 GHashTableIter tIter;
910 stonith_topology_t *tp = g_hash_table_lookup(topology, host);
911
912 if(tp != NULL) {
913 crm_trace("Found %s for %s in %d entries", tp->target, host, g_hash_table_size(topology));
914 return tp;
915 }
916
917 g_hash_table_iter_init(&tIter, topology);
918 while (g_hash_table_iter_next(&tIter, NULL, (gpointer *) & tp)) {
919 if (topology_matches(tp, host)) {
920 crm_trace("Found %s for %s in %d entries", tp->target, host, g_hash_table_size(topology));
921 return tp;
922 }
923 }
924
925 crm_trace("No matches for %s in %d topology entries", host, g_hash_table_size(topology));
926 return NULL;
927 }
928
929 /*!
930 * \internal
931 * \brief Set fencing operation's device list to target's next topology level
932 *
933 * \param[in,out] op Remote fencing operation to modify
934 * \param[in] empty_ok If true, an operation without a target (i.e.
935 * queries) or a target without a topology will get a
936 * pcmk_rc_ok return value instead of ENODEV
937 *
938 * \return Standard Pacemaker return value
939 */
940 static int
941 advance_topology_level(remote_fencing_op_t *op, bool empty_ok)
942 {
943 stonith_topology_t *tp = NULL;
944
945 if (op->target) {
946 tp = find_topology_for_host(op->target);
947 }
948 if (topology_is_empty(tp)) {
949 return empty_ok? pcmk_rc_ok : ENODEV;
950 }
951
952 pcmk__assert(tp->levels != NULL);
953
954 stonith__set_call_options(op->call_options, op->id, st_opt_topology);
955
956 /* This is a new level, so undo any remapping left over from previous */
957 undo_op_remap(op);
958
959 do {
960 op->level++;
961
962 } while (op->level < ST__LEVEL_COUNT && tp->levels[op->level] == NULL);
963
964 if (op->level < ST__LEVEL_COUNT) {
965 crm_trace("Attempting fencing level %d targeting %s (%d devices) "
966 "for client %s@%s (id=%.8s)",
967 op->level, op->target, g_list_length(tp->levels[op->level]),
968 op->client_name, op->originator, op->id);
969 set_op_device_list(op, tp->levels[op->level]);
970
971 // The requested delay has been applied for the first fencing level
972 if ((op->level > 1) && (op->client_delay > 0)) {
973 op->client_delay = 0;
974 }
975
976 if ((g_list_next(op->devices_list) != NULL)
977 && pcmk__str_eq(op->action, PCMK_ACTION_REBOOT, pcmk__str_none)) {
978 /* A reboot has been requested for a topology level with multiple
979 * devices. Instead of rebooting the devices sequentially, we will
980 * turn them all off, then turn them all on again. (Think about
981 * switched power outlets for redundant power supplies.)
982 */
983 op_phase_off(op);
984 }
985 return pcmk_rc_ok;
986 }
987
988 crm_info("All %sfencing options targeting %s for client %s@%s failed "
989 QB_XS " id=%.8s",
990 (stonith_watchdog_timeout_ms > 0)?"non-watchdog ":"",
991 op->target, op->client_name, op->originator, op->id);
992 return ENODEV;
993 }
994
995 /*!
996 * \internal
997 * \brief If fencing operation is a duplicate, merge it into the other one
998 *
999 * \param[in,out] op Fencing operation to check
1000 */
1001 static void
1002 merge_duplicates(remote_fencing_op_t *op)
1003 {
1004 GHashTableIter iter;
1005 remote_fencing_op_t *other = NULL;
1006
1007 time_t now = time(NULL);
1008
1009 g_hash_table_iter_init(&iter, stonith_remote_op_list);
1010 while (g_hash_table_iter_next(&iter, NULL, (void **)&other)) {
1011 const char *other_action = op_requested_action(other);
1012 pcmk__node_status_t *node = NULL;
1013
1014 if (!strcmp(op->id, other->id)) {
1015 continue; // Don't compare against self
1016 }
1017 if (other->state > st_exec) {
1018 crm_trace("%.8s not duplicate of %.8s: not in progress",
1019 op->id, other->id);
1020 continue;
1021 }
1022 if (!pcmk__str_eq(op->target, other->target, pcmk__str_casei)) {
1023 crm_trace("%.8s not duplicate of %.8s: node %s vs. %s",
1024 op->id, other->id, op->target, other->target);
1025 continue;
1026 }
1027 if (!pcmk__str_eq(op->action, other_action, pcmk__str_none)) {
1028 crm_trace("%.8s not duplicate of %.8s: action %s vs. %s",
1029 op->id, other->id, op->action, other_action);
1030 continue;
1031 }
1032 if (pcmk__str_eq(op->client_name, other->client_name, pcmk__str_casei)) {
1033 crm_trace("%.8s not duplicate of %.8s: same client %s",
1034 op->id, other->id, op->client_name);
1035 continue;
1036 }
1037 if (pcmk__str_eq(other->target, other->originator, pcmk__str_casei)) {
1038 crm_trace("%.8s not duplicate of %.8s: self-fencing for %s",
1039 op->id, other->id, other->target);
1040 continue;
1041 }
1042
1043 node = pcmk__get_node(0, other->originator, NULL,
1044 pcmk__node_search_cluster_member);
1045
1046 if (!fencing_peer_active(node)) {
1047 crm_notice("Failing action '%s' targeting %s originating from "
1048 "client %s@%s: Originator is dead " QB_XS " id=%.8s",
1049 other->action, other->target, other->client_name,
1050 other->originator, other->id);
1051 crm_trace("%.8s not duplicate of %.8s: originator dead",
1052 op->id, other->id);
1053 other->state = st_failed;
1054 continue;
1055 }
1056 if ((other->total_timeout > 0)
1057 && (now > (other->total_timeout + other->created))) {
1058 crm_trace("%.8s not duplicate of %.8s: old (%lld vs. %lld + %ds)",
1059 op->id, other->id, (long long)now, (long long)other->created,
1060 other->total_timeout);
1061 continue;
1062 }
1063
1064 /* There is another in-flight request to fence the same host
1065 * Piggyback on that instead. If it fails, so do we.
1066 */
1067 other->duplicates = g_list_append(other->duplicates, op);
1068 if (other->total_timeout == 0) {
1069 other->total_timeout = op->total_timeout =
1070 TIMEOUT_MULTIPLY_FACTOR * get_op_total_timeout(op, NULL);
1071 crm_trace("Best guess as to timeout used for %.8s: %ds",
1072 other->id, other->total_timeout);
1073 }
1074 crm_notice("Merging fencing action '%s' targeting %s originating from "
1075 "client %s with identical request from %s@%s "
1076 QB_XS " original=%.8s duplicate=%.8s total_timeout=%ds",
1077 op->action, op->target, op->client_name,
1078 other->client_name, other->originator,
1079 op->id, other->id, other->total_timeout);
1080 report_timeout_period(op, other->total_timeout);
1081 op->state = st_duplicate;
1082 }
1083 }
1084
1085 static uint32_t fencing_active_peers(void)
1086 {
1087 uint32_t count = 0;
1088 pcmk__node_status_t *entry = NULL;
1089 GHashTableIter gIter;
1090
1091 g_hash_table_iter_init(&gIter, pcmk__peer_cache);
1092 while (g_hash_table_iter_next(&gIter, NULL, (void **)&entry)) {
1093 if(fencing_peer_active(entry)) {
1094 count++;
1095 }
1096 }
1097 return count;
1098 }
1099
1100 /*!
1101 * \internal
1102 * \brief Process a manual confirmation of a pending fence action
1103 *
1104 * \param[in] client IPC client that sent confirmation
1105 * \param[in,out] msg Request XML with manual confirmation
1106 *
1107 * \return Standard Pacemaker return code
1108 */
1109 int
1110 fenced_handle_manual_confirmation(const pcmk__client_t *client, xmlNode *msg)
1111 {
1112 remote_fencing_op_t *op = NULL;
1113 xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_TARGET, msg, LOG_ERR);
1114
1115 CRM_CHECK(dev != NULL, return EPROTO);
1116
1117 crm_notice("Received manual confirmation that %s has been fenced",
1118 pcmk__s(crm_element_value(dev, PCMK__XA_ST_TARGET),
1119 "unknown target"));
1120 op = initiate_remote_stonith_op(client, msg, TRUE);
1121 if (op == NULL) {
1122 return EPROTO;
1123 }
1124 op->state = st_done;
1125 op->delegate = pcmk__str_copy("a human");
1126
1127 // For the fencer's purposes, the fencing operation is done
1128 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
1129 finalize_op(op, msg, false);
1130
1131 /* For the requester's purposes, the operation is still pending. The
1132 * actual result will be sent asynchronously via the operation's done_cb().
1133 */
1134 return EINPROGRESS;
1135 }
1136
1137 /*!
1138 * \internal
1139 * \brief Create a new remote stonith operation
1140 *
1141 * \param[in] client ID of local stonith client that initiated the operation
1142 * \param[in] request The request from the client that started the operation
1143 * \param[in] peer TRUE if this operation is owned by another stonith peer
1144 * (an operation owned by one peer is stored on all peers,
1145 * but only the owner executes it; all nodes get the results
1146 * once the owner finishes execution)
1147 */
1148 void *
1149 create_remote_stonith_op(const char *client, xmlNode *request, gboolean peer)
1150 {
1151 remote_fencing_op_t *op = NULL;
1152 xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_TARGET, request,
1153 LOG_NEVER);
1154 int rc = pcmk_rc_ok;
1155 const char *operation = NULL;
1156
1157 init_stonith_remote_op_hash_table(&stonith_remote_op_list);
1158
1159 /* If this operation is owned by another node, check to make
1160 * sure we haven't already created this operation. */
1161 if (peer && dev) {
1162 const char *op_id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
1163
1164 CRM_CHECK(op_id != NULL, return NULL);
1165
1166 op = g_hash_table_lookup(stonith_remote_op_list, op_id);
1167 if (op) {
1168 crm_debug("Reusing existing remote fencing op %.8s for %s",
1169 op_id, ((client == NULL)? "unknown client" : client));
1170 return op;
1171 }
1172 }
1173
1174 op = pcmk__assert_alloc(1, sizeof(remote_fencing_op_t));
1175
1176 crm_element_value_int(request, PCMK__XA_ST_TIMEOUT, &(op->base_timeout));
1177 // Value -1 means disable any static/random fencing delays
1178 crm_element_value_int(request, PCMK__XA_ST_DELAY, &(op->client_delay));
1179
1180 if (peer && dev) {
1181 op->id = crm_element_value_copy(dev, PCMK__XA_ST_REMOTE_OP);
1182 } else {
1183 op->id = crm_generate_uuid();
1184 }
1185
1186 g_hash_table_replace(stonith_remote_op_list, op->id, op);
1187
1188 op->state = st_query;
1189 op->replies_expected = fencing_active_peers();
1190 op->action = crm_element_value_copy(dev, PCMK__XA_ST_DEVICE_ACTION);
1191
1192 /* The node initiating the stonith operation. If an operation is relayed,
1193 * this is the last node the operation lands on. When in standalone mode,
1194 * origin is the ID of the client that originated the operation.
1195 *
1196 * Or may be the name of the function that created the operation.
1197 */
1198 op->originator = crm_element_value_copy(dev, PCMK__XA_ST_ORIGIN);
1199 if (op->originator == NULL) {
1200 /* Local or relayed request */
1201 op->originator = pcmk__str_copy(fenced_get_local_node());
1202 }
1203
1204 // Delegate may not be set
1205 op->delegate = crm_element_value_copy(dev, PCMK__XA_ST_DELEGATE);
1206 op->created = time(NULL);
1207
1208 CRM_LOG_ASSERT(client != NULL);
1209 op->client_id = pcmk__str_copy(client);
1210
1211 /* For a RELAY operation, set fenced on the client. */
1212 operation = crm_element_value(request, PCMK__XA_ST_OP);
1213
1214 if (pcmk__str_eq(operation, STONITH_OP_RELAY, pcmk__str_none)) {
1215 op->client_name = crm_strdup_printf("%s.%lu", crm_system_name,
1216 (unsigned long) getpid());
1217 } else {
1218 op->client_name = crm_element_value_copy(request,
1219 PCMK__XA_ST_CLIENTNAME);
1220 }
1221
1222 op->target = crm_element_value_copy(dev, PCMK__XA_ST_TARGET);
1223
1224 // @TODO Figure out how to avoid copying XML here
1225 op->request = pcmk__xml_copy(NULL, request);
1226
1227 rc = pcmk__xe_get_flags(request, PCMK__XA_ST_CALLOPT, &(op->call_options),
1228 0U);
1229 if (rc != pcmk_rc_ok) {
1230 crm_warn("Couldn't parse options from request %s: %s",
1231 op->id, pcmk_rc_str(rc));
1232 }
1233
1234 crm_element_value_int(request, PCMK__XA_ST_CALLID, &(op->client_callid));
1235
1236 crm_trace("%s new fencing op %s ('%s' targeting %s for client %s, "
1237 "base timeout %ds, %u %s expected)",
1238 (peer && dev)? "Recorded" : "Generated", op->id, op->action,
1239 op->target, op->client_name, op->base_timeout,
1240 op->replies_expected,
1241 pcmk__plural_alt(op->replies_expected, "reply", "replies"));
1242
1243 if (op->call_options & st_opt_cs_nodeid) {
1244 int nodeid;
1245 pcmk__node_status_t *node = NULL;
1246
1247 pcmk__scan_min_int(op->target, &nodeid, 0);
1248 node = pcmk__search_node_caches(nodeid, NULL, NULL,
1249 pcmk__node_search_any
1250 |pcmk__node_search_cluster_cib);
1251
1252 /* Ensure the conversion only happens once */
1253 stonith__clear_call_options(op->call_options, op->id, st_opt_cs_nodeid);
1254
1255 if ((node != NULL) && (node->name != NULL)) {
1256 pcmk__str_update(&(op->target), node->name);
1257
1258 } else {
1259 crm_warn("Could not expand nodeid '%s' into a host name", op->target);
1260 }
1261 }
1262
1263 /* check to see if this is a duplicate operation of another in-flight operation */
1264 merge_duplicates(op);
1265
1266 if (op->state != st_duplicate) {
1267 /* kick history readers */
1268 fenced_send_notification(PCMK__VALUE_ST_NOTIFY_HISTORY, NULL, NULL);
1269 }
1270
1271 /* safe to trim as long as that doesn't touch pending ops */
1272 stonith_fence_history_trim();
1273
1274 return op;
1275 }
1276
1277 /*!
1278 * \internal
1279 * \brief Create a peer fencing operation from a request, and initiate it
1280 *
1281 * \param[in] client IPC client that made request (NULL to get from request)
1282 * \param[in] request Request XML
1283 * \param[in] manual_ack Whether this is a manual action confirmation
1284 *
1285 * \return Newly created operation on success, otherwise NULL
1286 */
1287 remote_fencing_op_t *
1288 initiate_remote_stonith_op(const pcmk__client_t *client, xmlNode *request,
1289 gboolean manual_ack)
1290 {
1291 int query_timeout = 0;
1292 xmlNode *query = NULL;
1293 const char *client_id = NULL;
1294 remote_fencing_op_t *op = NULL;
1295 const char *relay_op_id = NULL;
1296 const char *operation = NULL;
1297
1298 if (client) {
1299 client_id = client->id;
1300 } else {
1301 client_id = crm_element_value(request, PCMK__XA_ST_CLIENTID);
1302 }
1303
1304 CRM_LOG_ASSERT(client_id != NULL);
1305 op = create_remote_stonith_op(client_id, request, FALSE);
1306 op->owner = TRUE;
1307 if (manual_ack) {
1308 return op;
1309 }
1310
1311 CRM_CHECK(op->action, return NULL);
1312
1313 if (advance_topology_level(op, true) != pcmk_rc_ok) {
1314 op->state = st_failed;
1315 }
1316
1317 switch (op->state) {
1318 case st_failed:
1319 // advance_topology_level() exhausted levels
1320 pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
1321 "All topology levels failed");
1322 crm_warn("Could not request peer fencing (%s) targeting %s "
1323 QB_XS " id=%.8s", op->action, op->target, op->id);
1324 finalize_op(op, NULL, false);
1325 return op;
1326
1327 case st_duplicate:
1328 crm_info("Requesting peer fencing (%s) targeting %s (duplicate) "
1329 QB_XS " id=%.8s", op->action, op->target, op->id);
1330 return op;
1331
1332 default:
1333 crm_notice("Requesting peer fencing (%s) targeting %s "
1334 QB_XS " id=%.8s state=%s base_timeout=%ds",
1335 op->action, op->target, op->id,
1336 stonith_op_state_str(op->state), op->base_timeout);
1337 }
1338
1339 query = stonith_create_op(op->client_callid, op->id, STONITH_OP_QUERY,
1340 NULL, op->call_options);
1341
1342 crm_xml_add(query, PCMK__XA_ST_REMOTE_OP, op->id);
1343 crm_xml_add(query, PCMK__XA_ST_TARGET, op->target);
1344 crm_xml_add(query, PCMK__XA_ST_DEVICE_ACTION, op_requested_action(op));
1345 crm_xml_add(query, PCMK__XA_ST_ORIGIN, op->originator);
1346 crm_xml_add(query, PCMK__XA_ST_CLIENTID, op->client_id);
1347 crm_xml_add(query, PCMK__XA_ST_CLIENTNAME, op->client_name);
1348 crm_xml_add_int(query, PCMK__XA_ST_TIMEOUT, op->base_timeout);
1349
1350 /* In case of RELAY operation, RELAY information is added to the query to delete the original operation of RELAY. */
1351 operation = crm_element_value(request, PCMK__XA_ST_OP);
1352 if (pcmk__str_eq(operation, STONITH_OP_RELAY, pcmk__str_none)) {
1353 relay_op_id = crm_element_value(request, PCMK__XA_ST_REMOTE_OP);
1354 if (relay_op_id) {
1355 crm_xml_add(query, PCMK__XA_ST_REMOTE_OP_RELAY, relay_op_id);
1356 }
1357 }
1358
1359 pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query);
1360 pcmk__xml_free(query);
1361
1362 query_timeout = op->base_timeout * TIMEOUT_MULTIPLY_FACTOR;
1363 op->query_timer = pcmk__create_timer((1000 * query_timeout), remote_op_query_timeout, op);
1364
1365 return op;
1366 }
1367
1368 enum find_best_peer_options {
1369 /*! Skip checking the target peer for capable fencing devices */
1370 FIND_PEER_SKIP_TARGET = 0x0001,
1371 /*! Only check the target peer for capable fencing devices */
1372 FIND_PEER_TARGET_ONLY = 0x0002,
1373 /*! Skip peers and devices that are not verified */
1374 FIND_PEER_VERIFIED_ONLY = 0x0004,
1375 };
1376
1377 static bool
1378 is_watchdog_fencing(const remote_fencing_op_t *op, const char *device)
1379 {
1380 return (stonith_watchdog_timeout_ms > 0
1381 // Only an explicit mismatch is considered not a watchdog fencing.
1382 && pcmk__str_eq(device, STONITH_WATCHDOG_ID, pcmk__str_null_matches)
1383 && pcmk__is_fencing_action(op->action)
1384 && node_does_watchdog_fencing(op->target));
1385 }
1386
1387 static peer_device_info_t *
1388 find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer_options options)
1389 {
1390 GList *iter = NULL;
1391 gboolean verified_devices_only = (options & FIND_PEER_VERIFIED_ONLY) ? TRUE : FALSE;
1392
1393 if (!device && pcmk_is_set(op->call_options, st_opt_topology)) {
1394 return NULL;
1395 }
1396
1397 for (iter = op->query_results; iter != NULL; iter = iter->next) {
1398 peer_device_info_t *peer = iter->data;
1399
1400 crm_trace("Testing result from %s targeting %s with %d device%s: %d %x",
1401 peer->host, op->target, peer->ndevices,
1402 pcmk__plural_s(peer->ndevices), peer->tried, options);
1403 if ((options & FIND_PEER_SKIP_TARGET) && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
1404 continue;
1405 }
1406 if ((options & FIND_PEER_TARGET_ONLY) && !pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
1407 continue;
1408 }
1409
1410 if (pcmk_is_set(op->call_options, st_opt_topology)) {
1411
1412 if (grab_peer_device(op, peer, device, verified_devices_only)) {
1413 return peer;
1414 }
1415
1416 } else if (!peer->tried
1417 && count_peer_devices(op, peer, verified_devices_only,
1418 fenced_support_flag(op->action))) {
1419 /* No topology: Use the current best peer */
1420 crm_trace("Simple fencing");
1421 return peer;
1422 }
1423 }
1424
1425 return NULL;
1426 }
1427
1428 static peer_device_info_t *
1429 stonith_choose_peer(remote_fencing_op_t * op)
1430 {
1431 const char *device = NULL;
1432 peer_device_info_t *peer = NULL;
1433 uint32_t active = fencing_active_peers();
1434
1435 do {
1436 if (op->devices) {
1437 device = op->devices->data;
1438 crm_trace("Checking for someone to fence (%s) %s using %s",
1439 op->action, op->target, device);
1440 } else {
1441 crm_trace("Checking for someone to fence (%s) %s",
1442 op->action, op->target);
1443 }
1444
1445 /* Best choice is a peer other than the target with verified access */
1446 peer = find_best_peer(device, op, FIND_PEER_SKIP_TARGET|FIND_PEER_VERIFIED_ONLY);
1447 if (peer) {
1448 crm_trace("Found verified peer %s for %s", peer->host, device?device:"<any>");
1449 return peer;
1450 }
1451
1452 if(op->query_timer != 0 && op->replies < QB_MIN(op->replies_expected, active)) {
1453 crm_trace("Waiting before looking for unverified devices to fence %s", op->target);
1454 return NULL;
1455 }
1456
1457 /* If no other peer has verified access, next best is unverified access */
1458 peer = find_best_peer(device, op, FIND_PEER_SKIP_TARGET);
1459 if (peer) {
1460 crm_trace("Found best unverified peer %s", peer->host);
1461 return peer;
1462 }
1463
1464 /* If no other peer can do it, last option is self-fencing
1465 * (which is never allowed for the "on" phase of a remapped reboot)
1466 */
1467 if (op->phase != st_phase_on) {
1468 peer = find_best_peer(device, op, FIND_PEER_TARGET_ONLY);
1469 if (peer) {
1470 crm_trace("%s will fence itself", peer->host);
1471 return peer;
1472 }
1473 }
1474
1475 /* Try the next fencing level if there is one (unless we're in the "on"
1476 * phase of a remapped "reboot", because we ignore errors in that case)
1477 */
1478 } while ((op->phase != st_phase_on)
1479 && pcmk_is_set(op->call_options, st_opt_topology)
1480 && (advance_topology_level(op, false) == pcmk_rc_ok));
1481
1482 /* With a simple watchdog fencing configuration without a topology,
1483 * "device" is NULL here. Consider it should be done with watchdog fencing.
1484 */
1485 if (is_watchdog_fencing(op, device)) {
1486 crm_info("Couldn't contact watchdog-fencing target-node (%s)",
1487 op->target);
1488 /* check_watchdog_fencing_and_wait will log additional info */
1489 } else {
1490 crm_notice("Couldn't find anyone to fence (%s) %s using %s",
1491 op->action, op->target, (device? device : "any device"));
1492 }
1493 return NULL;
1494 }
1495
1496 static int
1497 valid_fencing_timeout(int specified_timeout, bool action_specific,
1498 const remote_fencing_op_t *op, const char *device)
1499 {
1500 int timeout = specified_timeout;
1501
1502 if (!is_watchdog_fencing(op, device)) {
1503 return timeout;
1504 }
1505
1506 timeout = (int) QB_MIN(QB_MAX(specified_timeout,
1507 pcmk__timeout_ms2s(stonith_watchdog_timeout_ms)),
1508 INT_MAX);
1509
1510 if (timeout > specified_timeout) {
1511 if (action_specific) {
1512 crm_warn("pcmk_%s_timeout %ds for %s is too short (must be >= "
1513 PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " %ds), using %ds "
1514 "instead",
1515 op->action, specified_timeout, device? device : "watchdog",
1516 timeout, timeout);
1517
1518 } else {
1519 crm_warn("Fencing timeout %ds is too short (must be >= "
1520 PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " %ds), using %ds "
1521 "instead",
1522 specified_timeout, timeout, timeout);
1523 }
1524 }
1525
1526 return timeout;
1527 }
1528
1529 static int
1530 get_device_timeout(const remote_fencing_op_t *op,
1531 const peer_device_info_t *peer, const char *device,
1532 bool with_delay)
1533 {
1534 int timeout = op->base_timeout;
1535 device_properties_t *props;
1536
1537 timeout = valid_fencing_timeout(op->base_timeout, false, op, device);
1538
1539 if (!peer || !device) {
1540 return timeout;
1541 }
1542
1543 props = g_hash_table_lookup(peer->devices, device);
1544 if (!props) {
1545 return timeout;
1546 }
1547
1548 if (props->custom_action_timeout[op->phase]) {
1549 timeout = valid_fencing_timeout(props->custom_action_timeout[op->phase],
1550 true, op, device);
1551 }
1552
1553 // op->client_delay < 0 means disable any static/random fencing delays
1554 if (with_delay && (op->client_delay >= 0)) {
1555 // delay_base is eventually limited by delay_max
1556 timeout += (props->delay_max[op->phase] > 0 ?
1557 props->delay_max[op->phase] : props->delay_base[op->phase]);
1558 }
1559
1560 return timeout;
1561 }
1562
1563 struct timeout_data {
1564 const remote_fencing_op_t *op;
1565 const peer_device_info_t *peer;
1566 int total_timeout;
1567 };
1568
1569 /*!
1570 * \internal
1571 * \brief Add timeout to a total if device has not been executed yet
1572 *
1573 * \param[in] key GHashTable key (device ID)
1574 * \param[in] value GHashTable value (device properties)
1575 * \param[in,out] user_data Timeout data
1576 */
1577 static void
1578 add_device_timeout(gpointer key, gpointer value, gpointer user_data)
1579 {
1580 const char *device_id = key;
1581 device_properties_t *props = value;
1582 struct timeout_data *timeout = user_data;
1583
1584 if (!props->executed[timeout->op->phase]
1585 && !props->disallowed[timeout->op->phase]) {
1586 timeout->total_timeout += get_device_timeout(timeout->op, timeout->peer,
1587 device_id, true);
1588 }
1589 }
1590
1591 static int
1592 get_peer_timeout(const remote_fencing_op_t *op, const peer_device_info_t *peer)
1593 {
1594 struct timeout_data timeout;
1595
1596 timeout.op = op;
1597 timeout.peer = peer;
1598 timeout.total_timeout = 0;
1599
1600 g_hash_table_foreach(peer->devices, add_device_timeout, &timeout);
1601
1602 return (timeout.total_timeout? timeout.total_timeout : op->base_timeout);
1603 }
1604
1605 static int
1606 get_op_total_timeout(const remote_fencing_op_t *op,
1607 const peer_device_info_t *chosen_peer)
1608 {
1609 long long total_timeout = 0;
1610 stonith_topology_t *tp = find_topology_for_host(op->target);
1611
|
(1) Event path: |
Condition "pcmk_all_flags_set(op->call_options, st_opt_topology)", taking true branch. |
|
(2) Event path: |
Condition "tp", taking true branch. |
1612 if (pcmk_is_set(op->call_options, st_opt_topology) && tp) {
1613 int i;
1614 GList *device_list = NULL;
1615 GList *iter = NULL;
1616 GList *auto_list = NULL;
1617
|
(3) Event path: |
Condition "pcmk__str_eq(op->action, "on", pcmk__str_none)", taking true branch. |
|
(4) Event path: |
Condition "op->automatic_list != NULL", taking true branch. |
1618 if (pcmk__str_eq(op->action, PCMK_ACTION_ON, pcmk__str_none)
1619 && (op->automatic_list != NULL)) {
1620 auto_list = g_list_copy(op->automatic_list);
1621 }
1622
1623 /* Yep, this looks scary, nested loops all over the place.
1624 * Here is what is going on.
1625 * Loop1: Iterate through fencing levels.
1626 * Loop2: If a fencing level has devices, loop through each device
1627 * Loop3: For each device in a fencing level, see what peer owns it
1628 * and what that peer has reported the timeout is for the device.
1629 */
|
(5) Event path: |
Condition "i < 10", taking true branch. |
|
(8) Event path: |
Condition "i < 10", taking true branch. |
|
(11) Event path: |
Condition "i < 10", taking true branch. |
|
(38) Event path: |
Condition "i < 10", taking false branch. |
1630 for (i = 0; i < ST__LEVEL_COUNT; i++) {
|
(6) Event path: |
Condition "!tp->levels[i]", taking true branch. |
|
(9) Event path: |
Condition "!tp->levels[i]", taking true branch. |
|
(12) Event path: |
Condition "!tp->levels[i]", taking false branch. |
1631 if (!tp->levels[i]) {
|
(7) Event path: |
Continuing loop. |
|
(10) Event path: |
Continuing loop. |
1632 continue;
1633 }
|
(13) Event path: |
Condition "device_list", taking true branch. |
|
(26) Event path: |
Condition "device_list", taking true branch. |
|
(36) Event path: |
Condition "device_list", taking false branch. |
1634 for (device_list = tp->levels[i]; device_list; device_list = device_list->next) {
1635 bool found = false;
1636
|
(14) Event path: |
Condition "iter != NULL", taking true branch. |
|
(19) Event path: |
Condition "iter != NULL", taking true branch. |
|
(27) Event path: |
Condition "iter != NULL", taking true branch. |
|
(32) Event path: |
Condition "iter != NULL", taking false branch. |
1637 for (iter = op->query_results; iter != NULL; iter = iter->next) {
1638 const peer_device_info_t *peer = iter->data;
1639
|
(15) Event path: |
Condition "auto_list", taking true branch. |
|
(20) Event path: |
Condition "auto_list", taking true branch. |
|
(28) Event path: |
Condition "auto_list", taking true branch. |
1640 if (auto_list) {
1641 GList *match = g_list_find_custom(auto_list, device_list->data,
1642 sort_strings);
|
(16) Event path: |
Condition "match", taking true branch. |
|
(21) Event path: |
Condition "match", taking true branch. |
|
(29) Event path: |
Condition "match", taking true branch. |
1643 if (match) {
1644 auto_list = g_list_remove(auto_list, match->data);
1645 }
1646 }
1647
|
(17) Event path: |
Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking false branch. |
|
(22) Event path: |
Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking true branch. |
|
(30) Event path: |
Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking false branch. |
1648 if (find_peer_device(op, peer, device_list->data,
1649 fenced_support_flag(op->action))) {
1650 total_timeout += get_device_timeout(op, peer,
1651 device_list->data,
1652 true);
1653 found = true;
|
(23) Event path: |
Breaking from loop. |
1654 break;
1655 }
|
(18) Event path: |
Jumping back to the beginning of the loop. |
|
(31) Event path: |
Jumping back to the beginning of the loop. |
1656 } /* End Loop3: match device with peer that owns device, find device's timeout period */
1657
1658 /* in case of watchdog-device we add the timeout to the budget
1659 if didn't get a reply
1660 */
|
(24) Event path: |
Condition "!found", taking false branch. |
|
(33) Event path: |
Condition "!found", taking true branch. |
|
(34) Event path: |
Condition "is_watchdog_fencing(op, device_list->data)", taking true branch. |
1661 if (!found && is_watchdog_fencing(op, device_list->data)) {
1662 total_timeout += pcmk__timeout_ms2s(stonith_watchdog_timeout_ms);
1663 }
|
(25) Event path: |
Jumping back to the beginning of the loop. |
|
(35) Event path: |
Jumping back to the beginning of the loop. |
1664 } /* End Loop2: iterate through devices at a specific level */
|
(37) Event path: |
Jumping back to the beginning of the loop. |
1665 } /*End Loop1: iterate through fencing levels */
1666
1667 //Add only exists automatic_list device timeout
|
(39) Event path: |
Condition "auto_list", taking true branch. |
1668 if (auto_list) {
|
(40) Event path: |
Condition "iter != NULL", taking true branch. |
1669 for (iter = auto_list; iter != NULL; iter = iter->next) {
1670 GList *iter2 = NULL;
1671
|
(41) Event path: |
Condition "iter2 != NULL", taking true branch. |
|
(44) Event null_field: |
Reading field "next", which is expected to possibly be "NULL" in "iter2->next" (checked 454 out of 456 times). |
|
(45) Event alias_transfer: |
Assigning: "iter" = "iter2->next". |
|
(46) Event path: |
Condition "iter2 != NULL", taking true branch. |
| Also see events: |
[dereference][example_checked][example_checked][example_checked][example_checked][example_checked] |
1672 for (iter2 = op->query_results; iter2 != NULL; iter = iter2->next) {
1673 peer_device_info_t *peer = iter2->data;
|
CID (unavailable; MK=eb81cf483c48825540e07bbd95bb12d8) (#1 of 1): Dereference of potentially null field (NULL_FIELD): |
1674 if (find_peer_device(op, peer, iter->data, st_device_supports_on)) {
1675 total_timeout += get_device_timeout(op, peer,
1676 iter->data, true);
1677 break;
1678 }
|
(43) Event path: |
Jumping back to the beginning of the loop. |
1679 }
1680 }
1681 }
1682
1683 g_list_free(auto_list);
1684
1685 } else if (chosen_peer) {
1686 total_timeout = get_peer_timeout(op, chosen_peer);
1687
1688 } else {
1689 total_timeout = valid_fencing_timeout(op->base_timeout, false, op,
1690 NULL);
1691 }
1692
1693 if (total_timeout <= 0) {
1694 total_timeout = op->base_timeout;
1695 }
1696
1697 /* Take any requested fencing delay into account to prevent it from eating
1698 * up the total timeout.
1699 */
1700 if (op->client_delay > 0) {
1701 total_timeout += op->client_delay;
1702 }
1703 return (int) QB_MIN(total_timeout, INT_MAX);
1704 }
1705
1706 static void
1707 report_timeout_period(remote_fencing_op_t * op, int op_timeout)
1708 {
1709 GList *iter = NULL;
1710 xmlNode *update = NULL;
1711 const char *client_node = NULL;
1712 const char *client_id = NULL;
1713 const char *call_id = NULL;
1714
1715 if (op->call_options & st_opt_sync_call) {
1716 /* There is no reason to report the timeout for a synchronous call. It
1717 * is impossible to use the reported timeout to do anything when the client
1718 * is blocking for the response. This update is only important for
1719 * async calls that require a callback to report the results in. */
1720 return;
1721 } else if (!op->request) {
1722 return;
1723 }
1724
1725 crm_trace("Reporting timeout for %s (id=%.8s)", op->client_name, op->id);
1726 client_node = crm_element_value(op->request, PCMK__XA_ST_CLIENTNODE);
1727 call_id = crm_element_value(op->request, PCMK__XA_ST_CALLID);
1728 client_id = crm_element_value(op->request, PCMK__XA_ST_CLIENTID);
1729 if (!client_node || !call_id || !client_id) {
1730 return;
1731 }
1732
1733 if (pcmk__str_eq(client_node, fenced_get_local_node(), pcmk__str_casei)) {
1734 // Client is connected to this node, so send update directly to them
1735 do_stonith_async_timeout_update(client_id, call_id, op_timeout);
1736 return;
1737 }
1738
1739 /* The client is connected to another node, relay this update to them */
1740 update = stonith_create_op(op->client_callid, op->id, STONITH_OP_TIMEOUT_UPDATE, NULL, 0);
1741 crm_xml_add(update, PCMK__XA_ST_REMOTE_OP, op->id);
1742 crm_xml_add(update, PCMK__XA_ST_CLIENTID, client_id);
1743 crm_xml_add(update, PCMK__XA_ST_CALLID, call_id);
1744 crm_xml_add_int(update, PCMK__XA_ST_TIMEOUT, op_timeout);
1745
1746 pcmk__cluster_send_message(pcmk__get_node(0, client_node, NULL,
1747 pcmk__node_search_cluster_member),
1748 pcmk_ipc_fenced, update);
1749
1750 pcmk__xml_free(update);
1751
1752 for (iter = op->duplicates; iter != NULL; iter = iter->next) {
1753 remote_fencing_op_t *dup = iter->data;
1754
1755 crm_trace("Reporting timeout for duplicate %.8s to client %s",
1756 dup->id, dup->client_name);
1757 report_timeout_period(iter->data, op_timeout);
1758 }
1759 }
1760
1761 /*!
1762 * \internal
1763 * \brief Advance an operation to the next device in its topology
1764 *
1765 * \param[in,out] op Fencer operation to advance
1766 * \param[in] device ID of device that just completed
1767 * \param[in,out] msg If not NULL, XML reply of last delegated operation
1768 */
1769 static void
1770 advance_topology_device_in_level(remote_fencing_op_t *op, const char *device,
1771 xmlNode *msg)
1772 {
1773 /* Advance to the next device at this topology level, if any */
1774 if (op->devices) {
1775 op->devices = op->devices->next;
1776 }
1777
1778 /* Handle automatic unfencing if an "on" action was requested */
1779 if ((op->phase == st_phase_requested)
1780 && pcmk__str_eq(op->action, PCMK_ACTION_ON, pcmk__str_none)) {
1781 /* If the device we just executed was required, it's not anymore */
1782 remove_required_device(op, device);
1783
1784 /* If there are no more devices at this topology level, run through any
1785 * remaining devices with automatic unfencing
1786 */
1787 if (op->devices == NULL) {
1788 op->devices = op->automatic_list;
1789 }
1790 }
1791
1792 if ((op->devices == NULL) && (op->phase == st_phase_off)) {
1793 /* We're done with this level and with required devices, but we had
1794 * remapped "reboot" to "off", so start over with "on". If any devices
1795 * need to be turned back on, op->devices will be non-NULL after this.
1796 */
1797 op_phase_on(op);
1798 }
1799
1800 // This function is only called if the previous device succeeded
1801 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
1802
1803 if (op->devices) {
1804 /* Necessary devices remain, so execute the next one */
1805 crm_trace("Next targeting %s on behalf of %s@%s",
1806 op->target, op->client_name, op->originator);
1807
1808 // The requested delay has been applied for the first device
1809 if (op->client_delay > 0) {
1810 op->client_delay = 0;
1811 }
1812
1813 request_peer_fencing(op, NULL);
1814 } else {
1815 /* We're done with all devices and phases, so finalize operation */
1816 crm_trace("Marking complex fencing op targeting %s as complete",
1817 op->target);
1818 op->state = st_done;
1819 finalize_op(op, msg, false);
1820 }
1821 }
1822
1823 static gboolean
1824 check_watchdog_fencing_and_wait(remote_fencing_op_t * op)
1825 {
1826 if (node_does_watchdog_fencing(op->target)) {
1827 guint timeout_ms = QB_MIN(stonith_watchdog_timeout_ms, UINT_MAX);
1828
1829 crm_notice("Waiting %s for %s to self-fence (%s) for "
1830 "client %s " QB_XS " id=%.8s",
1831 pcmk__readable_interval(timeout_ms), op->target, op->action,
1832 op->client_name, op->id);
1833
1834 if (op->op_timer_one) {
1835 g_source_remove(op->op_timer_one);
1836 }
1837 op->op_timer_one = pcmk__create_timer(timeout_ms, remote_op_watchdog_done,
1838 op);
1839 return TRUE;
1840 } else {
1841 crm_debug("Skipping fallback to watchdog-fencing as %s is "
1842 "not in host-list", op->target);
1843 }
1844 return FALSE;
1845 }
1846
1847 /*!
1848 * \internal
1849 * \brief Ask a peer to execute a fencing operation
1850 *
1851 * \param[in,out] op Fencing operation to be executed
1852 * \param[in,out] peer If NULL or topology is in use, choose best peer to
1853 * execute the fencing, otherwise use this peer
1854 */
1855 static void
1856 request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer)
1857 {
1858 const char *device = NULL;
1859 int timeout;
1860
1861 CRM_CHECK(op != NULL, return);
1862
1863 crm_trace("Action %.8s targeting %s for %s is %s",
1864 op->id, op->target, op->client_name,
1865 stonith_op_state_str(op->state));
1866
1867 if ((op->phase == st_phase_on) && (op->devices != NULL)) {
1868 /* We are in the "on" phase of a remapped topology reboot. If this
1869 * device has pcmk_reboot_action="off", or doesn't support the "on"
1870 * action, skip it.
1871 *
1872 * We can't check device properties at this point because we haven't
1873 * chosen a peer for this stage yet. Instead, we check the local node's
1874 * knowledge about the device. If different versions of the fence agent
1875 * are installed on different nodes, there's a chance this could be
1876 * mistaken, but the worst that could happen is we don't try turning the
1877 * node back on when we should.
1878 */
1879 device = op->devices->data;
1880 if (pcmk__str_eq(fenced_device_reboot_action(device), PCMK_ACTION_OFF,
1881 pcmk__str_none)) {
1882 crm_info("Not turning %s back on using %s because the device is "
1883 "configured to stay off (pcmk_reboot_action='off')",
1884 op->target, device);
1885 advance_topology_device_in_level(op, device, NULL);
1886 return;
1887 }
1888 if (!fenced_device_supports_on(device)) {
1889 crm_info("Not turning %s back on using %s because the agent "
1890 "doesn't support 'on'", op->target, device);
1891 advance_topology_device_in_level(op, device, NULL);
1892 return;
1893 }
1894 }
1895
1896 timeout = op->base_timeout;
1897 if ((peer == NULL) && !pcmk_is_set(op->call_options, st_opt_topology)) {
1898 peer = stonith_choose_peer(op);
1899 }
1900
1901 if (!op->op_timer_total) {
1902 op->total_timeout = TIMEOUT_MULTIPLY_FACTOR * get_op_total_timeout(op, peer);
1903 op->op_timer_total = pcmk__create_timer(1000 * op->total_timeout, remote_op_timeout, op);
1904 report_timeout_period(op, op->total_timeout);
1905 crm_info("Total timeout set to %ds for peer's fencing targeting %s for %s "
1906 QB_XS " id=%.8s",
1907 op->total_timeout, op->target, op->client_name, op->id);
1908 }
1909
1910 if (pcmk_is_set(op->call_options, st_opt_topology) && op->devices) {
1911 /* Ignore the caller's peer preference if topology is in use, because
1912 * that peer might not have access to the required device. With
1913 * topology, stonith_choose_peer() removes the device from further
1914 * consideration, so the timeout must be calculated beforehand.
1915 *
1916 * @TODO Basing the total timeout on the caller's preferred peer (above)
1917 * is less than ideal.
1918 */
1919 peer = stonith_choose_peer(op);
1920
1921 device = op->devices->data;
1922 /* Fencing timeout sent to peer takes no delay into account.
1923 * The peer will add a dedicated timer for any delay upon
1924 * schedule_stonith_command().
1925 */
1926 timeout = get_device_timeout(op, peer, device, false);
1927 }
1928
1929 if (peer) {
1930 int timeout_one = 0;
1931 xmlNode *remote_op = stonith_create_op(op->client_callid, op->id, STONITH_OP_FENCE, NULL, 0);
1932 const pcmk__node_status_t *peer_node =
1933 pcmk__get_node(0, peer->host, NULL,
1934 pcmk__node_search_cluster_member);
1935
1936 if (op->client_delay > 0) {
1937 /* Take requested fencing delay into account to prevent it from
1938 * eating up the timeout.
1939 */
1940 timeout_one = TIMEOUT_MULTIPLY_FACTOR * op->client_delay;
1941 }
1942
1943 crm_xml_add(remote_op, PCMK__XA_ST_REMOTE_OP, op->id);
1944 crm_xml_add(remote_op, PCMK__XA_ST_TARGET, op->target);
1945 crm_xml_add(remote_op, PCMK__XA_ST_DEVICE_ACTION, op->action);
1946 crm_xml_add(remote_op, PCMK__XA_ST_ORIGIN, op->originator);
1947 crm_xml_add(remote_op, PCMK__XA_ST_CLIENTID, op->client_id);
1948 crm_xml_add(remote_op, PCMK__XA_ST_CLIENTNAME, op->client_name);
1949 crm_xml_add_int(remote_op, PCMK__XA_ST_TIMEOUT, timeout);
1950 crm_xml_add_int(remote_op, PCMK__XA_ST_CALLOPT, op->call_options);
1951 crm_xml_add_int(remote_op, PCMK__XA_ST_DELAY, op->client_delay);
1952
1953 if (device) {
1954 timeout_one += TIMEOUT_MULTIPLY_FACTOR *
1955 get_device_timeout(op, peer, device, true);
1956 crm_notice("Requesting that %s perform '%s' action targeting %s "
1957 "using %s " QB_XS " for client %s (%ds)",
1958 peer->host, op->action, op->target, device,
1959 op->client_name, timeout_one);
1960 crm_xml_add(remote_op, PCMK__XA_ST_DEVICE_ID, device);
1961
1962 } else {
1963 timeout_one += TIMEOUT_MULTIPLY_FACTOR * get_peer_timeout(op, peer);
1964 crm_notice("Requesting that %s perform '%s' action targeting %s "
1965 QB_XS " for client %s (%ds, %s)",
1966 peer->host, op->action, op->target, op->client_name,
1967 timeout_one,
1968 pcmk__readable_interval(stonith_watchdog_timeout_ms));
1969 }
1970
1971 op->state = st_exec;
1972 if (op->op_timer_one) {
1973 g_source_remove(op->op_timer_one);
1974 op->op_timer_one = 0;
1975 }
1976
1977 if (!is_watchdog_fencing(op, device)
1978 || !check_watchdog_fencing_and_wait(op)) {
1979
1980 /* Some thoughts about self-fencing cases reaching this point:
1981 - Actually check in check_watchdog_fencing_and_wait
1982 shouldn't fail if STONITH_WATCHDOG_ID is
1983 chosen as fencing-device and it being present implies
1984 watchdog-fencing is enabled anyway
1985 - If watchdog-fencing is disabled either in general or for
1986 a specific target - detected in check_watchdog_fencing_and_wait -
1987 for some other kind of self-fencing we can't expect
1988 a success answer but timeout is fine if the node doesn't
1989 come back in between
1990 - Delicate might be the case where we have watchdog-fencing
1991 enabled for a node but the watchdog-fencing-device isn't
1992 explicitly chosen for self-fencing. Local scheduler execution
1993 in sbd might detect the node as unclean and lead to timely
1994 self-fencing. Otherwise the selection of
1995 PCMK_OPT_STONITH_WATCHDOG_TIMEOUT at least is questionable.
1996 */
1997
1998 /* coming here we're not waiting for watchdog timeout -
1999 thus engage timer with timout evaluated before */
2000 op->op_timer_one = pcmk__create_timer((1000 * timeout_one), remote_op_timeout_one, op);
2001 }
2002
2003 pcmk__cluster_send_message(peer_node, pcmk_ipc_fenced, remote_op);
2004 peer->tried = TRUE;
2005 pcmk__xml_free(remote_op);
2006 return;
2007
2008 } else if (op->phase == st_phase_on) {
2009 /* A remapped "on" cannot be executed, but the node was already
2010 * turned off successfully, so ignore the error and continue.
2011 */
2012 crm_warn("Ignoring %s 'on' failure (no capable peers) targeting %s "
2013 "after successful 'off'", device, op->target);
2014 advance_topology_device_in_level(op, device, NULL);
2015 return;
2016
2017 } else if (op->owner == FALSE) {
2018 crm_err("Fencing (%s) targeting %s for client %s is not ours to control",
2019 op->action, op->target, op->client_name);
2020
2021 } else if (op->query_timer == 0) {
2022 /* We've exhausted all available peers */
2023 crm_info("No remaining peers capable of fencing (%s) %s for client %s "
2024 QB_XS " state=%s", op->action, op->target, op->client_name,
2025 stonith_op_state_str(op->state));
2026 CRM_CHECK(op->state < st_done, return);
2027 finalize_timed_out_op(op, "All nodes failed, or are unable, to "
2028 "fence target");
2029
2030 } else if(op->replies >= op->replies_expected || op->replies >= fencing_active_peers()) {
2031 /* if the operation never left the query state,
2032 * but we have all the expected replies, then no devices
2033 * are available to execute the fencing operation. */
2034
2035 if (is_watchdog_fencing(op, device)
2036 && check_watchdog_fencing_and_wait(op)) {
2037 /* Consider a watchdog fencing targeting an offline node executing
2038 * once it starts waiting for the target to self-fence. So that when
2039 * the query timer pops, remote_op_query_timeout() considers the
2040 * fencing already in progress.
2041 */
2042 op->state = st_exec;
2043 return;
2044 }
2045
2046 if (op->state == st_query) {
2047 crm_info("No peers (out of %d) have devices capable of fencing "
2048 "(%s) %s for client %s " QB_XS " state=%s",
2049 op->replies, op->action, op->target, op->client_name,
2050 stonith_op_state_str(op->state));
2051
2052 pcmk__reset_result(&op->result);
2053 pcmk__set_result(&op->result, CRM_EX_ERROR,
2054 PCMK_EXEC_NO_FENCE_DEVICE, NULL);
2055 } else {
2056 if (pcmk_is_set(op->call_options, st_opt_topology)) {
2057 pcmk__reset_result(&op->result);
2058 pcmk__set_result(&op->result, CRM_EX_ERROR,
2059 PCMK_EXEC_NO_FENCE_DEVICE, NULL);
2060 }
2061 /* ... else use existing result from previous failed attempt
2062 * (topology is not in use, and no devices remain to be attempted).
2063 * Overwriting the result with PCMK_EXEC_NO_FENCE_DEVICE would
2064 * prevent finalize_op() from setting the correct delegate if
2065 * needed.
2066 */
2067
2068 crm_info("No peers (out of %d) are capable of fencing (%s) %s "
2069 "for client %s " QB_XS " state=%s",
2070 op->replies, op->action, op->target, op->client_name,
2071 stonith_op_state_str(op->state));
2072 }
2073
2074 op->state = st_failed;
2075 finalize_op(op, NULL, false);
2076
2077 } else {
2078 crm_info("Waiting for additional peers capable of fencing (%s) %s%s%s "
2079 "for client %s " QB_XS " id=%.8s",
2080 op->action, op->target, (device? " using " : ""),
2081 (device? device : ""), op->client_name, op->id);
2082 }
2083 }
2084
2085 /*!
2086 * \internal
2087 * \brief Comparison function for sorting query results
2088 *
2089 * \param[in] a GList item to compare
2090 * \param[in] b GList item to compare
2091 *
2092 * \return Per the glib documentation, "a negative integer if the first value
2093 * comes before the second, 0 if they are equal, or a positive integer
2094 * if the first value comes after the second."
2095 */
2096 static gint
2097 sort_peers(gconstpointer a, gconstpointer b)
2098 {
2099 const peer_device_info_t *peer_a = a;
2100 const peer_device_info_t *peer_b = b;
2101
2102 return (peer_b->ndevices - peer_a->ndevices);
2103 }
2104
2105 /*!
2106 * \internal
2107 * \brief Determine if all the devices in the topology are found or not
2108 *
2109 * \param[in] op Fencing operation with topology to check
2110 */
2111 static gboolean
2112 all_topology_devices_found(const remote_fencing_op_t *op)
2113 {
2114 GList *device = NULL;
2115 GList *iter = NULL;
2116 device_properties_t *match = NULL;
2117 stonith_topology_t *tp = NULL;
2118 gboolean skip_target = FALSE;
2119 int i;
2120
2121 tp = find_topology_for_host(op->target);
2122 if (!tp) {
2123 return FALSE;
2124 }
2125 if (pcmk__is_fencing_action(op->action)) {
2126 /* Don't count the devices on the target node if we are killing
2127 * the target node. */
2128 skip_target = TRUE;
2129 }
2130
2131 for (i = 0; i < ST__LEVEL_COUNT; i++) {
2132 for (device = tp->levels[i]; device; device = device->next) {
2133 match = NULL;
2134 for (iter = op->query_results; iter && !match; iter = iter->next) {
2135 peer_device_info_t *peer = iter->data;
2136
2137 if (skip_target && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
2138 continue;
2139 }
2140 match = find_peer_device(op, peer, device->data, st_device_supports_none);
2141 }
2142 if (!match) {
2143 return FALSE;
2144 }
2145 }
2146 }
2147
2148 return TRUE;
2149 }
2150
2151 /*!
2152 * \internal
2153 * \brief Parse action-specific device properties from XML
2154 *
2155 * \param[in] xml XML element containing the properties
2156 * \param[in] peer Name of peer that sent XML (for logs)
2157 * \param[in] device Device ID (for logs)
2158 * \param[in] action Action the properties relate to (for logs)
2159 * \param[in,out] op Fencing operation that properties are being parsed for
2160 * \param[in] phase Phase the properties relate to
2161 * \param[in,out] props Device properties to update
2162 */
2163 static void
2164 parse_action_specific(const xmlNode *xml, const char *peer, const char *device,
2165 const char *action, remote_fencing_op_t *op,
2166 enum st_remap_phase phase, device_properties_t *props)
2167 {
2168 props->custom_action_timeout[phase] = 0;
2169 crm_element_value_int(xml, PCMK__XA_ST_ACTION_TIMEOUT,
2170 &props->custom_action_timeout[phase]);
2171 if (props->custom_action_timeout[phase]) {
2172 crm_trace("Peer %s with device %s returned %s action timeout %ds",
2173 peer, device, action, props->custom_action_timeout[phase]);
2174 }
2175
2176 props->delay_max[phase] = 0;
2177 crm_element_value_int(xml, PCMK__XA_ST_DELAY_MAX, &props->delay_max[phase]);
2178 if (props->delay_max[phase]) {
2179 crm_trace("Peer %s with device %s returned maximum of random delay %ds for %s",
2180 peer, device, props->delay_max[phase], action);
2181 }
2182
2183 props->delay_base[phase] = 0;
2184 crm_element_value_int(xml, PCMK__XA_ST_DELAY_BASE,
2185 &props->delay_base[phase]);
2186 if (props->delay_base[phase]) {
2187 crm_trace("Peer %s with device %s returned base delay %ds for %s",
2188 peer, device, props->delay_base[phase], action);
2189 }
2190
2191 /* Handle devices with automatic unfencing */
2192 if (pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none)) {
2193 int required = 0;
2194
2195 crm_element_value_int(xml, PCMK__XA_ST_REQUIRED, &required);
2196 if (required) {
2197 crm_trace("Peer %s requires device %s to execute for action %s",
2198 peer, device, action);
2199 add_required_device(op, device);
2200 }
2201 }
2202
2203 /* If a reboot is remapped to off+on, it's possible that a node is allowed
2204 * to perform one action but not another.
2205 */
2206 if (pcmk__xe_attr_is_true(xml, PCMK__XA_ST_ACTION_DISALLOWED)) {
2207 props->disallowed[phase] = TRUE;
2208 crm_trace("Peer %s is disallowed from executing %s for device %s",
2209 peer, action, device);
2210 }
2211 }
2212
2213 /*!
2214 * \internal
2215 * \brief Parse one device's properties from peer's XML query reply
2216 *
2217 * \param[in] xml XML node containing device properties
2218 * \param[in,out] op Operation that query and reply relate to
2219 * \param[in,out] peer Peer's device information
2220 * \param[in] device ID of device being parsed
2221 */
2222 static void
2223 add_device_properties(const xmlNode *xml, remote_fencing_op_t *op,
2224 peer_device_info_t *peer, const char *device)
2225 {
2226 xmlNode *child;
2227 int verified = 0;
2228 device_properties_t *props =
2229 pcmk__assert_alloc(1, sizeof(device_properties_t));
2230 int rc = pcmk_rc_ok;
2231
2232 /* Add a new entry to this peer's devices list */
2233 g_hash_table_insert(peer->devices, pcmk__str_copy(device), props);
2234
2235 /* Peers with verified (monitored) access will be preferred */
2236 crm_element_value_int(xml, PCMK__XA_ST_MONITOR_VERIFIED, &verified);
2237 if (verified) {
2238 crm_trace("Peer %s has confirmed a verified device %s",
2239 peer->host, device);
2240 props->verified = TRUE;
2241 }
2242
2243 // Nodes <2.1.5 won't set this, so assume unfencing in that case
2244 rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_DEVICE_SUPPORT_FLAGS,
2245 &(props->device_support_flags),
2246 st_device_supports_on);
2247 if (rc != pcmk_rc_ok) {
2248 crm_warn("Couldn't determine device support for %s "
2249 "(assuming unfencing): %s", device, pcmk_rc_str(rc));
2250 }
2251
2252 /* Parse action-specific device properties */
2253 parse_action_specific(xml, peer->host, device, op_requested_action(op),
2254 op, st_phase_requested, props);
2255 for (child = pcmk__xe_first_child(xml, NULL, NULL, NULL); child != NULL;
2256 child = pcmk__xe_next(child, NULL)) {
2257 /* Replies for "reboot" operations will include the action-specific
2258 * values for "off" and "on" in child elements, just in case the reboot
2259 * winds up getting remapped.
2260 */
2261 if (pcmk__str_eq(pcmk__xe_id(child), PCMK_ACTION_OFF, pcmk__str_none)) {
2262 parse_action_specific(child, peer->host, device, PCMK_ACTION_OFF,
2263 op, st_phase_off, props);
2264
2265 } else if (pcmk__str_eq(pcmk__xe_id(child), PCMK_ACTION_ON,
2266 pcmk__str_none)) {
2267 parse_action_specific(child, peer->host, device, PCMK_ACTION_ON,
2268 op, st_phase_on, props);
2269 }
2270 }
2271 }
2272
2273 /*!
2274 * \internal
2275 * \brief Parse a peer's XML query reply and add it to operation's results
2276 *
2277 * \param[in,out] op Operation that query and reply relate to
2278 * \param[in] host Name of peer that sent this reply
2279 * \param[in] ndevices Number of devices expected in reply
2280 * \param[in] xml XML node containing device list
2281 *
2282 * \return Newly allocated result structure with parsed reply
2283 */
2284 static peer_device_info_t *
2285 add_result(remote_fencing_op_t *op, const char *host, int ndevices,
2286 const xmlNode *xml)
2287 {
2288 peer_device_info_t *peer = pcmk__assert_alloc(1,
2289 sizeof(peer_device_info_t));
2290 xmlNode *child;
2291
2292 peer->host = pcmk__str_copy(host);
2293 peer->devices = pcmk__strkey_table(free, free);
2294
2295 /* Each child element describes one capable device available to the peer */
2296 for (child = pcmk__xe_first_child(xml, NULL, NULL, NULL); child != NULL;
2297 child = pcmk__xe_next(child, NULL)) {
2298 const char *device = pcmk__xe_id(child);
2299
2300 if (device) {
2301 add_device_properties(child, op, peer, device);
2302 }
2303 }
2304
2305 peer->ndevices = g_hash_table_size(peer->devices);
2306 CRM_CHECK(ndevices == peer->ndevices,
2307 crm_err("Query claimed to have %d device%s but %d found",
2308 ndevices, pcmk__plural_s(ndevices), peer->ndevices));
2309
2310 op->query_results = g_list_insert_sorted(op->query_results, peer, sort_peers);
2311 return peer;
2312 }
2313
2314 /*!
2315 * \internal
2316 * \brief Handle a peer's reply to our fencing query
2317 *
2318 * Parse a query result from XML and store it in the remote operation
2319 * table, and when enough replies have been received, issue a fencing request.
2320 *
2321 * \param[in] msg XML reply received
2322 *
2323 * \return pcmk_ok on success, -errno on error
2324 *
2325 * \note See initiate_remote_stonith_op() for how the XML query was initially
2326 * formed, and stonith_query() for how the peer formed its XML reply.
2327 */
2328 int
2329 process_remote_stonith_query(xmlNode *msg)
2330 {
2331 int ndevices = 0;
2332 gboolean host_is_target = FALSE;
2333 gboolean have_all_replies = FALSE;
2334 const char *id = NULL;
2335 const char *host = NULL;
2336 remote_fencing_op_t *op = NULL;
2337 peer_device_info_t *peer = NULL;
2338 uint32_t replies_expected;
2339 xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_REMOTE_OP, msg, LOG_ERR);
2340
2341 CRM_CHECK(dev != NULL, return -EPROTO);
2342
2343 id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
2344 CRM_CHECK(id != NULL, return -EPROTO);
2345
2346 dev = get_xpath_object("//@" PCMK__XA_ST_AVAILABLE_DEVICES, msg, LOG_ERR);
2347 CRM_CHECK(dev != NULL, return -EPROTO);
2348 crm_element_value_int(dev, PCMK__XA_ST_AVAILABLE_DEVICES, &ndevices);
2349
2350 op = g_hash_table_lookup(stonith_remote_op_list, id);
2351 if (op == NULL) {
2352 crm_debug("Received query reply for unknown or expired operation %s",
2353 id);
2354 return -EOPNOTSUPP;
2355 }
2356
2357 replies_expected = fencing_active_peers();
2358 if (op->replies_expected < replies_expected) {
2359 replies_expected = op->replies_expected;
2360 }
2361 if ((++op->replies >= replies_expected) && (op->state == st_query)) {
2362 have_all_replies = TRUE;
2363 }
2364 host = crm_element_value(msg, PCMK__XA_SRC);
2365 host_is_target = pcmk__str_eq(host, op->target, pcmk__str_casei);
2366
2367 crm_info("Query result %d of %d from %s for %s/%s (%d device%s) %s",
2368 op->replies, replies_expected, host,
2369 op->target, op->action, ndevices, pcmk__plural_s(ndevices), id);
2370 if (ndevices > 0) {
2371 peer = add_result(op, host, ndevices, dev);
2372 }
2373
2374 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
2375
2376 if (pcmk_is_set(op->call_options, st_opt_topology)) {
2377 /* If we start the fencing before all the topology results are in,
2378 * it is possible fencing levels will be skipped because of the missing
2379 * query results. */
2380 if (op->state == st_query && all_topology_devices_found(op)) {
2381 /* All the query results are in for the topology, start the fencing ops. */
2382 crm_trace("All topology devices found");
2383 request_peer_fencing(op, peer);
2384
2385 } else if (have_all_replies) {
2386 crm_info("All topology query replies have arrived, continuing (%d expected/%d received) ",
2387 replies_expected, op->replies);
2388 request_peer_fencing(op, NULL);
2389 }
2390
2391 } else if (op->state == st_query) {
2392 int nverified = count_peer_devices(op, peer, TRUE,
2393 fenced_support_flag(op->action));
2394
2395 /* We have a result for a non-topology fencing op that looks promising,
2396 * go ahead and start fencing before query timeout */
2397 if ((peer != NULL) && !host_is_target && nverified) {
2398 /* we have a verified device living on a peer that is not the target */
2399 crm_trace("Found %d verified device%s",
2400 nverified, pcmk__plural_s(nverified));
2401 request_peer_fencing(op, peer);
2402
2403 } else if (have_all_replies) {
2404 crm_info("All query replies have arrived, continuing (%d expected/%d received) ",
2405 replies_expected, op->replies);
2406 request_peer_fencing(op, NULL);
2407
2408 } else {
2409 crm_trace("Waiting for more peer results before launching fencing operation");
2410 }
2411
2412 } else if ((peer != NULL) && (op->state == st_done)) {
2413 crm_info("Discarding query result from %s (%d device%s): "
2414 "Operation is %s", peer->host,
2415 peer->ndevices, pcmk__plural_s(peer->ndevices),
2416 stonith_op_state_str(op->state));
2417 }
2418
2419 return pcmk_ok;
2420 }
2421
2422 /*!
2423 * \internal
2424 * \brief Handle a peer's reply to a fencing request
2425 *
2426 * Parse a fencing reply from XML, and either finalize the operation
2427 * or attempt another device as appropriate.
2428 *
2429 * \param[in] msg XML reply received
2430 */
2431 void
2432 fenced_process_fencing_reply(xmlNode *msg)
2433 {
2434 const char *id = NULL;
2435 const char *device = NULL;
2436 remote_fencing_op_t *op = NULL;
2437 xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_REMOTE_OP, msg, LOG_ERR);
2438 pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
2439
2440 CRM_CHECK(dev != NULL, return);
2441
2442 id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
2443 CRM_CHECK(id != NULL, return);
2444
2445 dev = stonith__find_xe_with_result(msg);
2446 CRM_CHECK(dev != NULL, return);
2447
2448 stonith__xe_get_result(dev, &result);
2449
2450 device = crm_element_value(dev, PCMK__XA_ST_DEVICE_ID);
2451
2452 if (stonith_remote_op_list) {
2453 op = g_hash_table_lookup(stonith_remote_op_list, id);
2454 }
2455
2456 if ((op == NULL) && pcmk__result_ok(&result)) {
2457 /* Record successful fencing operations */
2458 const char *client_id = crm_element_value(dev, PCMK__XA_ST_CLIENTID);
2459
2460 op = create_remote_stonith_op(client_id, dev, TRUE);
2461 }
2462
2463 if (op == NULL) {
2464 /* Could be for an event that began before we started */
2465 /* TODO: Record the op for later querying */
2466 crm_info("Received peer result of unknown or expired operation %s", id);
2467 pcmk__reset_result(&result);
2468 return;
2469 }
2470
2471 pcmk__reset_result(&op->result);
2472 op->result = result; // The operation takes ownership of the result
2473
2474 if (op->devices && device && !pcmk__str_eq(op->devices->data, device, pcmk__str_casei)) {
2475 crm_err("Received outdated reply for device %s (instead of %s) to "
2476 "fence (%s) %s. Operation already timed out at peer level.",
2477 device, (const char *) op->devices->data, op->action, op->target);
2478 return;
2479 }
2480
2481 if (pcmk__str_eq(crm_element_value(msg, PCMK__XA_SUBT),
2482 PCMK__VALUE_BROADCAST, pcmk__str_none)) {
2483
2484 if (pcmk__result_ok(&op->result)) {
2485 op->state = st_done;
2486 } else {
2487 op->state = st_failed;
2488 }
2489 finalize_op(op, msg, false);
2490 return;
2491
2492 } else if (!pcmk__str_eq(op->originator, fenced_get_local_node(),
2493 pcmk__str_casei)) {
2494 /* If this isn't a remote level broadcast, and we are not the
2495 * originator of the operation, we should not be receiving this msg. */
2496 crm_err("Received non-broadcast fencing result for operation %.8s "
2497 "we do not own (device %s targeting %s)",
2498 op->id, device, op->target);
2499 return;
2500 }
2501
2502 if (pcmk_is_set(op->call_options, st_opt_topology)) {
2503 const char *device = NULL;
2504 const char *reason = op->result.exit_reason;
2505
2506 /* We own the op, and it is complete. broadcast the result to all nodes
2507 * and notify our local clients. */
2508 if (op->state == st_done) {
2509 finalize_op(op, msg, false);
2510 return;
2511 }
2512
2513 device = crm_element_value(msg, PCMK__XA_ST_DEVICE_ID);
2514
2515 if ((op->phase == 2) && !pcmk__result_ok(&op->result)) {
2516 /* A remapped "on" failed, but the node was already turned off
2517 * successfully, so ignore the error and continue.
2518 */
2519 crm_warn("Ignoring %s 'on' failure (%s%s%s) targeting %s "
2520 "after successful 'off'",
2521 device, pcmk_exec_status_str(op->result.execution_status),
2522 (reason == NULL)? "" : ": ",
2523 (reason == NULL)? "" : reason,
2524 op->target);
2525 pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
2526 } else {
2527 crm_notice("Action '%s' targeting %s%s%s on behalf of %s@%s: "
2528 "%s%s%s%s",
2529 op->action, op->target,
2530 ((device == NULL)? "" : " using "),
2531 ((device == NULL)? "" : device),
2532 op->client_name,
2533 op->originator,
2534 pcmk_exec_status_str(op->result.execution_status),
2535 (reason == NULL)? "" : " (",
2536 (reason == NULL)? "" : reason,
2537 (reason == NULL)? "" : ")");
2538 }
2539
2540 if (pcmk__result_ok(&op->result)) {
2541 /* An operation completed successfully. Try another device if
2542 * necessary, otherwise mark the operation as done. */
2543 advance_topology_device_in_level(op, device, msg);
2544 return;
2545 } else {
2546 /* This device failed, time to try another topology level. If no other
2547 * levels are available, mark this operation as failed and report results. */
2548 if (advance_topology_level(op, false) != pcmk_rc_ok) {
2549 op->state = st_failed;
2550 finalize_op(op, msg, false);
2551 return;
2552 }
2553 }
2554
2555 } else if (pcmk__result_ok(&op->result) && (op->devices == NULL)) {
2556 op->state = st_done;
2557 finalize_op(op, msg, false);
2558 return;
2559
2560 } else if ((op->result.execution_status == PCMK_EXEC_TIMEOUT)
2561 && (op->devices == NULL)) {
2562 /* If the operation timed out don't bother retrying other peers. */
2563 op->state = st_failed;
2564 finalize_op(op, msg, false);
2565 return;
2566
2567 } else {
2568 /* fall-through and attempt other fencing action using another peer */
2569 }
2570
2571 /* Retry on failure */
2572 crm_trace("Next for %s on behalf of %s@%s (result was: %s)",
2573 op->target, op->originator, op->client_name,
2574 pcmk_exec_status_str(op->result.execution_status));
2575 request_peer_fencing(op, NULL);
2576 }
2577
2578 gboolean
2579 stonith_check_fence_tolerance(int tolerance, const char *target, const char *action)
2580 {
2581 GHashTableIter iter;
2582 time_t now = time(NULL);
2583 remote_fencing_op_t *rop = NULL;
2584
2585 if (tolerance <= 0 || !stonith_remote_op_list || target == NULL ||
2586 action == NULL) {
2587 return FALSE;
2588 }
2589
2590 g_hash_table_iter_init(&iter, stonith_remote_op_list);
2591 while (g_hash_table_iter_next(&iter, NULL, (void **)&rop)) {
2592 if (strcmp(rop->target, target) != 0) {
2593 continue;
2594 } else if (rop->state != st_done) {
2595 continue;
2596 /* We don't have to worry about remapped reboots here
2597 * because if state is done, any remapping has been undone
2598 */
2599 } else if (strcmp(rop->action, action) != 0) {
2600 continue;
2601 } else if ((rop->completed + tolerance) < now) {
2602 continue;
2603 }
2604
2605 crm_notice("Target %s was fenced (%s) less than %ds ago by %s on behalf of %s",
2606 target, action, tolerance, rop->delegate, rop->originator);
2607 return TRUE;
2608 }
2609 return FALSE;
2610 }
2611