root/lib/pengine/utils.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pe_rsc_action_details
  2. pe_free_rsc_action_details
  3. pe_can_fence
  4. pe__copy_node
  5. node_list_exclude
  6. pe__node_list2table
  7. sort_node_uname
  8. pe__output_node_weights
  9. pe__log_node_weights
  10. pe__show_node_weights_as
  11. sort_rsc_index
  12. sort_rsc_priority
  13. effective_quorum_policy
  14. custom_action
  15. valid_stop_on_fail
  16. unpack_operation_on_fail
  17. find_min_interval_mon
  18. unpack_start_delay
  19. unpack_interval_origin
  20. unpack_timeout
  21. pe_get_configured_timeout
  22. unpack_versioned_meta
  23. unpack_operation
  24. find_rsc_op_entry_helper
  25. find_rsc_op_entry
  26. print_str_str
  27. pe_free_action
  28. find_recurring_actions
  29. get_complex_task
  30. find_first_action
  31. find_actions
  32. find_actions_exact
  33. pe__resource_actions
  34. resource_node_score
  35. resource_location
  36. sort_op_by_callid
  37. get_effective_time
  38. get_target_role
  39. order_actions
  40. get_pseudo_op
  41. destroy_ticket
  42. ticket_new
  43. rsc_printable_id
  44. pe__clear_resource_flags_recursive
  45. pe__clear_resource_flags_on_all
  46. pe__set_resource_flags_recursive
  47. find_unfencing_devices
  48. node_priority_fencing_delay
  49. pe_fence_op
  50. trigger_unfencing
  51. add_tag_ref
  52. pe_action_set_flag_reason
  53. pe_action_set_reason
  54. pe__shutdown_requested
  55. pe__update_recheck_time
  56. pe__unpack_dataset_nvpairs
  57. pe__resource_is_disabled
  58. pe__clear_resource_history
  59. pe__rsc_running_on_any_node_in_list
  60. pcmk__rsc_filtered_by_node
  61. pe__filter_rsc_list
  62. pe__build_node_name_list
  63. pe__build_rsc_list

   1 /*
   2  * Copyright 2004-2021 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 #include <crm/crm.h>
  12 #include <crm/msg_xml.h>
  13 #include <crm/common/xml.h>
  14 #include <crm/common/xml_internal.h>
  15 #include <crm/common/util.h>
  16 
  17 #include <glib.h>
  18 #include <stdbool.h>
  19 
  20 #include <crm/pengine/rules.h>
  21 #include <crm/pengine/internal.h>
  22 #include "pe_status_private.h"
  23 
  24 extern bool pcmk__is_daemon;
  25 
  26 extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
  27 void print_str_str(gpointer key, gpointer value, gpointer user_data);
  28 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
  29 static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
  30                              pe_working_set_t * data_set, guint interval_ms);
  31 static xmlNode *find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key,
  32                                          gboolean include_disabled);
  33 
  34 #if ENABLE_VERSIONED_ATTRS
  35 pe_rsc_action_details_t *
  36 pe_rsc_action_details(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38     pe_rsc_action_details_t *details;
  39 
  40     CRM_CHECK(action != NULL, return NULL);
  41 
  42     if (action->action_details == NULL) {
  43         action->action_details = calloc(1, sizeof(pe_rsc_action_details_t));
  44         CRM_CHECK(action->action_details != NULL, return NULL);
  45     }
  46 
  47     details = (pe_rsc_action_details_t *) action->action_details;
  48     if (details->versioned_parameters == NULL) {
  49         details->versioned_parameters = create_xml_node(NULL,
  50                                                         XML_TAG_OP_VER_ATTRS);
  51     }
  52     if (details->versioned_meta == NULL) {
  53         details->versioned_meta = create_xml_node(NULL, XML_TAG_OP_VER_META);
  54     }
  55     return details;
  56 }
  57 
  58 static void
  59 pe_free_rsc_action_details(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     pe_rsc_action_details_t *details;
  62 
  63     if ((action == NULL) || (action->action_details == NULL)) {
  64         return;
  65     }
  66 
  67     details = (pe_rsc_action_details_t *) action->action_details;
  68 
  69     if (details->versioned_parameters) {
  70         free_xml(details->versioned_parameters);
  71     }
  72     if (details->versioned_meta) {
  73         free_xml(details->versioned_meta);
  74     }
  75 
  76     action->action_details = NULL;
  77 }
  78 #endif
  79 
  80 /*!
  81  * \internal
  82  * \brief Check whether we can fence a particular node
  83  *
  84  * \param[in] data_set  Working set for cluster
  85  * \param[in] node      Name of node to check
  86  *
  87  * \return true if node can be fenced, false otherwise
  88  */
  89 bool
  90 pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92     if (pe__is_guest_node(node)) {
  93         /* Guest nodes are fenced by stopping their container resource. We can
  94          * do that if the container's host is either online or fenceable.
  95          */
  96         pe_resource_t *rsc = node->details->remote_rsc->container;
  97 
  98         for (GList *n = rsc->running_on; n != NULL; n = n->next) {
  99             pe_node_t *container_node = n->data;
 100 
 101             if (!container_node->details->online
 102                 && !pe_can_fence(data_set, container_node)) {
 103                 return false;
 104             }
 105         }
 106         return true;
 107 
 108     } else if (!pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
 109         return false; /* Turned off */
 110 
 111     } else if (!pcmk_is_set(data_set->flags, pe_flag_have_stonith_resource)) {
 112         return false; /* No devices */
 113 
 114     } else if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)) {
 115         return true;
 116 
 117     } else if (data_set->no_quorum_policy == no_quorum_ignore) {
 118         return true;
 119 
 120     } else if(node == NULL) {
 121         return false;
 122 
 123     } else if(node->details->online) {
 124         crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
 125         return true;
 126     }
 127 
 128     crm_trace("Cannot fence %s", node->details->uname);
 129     return false;
 130 }
 131 
 132 /*!
 133  * \internal
 134  * \brief Copy a node object
 135  *
 136  * \param[in] this_node  Node object to copy
 137  *
 138  * \return Newly allocated shallow copy of this_node
 139  * \note This function asserts on errors and is guaranteed to return non-NULL.
 140  */
 141 pe_node_t *
 142 pe__copy_node(const pe_node_t *this_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     pe_node_t *new_node = NULL;
 145 
 146     CRM_ASSERT(this_node != NULL);
 147 
 148     new_node = calloc(1, sizeof(pe_node_t));
 149     CRM_ASSERT(new_node != NULL);
 150 
 151     new_node->rsc_discover_mode = this_node->rsc_discover_mode;
 152     new_node->weight = this_node->weight;
 153     new_node->fixed = this_node->fixed;
 154     new_node->details = this_node->details;
 155 
 156     return new_node;
 157 }
 158 
 159 /* any node in list1 or list2 and not in the other gets a score of -INFINITY */
 160 void
 161 node_list_exclude(GHashTable * hash, GList *list, gboolean merge_scores)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     GHashTable *result = hash;
 164     pe_node_t *other_node = NULL;
 165     GList *gIter = list;
 166 
 167     GHashTableIter iter;
 168     pe_node_t *node = NULL;
 169 
 170     g_hash_table_iter_init(&iter, hash);
 171     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 172 
 173         other_node = pe_find_node_id(list, node->details->id);
 174         if (other_node == NULL) {
 175             node->weight = -INFINITY;
 176         } else if (merge_scores) {
 177             node->weight = pe__add_scores(node->weight, other_node->weight);
 178         }
 179     }
 180 
 181     for (; gIter != NULL; gIter = gIter->next) {
 182         pe_node_t *node = (pe_node_t *) gIter->data;
 183 
 184         other_node = pe_hash_table_lookup(result, node->details->id);
 185 
 186         if (other_node == NULL) {
 187             pe_node_t *new_node = pe__copy_node(node);
 188 
 189             new_node->weight = -INFINITY;
 190             g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
 191         }
 192     }
 193 }
 194 
 195 /*!
 196  * \internal
 197  * \brief Create a node hash table from a node list
 198  *
 199  * \param[in] list  Node list
 200  *
 201  * \return Hash table equivalent of node list
 202  */
 203 GHashTable *
 204 pe__node_list2table(GList *list)
     /* [previous][next][first][last][top][bottom][index][help] */
 205 {
 206     GHashTable *result = NULL;
 207 
 208     result = pcmk__strkey_table(NULL, free);
 209     for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
 210         pe_node_t *new_node = pe__copy_node((pe_node_t *) gIter->data);
 211 
 212         g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
 213     }
 214     return result;
 215 }
 216 
 217 gint
 218 sort_node_uname(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220     return pcmk__numeric_strcasecmp(((const pe_node_t *) a)->details->uname,
 221                                     ((const pe_node_t *) b)->details->uname);
 222 }
 223 
 224 /*!
 225  * \internal
 226  * \brief Output node weights to stdout
 227  *
 228  * \param[in] rsc       Use allowed nodes for this resource
 229  * \param[in] comment   Text description to prefix lines with
 230  * \param[in] nodes     If rsc is not specified, use these nodes
 231  */
 232 static void
 233 pe__output_node_weights(pe_resource_t *rsc, const char *comment,
     /* [previous][next][first][last][top][bottom][index][help] */
 234                         GHashTable *nodes, pe_working_set_t *data_set)
 235 {
 236     pcmk__output_t *out = data_set->priv;
 237     char score[128]; // Stack-allocated since this is called frequently
 238 
 239     // Sort the nodes so the output is consistent for regression tests
 240     GList *list = g_list_sort(g_hash_table_get_values(nodes), sort_node_uname);
 241 
 242     for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
 243         pe_node_t *node = (pe_node_t *) gIter->data;
 244 
 245         score2char_stack(node->weight, score, sizeof(score));
 246         out->message(out, "node-weight", rsc, comment, node->details->uname, score);
 247     }
 248     g_list_free(list);
 249 }
 250 
 251 /*!
 252  * \internal
 253  * \brief Log node weights at trace level
 254  *
 255  * \param[in] file      Caller's filename
 256  * \param[in] function  Caller's function name
 257  * \param[in] line      Caller's line number
 258  * \param[in] rsc       Use allowed nodes for this resource
 259  * \param[in] comment   Text description to prefix lines with
 260  * \param[in] nodes     If rsc is not specified, use these nodes
 261  */
 262 static void
 263 pe__log_node_weights(const char *file, const char *function, int line,
     /* [previous][next][first][last][top][bottom][index][help] */
 264                      pe_resource_t *rsc, const char *comment, GHashTable *nodes)
 265 {
 266     GHashTableIter iter;
 267     pe_node_t *node = NULL;
 268     char score[128]; // Stack-allocated since this is called frequently
 269 
 270     // Don't waste time if we're not tracing at this point
 271     pcmk__log_else(LOG_TRACE, return);
 272 
 273     g_hash_table_iter_init(&iter, nodes);
 274     while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
 275         score2char_stack(node->weight, score, sizeof(score));
 276         if (rsc) {
 277             qb_log_from_external_source(function, file,
 278                                         "%s: %s allocation score on %s: %s",
 279                                         LOG_TRACE, line, 0,
 280                                         comment, rsc->id,
 281                                         node->details->uname, score);
 282         } else {
 283             qb_log_from_external_source(function, file, "%s: %s = %s",
 284                                         LOG_TRACE, line, 0,
 285                                         comment, node->details->uname,
 286                                         score);
 287         }
 288     }
 289 }
 290 
 291 /*!
 292  * \internal
 293  * \brief Log or output node weights
 294  *
 295  * \param[in] file      Caller's filename
 296  * \param[in] function  Caller's function name
 297  * \param[in] line      Caller's line number
 298  * \param[in] to_log    Log if true, otherwise output
 299  * \param[in] rsc       Use allowed nodes for this resource
 300  * \param[in] comment   Text description to prefix lines with
 301  * \param[in] nodes     Use these nodes
 302  */
 303 void
 304 pe__show_node_weights_as(const char *file, const char *function, int line,
     /* [previous][next][first][last][top][bottom][index][help] */
 305                          bool to_log, pe_resource_t *rsc, const char *comment,
 306                          GHashTable *nodes, pe_working_set_t *data_set)
 307 {
 308     if (rsc != NULL && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
 309         // Don't show allocation scores for orphans
 310         return;
 311     }
 312     if (nodes == NULL) {
 313         // Nothing to show
 314         return;
 315     }
 316 
 317     if (to_log) {
 318         pe__log_node_weights(file, function, line, rsc, comment, nodes);
 319     } else {
 320         pe__output_node_weights(rsc, comment, nodes, data_set);
 321     }
 322 
 323     // If this resource has children, repeat recursively for each
 324     if (rsc && rsc->children) {
 325         for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 326             pe_resource_t *child = (pe_resource_t *) gIter->data;
 327 
 328             pe__show_node_weights_as(file, function, line, to_log, child,
 329                                      comment, child->allowed_nodes, data_set);
 330         }
 331     }
 332 }
 333 
 334 gint
 335 sort_rsc_index(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 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->sort_index > resource2->sort_index) {
 351         return -1;
 352     }
 353 
 354     if (resource1->sort_index < resource2->sort_index) {
 355         return 1;
 356     }
 357 
 358     return 0;
 359 }
 360 
 361 gint
 362 sort_rsc_priority(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364     const pe_resource_t *resource1 = (const pe_resource_t *)a;
 365     const pe_resource_t *resource2 = (const pe_resource_t *)b;
 366 
 367     if (a == NULL && b == NULL) {
 368         return 0;
 369     }
 370     if (a == NULL) {
 371         return 1;
 372     }
 373     if (b == NULL) {
 374         return -1;
 375     }
 376 
 377     if (resource1->priority > resource2->priority) {
 378         return -1;
 379     }
 380 
 381     if (resource1->priority < resource2->priority) {
 382         return 1;
 383     }
 384 
 385     return 0;
 386 }
 387 
 388 static enum pe_quorum_policy
 389 effective_quorum_policy(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391     enum pe_quorum_policy policy = data_set->no_quorum_policy;
 392 
 393     if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)) {
 394         policy = no_quorum_ignore;
 395 
 396     } else if (data_set->no_quorum_policy == no_quorum_demote) {
 397         switch (rsc->role) {
 398             case RSC_ROLE_PROMOTED:
 399             case RSC_ROLE_UNPROMOTED:
 400                 if (rsc->next_role > RSC_ROLE_UNPROMOTED) {
 401                     pe__set_next_role(rsc, RSC_ROLE_UNPROMOTED,
 402                                       "no-quorum-policy=demote");
 403                 }
 404                 policy = no_quorum_ignore;
 405                 break;
 406             default:
 407                 policy = no_quorum_stop;
 408                 break;
 409         }
 410     }
 411     return policy;
 412 }
 413 
 414 pe_action_t *
 415 custom_action(pe_resource_t * rsc, char *key, const char *task,
     /* [previous][next][first][last][top][bottom][index][help] */
 416               pe_node_t * on_node, gboolean optional, gboolean save_action,
 417               pe_working_set_t * data_set)
 418 {
 419     pe_action_t *action = NULL;
 420     GList *possible_matches = NULL;
 421 
 422     CRM_CHECK(key != NULL, return NULL);
 423     CRM_CHECK(task != NULL, free(key); return NULL);
 424 
 425     if (save_action && rsc != NULL) {
 426         possible_matches = find_actions(rsc->actions, key, on_node);
 427     } else if(save_action) {
 428 #if 0
 429         action = g_hash_table_lookup(data_set->singletons, key);
 430 #else
 431         /* More expensive but takes 'node' into account */
 432         possible_matches = find_actions(data_set->actions, key, on_node);
 433 #endif
 434     }
 435 
 436     if(data_set->singletons == NULL) {
 437         data_set->singletons = pcmk__strkey_table(NULL, NULL);
 438     }
 439 
 440     if (possible_matches != NULL) {
 441         if (pcmk__list_of_multiple(possible_matches)) {
 442             pe_warn("Action %s for %s on %s exists %d times",
 443                     task, rsc ? rsc->id : "<NULL>",
 444                     on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
 445         }
 446 
 447         action = g_list_nth_data(possible_matches, 0);
 448         pe_rsc_trace(rsc, "Found action %d: %s for %s (%s) on %s",
 449                      action->id, task, (rsc? rsc->id : "no resource"),
 450                      action->uuid,
 451                      (on_node? on_node->details->uname : "no node"));
 452         g_list_free(possible_matches);
 453     }
 454 
 455     if (action == NULL) {
 456         if (save_action) {
 457             pe_rsc_trace(rsc, "Creating action %d (%s): %s for %s (%s) on %s",
 458                          data_set->action_id,
 459                          (optional? "optional" : "required"),
 460                          task, (rsc? rsc->id : "no resource"), key,
 461                          (on_node? on_node->details->uname : "no node"));
 462         }
 463 
 464         action = calloc(1, sizeof(pe_action_t));
 465         if (save_action) {
 466             action->id = data_set->action_id++;
 467         } else {
 468             action->id = 0;
 469         }
 470         action->rsc = rsc;
 471         action->task = strdup(task);
 472         if (on_node) {
 473             action->node = pe__copy_node(on_node);
 474         }
 475         action->uuid = strdup(key);
 476 
 477         if (pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
 478             // Resource history deletion for a node can be done on the DC
 479             pe__set_action_flags(action, pe_action_dc);
 480         }
 481 
 482         pe__set_action_flags(action, pe_action_runnable);
 483         if (optional) {
 484             pe__set_action_flags(action, pe_action_optional);
 485         } else {
 486             pe__clear_action_flags(action, pe_action_optional);
 487         }
 488 
 489         action->extra = pcmk__strkey_table(free, free);
 490         action->meta = pcmk__strkey_table(free, free);
 491 
 492         if (save_action) {
 493             data_set->actions = g_list_prepend(data_set->actions, action);
 494             if(rsc == NULL) {
 495                 g_hash_table_insert(data_set->singletons, action->uuid, action);
 496             }
 497         }
 498 
 499         if (rsc != NULL) {
 500             guint interval_ms = 0;
 501 
 502             action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
 503             parse_op_key(key, NULL, NULL, &interval_ms);
 504 
 505             unpack_operation(action, action->op_entry, rsc->container, data_set,
 506                              interval_ms);
 507 
 508             if (save_action) {
 509                 rsc->actions = g_list_prepend(rsc->actions, action);
 510             }
 511         }
 512     }
 513 
 514     if (!optional && pcmk_is_set(action->flags, pe_action_optional)) {
 515         pe__clear_action_flags(action, pe_action_optional);
 516     }
 517 
 518     if (rsc != NULL) {
 519         enum action_tasks a_task = text2task(action->task);
 520         enum pe_quorum_policy quorum_policy = effective_quorum_policy(rsc, data_set);
 521         int warn_level = LOG_TRACE;
 522 
 523         if (save_action) {
 524             warn_level = LOG_WARNING;
 525         }
 526 
 527         if (!pcmk_is_set(action->flags, pe_action_have_node_attrs)
 528             && action->node != NULL && action->op_entry != NULL) {
 529             pe_rule_eval_data_t rule_data = {
 530                 .node_hash = action->node->details->attrs,
 531                 .role = RSC_ROLE_UNKNOWN,
 532                 .now = data_set->now,
 533                 .match_data = NULL,
 534                 .rsc_data = NULL,
 535                 .op_data = NULL
 536             };
 537 
 538             pe__set_action_flags(action, pe_action_have_node_attrs);
 539             pe__unpack_dataset_nvpairs(action->op_entry, XML_TAG_ATTR_SETS,
 540                                        &rule_data, action->extra, NULL,
 541                                        FALSE, data_set);
 542         }
 543 
 544         if (pcmk_is_set(action->flags, pe_action_pseudo)) {
 545             /* leave untouched */
 546 
 547         } else if (action->node == NULL) {
 548             pe_rsc_trace(rsc, "%s is unrunnable (unallocated)",
 549                          action->uuid);
 550             pe__clear_action_flags(action, pe_action_runnable);
 551 
 552         } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)
 553                    && g_hash_table_lookup(action->meta,
 554                                           XML_LRM_ATTR_INTERVAL_MS) == NULL) {
 555             pe_rsc_debug(rsc, "%s on %s is optional (%s is unmanaged)",
 556                          action->uuid, action->node->details->uname, rsc->id);
 557             pe__set_action_flags(action, pe_action_optional);
 558             //pe__clear_action_flags(action, pe_action_runnable);
 559 
 560         } else if (!pcmk_is_set(action->flags, pe_action_dc)
 561                    && !(action->node->details->online)
 562                    && (!pe__is_guest_node(action->node)
 563                        || action->node->details->remote_requires_reset)) {
 564             pe__clear_action_flags(action, pe_action_runnable);
 565             do_crm_log(warn_level,
 566                        "%s on %s is unrunnable (node is offline)",
 567                        action->uuid, action->node->details->uname);
 568             if (pcmk_is_set(action->rsc->flags, pe_rsc_managed)
 569                 && save_action && a_task == stop_rsc
 570                 && action->node->details->unclean == FALSE) {
 571                 pe_fence_node(data_set, action->node, "resource actions are unrunnable", FALSE);
 572             }
 573 
 574         } else if (!pcmk_is_set(action->flags, pe_action_dc)
 575                    && action->node->details->pending) {
 576             pe__clear_action_flags(action, pe_action_runnable);
 577             do_crm_log(warn_level,
 578                        "Action %s on %s is unrunnable (node is pending)",
 579                        action->uuid, action->node->details->uname);
 580 
 581         } else if (action->needs == rsc_req_nothing) {
 582             pe_action_set_reason(action, NULL, TRUE);
 583             if (pe__is_guest_node(action->node)
 584                 && !pe_can_fence(data_set, action->node)) {
 585                 /* An action that requires nothing usually does not require any
 586                  * fencing in order to be runnable. However, there is an
 587                  * exception: an action cannot be completed if it is on a guest
 588                  * node whose host is unclean and cannot be fenced.
 589                  */
 590                 pe_rsc_debug(rsc, "%s on %s is unrunnable "
 591                              "(node's host cannot be fenced)",
 592                              action->uuid, action->node->details->uname);
 593                 pe__clear_action_flags(action, pe_action_runnable);
 594             } else {
 595                 pe_rsc_trace(rsc, "%s on %s does not require fencing or quorum",
 596                              action->uuid, action->node->details->uname);
 597                 pe__set_action_flags(action, pe_action_runnable);
 598             }
 599 #if 0
 600             /*
 601              * No point checking this
 602              * - if we don't have quorum we can't stonith anyway
 603              */
 604         } else if (action->needs == rsc_req_stonith) {
 605             crm_trace("Action %s requires only stonith", action->uuid);
 606             action->runnable = TRUE;
 607 #endif
 608         } else if (quorum_policy == no_quorum_stop) {
 609             pe_rsc_debug(rsc, "%s on %s is unrunnable (no quorum)",
 610                          action->uuid, action->node->details->uname);
 611             pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
 612                                       "no quorum", pe_action_runnable, TRUE);
 613 
 614         } else if (quorum_policy == no_quorum_freeze) {
 615             if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
 616                 pe_rsc_debug(rsc, "%s on %s is unrunnable (no quorum)",
 617                              action->uuid, action->node->details->uname);
 618                 pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
 619                                           "quorum freeze", pe_action_runnable,
 620                                           TRUE);
 621             }
 622 
 623         } else {
 624             //pe_action_set_reason(action, NULL, TRUE);
 625             pe__set_action_flags(action, pe_action_runnable);
 626         }
 627 
 628         if (save_action) {
 629             switch (a_task) {
 630                 case stop_rsc:
 631                     pe__set_resource_flags(rsc, pe_rsc_stopping);
 632                     break;
 633                 case start_rsc:
 634                     pe__clear_resource_flags(rsc, pe_rsc_starting);
 635                     if (pcmk_is_set(action->flags, pe_action_runnable)) {
 636                         pe__set_resource_flags(rsc, pe_rsc_starting);
 637                     }
 638                     break;
 639                 default:
 640                     break;
 641             }
 642         }
 643     }
 644 
 645     free(key);
 646     return action;
 647 }
 648 
 649 static bool
 650 valid_stop_on_fail(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 651 {
 652     return !pcmk__strcase_any_of(value, "standby", "demote", "stop", NULL);
 653 }
 654 
 655 static const char *
 656 unpack_operation_on_fail(pe_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658 
 659     const char *name = NULL;
 660     const char *role = NULL;
 661     const char *on_fail = NULL;
 662     const char *interval_spec = NULL;
 663     const char *enabled = NULL;
 664     const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
 665 
 666     if (pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)
 667         && !valid_stop_on_fail(value)) {
 668 
 669         pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s stop "
 670                          "action to default value because '%s' is not "
 671                          "allowed for stop", action->rsc->id, value);
 672         return NULL;
 673 
 674     } else if (pcmk__str_eq(action->task, CRMD_ACTION_DEMOTE, pcmk__str_casei) && !value) {
 675         // demote on_fail defaults to monitor value for promoted role if present
 676         xmlNode *operation = NULL;
 677 
 678         CRM_CHECK(action->rsc != NULL, return NULL);
 679 
 680         for (operation = pcmk__xe_first_child(action->rsc->ops_xml);
 681              (operation != NULL) && (value == NULL);
 682              operation = pcmk__xe_next(operation)) {
 683 
 684             if (!pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
 685                 continue;
 686             }
 687             name = crm_element_value(operation, "name");
 688             role = crm_element_value(operation, "role");
 689             on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
 690             enabled = crm_element_value(operation, "enabled");
 691             interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
 692             if (!on_fail) {
 693                 continue;
 694             } else if (enabled && !crm_is_true(enabled)) {
 695                 continue;
 696             } else if (!pcmk__str_eq(name, "monitor", pcmk__str_casei)
 697                        || !pcmk__strcase_any_of(role, RSC_ROLE_PROMOTED_S,
 698                                                 RSC_ROLE_PROMOTED_LEGACY_S,
 699                                                 NULL)) {
 700                 continue;
 701             } else if (crm_parse_interval_spec(interval_spec) == 0) {
 702                 continue;
 703             } else if (pcmk__str_eq(on_fail, "demote", pcmk__str_casei)) {
 704                 continue;
 705             }
 706 
 707             value = on_fail;
 708         }
 709     } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
 710         value = "ignore";
 711 
 712     } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
 713         name = crm_element_value(action->op_entry, "name");
 714         role = crm_element_value(action->op_entry, "role");
 715         interval_spec = crm_element_value(action->op_entry,
 716                                           XML_LRM_ATTR_INTERVAL);
 717 
 718         if (!pcmk__str_eq(name, CRMD_ACTION_PROMOTE, pcmk__str_casei)
 719             && (!pcmk__str_eq(name, CRMD_ACTION_STATUS, pcmk__str_casei)
 720                 || !pcmk__strcase_any_of(role, RSC_ROLE_PROMOTED_S,
 721                                          RSC_ROLE_PROMOTED_LEGACY_S, NULL)
 722                 || (crm_parse_interval_spec(interval_spec) == 0))) {
 723             pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for %s %s "
 724                              "action to default value because 'demote' is not "
 725                              "allowed for it", action->rsc->id, name);
 726             return NULL;
 727         }
 728     }
 729 
 730     return value;
 731 }
 732 
 733 static xmlNode *
 734 find_min_interval_mon(pe_resource_t * rsc, gboolean include_disabled)
     /* [previous][next][first][last][top][bottom][index][help] */
 735 {
 736     guint interval_ms = 0;
 737     guint min_interval_ms = G_MAXUINT;
 738     const char *name = NULL;
 739     const char *value = NULL;
 740     const char *interval_spec = NULL;
 741     xmlNode *op = NULL;
 742     xmlNode *operation = NULL;
 743 
 744     for (operation = pcmk__xe_first_child(rsc->ops_xml);
 745          operation != NULL;
 746          operation = pcmk__xe_next(operation)) {
 747 
 748         if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
 749             name = crm_element_value(operation, "name");
 750             interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
 751             value = crm_element_value(operation, "enabled");
 752             if (!include_disabled && value && crm_is_true(value) == FALSE) {
 753                 continue;
 754             }
 755 
 756             if (!pcmk__str_eq(name, RSC_STATUS, pcmk__str_casei)) {
 757                 continue;
 758             }
 759 
 760             interval_ms = crm_parse_interval_spec(interval_spec);
 761 
 762             if (interval_ms && (interval_ms < min_interval_ms)) {
 763                 min_interval_ms = interval_ms;
 764                 op = operation;
 765             }
 766         }
 767     }
 768 
 769     return op;
 770 }
 771 
 772 static int
 773 unpack_start_delay(const char *value, GHashTable *meta)
     /* [previous][next][first][last][top][bottom][index][help] */
 774 {
 775     int start_delay = 0;
 776 
 777     if (value != NULL) {
 778         start_delay = crm_get_msec(value);
 779 
 780         if (start_delay < 0) {
 781             start_delay = 0;
 782         }
 783 
 784         if (meta) {
 785             g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
 786                                  pcmk__itoa(start_delay));
 787         }
 788     }
 789 
 790     return start_delay;
 791 }
 792 
 793 // true if value contains valid, non-NULL interval origin for recurring op
 794 static bool
 795 unpack_interval_origin(const char *value, xmlNode *xml_obj, guint interval_ms,
     /* [previous][next][first][last][top][bottom][index][help] */
 796                        crm_time_t *now, long long *start_delay)
 797 {
 798     long long result = 0;
 799     guint interval_sec = interval_ms / 1000;
 800     crm_time_t *origin = NULL;
 801 
 802     // Ignore unspecified values and non-recurring operations
 803     if ((value == NULL) || (interval_ms == 0) || (now == NULL)) {
 804         return false;
 805     }
 806 
 807     // Parse interval origin from text
 808     origin = crm_time_new(value);
 809     if (origin == NULL) {
 810         pcmk__config_err("Ignoring '" XML_OP_ATTR_ORIGIN "' for operation "
 811                          "'%s' because '%s' is not valid",
 812                          (ID(xml_obj)? ID(xml_obj) : "(missing ID)"), value);
 813         return false;
 814     }
 815 
 816     // Get seconds since origin (negative if origin is in the future)
 817     result = crm_time_get_seconds(now) - crm_time_get_seconds(origin);
 818     crm_time_free(origin);
 819 
 820     // Calculate seconds from closest interval to now
 821     result = result % interval_sec;
 822 
 823     // Calculate seconds remaining until next interval
 824     result = ((result <= 0)? 0 : interval_sec) - result;
 825     crm_info("Calculated a start delay of %llds for operation '%s'",
 826              result,
 827              (ID(xml_obj)? ID(xml_obj) : "(unspecified)"));
 828 
 829     if (start_delay != NULL) {
 830         *start_delay = result * 1000; // milliseconds
 831     }
 832     return true;
 833 }
 834 
 835 static int
 836 unpack_timeout(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 837 {
 838     int timeout_ms = crm_get_msec(value);
 839 
 840     if (timeout_ms < 0) {
 841         timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
 842     }
 843     return timeout_ms;
 844 }
 845 
 846 int
 847 pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 848 {
 849     xmlNode *child = NULL;
 850     GHashTable *action_meta = NULL;
 851     const char *timeout_spec = NULL;
 852     int timeout_ms = 0;
 853 
 854     pe_rule_eval_data_t rule_data = {
 855         .node_hash = NULL,
 856         .role = RSC_ROLE_UNKNOWN,
 857         .now = data_set->now,
 858         .match_data = NULL,
 859         .rsc_data = NULL,
 860         .op_data = NULL
 861     };
 862 
 863     for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
 864          child != NULL; child = crm_next_same_xml(child)) {
 865         if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
 866                 pcmk__str_casei)) {
 867             timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
 868             break;
 869         }
 870     }
 871 
 872     if (timeout_spec == NULL && data_set->op_defaults) {
 873         action_meta = pcmk__strkey_table(free, free);
 874         pe__unpack_dataset_nvpairs(data_set->op_defaults, XML_TAG_META_SETS,
 875                                    &rule_data, action_meta, NULL, FALSE, data_set);
 876         timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
 877     }
 878 
 879     // @TODO check meta-attributes (including versioned meta-attributes)
 880     // @TODO maybe use min-interval monitor timeout as default for monitors
 881 
 882     timeout_ms = crm_get_msec(timeout_spec);
 883     if (timeout_ms < 0) {
 884         timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
 885     }
 886 
 887     if (action_meta != NULL) {
 888         g_hash_table_destroy(action_meta);
 889     }
 890     return timeout_ms;
 891 }
 892 
 893 #if ENABLE_VERSIONED_ATTRS
 894 static void
 895 unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj,
     /* [previous][next][first][last][top][bottom][index][help] */
 896                       guint interval_ms, crm_time_t *now)
 897 {
 898     xmlNode *attrs = NULL;
 899     xmlNode *attr = NULL;
 900 
 901     for (attrs = pcmk__xe_first_child(versioned_meta); attrs != NULL;
 902          attrs = pcmk__xe_next(attrs)) {
 903 
 904         for (attr = pcmk__xe_first_child(attrs); attr != NULL;
 905              attr = pcmk__xe_next(attr)) {
 906 
 907             const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
 908             const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
 909 
 910             if (pcmk__str_eq(name, XML_OP_ATTR_START_DELAY, pcmk__str_casei)) {
 911                 int start_delay = unpack_start_delay(value, NULL);
 912 
 913                 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
 914             } else if (pcmk__str_eq(name, XML_OP_ATTR_ORIGIN, pcmk__str_casei)) {
 915                 long long start_delay = 0;
 916 
 917                 if (unpack_interval_origin(value, xml_obj, interval_ms, now,
 918                                            &start_delay)) {
 919                     crm_xml_add(attr, XML_NVPAIR_ATTR_NAME,
 920                                 XML_OP_ATTR_START_DELAY);
 921                     crm_xml_add_ll(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
 922                 }
 923             } else if (pcmk__str_eq(name, XML_ATTR_TIMEOUT, pcmk__str_casei)) {
 924                 int timeout_ms = unpack_timeout(value);
 925 
 926                 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout_ms);
 927             }
 928         }
 929     }
 930 }
 931 #endif
 932 
 933 /*!
 934  * \brief Unpack operation XML into an action structure
 935  *
 936  * Unpack an operation's meta-attributes (normalizing the interval, timeout,
 937  * and start delay values as integer milliseconds), requirements, and
 938  * failure policy.
 939  *
 940  * \param[in,out] action      Action to unpack into
 941  * \param[in]     xml_obj     Operation XML (or NULL if all defaults)
 942  * \param[in]     container   Resource that contains affected resource, if any
 943  * \param[in]     data_set    Cluster state
 944  * \param[in]     interval_ms How frequently to perform the operation
 945  */
 946 static void
 947 unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container,
     /* [previous][next][first][last][top][bottom][index][help] */
 948                  pe_working_set_t * data_set, guint interval_ms)
 949 {
 950     int timeout_ms = 0;
 951     const char *value = NULL;
 952     bool is_probe = pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)
 953                     && (interval_ms == 0);
 954 #if ENABLE_VERSIONED_ATTRS
 955     pe_rsc_action_details_t *rsc_details = NULL;
 956 #endif
 957 
 958     pe_rsc_eval_data_t rsc_rule_data = {
 959         .standard = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_CLASS),
 960         .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER),
 961         .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE)
 962     };
 963 
 964     pe_op_eval_data_t op_rule_data = {
 965         .op_name = action->task,
 966         .interval = interval_ms
 967     };
 968 
 969     pe_rule_eval_data_t rule_data = {
 970         .node_hash = NULL,
 971         .role = RSC_ROLE_UNKNOWN,
 972         .now = data_set->now,
 973         .match_data = NULL,
 974         .rsc_data = &rsc_rule_data,
 975         .op_data = &op_rule_data
 976     };
 977 
 978     CRM_CHECK(action && action->rsc, return);
 979 
 980     // Cluster-wide <op_defaults> <meta_attributes>
 981     pe__unpack_dataset_nvpairs(data_set->op_defaults, XML_TAG_META_SETS, &rule_data,
 982                                action->meta, NULL, FALSE, data_set);
 983 
 984     // Determine probe default timeout differently
 985     if (is_probe) {
 986         xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
 987 
 988         if (min_interval_mon) {
 989             value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
 990             if (value) {
 991                 crm_trace("\t%s: Setting default timeout to minimum-interval "
 992                           "monitor's timeout '%s'", action->uuid, value);
 993                 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
 994                                      strdup(value));
 995             }
 996         }
 997     }
 998 
 999     if (xml_obj) {
1000         xmlAttrPtr xIter = NULL;
1001 
1002         // <op> <meta_attributes> take precedence over defaults
1003         pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, &rule_data,
1004                                    action->meta, NULL, TRUE, data_set);
1005 
1006 #if ENABLE_VERSIONED_ATTRS
1007         rsc_details = pe_rsc_action_details(action);
1008 
1009         pe_eval_versioned_attributes(data_set->input, xml_obj,
1010                                      XML_TAG_ATTR_SETS, &rule_data,
1011                                      rsc_details->versioned_parameters,
1012                                      NULL);
1013         pe_eval_versioned_attributes(data_set->input, xml_obj,
1014                                      XML_TAG_META_SETS, &rule_data,
1015                                      rsc_details->versioned_meta,
1016                                      NULL);
1017 #endif
1018 
1019         /* Anything set as an <op> XML property has highest precedence.
1020          * This ensures we use the name and interval from the <op> tag.
1021          */
1022         for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
1023             const char *prop_name = (const char *)xIter->name;
1024             const char *prop_value = crm_element_value(xml_obj, prop_name);
1025 
1026             g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
1027         }
1028     }
1029 
1030     g_hash_table_remove(action->meta, "id");
1031 
1032     // Normalize interval to milliseconds
1033     if (interval_ms > 0) {
1034         g_hash_table_replace(action->meta, strdup(XML_LRM_ATTR_INTERVAL),
1035                              crm_strdup_printf("%u", interval_ms));
1036     } else {
1037         g_hash_table_remove(action->meta, XML_LRM_ATTR_INTERVAL);
1038     }
1039 
1040     /*
1041      * Timeout order of precedence:
1042      *   1. pcmk_monitor_timeout (if rsc has pcmk_ra_cap_fence_params
1043      *      and task is start or a probe; pcmk_monitor_timeout works
1044      *      by default for a recurring monitor)
1045      *   2. explicit op timeout on the primitive
1046      *   3. default op timeout
1047      *      a. if probe, then min-interval monitor's timeout
1048      *      b. else, in XML_CIB_TAG_OPCONFIG
1049      *   4. CRM_DEFAULT_OP_TIMEOUT_S
1050      *
1051      * #1 overrides general rule of <op> XML property having highest
1052      * precedence.
1053      */
1054     if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
1055                     pcmk_ra_cap_fence_params)
1056         && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
1057             || is_probe)) {
1058 
1059         GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
1060 
1061         value = g_hash_table_lookup(params, "pcmk_monitor_timeout");
1062 
1063         if (value) {
1064             crm_trace("\t%s: Setting timeout to pcmk_monitor_timeout '%s', "
1065                       "overriding default", action->uuid, value);
1066             g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
1067                                  strdup(value));
1068         }
1069     }
1070 
1071     // Normalize timeout to positive milliseconds
1072     value = g_hash_table_lookup(action->meta, XML_ATTR_TIMEOUT);
1073     timeout_ms = unpack_timeout(value);
1074     g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT),
1075                          pcmk__itoa(timeout_ms));
1076 
1077     if (!pcmk__strcase_any_of(action->task, RSC_START, RSC_PROMOTE, NULL)) {
1078         action->needs = rsc_req_nothing;
1079         value = "nothing (not start or promote)";
1080 
1081     } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1082         action->needs = rsc_req_stonith;
1083         value = "fencing";
1084 
1085     } else if (pcmk_is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1086         action->needs = rsc_req_quorum;
1087         value = "quorum";
1088 
1089     } else {
1090         action->needs = rsc_req_nothing;
1091         value = "nothing";
1092     }
1093     pe_rsc_trace(action->rsc, "%s requires %s", action->uuid, value);
1094 
1095     value = unpack_operation_on_fail(action);
1096 
1097     if (value == NULL) {
1098 
1099     } else if (pcmk__str_eq(value, "block", pcmk__str_casei)) {
1100         action->on_fail = action_fail_block;
1101         g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1102         value = "block"; // The above could destroy the original string
1103 
1104     } else if (pcmk__str_eq(value, "fence", pcmk__str_casei)) {
1105         action->on_fail = action_fail_fence;
1106         value = "node fencing";
1107 
1108         if (!pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1109             pcmk__config_err("Resetting '" XML_OP_ATTR_ON_FAIL "' for "
1110                              "operation '%s' to 'stop' because 'fence' is not "
1111                              "valid when fencing is disabled", action->uuid);
1112             action->on_fail = action_fail_stop;
1113             action->fail_role = RSC_ROLE_STOPPED;
1114             value = "stop resource";
1115         }
1116 
1117     } else if (pcmk__str_eq(value, "standby", pcmk__str_casei)) {
1118         action->on_fail = action_fail_standby;
1119         value = "node standby";
1120 
1121     } else if (pcmk__strcase_any_of(value, "ignore", "nothing", NULL)) {
1122         action->on_fail = action_fail_ignore;
1123         value = "ignore";
1124 
1125     } else if (pcmk__str_eq(value, "migrate", pcmk__str_casei)) {
1126         action->on_fail = action_fail_migrate;
1127         value = "force migration";
1128 
1129     } else if (pcmk__str_eq(value, "stop", pcmk__str_casei)) {
1130         action->on_fail = action_fail_stop;
1131         action->fail_role = RSC_ROLE_STOPPED;
1132         value = "stop resource";
1133 
1134     } else if (pcmk__str_eq(value, "restart", pcmk__str_casei)) {
1135         action->on_fail = action_fail_recover;
1136         value = "restart (and possibly migrate)";
1137 
1138     } else if (pcmk__str_eq(value, "restart-container", pcmk__str_casei)) {
1139         if (container) {
1140             action->on_fail = action_fail_restart_container;
1141             value = "restart container (and possibly migrate)";
1142 
1143         } else {
1144             value = NULL;
1145         }
1146 
1147     } else if (pcmk__str_eq(value, "demote", pcmk__str_casei)) {
1148         action->on_fail = action_fail_demote;
1149         value = "demote instance";
1150 
1151     } else {
1152         pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1153         value = NULL;
1154     }
1155 
1156     /* defaults */
1157     if (value == NULL && container) {
1158         action->on_fail = action_fail_restart_container;
1159         value = "restart container (and possibly migrate) (default)";
1160 
1161     /* For remote nodes, ensure that any failure that results in dropping an
1162      * active connection to the node results in fencing of the node.
1163      *
1164      * There are only two action failures that don't result in fencing.
1165      * 1. probes - probe failures are expected.
1166      * 2. start - a start failure indicates that an active connection does not already
1167      * exist. The user can set op on-fail=fence if they really want to fence start
1168      * failures. */
1169     } else if (((value == NULL) || !pcmk_is_set(action->rsc->flags, pe_rsc_managed))
1170                && pe__resource_is_remote_conn(action->rsc, data_set)
1171                && !(pcmk__str_eq(action->task, CRMD_ACTION_STATUS, pcmk__str_casei)
1172                     && (interval_ms == 0))
1173                && !pcmk__str_eq(action->task, CRMD_ACTION_START, pcmk__str_casei)) {
1174 
1175         if (!pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
1176             action->on_fail = action_fail_stop;
1177             action->fail_role = RSC_ROLE_STOPPED;
1178             value = "stop unmanaged remote node (enforcing default)";
1179 
1180         } else {
1181             if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1182                 value = "fence remote node (default)";
1183             } else {
1184                 value = "recover remote node connection (default)";
1185             }
1186 
1187             if (action->rsc->remote_reconnect_ms) {
1188                 action->fail_role = RSC_ROLE_STOPPED;
1189             }
1190             action->on_fail = action_fail_reset_remote;
1191         }
1192 
1193     } else if (value == NULL && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
1194         if (pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1195             action->on_fail = action_fail_fence;
1196             value = "resource fence (default)";
1197 
1198         } else {
1199             action->on_fail = action_fail_block;
1200             value = "resource block (default)";
1201         }
1202 
1203     } else if (value == NULL) {
1204         action->on_fail = action_fail_recover;
1205         value = "restart (and possibly migrate) (default)";
1206     }
1207 
1208     pe_rsc_trace(action->rsc, "%s failure handling: %s",
1209                  action->uuid, value);
1210 
1211     value = NULL;
1212     if (xml_obj != NULL) {
1213         value = g_hash_table_lookup(action->meta, "role_after_failure");
1214         if (value) {
1215             pe_warn_once(pe_wo_role_after,
1216                         "Support for role_after_failure is deprecated and will be removed in a future release");
1217         }
1218     }
1219     if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1220         action->fail_role = text2role(value);
1221     }
1222     /* defaults */
1223     if (action->fail_role == RSC_ROLE_UNKNOWN) {
1224         if (pcmk__str_eq(action->task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
1225             action->fail_role = RSC_ROLE_UNPROMOTED;
1226         } else {
1227             action->fail_role = RSC_ROLE_STARTED;
1228         }
1229     }
1230     pe_rsc_trace(action->rsc, "%s failure results in: %s",
1231                  action->uuid, role2text(action->fail_role));
1232 
1233     value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1234     if (value) {
1235         unpack_start_delay(value, action->meta);
1236     } else {
1237         long long start_delay = 0;
1238 
1239         value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1240         if (unpack_interval_origin(value, xml_obj, interval_ms, data_set->now,
1241                                    &start_delay)) {
1242             g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
1243                                  crm_strdup_printf("%lld", start_delay));
1244         }
1245     }
1246 
1247 #if ENABLE_VERSIONED_ATTRS
1248     unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval_ms,
1249                           data_set->now);
1250 #endif
1251 }
1252 
1253 static xmlNode *
1254 find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key, gboolean include_disabled)
     /* [previous][next][first][last][top][bottom][index][help] */
