pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2023 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <glib.h>
13 #include <stdbool.h>
14 
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/pengine/rules.h>
18 #include <crm/pengine/internal.h>
19 
20 #include "pe_status_private.h"
21 
22 extern bool pcmk__is_daemon;
23 
24 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
25 
35 bool
37 {
38  if (pe__is_guest_node(node)) {
39  /* Guest nodes are fenced by stopping their container resource. We can
40  * do that if the container's host is either online or fenceable.
41  */
43 
44  for (GList *n = rsc->running_on; n != NULL; n = n->next) {
45  pe_node_t *container_node = n->data;
46 
47  if (!container_node->details->online
48  && !pe_can_fence(data_set, container_node)) {
49  return false;
50  }
51  }
52  return true;
53 
55  return false; /* Turned off */
56 
58  return false; /* No devices */
59 
61  return true;
62 
64  return true;
65 
66  } else if(node == NULL) {
67  return false;
68 
69  } else if(node->details->online) {
70  crm_notice("We can fence %s without quorum because they're in our membership",
71  pe__node_name(node));
72  return true;
73  }
74 
75  crm_trace("Cannot fence %s", pe__node_name(node));
76  return false;
77 }
78 
88 pe_node_t *
89 pe__copy_node(const pe_node_t *this_node)
90 {
91  pe_node_t *new_node = NULL;
92 
93  CRM_ASSERT(this_node != NULL);
94 
95  new_node = calloc(1, sizeof(pe_node_t));
96  CRM_ASSERT(new_node != NULL);
97 
98  new_node->rsc_discover_mode = this_node->rsc_discover_mode;
99  new_node->weight = this_node->weight;
100  new_node->fixed = this_node->fixed; // @COMPAT deprecated and unused
101  new_node->details = this_node->details;
102 
103  return new_node;
104 }
105 
106 /* any node in list1 or list2 and not in the other gets a score of -INFINITY */
107 void
108 node_list_exclude(GHashTable * hash, GList *list, gboolean merge_scores)
109 {
110  GHashTable *result = hash;
111  pe_node_t *other_node = NULL;
112  GList *gIter = list;
113 
114  GHashTableIter iter;
115  pe_node_t *node = NULL;
116 
117  g_hash_table_iter_init(&iter, hash);
118  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
119 
120  other_node = pe_find_node_id(list, node->details->id);
121  if (other_node == NULL) {
122  node->weight = -INFINITY;
123  crm_trace("Banning dependent from %s (no primary instance)",
124  pe__node_name(node));
125  } else if (merge_scores) {
126  node->weight = pcmk__add_scores(node->weight, other_node->weight);
127  crm_trace("Added primary's score %s to dependent's score for %s "
128  "(now %s)", pcmk_readable_score(other_node->weight),
129  pe__node_name(node), pcmk_readable_score(node->weight));
130  }
131  }
132 
133  for (; gIter != NULL; gIter = gIter->next) {
134  pe_node_t *node = (pe_node_t *) gIter->data;
135 
136  other_node = pe_hash_table_lookup(result, node->details->id);
137 
138  if (other_node == NULL) {
139  pe_node_t *new_node = pe__copy_node(node);
140 
141  new_node->weight = -INFINITY;
142  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
143  }
144  }
145 }
146 
155 GHashTable *
156 pe__node_list2table(const GList *list)
157 {
158  GHashTable *result = NULL;
159 
160  result = pcmk__strkey_table(NULL, free);
161  for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
162  pe_node_t *new_node = pe__copy_node((const pe_node_t *) gIter->data);
163 
164  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
165  }
166  return result;
167 }
168 
184 gint
185 pe__cmp_node_name(gconstpointer a, gconstpointer b)
186 {
187  const pe_node_t *node1 = (const pe_node_t *) a;
188  const pe_node_t *node2 = (const pe_node_t *) b;
189 
190  if ((node1 == NULL) && (node2 == NULL)) {
191  return 0;
192  }
193 
194  if (node1 == NULL) {
195  return -1;
196  }
197 
198  if (node2 == NULL) {
199  return 1;
200  }
201 
203  node2->details->uname);
204 }
205 
215 static void
216 pe__output_node_weights(const pe_resource_t *rsc, const char *comment,
217  GHashTable *nodes, pe_working_set_t *data_set)
218 {
219  pcmk__output_t *out = data_set->priv;
220 
221  // Sort the nodes so the output is consistent for regression tests
222  GList *list = g_list_sort(g_hash_table_get_values(nodes),
224 
225  for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
226  const pe_node_t *node = (const pe_node_t *) gIter->data;
227 
228  out->message(out, "node-weight", rsc, comment, node->details->uname,
229  pcmk_readable_score(node->weight));
230  }
231  g_list_free(list);
232 }
233 
245 static void
246 pe__log_node_weights(const char *file, const char *function, int line,
247  const pe_resource_t *rsc, const char *comment,
248  GHashTable *nodes)
249 {
250  GHashTableIter iter;
251  pe_node_t *node = NULL;
252 
253  // Don't waste time if we're not tracing at this point
254  pcmk__if_tracing({}, return);
255 
256  g_hash_table_iter_init(&iter, nodes);
257  while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
258  if (rsc) {
259  qb_log_from_external_source(function, file,
260  "%s: %s allocation score on %s: %s",
261  LOG_TRACE, line, 0,
262  comment, rsc->id,
263  pe__node_name(node),
264  pcmk_readable_score(node->weight));
265  } else {
266  qb_log_from_external_source(function, file, "%s: %s = %s",
267  LOG_TRACE, line, 0,
268  comment, pe__node_name(node),
269  pcmk_readable_score(node->weight));
270  }
271  }
272 }
273 
288 void
289 pe__show_node_weights_as(const char *file, const char *function, int line,
290  bool to_log, const pe_resource_t *rsc,
291  const char *comment, GHashTable *nodes,
293 {
294  if (rsc != NULL && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
295  // Don't show allocation scores for orphans
296  return;
297  }
298  if (nodes == NULL) {
299  // Nothing to show
300  return;
301  }
302 
303  if (to_log) {
304  pe__log_node_weights(file, function, line, rsc, comment, nodes);
305  } else {
306  pe__output_node_weights(rsc, comment, nodes, data_set);
307  }
308 
309  // If this resource has children, repeat recursively for each
310  if (rsc && rsc->children) {
311  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
312  pe_resource_t *child = (pe_resource_t *) gIter->data;
313 
314  pe__show_node_weights_as(file, function, line, to_log, child,
315  comment, child->allowed_nodes, data_set);
316  }
317  }
318 }
319 
334 gint
335 pe__cmp_rsc_priority(gconstpointer a, gconstpointer b)
336 {
337  const pe_resource_t *resource1 = (const pe_resource_t *)a;
338  const pe_resource_t *resource2 = (const pe_resource_t *)b;
339 
340  if (a == NULL && b == NULL) {
341  return 0;
342  }
343  if (a == NULL) {
344  return 1;
345  }
346  if (b == NULL) {
347  return -1;
348  }
349 
350  if (resource1->priority > resource2->priority) {
351  return -1;
352  }
353 
354  if (resource1->priority < resource2->priority) {
355  return 1;
356  }
357 
358  return 0;
359 }
360 
361 static void
362 resource_node_score(pe_resource_t *rsc, const pe_node_t *node, int score,
363  const char *tag)
364 {
365  pe_node_t *match = NULL;
366 
368  && pcmk__str_eq(tag, "symmetric_default", pcmk__str_casei)) {
369  /* This string comparision may be fragile, but exclusive resources and
370  * exclusive nodes should not have the symmetric_default constraint
371  * applied to them.
372  */
373  return;
374 
375  } else if (rsc->children) {
376  GList *gIter = rsc->children;
377 
378  for (; gIter != NULL; gIter = gIter->next) {
379  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
380 
381  resource_node_score(child_rsc, node, score, tag);
382  }
383  }
384 
385  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
386  if (match == NULL) {
387  match = pe__copy_node(node);
388  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
389  }
390  match->weight = pcmk__add_scores(match->weight, score);
391  pe_rsc_trace(rsc,
392  "Enabling %s preference (%s) for %s on %s (now %s)",
393  tag, pcmk_readable_score(score), rsc->id, pe__node_name(node),
394  pcmk_readable_score(match->weight));
395 }
396 
397 void
398 resource_location(pe_resource_t *rsc, const pe_node_t *node, int score,
399  const char *tag, pe_working_set_t *data_set)
400 {
401  if (node != NULL) {
402  resource_node_score(rsc, node, score, tag);
403 
404  } else if (data_set != NULL) {
405  GList *gIter = data_set->nodes;
406 
407  for (; gIter != NULL; gIter = gIter->next) {
408  pe_node_t *node_iter = (pe_node_t *) gIter->data;
409 
410  resource_node_score(rsc, node_iter, score, tag);
411  }
412 
413  } else {
414  GHashTableIter iter;
415  pe_node_t *node_iter = NULL;
416 
417  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
418  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
419  resource_node_score(rsc, node_iter, score, tag);
420  }
421  }
422 
423  if (node == NULL && score == -INFINITY) {
424  if (rsc->allocated_to) {
425  crm_info("Deallocating %s from %s",
426  rsc->id, pe__node_name(rsc->allocated_to));
427  free(rsc->allocated_to);
428  rsc->allocated_to = NULL;
429  }
430  }
431 }
432 
433 time_t
435 {
436  if(data_set) {
437  if (data_set->now == NULL) {
438  crm_trace("Recording a new 'now'");
439  data_set->now = crm_time_new(NULL);
440  }
442  }
443 
444  crm_trace("Defaulting to 'now'");
445  return time(NULL);
446 }
447 
448 gboolean
449 get_target_role(const pe_resource_t *rsc, enum rsc_role_e *role)
450 {
451  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
452  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
453 
454  CRM_CHECK(role != NULL, return FALSE);
455 
456  if (pcmk__str_eq(value, "started", pcmk__str_null_matches | pcmk__str_casei)
457  || pcmk__str_eq("default", value, pcmk__str_casei)) {
458  return FALSE;
459  }
460 
461  local_role = text2role(value);
462  if (local_role == RSC_ROLE_UNKNOWN) {
463  pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
464  "because '%s' is not valid", rsc->id, value);
465  return FALSE;
466 
467  } else if (local_role > RSC_ROLE_STARTED) {
468  if (pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
470  if (local_role > RSC_ROLE_UNPROMOTED) {
471  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
472  return FALSE;
473  }
474 
475  } else {
476  pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
477  "because '%s' only makes sense for promotable "
478  "clones", rsc->id, value);
479  return FALSE;
480  }
481  }
482 
483  *role = local_role;
484  return TRUE;
485 }
486 
487 gboolean
488 order_actions(pe_action_t * lh_action, pe_action_t * rh_action, enum pe_ordering order)
489 {
490  GList *gIter = NULL;
491  pe_action_wrapper_t *wrapper = NULL;
492  GList *list = NULL;
493 
494  if (order == pe_order_none) {
495  return FALSE;
496  }
497 
498  if (lh_action == NULL || rh_action == NULL) {
499  return FALSE;
500  }
501 
502  crm_trace("Creating action wrappers for ordering: %s then %s",
503  lh_action->uuid, rh_action->uuid);
504 
505  /* Ensure we never create a dependency on ourselves... it's happened */
506  CRM_ASSERT(lh_action != rh_action);
507 
508  /* Filter dups, otherwise update_action_states() has too much work to do */
509  gIter = lh_action->actions_after;
510  for (; gIter != NULL; gIter = gIter->next) {
511  pe_action_wrapper_t *after = (pe_action_wrapper_t *) gIter->data;
512 
513  if (after->action == rh_action && (after->type & order)) {
514  return FALSE;
515  }
516  }
517 
518  wrapper = calloc(1, sizeof(pe_action_wrapper_t));
519  wrapper->action = rh_action;
520  wrapper->type = order;
521  list = lh_action->actions_after;
522  list = g_list_prepend(list, wrapper);
523  lh_action->actions_after = list;
524 
525  wrapper = calloc(1, sizeof(pe_action_wrapper_t));
526  wrapper->action = lh_action;
527  wrapper->type = order;
528  list = rh_action->actions_before;
529  list = g_list_prepend(list, wrapper);
530  rh_action->actions_before = list;
531  return TRUE;
532 }
533 
534 void
536 {
537  pe_ticket_t *ticket = data;
538 
539  if (ticket->state) {
540  g_hash_table_destroy(ticket->state);
541  }
542  free(ticket->id);
543  free(ticket);
544 }
545 
546 pe_ticket_t *
547 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
548 {
549  pe_ticket_t *ticket = NULL;
550 
551  if (pcmk__str_empty(ticket_id)) {
552  return NULL;
553  }
554 
555  if (data_set->tickets == NULL) {
557  }
558 
559  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
560  if (ticket == NULL) {
561 
562  ticket = calloc(1, sizeof(pe_ticket_t));
563  if (ticket == NULL) {
564  crm_err("Cannot allocate ticket '%s'", ticket_id);
565  return NULL;
566  }
567 
568  crm_trace("Creaing ticket entry for %s", ticket_id);
569 
570  ticket->id = strdup(ticket_id);
571  ticket->granted = FALSE;
572  ticket->last_granted = -1;
573  ticket->standby = FALSE;
574  ticket->state = pcmk__strkey_table(free, free);
575 
576  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
577  }
578 
579  return ticket;
580 }
581 
582 const char *
584 {
585  return pcmk_is_set(rsc->flags, pe_rsc_unique)? rsc->id : ID(rsc->xml);
586 }
587 
588 void
590 {
592  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
594  }
595 }
596 
597 void
599 {
600  for (GList *lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
601  pe_resource_t *r = (pe_resource_t *) lpc->data;
603  }
604 }
605 
606 void
608 {
610  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
612  }
613 }
614 
615 void
616 trigger_unfencing(pe_resource_t *rsc, pe_node_t *node, const char *reason,
617  pe_action_t *dependency, pe_working_set_t *data_set)
618 {
620  /* No resources require it */
621  return;
622 
623  } else if ((rsc != NULL)
625  /* Wasn't a stonith device */
626  return;
627 
628  } else if(node
629  && node->details->online
630  && node->details->unclean == FALSE
631  && node->details->shutdown == FALSE) {
632  pe_action_t *unfence = pe_fence_op(node, "on", FALSE, reason, FALSE, data_set);
633 
634  if(dependency) {
635  order_actions(unfence, dependency, pe_order_optional);
636  }
637 
638  } else if(rsc) {
639  GHashTableIter iter;
640 
641  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
642  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
643  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
644  trigger_unfencing(rsc, node, reason, dependency, data_set);
645  }
646  }
647  }
648 }
649 
650 gboolean
651 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
652 {
653  pe_tag_t *tag = NULL;
654  GList *gIter = NULL;
655  gboolean is_existing = FALSE;
656 
657  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
658 
659  tag = g_hash_table_lookup(tags, tag_name);
660  if (tag == NULL) {
661  tag = calloc(1, sizeof(pe_tag_t));
662  if (tag == NULL) {
663  return FALSE;
664  }
665  tag->id = strdup(tag_name);
666  tag->refs = NULL;
667  g_hash_table_insert(tags, strdup(tag_name), tag);
668  }
669 
670  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
671  const char *existing_ref = (const char *) gIter->data;
672 
673  if (pcmk__str_eq(existing_ref, obj_ref, pcmk__str_none)){
674  is_existing = TRUE;
675  break;
676  }
677  }
678 
679  if (is_existing == FALSE) {
680  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
681  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
682  }
683 
684  return TRUE;
685 }
686 
699 bool
701 {
702  const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
703 
704  return !pcmk__str_eq(shutdown, "0", pcmk__str_null_matches);
705 }
706 
714 void
716 {
717  if ((recheck > get_effective_time(data_set))
718  && ((data_set->recheck_by == 0)
719  || (data_set->recheck_by > recheck))) {
720  data_set->recheck_by = recheck;
721  }
722 }
723 
736 void
737 pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name,
738  const pe_rule_eval_data_t *rule_data,
739  GHashTable *hash, const char *always_first,
740  gboolean overwrite, pe_working_set_t *data_set)
741 {
742  crm_time_t *next_change = crm_time_new_undefined();
743 
744  pe_eval_nvpairs(data_set->input, xml_obj, set_name, rule_data, hash,
745  always_first, overwrite, next_change);
746  if (crm_time_is_defined(next_change)) {
747  time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
748 
750  }
751  crm_time_free(next_change);
752 }
753 
754 bool
756 {
757  const char *target_role = NULL;
758 
759  CRM_CHECK(rsc != NULL, return false);
760  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
761  if (target_role) {
762  enum rsc_role_e target_role_e = text2role(target_role);
763 
764  if ((target_role_e == RSC_ROLE_STOPPED)
765  || ((target_role_e == RSC_ROLE_UNPROMOTED)
766  && pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
767  pe_rsc_promotable))) {
768  return true;
769  }
770  }
771  return false;
772 }
773 
783 bool
785 {
786  return (rsc != NULL) && pcmk__list_of_1(rsc->running_on)
787  && pe__same_node((const pe_node_t *) rsc->running_on->data, node);
788 }
789 
790 bool
791 pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
792 {
793  for (GList *ele = rsc->running_on; ele; ele = ele->next) {
794  pe_node_t *node = (pe_node_t *) ele->data;
795  if (pcmk__str_in_list(node->details->uname, node_list,
797  return true;
798  }
799  }
800 
801  return false;
802 }
803 
804 bool
806 {
807  return (rsc->fns->active(rsc, FALSE) && !pe__rsc_running_on_any(rsc, only_node));
808 }
809 
810 GList *
811 pe__filter_rsc_list(GList *rscs, GList *filter)
812 {
813  GList *retval = NULL;
814 
815  for (GList *gIter = rscs; gIter; gIter = gIter->next) {
816  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
817 
818  /* I think the second condition is safe here for all callers of this
819  * function. If not, it needs to move into pe__node_text.
820  */
823  retval = g_list_prepend(retval, rsc);
824  }
825  }
826 
827  return retval;
828 }
829 
830 GList *
832  GList *nodes = NULL;
833 
834  if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
835  /* Nothing was given so return a list of all node names. Or, '*' was
836  * given. This would normally fall into the pe__unames_with_tag branch
837  * where it will return an empty list. Catch it here instead.
838  */
839  nodes = g_list_prepend(nodes, strdup("*"));
840  } else {
841  pe_node_t *node = pe_find_node(data_set->nodes, s);
842 
843  if (node) {
844  /* The given string was a valid uname for a node. Return a
845  * singleton list containing just that uname.
846  */
847  nodes = g_list_prepend(nodes, strdup(s));
848  } else {
849  /* The given string was not a valid uname. It's either a tag or
850  * it's a typo or something. In the first case, we'll return a
851  * list of all the unames of the nodes with the given tag. In the
852  * second case, we'll return a NULL pointer and nothing will
853  * get displayed.
854  */
855  nodes = pe__unames_with_tag(data_set, s);
856  }
857  }
858 
859  return nodes;
860 }
861 
862 GList *
864  GList *resources = NULL;
865 
866  if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
867  resources = g_list_prepend(resources, strdup("*"));
868  } else {
871 
872  if (rsc) {
873  /* A colon in the name we were given means we're being asked to filter
874  * on a specific instance of a cloned resource. Put that exact string
875  * into the filter list. Otherwise, use the printable ID of whatever
876  * resource was found that matches what was asked for.
877  */
878  if (strstr(s, ":") != NULL) {
879  resources = g_list_prepend(resources, strdup(rsc->id));
880  } else {
881  resources = g_list_prepend(resources, strdup(rsc_printable_id(rsc)));
882  }
883  } else {
884  /* The given string was not a valid resource name. It's a tag or a
885  * typo or something. See pe__build_node_name_list() for more
886  * detail.
887  */
888  resources = pe__rscs_with_tag(data_set, s);
889  }
890  }
891 
892  return resources;
893 }
894 
895 xmlNode *
897 {
898  const pe_resource_t *parent = pe__const_top_resource(rsc, false);
899  const char *rsc_id = rsc->id;
900 
901  if (parent->variant == pe_clone) {
902  rsc_id = pe__clone_child_id(parent);
903  }
904 
905  for (xmlNode *xml_op = pcmk__xml_first_child(rsc->cluster->failed); xml_op != NULL;
906  xml_op = pcmk__xml_next(xml_op)) {
907  const char *value = NULL;
908  char *op_id = NULL;
909 
910  /* This resource operation is not a failed probe. */
911  if (!pcmk_xe_mask_probe_failure(xml_op)) {
912  continue;
913  }
914 
915  /* This resource operation was not run on the given node. Note that if name is
916  * NULL, this will always succeed.
917  */
918  value = crm_element_value(xml_op, XML_LRM_ATTR_TARGET);
919  if (value == NULL || !pcmk__str_eq(value, name, pcmk__str_casei|pcmk__str_null_matches)) {
920  continue;
921  }
922 
923  if (!parse_op_key(pe__xe_history_key(xml_op), &op_id, NULL, NULL)) {
924  continue; // This history entry is missing an operation key
925  }
926 
927  /* This resource operation's ID does not match the rsc_id we are looking for. */
928  if (!pcmk__str_eq(op_id, rsc_id, pcmk__str_none)) {
929  free(op_id);
930  continue;
931  }
932 
933  free(op_id);
934  return xml_op;
935  }
936 
937  return NULL;
938 }
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:126
#define LOG_TRACE
Definition: logging.h:37
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:172
A dumping ground.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:96
void destroy_ticket(gpointer data)
Definition: utils.c:535
#define crm_notice(fmt, args...)
Definition: logging.h:379
xmlNode * failed
Definition: pe_types.h:188
pe_resource_t * pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
Definition: status.c:397
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
gboolean fixed
Definition: pe_types.h:266
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
#define pcmk__if_tracing(if_action, else_action)
GHashTable * pe__node_list2table(const GList *list)
Definition: utils.c:156
void trigger_unfencing(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t *data_set)
Definition: utils.c:616
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:434
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:488
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:142
GHashTable * state
Definition: pe_types.h:484
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
GList * pe__build_rsc_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:863
pe_resource_t * container
Definition: pe_types.h:412
const char * name
Definition: cib.c:24
int(* message)(pcmk__output_t *out, const char *message_id,...)
struct crm_time_s crm_time_t
Definition: iso8601.h:32
GList * children
Definition: pe_types.h:409
gboolean standby
Definition: pe_types.h:483
xmlNode * xml
Definition: pe_types.h:349
gboolean exclusive_discover
Definition: pe_types.h:377
#define pcmk__config_err(fmt...)
pe_resource_t * remote_rsc
Definition: pe_types.h:253
GHashTable * meta
Definition: pe_types.h:405
#define pe_rsc_unique
Definition: pe_types.h:278
resource_object_functions_t * fns
Definition: pe_types.h:358
char * id
Definition: pe_types.h:488
const pe_resource_t * pe__const_top_resource(const pe_resource_t *rsc, bool include_bundle)
Definition: complex.c:947
GHashTable * tickets
Definition: pe_types.h:175
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
Definition: utils.c:805
pe_node_t * allocated_to
Definition: pe_types.h:395
pe_action_t * action
Definition: pe_types.h:557
#define pe_flag_have_quorum
Definition: pe_types.h:111
pe_ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:547
void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set)
Definition: utils.c:737
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:715
GList * pe__rscs_with_tag(pe_working_set_t *data_set, const char *tag_name)
Definition: tags.c:20
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:77
GList * resources
Definition: pe_types.h:181
GList * nodes
Definition: pe_types.h:180
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:651
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:185
int weight
Definition: pe_types.h:265
bool pcmk_xe_mask_probe_failure(const xmlNode *xml_op)
Definition: operations.c:516
void resource_location(pe_resource_t *rsc, const pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:398
bool pe__rsc_running_on_only(const pe_resource_t *rsc, const pe_node_t *node)
Definition: utils.c:784
#define XML_CIB_ATTR_SHUTDOWN
Definition: msg_xml.h:301
bool pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
Definition: utils.c:791
void pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:497
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
void node_list_exclude(GHashTable *hash, GList *list, gboolean merge_scores)
Definition: utils.c:108
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition: common.c:558
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
GList * actions_after
Definition: pe_types.h:471
bool pe__shutdown_requested(const pe_node_t *node)
Definition: utils.c:700
#define crm_trace(fmt, args...)
Definition: logging.h:383
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:268
bool pe_can_fence(const pe_working_set_t *data_set, const pe_node_t *node)
Definition: utils.c:36
unsigned long long flags
Definition: pe_types.h:373
const char * uname
Definition: pe_types.h:232
#define pe_rsc_promotable
Definition: pe_types.h:280
pe_working_set_t * data_set
time_t recheck_by
Definition: pe_types.h:210
const char * pe__clone_child_id(const pe_resource_t *rsc)
Definition: clone.c:1273
#define pe_flag_stonith_enabled
Definition: pe_types.h:115
time_t last_granted
Definition: pe_types.h:482
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:249
pe_node_t node1
char * uuid
Definition: pe_types.h:438
void pe__clear_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition: utils.c:589
match base name of any clone instance
Definition: pe_types.h:106
enum rsc_role_e text2role(const char *role)
Definition: common.c:479
xmlNode * input
Definition: pe_types.h:160
gboolean granted
Definition: pe_types.h:481
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:359
pe_node_t node2
int rsc_discover_mode
Definition: pe_types.h:269
const char * id
Definition: pe_types.h:231
char * id
Definition: pe_types.h:480
xmlNode * pe__failed_probe_for_rsc(const pe_resource_t *rsc, const char *name)
Definition: utils.c:896
#define pe_rsc_fence_device
Definition: pe_types.h:279
GList * refs
Definition: pe_types.h:489
match resource ID or LRM history ID
Definition: pe_types.h:101
pe_node_t * pe_find_node_id(const GList *node_list, const char *id)
Find a node by ID in a list of nodes.
Definition: status.c:448
GList * pe__build_node_name_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:831
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
pcmk__action_result_t result
Definition: pcmk_fence.c:35
bool pe__resource_is_disabled(const pe_resource_t *rsc)
Definition: utils.c:755
#define crm_err(fmt, args...)
Definition: logging.h:377
#define CRM_ASSERT(expr)
Definition: results.h:42
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
This structure contains everything that makes up a single output formatter.
gboolean shutdown
Definition: pe_types.h:242
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:83
pe_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
Definition: status.c:473
const char * rsc_printable_id(const pe_resource_t *rsc)
Definition: utils.c:583
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1023
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
void pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition: utils.c:607
GList * running_on
Definition: pe_types.h:398
pe_working_set_t * cluster
Definition: pe_types.h:353
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:116
void pe__clear_resource_flags_on_all(pe_working_set_t *data_set, uint64_t flag)
Definition: utils.c:598
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition: utils.c:811
bool pcmk__is_daemon
Definition: logging.c:47
#define pe_flag_have_stonith_resource
Definition: pe_types.h:116
#define pe_flag_enable_unfencing
Definition: pe_types.h:117
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:317
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:50
#define ID(x)
Definition: msg_xml.h:480
unsigned long long flags
Definition: pe_types.h:169
void pe__show_node_weights_as(const char *file, const char *function, int line, bool to_log, const pe_resource_t *rsc, const char *comment, GHashTable *nodes, pe_working_set_t *data_set)
Definition: utils.c:289
const char * parent
Definition: cib.c:25
GList * pe__unames_with_tag(pe_working_set_t *data_set, const char *tag_name)
Definition: tags.c:51
enum pe_ordering type
Definition: pe_types.h:555
gboolean unclean
Definition: pe_types.h:240
crm_time_t * now
Definition: pe_types.h:161
gboolean get_target_role(const pe_resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:449
#define crm_info(fmt, args...)
Definition: logging.h:380
#define pe_rsc_orphan
Definition: pe_types.h:272
gint pe__cmp_rsc_priority(gconstpointer a, gconstpointer b)
Definition: utils.c:335
pe_ordering
Definition: pe_types.h:506
gboolean online
Definition: pe_types.h:236
uint64_t flags
Definition: remote.c:215
GList * actions_before
Definition: pe_types.h:470
pe_resource_t * parent
Definition: pe_types.h:354
pe_action_t * pe_fence_op(pe_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pe_working_set_t *data_set)
Definition: pe_actions.c:1084
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:53
char * id
Definition: pe_types.h:347
GHashTable * allowed_nodes
Definition: pe_types.h:400
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:888
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150