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