1255 {
1256     guint interval_ms = 0;
1257     gboolean do_retry = TRUE;
1258     char *local_key = NULL;
1259     const char *name = NULL;
1260     const char *value = NULL;
1261     const char *interval_spec = NULL;
1262     char *match_key = NULL;
1263     xmlNode *op = NULL;
1264     xmlNode *operation = NULL;
1265 
1266   retry:
1267     for (operation = pcmk__xe_first_child(rsc->ops_xml); operation != NULL;
1268          operation = pcmk__xe_next(operation)) {
1269 
1270         if (pcmk__str_eq((const char *)operation->name, "op", pcmk__str_none)) {
1271             name = crm_element_value(operation, "name");
1272             interval_spec = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1273             value = crm_element_value(operation, "enabled");
1274             if (!include_disabled && value && crm_is_true(value) == FALSE) {
1275                 continue;
1276             }
1277 
1278             interval_ms = crm_parse_interval_spec(interval_spec);
1279             match_key = pcmk__op_key(rsc->id, name, interval_ms);
1280             if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
1281                 op = operation;
1282             }
1283             free(match_key);
1284 
1285             if (rsc->clone_name) {
1286                 match_key = pcmk__op_key(rsc->clone_name, name, interval_ms);
1287                 if (pcmk__str_eq(key, match_key, pcmk__str_casei)) {
1288                     op = operation;
1289                 }
1290                 free(match_key);
1291             }
1292 
1293             if (op != NULL) {
1294                 free(local_key);
1295                 return op;
1296             }
1297         }
1298     }
1299 
1300     free(local_key);
1301     if (do_retry == FALSE) {
1302         return NULL;
1303     }
1304 
1305     do_retry = FALSE;
1306     if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1307         local_key = pcmk__op_key(rsc->id, "migrate", 0);
1308         key = local_key;
1309         goto retry;
1310 
1311     } else if (strstr(key, "_notify_")) {
1312         local_key = pcmk__op_key(rsc->id, "notify", 0);
1313         key = local_key;
1314         goto retry;
1315     }
1316 
1317     return NULL;
1318 }
1319 
1320 xmlNode *
1321 find_rsc_op_entry(pe_resource_t * rsc, const char *key)
     /* [previous][next][first][last][top][bottom][index][help] */
