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