1322 {
1323     return find_rsc_op_entry_helper(rsc, key, FALSE);
1324 }
1325 
1326 /*
1327  * Used by the HashTable for-loop
1328  */
1329 void
1330 print_str_str(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1331 {
1332     crm_trace("%s%s %s ==> %s",
1333               user_data == NULL ? "" : (char *)user_data,
1334               user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1335 }
1336 
1337 void
1338 pe_free_action(pe_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
1339 {
1340     if (action == NULL) {
1341         return;
1342     }
1343     g_list_free_full(action->actions_before, free);     /* pe_action_wrapper_t* */
1344     g_list_free_full(action->actions_after, free);      /* pe_action_wrapper_t* */
1345     if (action->extra) {
1346         g_hash_table_destroy(action->extra);
1347     }
1348     if (action->meta) {
1349         g_hash_table_destroy(action->meta);
1350     }
1351 #if ENABLE_VERSIONED_ATTRS
1352     if (action->rsc) {
1353         pe_free_rsc_action_details(action);
1354     }
1355 #endif
1356     free(action->cancel_task);
1357     free(action->reason);
1358     free(action->task);
1359     free(action->uuid);
1360     free(action->node);
1361     free(action);
1362 }
1363 
1364 GList *
1365 find_recurring_actions(GList *input, pe_node_t * not_on_node)
     /* [previous][next][first][last][top][bottom][index][help] */
1366 {
1367     const char *value = NULL;
1368     GList *result = NULL;
1369     GList *gIter = input;
1370 
1371     CRM_CHECK(input != NULL, return NULL);
1372 
1373     for (; gIter != NULL; gIter = gIter->next) {
1374         pe_action_t *action = (pe_action_t *) gIter->data;
1375 
1376         value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL_MS);
1377         if (value == NULL) {
1378             /* skip */
1379         } else if (pcmk__str_eq(value, "0", pcmk__str_casei)) {
1380             /* skip */
1381         } else if (pcmk__str_eq(CRMD_ACTION_CANCEL, action->task, pcmk__str_casei)) {
1382             /* skip */
1383         } else if (not_on_node == NULL) {
1384             crm_trace("(null) Found: %s", action->uuid);
1385             result = g_list_prepend(result, action);
1386 
1387         } else if (action->node == NULL) {
1388             /* skip */
1389         } else if (action->node->details != not_on_node->details) {
1390             crm_trace("Found: %s", action->uuid);
1391             result = g_list_prepend(result, action);
1392         }
1393     }
1394 
1395     return result;
1396 }
1397 
1398 enum action_tasks
1399 get_complex_task(pe_resource_t * rsc, const char *name, gboolean allow_non_atomic)
     /* [previous][next][first][last][top][bottom][index][help] */
1400 {
1401     enum action_tasks task = text2task(name);
1402 
1403     if (rsc == NULL) {
1404         return task;
1405 
1406     } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1407         switch (task) {
1408             case stopped_rsc:
1409             case started_rsc:
1410             case action_demoted:
1411             case action_promoted:
1412                 crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1413                 return task - 1;
1414             default:
1415                 break;
1416         }
1417     }
1418     return task;
1419 }
1420 
1421 pe_action_t *
1422 find_first_action(GList *input, const char *uuid, const char *task, pe_node_t * on_node)
     /* [previous][next][first][last][top][bottom][index][help] */
1423 {
1424     GList *gIter = NULL;
1425 
1426     CRM_CHECK(uuid || task, return NULL);
1427 
1428     for (gIter = input; gIter != NULL; gIter = gIter->next) {
1429         pe_action_t *action = (pe_action_t *) gIter->data;
1430 
1431         if (uuid != NULL && !pcmk__str_eq(uuid, action->uuid, pcmk__str_casei)) {
1432             continue;
1433 
1434         } else if (task != NULL && !pcmk__str_eq(task, action->task, pcmk__str_casei)) {
1435             continue;
1436 
1437         } else if (on_node == NULL) {
1438             return action;
1439 
1440         } else if (action->node == NULL) {
1441             continue;
1442 
1443         } else if (on_node->details == action->node->details) {
1444             return action;
1445         }
1446     }
1447 
1448     return NULL;
1449 }
1450 
1451 GList *
1452 find_actions(GList *input, const char *key, const pe_node_t *on_node)
     /* [previous][next][first][last][top][bottom][index][help] */
1453 {
1454     GList *gIter = input;
1455     GList *result = NULL;
1456 
1457     CRM_CHECK(key != NULL, return NULL);
1458 
1459     for (; gIter != NULL; gIter = gIter->next) {
1460         pe_action_t *action = (pe_action_t *) gIter->data;
1461 
1462         if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1463             crm_trace("%s does not match action %s", key, action->uuid);
1464             continue;
1465 
1466         } else if (on_node == NULL) {
1467             crm_trace("Action %s matches (ignoring node)", key);
1468             result = g_list_prepend(result, action);
1469 
1470         } else if (action->node == NULL) {
1471             crm_trace("Action %s matches (unallocated, assigning to %s)",
1472                       key, on_node->details->uname);
1473 
1474             action->node = pe__copy_node(on_node);
1475             result = g_list_prepend(result, action);
1476 
1477         } else if (on_node->details == action->node->details) {
1478             crm_trace("Action %s on %s matches", key, on_node->details->uname);
1479             result = g_list_prepend(result, action);
1480 
1481         } else {
1482             crm_trace("Action %s on node %s does not match requested node %s",
1483                       key, action->node->details->uname,
1484                       on_node->details->uname);
1485         }
1486     }
1487 
1488     return result;
1489 }
1490 
1491 GList *
1492 find_actions_exact(GList *input, const char *key, const pe_node_t *on_node)
     /* [previous][next][first][last][top][bottom][index][help] */
1493 {
1494     GList *result = NULL;
1495 
1496     CRM_CHECK(key != NULL, return NULL);
1497 
1498     if (on_node == NULL) {
1499         crm_trace("Not searching for action %s because node not specified",
1500                   key);
1501         return NULL;
1502     }
1503 
1504     for (GList *gIter = input; gIter != NULL; gIter = gIter->next) {
1505         pe_action_t *action = (pe_action_t *) gIter->data;
1506 
1507         if (action->node == NULL) {
1508             crm_trace("Skipping comparison of %s vs action %s without node",
1509                       key, action->uuid);
1510 
1511         } else if (!pcmk__str_eq(key, action->uuid, pcmk__str_casei)) {
1512             crm_trace("Desired action %s doesn't match %s", key, action->uuid);
1513 
1514         } else if (!pcmk__str_eq(on_node->details->id, action->node->details->id, pcmk__str_casei)) {
1515             crm_trace("Action %s desired node ID %s doesn't match %s",
1516                       key, on_node->details->id, action->node->details->id);
1517 
1518         } else {
1519             crm_trace("Action %s matches", key);
1520             result = g_list_prepend(result, action);
1521         }
1522     }
1523 
1524     return result;
1525 }
1526 
1527 /*!
1528  * \brief Find all actions of given type for a resource
1529  *
1530  * \param[in] rsc           Resource to search
1531  * \param[in] node          Find only actions scheduled on this node
1532  * \param[in] task          Action name to search for
1533  * \param[in] require_node  If TRUE, NULL node or action node will not match
1534  *
1535  * \return List of actions found (or NULL if none)
1536  * \note If node is not NULL and require_node is FALSE, matching actions
1537  *       without a node will be assigned to node.
1538  */
1539 GList *
1540 pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
1541                      const char *task, bool require_node)
1542 {
1543     GList *result = NULL;
1544     char *key = pcmk__op_key(rsc->id, task, 0);
1545 
1546     if (require_node) {
1547         result = find_actions_exact(rsc->actions, key, node);
1548     } else {
1549         result = find_actions(rsc->actions, key, node);
1550     }
1551     free(key);
1552     return result;
1553 }
1554 
1555 static void
1556 resource_node_score(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag)
     /* [previous][next][first][last][top][bottom][index][help] */
1557 {
1558     pe_node_t *match = NULL;
1559 
1560     if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
1561         && pcmk__str_eq(tag, "symmetric_default", pcmk__str_casei)) {
1562         /* This string comparision may be fragile, but exclusive resources and
1563          * exclusive nodes should not have the symmetric_default constraint
1564          * applied to them.
1565          */
1566         return;
1567 
1568     } else if (rsc->children) {
1569         GList *gIter = rsc->children;
1570 
1571         for (; gIter != NULL; gIter = gIter->next) {
1572             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1573 
1574             resource_node_score(child_rsc, node, score, tag);
1575         }
1576     }
1577 
1578     pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1579     match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1580     if (match == NULL) {
1581         match = pe__copy_node(node);
1582         g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1583     }
1584     match->weight = pe__add_scores(match->weight, score);
1585 }
1586 
1587 void
1588 resource_location(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag,
     /* [previous][next][first][last][top][bottom][index][help] */
1589                   pe_working_set_t * data_set)
1590 {
1591     if (node != NULL) {
1592         resource_node_score(rsc, node, score, tag);
1593 
1594     } else if (data_set != NULL) {
1595         GList *gIter = data_set->nodes;
1596 
1597         for (; gIter != NULL; gIter = gIter->next) {
1598             pe_node_t *node_iter = (pe_node_t *) gIter->data;
1599 
1600             resource_node_score(rsc, node_iter, score, tag);
1601         }
1602 
1603     } else {
1604         GHashTableIter iter;
1605         pe_node_t *node_iter = NULL;
1606 
1607         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1608         while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1609             resource_node_score(rsc, node_iter, score, tag);
1610         }
1611     }
1612 
1613     if (node == NULL && score == -INFINITY) {
1614         if (rsc->allocated_to) {
1615             crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1616             free(rsc->allocated_to);
1617             rsc->allocated_to = NULL;
1618         }
1619     }
1620 }
1621 
1622 #define sort_return(an_int, why) do {                                   \
1623         free(a_uuid);                                           \
1624         free(b_uuid);                                           \
1625         crm_trace("%s (%d) %c %s (%d) : %s",                            \
1626                   a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=',   \
1627                   b_xml_id, b_call_id, why);                            \
1628         return an_int;                                                  \
1629     } while(0)
1630 
1631 gint
1632 sort_op_by_callid(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
1633 {
1634     int a_call_id = -1;
1635     int b_call_id = -1;
1636 
1637     char *a_uuid = NULL;
1638     char *b_uuid = NULL;
1639 
1640     const xmlNode *xml_a = a;
1641     const xmlNode *xml_b = b;
1642 
1643     const char *a_xml_id = crm_element_value(xml_a, XML_ATTR_ID);
1644     const char *b_xml_id = crm_element_value(xml_b, XML_ATTR_ID);
1645 
1646     if (pcmk__str_eq(a_xml_id, b_xml_id, pcmk__str_casei)) {
1647         /* We have duplicate lrm_rsc_op entries in the status
1648          * section which is unlikely to be a good thing
1649          *    - we can handle it easily enough, but we need to get
1650          *    to the bottom of why it's happening.
1651          */
1652         pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1653         sort_return(0, "duplicate");
1654     }
1655 
1656     crm_element_value_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1657     crm_element_value_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1658 
1659     if (a_call_id == -1 && b_call_id == -1) {
1660         /* both are pending ops so it doesn't matter since
1661          *   stops are never pending
1662          */
1663         sort_return(0, "pending");
1664 
1665     } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1666         sort_return(-1, "call id");
1667 
1668     } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1669         sort_return(1, "call id");
1670 
1671     } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1672         /*
1673          * The op and last_failed_op are the same
1674          * Order on last-rc-change
1675          */
1676         time_t last_a = -1;
1677         time_t last_b = -1;
1678 
1679         crm_element_value_epoch(xml_a, XML_RSC_OP_LAST_CHANGE, &last_a);
1680         crm_element_value_epoch(xml_b, XML_RSC_OP_LAST_CHANGE, &last_b);
1681 
1682         crm_trace("rc-change: %lld vs %lld",
1683                   (long long) last_a, (long long) last_b);
1684         if (last_a >= 0 && last_a < last_b) {
1685             sort_return(-1, "rc-change");
1686 
1687         } else if (last_b >= 0 && last_a > last_b) {
1688             sort_return(1, "rc-change");
1689         }
1690         sort_return(0, "rc-change");
1691 
1692     } else {
1693         /* One of the inputs is a pending operation
1694          * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1695          */
1696 
1697         int a_id = -1;
1698         int b_id = -1;
1699 
1700         const char *a_magic = crm_element_value(xml_a, XML_ATTR_TRANSITION_MAGIC);
1701         const char *b_magic = crm_element_value(xml_b, XML_ATTR_TRANSITION_MAGIC);
1702 
1703         CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1704         if (!decode_transition_magic(a_magic, &a_uuid, &a_id, NULL, NULL, NULL,
1705                                      NULL)) {
1706             sort_return(0, "bad magic a");
1707         }
1708         if (!decode_transition_magic(b_magic, &b_uuid, &b_id, NULL, NULL, NULL,
1709                                      NULL)) {
1710             sort_return(0, "bad magic b");
1711         }
1712         /* try to determine the relative age of the operation...
1713          * some pending operations (e.g. a start) may have been superseded
1714          *   by a subsequent stop
1715          *
1716          * [a|b]_id == -1 means it's a shutdown operation and _always_ comes last
1717          */
1718         if (!pcmk__str_eq(a_uuid, b_uuid, pcmk__str_casei) || a_id == b_id) {
1719             /*
1720              * some of the logic in here may be redundant...
1721              *
1722              * if the UUID from the TE doesn't match then one better
1723              *   be a pending operation.
1724              * pending operations don't survive between elections and joins
1725              *   because we query the LRM directly
1726              */
1727 
1728             if (b_call_id == -1) {
1729                 sort_return(-1, "transition + call");
1730 
1731             } else if (a_call_id == -1) {
1732                 sort_return(1, "transition + call");
1733             }
1734 
1735         } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1736             sort_return(-1, "transition");
1737 
1738         } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1739             sort_return(1, "transition");
1740         }
1741     }
1742 
1743     /* we should never end up here */
1744     CRM_CHECK(FALSE, sort_return(0, "default"));
1745 
1746 }
1747 
1748 time_t
1749 get_effective_time(pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1750 {
1751     if(data_set) {
1752         if (data_set->now == NULL) {
1753             crm_trace("Recording a new 'now'");
1754             data_set->now = crm_time_new(NULL);
1755         }
1756         return crm_time_get_seconds_since_epoch(data_set->now);
1757     }
1758 
1759     crm_trace("Defaulting to 'now'");
1760     return time(NULL);
1761 }
1762 
1763 gboolean
1764 get_target_role(pe_resource_t * rsc, enum rsc_role_e * role)
     /* [previous][next][first][last][top][bottom][index][help] */
1765 {
1766     enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1767     const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1768 
1769     CRM_CHECK(role != NULL, return FALSE);
1770 
1771     if (pcmk__str_eq(value, "started", pcmk__str_null_matches | pcmk__str_casei)
1772         || pcmk__str_eq("default", value, pcmk__str_casei)) {
1773         return FALSE;
1774     }
1775 
1776     local_role = text2role(value);
1777     if (local_role == RSC_ROLE_UNKNOWN) {
1778         pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1779                          "because '%s' is not valid", rsc->id, value);
1780         return FALSE;
1781 
1782     } else if (local_role > RSC_ROLE_STARTED) {
1783         if (pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
1784             if (local_role > RSC_ROLE_UNPROMOTED) {
1785                 /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1786                 return FALSE;
1787             }
1788 
1789         } else {
1790             pcmk__config_err("Ignoring '" XML_RSC_ATTR_TARGET_ROLE "' for %s "
1791                              "because '%s' only makes sense for promotable "
1792                              "clones", rsc->id, value);
1793             return FALSE;
1794         }
1795     }
1796 
1797     *role = local_role;
1798     return TRUE;
1799 }
1800 
1801 gboolean
1802 order_actions(pe_action_t * lh_action, pe_action_t * rh_action, enum pe_ordering order)
     /* [previous][next][first][last][top][bottom][index][help] */
1803 {
1804     GList *gIter = NULL;
1805     pe_action_wrapper_t *wrapper = NULL;
1806     GList *list = NULL;
1807 
1808     if (order == pe_order_none) {
1809         return FALSE;
1810     }
1811 
1812     if (lh_action == NULL || rh_action == NULL) {
1813         return FALSE;
1814     }
1815 
1816     crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1817 
1818     /* Ensure we never create a dependency on ourselves... it's happened */
1819     CRM_ASSERT(lh_action != rh_action);
1820 
1821     /* Filter dups, otherwise update_action_states() has too much work to do */
1822     gIter = lh_action->actions_after;
1823     for (; gIter != NULL; gIter = gIter->next) {
1824         pe_action_wrapper_t *after = (pe_action_wrapper_t *) gIter->data;
1825 
1826         if (after->action == rh_action && (after->type & order)) {
1827             return FALSE;
1828         }
1829     }
1830 
1831     wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1832     wrapper->action = rh_action;
1833     wrapper->type = order;
1834     list = lh_action->actions_after;
1835     list = g_list_prepend(list, wrapper);
1836     lh_action->actions_after = list;
1837 
1838     wrapper = calloc(1, sizeof(pe_action_wrapper_t));
1839     wrapper->action = lh_action;
1840     wrapper->type = order;
1841     list = rh_action->actions_before;
1842     list = g_list_prepend(list, wrapper);
1843     rh_action->actions_before = list;
1844     return TRUE;
1845 }
1846 
1847 pe_action_t *
1848 get_pseudo_op(const char *name, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1849 {
1850     pe_action_t *op = NULL;
1851 
1852     if(data_set->singletons) {
1853         op = g_hash_table_lookup(data_set->singletons, name);
1854     }
1855     if (op == NULL) {
1856         op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1857         pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
1858     }
1859 
1860     return op;
1861 }
1862 
1863 void
1864 destroy_ticket(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
1865 {
1866     pe_ticket_t *ticket = data;
1867 
1868     if (ticket->state) {
1869         g_hash_table_destroy(ticket->state);
1870     }
1871     free(ticket->id);
1872     free(ticket);
1873 }
1874 
1875 pe_ticket_t *
1876 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1877 {
1878     pe_ticket_t *ticket = NULL;
1879 
1880     if (pcmk__str_empty(ticket_id)) {
1881         return NULL;
1882     }
1883 
1884     if (data_set->tickets == NULL) {
1885         data_set->tickets = pcmk__strkey_table(free, destroy_ticket);
1886     }
1887 
1888     ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1889     if (ticket == NULL) {
1890 
1891         ticket = calloc(1, sizeof(pe_ticket_t));
1892         if (ticket == NULL) {
1893             crm_err("Cannot allocate ticket '%s'", ticket_id);
1894             return NULL;
1895         }
1896 
1897         crm_trace("Creaing ticket entry for %s", ticket_id);
1898 
1899         ticket->id = strdup(ticket_id);
1900         ticket->granted = FALSE;
1901         ticket->last_granted = -1;
1902         ticket->standby = FALSE;
1903         ticket->state = pcmk__strkey_table(free, free);
1904 
1905         g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1906     }
1907 
1908     return ticket;
1909 }
1910 
1911 const char *rsc_printable_id(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1912 {
1913     if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1914         return ID(rsc->xml);
1915     }
1916     return rsc->id;
1917 }
1918 
1919 void
1920 pe__clear_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1921 {
1922     pe__clear_resource_flags(rsc, flags);
1923     for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1924         pe__clear_resource_flags_recursive((pe_resource_t *) gIter->data, flags);
1925     }
1926 }
1927 
1928 void
1929 pe__clear_resource_flags_on_all(pe_working_set_t *data_set, uint64_t flag)
     /* [previous][next][first][last][top][bottom][index][help] */
1930 {
1931     for (GList *lpc = data_set->resources; lpc != NULL; lpc = lpc->next) {
1932         pe_resource_t *r = (pe_resource_t *) lpc->data;
1933         pe__clear_resource_flags_recursive(r, flag);
1934     }
1935 }
1936 
1937 void
1938 pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1939 {
1940     pe__set_resource_flags(rsc, flags);
1941     for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1942         pe__set_resource_flags_recursive((pe_resource_t *) gIter->data, flags);
1943     }
1944 }
1945 
1946 static GList *
1947 find_unfencing_devices(GList *candidates, GList *matches) 
     /* [previous][next][first][last][top][bottom][index][help] */
1948 {
1949     for (GList *gIter = candidates; gIter != NULL; gIter = gIter->next) {
1950         pe_resource_t *candidate = gIter->data;
1951         const char *provides = g_hash_table_lookup(candidate->meta,
1952                                                    PCMK_STONITH_PROVIDES);
1953         const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
1954 
1955         if(candidate->children) {
1956             matches = find_unfencing_devices(candidate->children, matches);
1957         } else if (!pcmk_is_set(candidate->flags, pe_rsc_fence_device)) {
1958             continue;
1959 
1960         } else if (pcmk__str_eq(provides, "unfencing", pcmk__str_casei) || pcmk__str_eq(requires, "unfencing", pcmk__str_casei)) {
1961             matches = g_list_prepend(matches, candidate);
1962         }
1963     }
1964     return matches;
1965 }
1966 
1967 static int
1968 node_priority_fencing_delay(pe_node_t * node, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1969 {
1970     int member_count = 0;
1971     int online_count = 0;
1972     int top_priority = 0;
1973     int lowest_priority = 0;
1974     GList *gIter = NULL;
1975 
1976     // `priority-fencing-delay` is disabled
1977     if (data_set->priority_fencing_delay <= 0) {
1978         return 0;
1979     }
1980 
1981     /* No need to request a delay if the fencing target is not a normal cluster
1982      * member, for example if it's a remote node or a guest node. */
1983     if (node->details->type != node_member) {
1984         return 0;
1985     }
1986 
1987     // No need to request a delay if the fencing target is in our partition
1988     if (node->details->online) {
1989         return 0;
1990     }
1991 
1992     for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1993         pe_node_t *n =  gIter->data;
1994 
1995         if (n->details->type != node_member) {
1996             continue;
1997         }
1998 
1999         member_count ++;
2000 
2001         if (n->details->online) {
2002             online_count++;
2003         }
2004 
2005         if (member_count == 1
2006             || n->details->priority > top_priority) {
2007             top_priority = n->details->priority;
2008         }
2009 
2010         if (member_count == 1
2011             || n->details->priority < lowest_priority) {
2012             lowest_priority = n->details->priority;
2013         }
2014     }
2015 
2016     // No need to delay if we have more than half of the cluster members
2017     if (online_count > member_count / 2) {
2018         return 0;
2019     }
2020 
2021     /* All the nodes have equal priority.
2022      * Any configured corresponding `pcmk_delay_base/max` will be applied. */
2023     if (lowest_priority == top_priority) {
2024         return 0;
2025     }
2026 
2027     if (node->details->priority < top_priority) {
2028         return 0;
2029     }
2030 
2031     return data_set->priority_fencing_delay;
2032 }
2033 
2034 pe_action_t *
2035 pe_fence_op(pe_node_t * node, const char *op, bool optional, const char *reason,
     /* [previous][next][first][last][top][bottom][index][help] */
2036             bool priority_delay, pe_working_set_t * data_set)
2037 {
2038     char *op_key = NULL;
2039     pe_action_t *stonith_op = NULL;
2040 
2041     if(op == NULL) {
2042         op = data_set->stonith_action;
2043     }
2044 
2045     op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2046 
2047     if(data_set->singletons) {
2048         stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2049     }
2050 
2051     if(stonith_op == NULL) {
2052         stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2053 
2054         add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2055         add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2056         add_hash_param(stonith_op->meta, "stonith_action", op);
2057 
2058         if (pe__is_guest_or_remote_node(node)
2059             && pcmk_is_set(data_set->flags, pe_flag_enable_unfencing)) {
2060             /* Extra work to detect device changes on remotes
2061              *
2062              * We may do this for all nodes in the future, but for now
2063              * the check_action_definition() based stuff works fine.
2064              */
2065             long max = 1024;
2066             long digests_all_offset = 0;
2067             long digests_secure_offset = 0;
2068 
2069             char *digests_all = calloc(max, sizeof(char));
2070             char *digests_secure = calloc(max, sizeof(char));
2071             GList *matches = find_unfencing_devices(data_set->resources, NULL);
2072 
2073             for (GList *gIter = matches; gIter != NULL; gIter = gIter->next) {
2074                 pe_resource_t *match = gIter->data;
2075                 const char *agent = g_hash_table_lookup(match->meta,
2076                                                         XML_ATTR_TYPE);
2077                 op_digest_cache_t *data = NULL;
2078 
2079                 data = pe__compare_fencing_digest(match, agent, node, data_set);
2080                 if(data->rc == RSC_DIGEST_ALL) {
2081                     optional = FALSE;
2082                     crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2083                     if (!pcmk__is_daemon && data_set->priv != NULL) {
2084                         pcmk__output_t *out = data_set->priv;
2085                         out->info(out, "notice: Unfencing %s (remote): because the definition of %s changed",
2086                                   node->details->uname, match->id);
2087                     }
2088                 }
2089 
2090                 digests_all_offset += snprintf(
2091                     digests_all+digests_all_offset, max-digests_all_offset,
2092                     "%s:%s:%s,", match->id, agent, data->digest_all_calc);
2093 
2094                 digests_secure_offset += snprintf(
2095                     digests_secure+digests_secure_offset, max-digests_secure_offset,
2096                     "%s:%s:%s,", match->id, agent, data->digest_secure_calc);
2097             }
2098             g_hash_table_insert(stonith_op->meta,
2099                                 strdup(XML_OP_ATTR_DIGESTS_ALL),
2100                                 digests_all);
2101             g_hash_table_insert(stonith_op->meta,
2102                                 strdup(XML_OP_ATTR_DIGESTS_SECURE),
2103                                 digests_secure);
2104         }
2105 
2106     } else {
2107         free(op_key);
2108     }
2109 
2110     if (data_set->priority_fencing_delay > 0
2111 
2112             /* It's a suitable case where `priority-fencing-delay` applies.
2113              * At least add `priority-fencing-delay` field as an indicator. */
2114         && (priority_delay
2115 
2116             /* Re-calculate priority delay for the suitable case when
2117              * pe_fence_op() is called again by stage6() after node priority has
2118              * been actually calculated with native_add_running() */
2119             || g_hash_table_lookup(stonith_op->meta,
2120                                    XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY) != NULL)) {
2121 
2122             /* Add `priority-fencing-delay` to the fencing op even if it's 0 for
2123              * the targeting node. So that it takes precedence over any possible
2124              * `pcmk_delay_base/max`.
2125              */
2126             char *delay_s = pcmk__itoa(node_priority_fencing_delay(node, data_set));
2127 
2128             g_hash_table_insert(stonith_op->meta,
2129                                 strdup(XML_CONFIG_ATTR_PRIORITY_FENCING_DELAY),
2130                                 delay_s);
2131     }
2132 
2133     if(optional == FALSE && pe_can_fence(data_set, node)) {
2134         pe_action_required(stonith_op, NULL, reason);
2135     } else if(reason && stonith_op->reason == NULL) {
2136         stonith_op->reason = strdup(reason);
2137     }
2138 
2139     return stonith_op;
2140 }
2141 
2142 void
2143 trigger_unfencing(
     /* [previous][next][first][last][top][bottom][index][help] */
2144     pe_resource_t * rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t * data_set) 
2145 {
2146     if (!pcmk_is_set(data_set->flags, pe_flag_enable_unfencing)) {
2147         /* No resources require it */
2148         return;
2149 
2150     } else if ((rsc != NULL)
2151                && !pcmk_is_set(rsc->flags, pe_rsc_fence_device)) {
2152         /* Wasn't a stonith device */
2153         return;
2154 
2155     } else if(node
2156               && node->details->online
2157               && node->details->unclean == FALSE
2158               && node->details->shutdown == FALSE) {
2159         pe_action_t *unfence = pe_fence_op(node, "on", FALSE, reason, FALSE, data_set);
2160 
2161         if(dependency) {
2162             order_actions(unfence, dependency, pe_order_optional);
2163         }
2164 
2165     } else if(rsc) {
2166         GHashTableIter iter;
2167 
2168         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2169         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2170             if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2171                 trigger_unfencing(rsc, node, reason, dependency, data_set);
2172             }
2173         }
2174     }
2175 }
2176 
2177 gboolean
2178 add_tag_ref(GHashTable * tags, const char * tag_name,  const char * obj_ref)
     /* [previous][next][first][last][top][bottom][index][help] */
2179 {
2180     pe_tag_t *tag = NULL;
2181     GList *gIter = NULL;
2182     gboolean is_existing = FALSE;
2183 
2184     CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2185 
2186     tag = g_hash_table_lookup(tags, tag_name);
2187     if (tag == NULL) {
2188         tag = calloc(1, sizeof(pe_tag_t));
2189         if (tag == NULL) {
2190             return FALSE;
2191         }
2192         tag->id = strdup(tag_name);
2193         tag->refs = NULL;
2194         g_hash_table_insert(tags, strdup(tag_name), tag);
2195     }
2196 
2197     for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2198         const char *existing_ref = (const char *) gIter->data;
2199 
2200         if (pcmk__str_eq(existing_ref, obj_ref, pcmk__str_none)){
2201             is_existing = TRUE;
2202             break;
2203         }
2204     }
2205 
2206     if (is_existing == FALSE) {
2207         tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2208         crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2209     }
2210 
2211     return TRUE;
2212 }
2213 
2214 void pe_action_set_flag_reason(const char *function, long line,
     /* [previous][next][first][last][top][bottom][index][help] */
2215                                pe_action_t *action, pe_action_t *reason, const char *text,
2216                                enum pe_action_flags flags, bool overwrite)
2217 {
2218     bool unset = FALSE;
2219     bool update = FALSE;
2220     const char *change = NULL;
2221 
2222     if (pcmk_is_set(flags, pe_action_runnable)) {
2223         unset = TRUE;
2224         change = "unrunnable";
2225     } else if (pcmk_is_set(flags, pe_action_optional)) {
2226         unset = TRUE;
2227         change = "required";
2228     } else if (pcmk_is_set(flags, pe_action_migrate_runnable)) {
2229         unset = TRUE;
2230         overwrite = TRUE;
2231         change = "unrunnable";
2232     } else if (pcmk_is_set(flags, pe_action_dangle)) {
2233         change = "dangling";
2234     } else if (pcmk_is_set(flags, pe_action_requires_any)) {
2235         change = "required";
2236     } else {
2237         crm_err("Unknown flag change to %x by %s: 0x%s",
2238                 flags, action->uuid, (reason? reason->uuid : "0"));
2239     }
2240 
2241     if(unset) {
2242         if (pcmk_is_set(action->flags, flags)) {
2243             pe__clear_action_flags_as(function, line, action, flags);
2244             update = TRUE;
2245         }
2246 
2247     } else {
2248         if (!pcmk_is_set(action->flags, flags)) {
2249             pe__set_action_flags_as(function, line, action, flags);
2250             update = TRUE;
2251         }
2252     }
2253 
2254     if((change && update) || text) {
2255         char *reason_text = NULL;
2256         if(reason == NULL) {
2257             pe_action_set_reason(action, text, overwrite);
2258 
2259         } else if(reason->rsc == NULL) {
2260             reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2261         } else {
2262             reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2263         }
2264 
2265         if(reason_text && action->rsc != reason->rsc) {
2266             pe_action_set_reason(action, reason_text, overwrite);
2267         }
2268         free(reason_text);
2269     }
2270  }
2271 
2272 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite) 
     /* [previous][next][first][last][top][bottom][index][help] */
2273 {
2274     if (action->reason != NULL && overwrite) {
2275         pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'",
2276                      action->uuid, action->reason, crm_str(reason));
2277         free(action->reason);
2278     } else if (action->reason == NULL) {
2279         pe_rsc_trace(action->rsc, "Set %s reason to '%s'",
2280                      action->uuid, crm_str(reason));
2281     } else {
2282         // crm_assert(action->reason != NULL && !overwrite);
2283         return;
2284     }
2285 
2286     if (reason != NULL) {
2287         action->reason = strdup(reason);
2288     } else {
2289         action->reason = NULL;
2290     }
2291 }
2292 
2293 /*!
2294  * \internal
2295  * \brief Check whether shutdown has been requested for a node
2296  *
2297  * \param[in] node  Node to check
2298  *
2299  * \return TRUE if node has shutdown attribute set and nonzero, FALSE otherwise
2300  * \note This differs from simply using node->details->shutdown in that it can
2301  *       be used before that has been determined (and in fact to determine it),
2302  *       and it can also be used to distinguish requested shutdown from implicit
2303  *       shutdown of remote nodes by virtue of their connection stopping.
2304  */
2305 bool
2306 pe__shutdown_requested(pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
2307 {
2308     const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
2309 
2310     return !pcmk__str_eq(shutdown, "0", pcmk__str_null_matches);
2311 }
2312 
2313 /*!
2314  * \internal
2315  * \brief Update a data set's "recheck by" time
2316  *
2317  * \param[in]     recheck   Epoch time when recheck should happen
2318  * \param[in,out] data_set  Current working set
2319  */
2320 void
2321 pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
2322 {
2323     if ((recheck > get_effective_time(data_set))
2324         && ((data_set->recheck_by == 0)
2325             || (data_set->recheck_by > recheck))) {
2326         data_set->recheck_by = recheck;
2327     }
2328 }
2329 
2330 /*!
2331  * \internal
2332  * \brief Wrapper for pe_unpack_nvpairs() using a cluster working set
2333  */
2334 void
2335 pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name,
     /* [previous][next][first][last][top][bottom][index][help] */
2336                            pe_rule_eval_data_t *rule_data, GHashTable *hash,
2337                            const char *always_first, gboolean overwrite,
2338                            pe_working_set_t *data_set)
2339 {
2340     crm_time_t *next_change = crm_time_new_undefined();
2341 
2342     pe_eval_nvpairs(data_set->input, xml_obj, set_name, rule_data, hash,
2343                     always_first, overwrite, next_change);
2344     if (crm_time_is_defined(next_change)) {
2345         time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
2346 
2347         pe__update_recheck_time(recheck, data_set);
2348     }
2349     crm_time_free(next_change);
2350 }
2351 
2352 bool
2353 pe__resource_is_disabled(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
2354 {
2355     const char *target_role = NULL;
2356 
2357     CRM_CHECK(rsc != NULL, return false);
2358     target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
2359     if (target_role) {
2360         enum rsc_role_e target_role_e = text2role(target_role);
2361 
2362         if ((target_role_e == RSC_ROLE_STOPPED)
2363             || ((target_role_e == RSC_ROLE_UNPROMOTED)
2364                 && pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable))) {
2365             return true;
2366         }
2367     }
2368     return false;
2369 }
2370 
2371 /*!
2372  * \internal
2373  * \brief Create an action to clear a resource's history from CIB
2374  *
2375  * \param[in] rsc   Resource to clear
2376  * \param[in] node  Node to clear history on
2377  *
2378  * \return New action to clear resource history
2379  */
2380 pe_action_t *
2381 pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
2382                            pe_working_set_t *data_set)
2383 {
2384     char *key = NULL;
2385 
2386     CRM_ASSERT(rsc && node);
2387     key = pcmk__op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
2388     return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
2389                          data_set);
2390 }
2391 
2392 bool
2393 pe__rsc_running_on_any_node_in_list(pe_resource_t *rsc, GList *node_list)
     /* [previous][next][first][last][top][bottom][index][help] */
2394 {
2395     for (GList *ele = rsc->running_on; ele; ele = ele->next) {
2396         pe_node_t *node = (pe_node_t *) ele->data;
2397         if (pcmk__str_in_list(node_list, node->details->uname)) {
2398             return true;
2399         }
2400     }
2401 
2402     return false;
2403 }
2404 
2405 bool
2406 pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
     /* [previous][next][first][last][top][bottom][index][help] */
2407 {
2408     return (rsc->fns->active(rsc, FALSE) && !pe__rsc_running_on_any_node_in_list(rsc, only_node));
2409 }
2410 
2411 GList *
2412 pe__filter_rsc_list(GList *rscs, GList *filter)
     /* [previous][next][first][last][top][bottom][index][help] */
2413 {
2414     GList *retval = NULL;
2415 
2416     for (GList *gIter = rscs; gIter; gIter = gIter->next) {
2417         pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2418 
2419         /* I think the second condition is safe here for all callers of this
2420          * function.  If not, it needs to move into pe__node_text.
2421          */
2422         if (pcmk__str_in_list(filter, rsc_printable_id(rsc)) ||
2423             (rsc->parent && pcmk__str_in_list(filter, rsc_printable_id(rsc->parent)))) {
2424             retval = g_list_prepend(retval, rsc);
2425         }
2426     }
2427 
2428     return retval;
2429 }
2430 
2431 GList *
2432 pe__build_node_name_list(pe_working_set_t *data_set, const char *s) {
     /* [previous][next][first][last][top][bottom][index][help] */
2433     GList *nodes = NULL;
2434 
2435     if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
2436         /* Nothing was given so return a list of all node names.  Or, '*' was
2437          * given.  This would normally fall into the pe__unames_with_tag branch
2438          * where it will return an empty list.  Catch it here instead.
2439          */
2440         nodes = g_list_prepend(nodes, strdup("*"));
2441     } else {
2442         pe_node_t *node = pe_find_node(data_set->nodes, s);
2443 
2444         if (node) {
2445             /* The given string was a valid uname for a node.  Return a
2446              * singleton list containing just that uname.
2447              */
2448             nodes = g_list_prepend(nodes, strdup(s));
2449         } else {
2450             /* The given string was not a valid uname.  It's either a tag or
2451              * it's a typo or something.  In the first case, we'll return a
2452              * list of all the unames of the nodes with the given tag.  In the
2453              * second case, we'll return a NULL pointer and nothing will
2454              * get displayed.
2455              */
2456             nodes = pe__unames_with_tag(data_set, s);
2457         }
2458     }
2459 
2460     return nodes;
2461 }
2462 
2463 GList *
2464 pe__build_rsc_list(pe_working_set_t *data_set, const char *s) {
     /* [previous][next][first][last][top][bottom][index][help] */
2465     GList *resources = NULL;
2466 
2467     if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
2468         resources = g_list_prepend(resources, strdup("*"));
2469     } else {
2470         pe_resource_t *rsc = pe_find_resource_with_flags(data_set->resources, s,
2471                                                          pe_find_renamed|pe_find_any);
2472 
2473         if (rsc) {
2474             /* A colon in the name we were given means we're being asked to filter
2475              * on a specific instance of a cloned resource.  Put that exact string
2476              * into the filter list.  Otherwise, use the printable ID of whatever
2477              * resource was found that matches what was asked for.
2478              */
2479             if (strstr(s, ":") != NULL) {
2480                 resources = g_list_prepend(resources, strdup(rsc->id));
2481             } else {
2482                 resources = g_list_prepend(resources, strdup(rsc_printable_id(rsc)));
2483             }
2484         } else {
2485             /* The given string was not a valid resource name.  It's either
2486              * a tag or it's a typo or something.  See build_uname_list for
2487              * more detail.
2488              */
2489             resources = pe__rscs_with_tag(data_set, s);
2490         }
2491     }
2492 
2493     return resources;
2494 }

/* [previous][next][first][last][top][bottom][index][help] */