LCOV - code coverage report
Current view: top level - pacemaker - pcmk_sched_tickets.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 238 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2004-2024 the Pacemaker project contributors
       3             :  *
       4             :  * The version control history for this file may have further details.
       5             :  *
       6             :  * This source code is licensed under the GNU General Public License version 2
       7             :  * or later (GPLv2+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : 
      12             : #include <stdbool.h>
      13             : #include <glib.h>
      14             : 
      15             : #include <crm/crm.h>
      16             : #include <crm/common/scheduler_internal.h>
      17             : #include <crm/pengine/status.h>
      18             : #include <pacemaker-internal.h>
      19             : 
      20             : #include "libpacemaker_private.h"
      21             : 
      22             : enum loss_ticket_policy {
      23             :     loss_ticket_stop,
      24             :     loss_ticket_demote,
      25             :     loss_ticket_fence,
      26             :     loss_ticket_freeze
      27             : };
      28             : 
      29             : typedef struct {
      30             :     const char *id;
      31             :     pcmk_resource_t *rsc;
      32             :     pcmk_ticket_t *ticket;
      33             :     enum loss_ticket_policy loss_policy;
      34             :     int role;
      35             : } rsc_ticket_t;
      36             : 
      37             : /*!
      38             :  * \brief Check whether a ticket constraint matches a resource by role
      39             :  *
      40             :  * \param[in] rsc_ticket  Ticket constraint
      41             :  * \param[in] rsc         Resource to compare with ticket
      42             :  *
      43             :  * \param[in] true if constraint has no role or resource's role matches
      44             :  *            constraint's, otherwise false
      45             :  */
      46             : static bool
      47           0 : ticket_role_matches(const pcmk_resource_t *rsc, const rsc_ticket_t *rsc_ticket)
      48             : {
      49           0 :     if ((rsc_ticket->role == pcmk_role_unknown)
      50           0 :         || (rsc_ticket->role == rsc->role)) {
      51           0 :         return true;
      52             :     }
      53           0 :     pcmk__rsc_trace(rsc, "Skipping constraint: \"%s\" state filter",
      54             :                     pcmk_role_text(rsc_ticket->role));
      55           0 :     return false;
      56             : }
      57             : 
      58             : /*!
      59             :  * \brief Create location constraints and fencing as needed for a ticket
      60             :  *
      61             :  * \param[in,out] rsc         Resource affected by ticket
      62             :  * \param[in]     rsc_ticket  Ticket
      63             :  */
      64             : static void
      65           0 : constraints_for_ticket(pcmk_resource_t *rsc, const rsc_ticket_t *rsc_ticket)
      66             : {
      67           0 :     GList *iter = NULL;
      68             : 
      69           0 :     CRM_CHECK((rsc != NULL) && (rsc_ticket != NULL), return);
      70             : 
      71           0 :     if (rsc_ticket->ticket->granted && !rsc_ticket->ticket->standby) {
      72           0 :         return;
      73             :     }
      74             : 
      75           0 :     if (rsc->children) {
      76           0 :         pcmk__rsc_trace(rsc, "Processing ticket dependencies from %s", rsc->id);
      77           0 :         for (iter = rsc->children; iter != NULL; iter = iter->next) {
      78           0 :             constraints_for_ticket((pcmk_resource_t *) iter->data, rsc_ticket);
      79             :         }
      80           0 :         return;
      81             :     }
      82             : 
      83           0 :     pcmk__rsc_trace(rsc, "%s: Processing ticket dependency on %s (%s, %s)",
      84             :                     rsc->id, rsc_ticket->ticket->id, rsc_ticket->id,
      85             :                     pcmk_role_text(rsc_ticket->role));
      86             : 
      87           0 :     if (!rsc_ticket->ticket->granted && (rsc->running_on != NULL)) {
      88             : 
      89           0 :         switch (rsc_ticket->loss_policy) {
      90           0 :             case loss_ticket_stop:
      91           0 :                 resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
      92             :                                   "__loss_of_ticket__", rsc->cluster);
      93           0 :                 break;
      94             : 
      95           0 :             case loss_ticket_demote:
      96             :                 // Promotion score will be set to -INFINITY in promotion_order()
      97           0 :                 if (rsc_ticket->role != pcmk_role_promoted) {
      98           0 :                     resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
      99             :                                       "__loss_of_ticket__", rsc->cluster);
     100             :                 }
     101           0 :                 break;
     102             : 
     103           0 :             case loss_ticket_fence:
     104           0 :                 if (!ticket_role_matches(rsc, rsc_ticket)) {
     105           0 :                     return;
     106             :                 }
     107             : 
     108           0 :                 resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
     109             :                                   "__loss_of_ticket__", rsc->cluster);
     110             : 
     111           0 :                 for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
     112           0 :                     pe_fence_node(rsc->cluster, (pcmk_node_t *) iter->data,
     113             :                                   "deadman ticket was lost", FALSE);
     114             :                 }
     115           0 :                 break;
     116             : 
     117           0 :             case loss_ticket_freeze:
     118           0 :                 if (!ticket_role_matches(rsc, rsc_ticket)) {
     119           0 :                     return;
     120             :                 }
     121           0 :                 if (rsc->running_on != NULL) {
     122           0 :                     pcmk__clear_rsc_flags(rsc, pcmk_rsc_managed);
     123           0 :                     pcmk__set_rsc_flags(rsc, pcmk_rsc_blocked);
     124             :                 }
     125           0 :                 break;
     126             :         }
     127             : 
     128           0 :     } else if (!rsc_ticket->ticket->granted) {
     129             : 
     130           0 :         if ((rsc_ticket->role != pcmk_role_promoted)
     131           0 :             || (rsc_ticket->loss_policy == loss_ticket_stop)) {
     132           0 :             resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
     133             :                               "__no_ticket__", rsc->cluster);
     134             :         }
     135             : 
     136           0 :     } else if (rsc_ticket->ticket->standby) {
     137             : 
     138           0 :         if ((rsc_ticket->role != pcmk_role_promoted)
     139           0 :             || (rsc_ticket->loss_policy == loss_ticket_stop)) {
     140           0 :             resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
     141             :                               "__ticket_standby__", rsc->cluster);
     142             :         }
     143             :     }
     144             : }
     145             : 
     146             : static void
     147           0 : rsc_ticket_new(const char *id, pcmk_resource_t *rsc, pcmk_ticket_t *ticket,
     148             :                const char *state, const char *loss_policy)
     149             : {
     150           0 :     rsc_ticket_t *new_rsc_ticket = NULL;
     151             : 
     152           0 :     if (rsc == NULL) {
     153           0 :         pcmk__config_err("Ignoring ticket '%s' because resource "
     154             :                          "does not exist", id);
     155           0 :         return;
     156             :     }
     157             : 
     158           0 :     new_rsc_ticket = calloc(1, sizeof(rsc_ticket_t));
     159           0 :     if (new_rsc_ticket == NULL) {
     160           0 :         return;
     161             :     }
     162             : 
     163           0 :     if (pcmk__str_eq(state, PCMK_ROLE_STARTED,
     164             :                      pcmk__str_null_matches|pcmk__str_casei)) {
     165           0 :         state = PCMK__ROLE_UNKNOWN;
     166             :     }
     167             : 
     168           0 :     new_rsc_ticket->id = id;
     169           0 :     new_rsc_ticket->ticket = ticket;
     170           0 :     new_rsc_ticket->rsc = rsc;
     171           0 :     new_rsc_ticket->role = pcmk_parse_role(state);
     172             : 
     173           0 :     if (pcmk__str_eq(loss_policy, PCMK_VALUE_FENCE, pcmk__str_casei)) {
     174           0 :         if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_fencing_enabled)) {
     175           0 :             new_rsc_ticket->loss_policy = loss_ticket_fence;
     176             :         } else {
     177           0 :             pcmk__config_err("Resetting '" PCMK_XA_LOSS_POLICY "' "
     178             :                              "for ticket '%s' to '" PCMK_VALUE_STOP "' "
     179             :                              "because fencing is not configured", ticket->id);
     180           0 :             loss_policy = PCMK_VALUE_STOP;
     181             :         }
     182             :     }
     183             : 
     184           0 :     if (new_rsc_ticket->loss_policy == loss_ticket_fence) {
     185           0 :         crm_debug("On loss of ticket '%s': Fence the nodes running %s (%s)",
     186             :                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     187             :                   pcmk_role_text(new_rsc_ticket->role));
     188             : 
     189           0 :     } else if (pcmk__str_eq(loss_policy, PCMK_VALUE_FREEZE, pcmk__str_casei)) {
     190           0 :         crm_debug("On loss of ticket '%s': Freeze %s (%s)",
     191             :                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     192             :                   pcmk_role_text(new_rsc_ticket->role));
     193           0 :         new_rsc_ticket->loss_policy = loss_ticket_freeze;
     194             : 
     195           0 :     } else if (pcmk__str_eq(loss_policy, PCMK_VALUE_DEMOTE, pcmk__str_casei)) {
     196           0 :         crm_debug("On loss of ticket '%s': Demote %s (%s)",
     197             :                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     198             :                   pcmk_role_text(new_rsc_ticket->role));
     199           0 :         new_rsc_ticket->loss_policy = loss_ticket_demote;
     200             : 
     201           0 :     } else if (pcmk__str_eq(loss_policy, PCMK_VALUE_STOP, pcmk__str_casei)) {
     202           0 :         crm_debug("On loss of ticket '%s': Stop %s (%s)",
     203             :                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     204             :                   pcmk_role_text(new_rsc_ticket->role));
     205           0 :         new_rsc_ticket->loss_policy = loss_ticket_stop;
     206             : 
     207             :     } else {
     208           0 :         if (new_rsc_ticket->role == pcmk_role_promoted) {
     209           0 :             crm_debug("On loss of ticket '%s': Default to demote %s (%s)",
     210             :                       new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     211             :                       pcmk_role_text(new_rsc_ticket->role));
     212           0 :             new_rsc_ticket->loss_policy = loss_ticket_demote;
     213             : 
     214             :         } else {
     215           0 :             crm_debug("On loss of ticket '%s': Default to stop %s (%s)",
     216             :                       new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
     217             :                       pcmk_role_text(new_rsc_ticket->role));
     218           0 :             new_rsc_ticket->loss_policy = loss_ticket_stop;
     219             :         }
     220             :     }
     221             : 
     222           0 :     pcmk__rsc_trace(rsc, "%s (%s) ==> %s",
     223             :                     rsc->id, pcmk_role_text(new_rsc_ticket->role), ticket->id);
     224             : 
     225           0 :     rsc->rsc_tickets = g_list_append(rsc->rsc_tickets, new_rsc_ticket);
     226             : 
     227           0 :     rsc->cluster->ticket_constraints = g_list_append(
     228           0 :         rsc->cluster->ticket_constraints, new_rsc_ticket);
     229             : 
     230           0 :     if (!(new_rsc_ticket->ticket->granted) || new_rsc_ticket->ticket->standby) {
     231           0 :         constraints_for_ticket(rsc, new_rsc_ticket);
     232             :     }
     233             : }
     234             : 
     235             : // \return Standard Pacemaker return code
     236             : static int
     237           0 : unpack_rsc_ticket_set(xmlNode *set, pcmk_ticket_t *ticket,
     238             :                       const char *loss_policy, pcmk_scheduler_t *scheduler)
     239             : {
     240           0 :     const char *set_id = NULL;
     241           0 :     const char *role = NULL;
     242             : 
     243           0 :     CRM_CHECK(set != NULL, return EINVAL);
     244           0 :     CRM_CHECK(ticket != NULL, return EINVAL);
     245             : 
     246           0 :     set_id = pcmk__xe_id(set);
     247           0 :     if (set_id == NULL) {
     248           0 :         pcmk__config_err("Ignoring <" PCMK_XE_RESOURCE_SET "> without "
     249             :                          PCMK_XA_ID);
     250           0 :         return pcmk_rc_unpack_error;
     251             :     }
     252             : 
     253           0 :     role = crm_element_value(set, PCMK_XA_ROLE);
     254             : 
     255           0 :     for (xmlNode *xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF,
     256             :                                                  NULL, NULL);
     257           0 :          xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
     258             : 
     259           0 :         pcmk_resource_t *resource = NULL;
     260             : 
     261           0 :         resource = pcmk__find_constraint_resource(scheduler->resources,
     262             :                                                   pcmk__xe_id(xml_rsc));
     263           0 :         if (resource == NULL) {
     264           0 :             pcmk__config_err("%s: No resource found for %s",
     265             :                              set_id, pcmk__xe_id(xml_rsc));
     266           0 :             return pcmk_rc_unpack_error;
     267             :         }
     268           0 :         pcmk__rsc_trace(resource, "Resource '%s' depends on ticket '%s'",
     269             :                         resource->id, ticket->id);
     270           0 :         rsc_ticket_new(set_id, resource, ticket, role, loss_policy);
     271             :     }
     272             : 
     273           0 :     return pcmk_rc_ok;
     274             : }
     275             : 
     276             : static void
     277           0 : unpack_simple_rsc_ticket(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
     278             : {
     279           0 :     const char *id = NULL;
     280           0 :     const char *ticket_str = crm_element_value(xml_obj, PCMK_XA_TICKET);
     281           0 :     const char *loss_policy = crm_element_value(xml_obj, PCMK_XA_LOSS_POLICY);
     282             : 
     283           0 :     pcmk_ticket_t *ticket = NULL;
     284             : 
     285           0 :     const char *rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
     286           0 :     const char *state = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
     287             : 
     288             :     // @COMPAT: Deprecated since 2.1.5
     289           0 :     const char *instance = crm_element_value(xml_obj, PCMK__XA_RSC_INSTANCE);
     290             : 
     291           0 :     pcmk_resource_t *rsc = NULL;
     292             : 
     293           0 :     if (instance != NULL) {
     294           0 :         pcmk__warn_once(pcmk__wo_coloc_inst,
     295             :                         "Support for " PCMK__XA_RSC_INSTANCE " is deprecated "
     296             :                         "and will be removed in a future release");
     297             :     }
     298             : 
     299           0 :     CRM_CHECK(xml_obj != NULL, return);
     300             : 
     301           0 :     id = pcmk__xe_id(xml_obj);
     302           0 :     if (id == NULL) {
     303           0 :         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
     304             :                          xml_obj->name);
     305           0 :         return;
     306             :     }
     307             : 
     308           0 :     if (ticket_str == NULL) {
     309           0 :         pcmk__config_err("Ignoring constraint '%s' without ticket specified",
     310             :                          id);
     311           0 :         return;
     312             :     } else {
     313           0 :         ticket = g_hash_table_lookup(scheduler->tickets, ticket_str);
     314             :     }
     315             : 
     316           0 :     if (ticket == NULL) {
     317           0 :         pcmk__config_err("Ignoring constraint '%s' because ticket '%s' "
     318             :                          "does not exist", id, ticket_str);
     319           0 :         return;
     320             :     }
     321             : 
     322           0 :     if (rsc_id == NULL) {
     323           0 :         pcmk__config_err("Ignoring constraint '%s' without resource", id);
     324           0 :         return;
     325             :     } else {
     326           0 :         rsc = pcmk__find_constraint_resource(scheduler->resources, rsc_id);
     327             :     }
     328             : 
     329           0 :     if (rsc == NULL) {
     330           0 :         pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
     331             :                          "does not exist", id, rsc_id);
     332           0 :         return;
     333             : 
     334           0 :     } else if ((instance != NULL) && !pcmk__is_clone(rsc)) {
     335           0 :         pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
     336             :                          "is not a clone but instance '%s' was requested",
     337             :                          id, rsc_id, instance);
     338           0 :         return;
     339             :     }
     340             : 
     341           0 :     if (instance != NULL) {
     342           0 :         rsc = find_clone_instance(rsc, instance);
     343           0 :         if (rsc == NULL) {
     344           0 :             pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
     345             :                               "does not have an instance '%s'",
     346             :                               "'%s'", id, rsc_id, instance);
     347           0 :             return;
     348             :         }
     349             :     }
     350             : 
     351           0 :     rsc_ticket_new(id, rsc, ticket, state, loss_policy);
     352             : }
     353             : 
     354             : // \return Standard Pacemaker return code
     355             : static int
     356           0 : unpack_rsc_ticket_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
     357             :                        pcmk_scheduler_t *scheduler)
     358             : {
     359           0 :     const char *id = NULL;
     360           0 :     const char *rsc_id = NULL;
     361           0 :     const char *state = NULL;
     362             : 
     363           0 :     pcmk_resource_t *rsc = NULL;
     364           0 :     pcmk_tag_t *tag = NULL;
     365             : 
     366           0 :     xmlNode *rsc_set = NULL;
     367             : 
     368           0 :     *expanded_xml = NULL;
     369             : 
     370           0 :     CRM_CHECK(xml_obj != NULL, return EINVAL);
     371             : 
     372           0 :     id = pcmk__xe_id(xml_obj);
     373           0 :     if (id == NULL) {
     374           0 :         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
     375             :                          xml_obj->name);
     376           0 :         return pcmk_rc_unpack_error;
     377             :     }
     378             : 
     379             :     // Check whether there are any resource sets with template or tag references
     380           0 :     *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
     381           0 :     if (*expanded_xml != NULL) {
     382           0 :         crm_log_xml_trace(*expanded_xml, "Expanded rsc_ticket");
     383           0 :         return pcmk_rc_ok;
     384             :     }
     385             : 
     386           0 :     rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
     387           0 :     if (rsc_id == NULL) {
     388           0 :         return pcmk_rc_ok;
     389             :     }
     390             : 
     391           0 :     if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
     392           0 :         pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
     393             :                          "valid resource or tag", id, rsc_id);
     394           0 :         return pcmk_rc_unpack_error;
     395             : 
     396           0 :     } else if (rsc != NULL) {
     397             :         // No template or tag is referenced
     398           0 :         return pcmk_rc_ok;
     399             :     }
     400             : 
     401           0 :     state = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
     402             : 
     403           0 :     *expanded_xml = pcmk__xml_copy(NULL, xml_obj);
     404             : 
     405             :     /* Convert any template or tag reference in "rsc" into ticket
     406             :      * PCMK_XE_RESOURCE_SET
     407             :      */
     408           0 :     if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC, false,
     409             :                           scheduler)) {
     410           0 :         free_xml(*expanded_xml);
     411           0 :         *expanded_xml = NULL;
     412           0 :         return pcmk_rc_unpack_error;
     413             :     }
     414             : 
     415           0 :     if (rsc_set != NULL) {
     416           0 :         if (state != NULL) {
     417             :             /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as a
     418             :              * PCMK_XA_ROLE attribute
     419             :              */
     420           0 :             crm_xml_add(rsc_set, PCMK_XA_ROLE, state);
     421           0 :             pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_RSC_ROLE);
     422             :         }
     423             : 
     424             :     } else {
     425           0 :         free_xml(*expanded_xml);
     426           0 :         *expanded_xml = NULL;
     427             :     }
     428             : 
     429           0 :     return pcmk_rc_ok;
     430             : }
     431             : 
     432             : void
     433           0 : pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
     434             : {
     435           0 :     xmlNode *set = NULL;
     436           0 :     bool any_sets = false;
     437             : 
     438           0 :     const char *id = NULL;
     439           0 :     const char *ticket_str = NULL;
     440             : 
     441           0 :     pcmk_ticket_t *ticket = NULL;
     442             : 
     443           0 :     xmlNode *orig_xml = NULL;
     444           0 :     xmlNode *expanded_xml = NULL;
     445             : 
     446           0 :     CRM_CHECK(xml_obj != NULL, return);
     447             : 
     448           0 :     id = pcmk__xe_id(xml_obj);
     449           0 :     if (id == NULL) {
     450           0 :         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
     451             :                          xml_obj->name);
     452           0 :         return;
     453             :     }
     454             : 
     455           0 :     if (scheduler->tickets == NULL) {
     456           0 :         scheduler->tickets = pcmk__strkey_table(free, destroy_ticket);
     457             :     }
     458             : 
     459           0 :     ticket_str = crm_element_value(xml_obj, PCMK_XA_TICKET);
     460           0 :     if (ticket_str == NULL) {
     461           0 :         pcmk__config_err("Ignoring constraint '%s' without ticket", id);
     462           0 :         return;
     463             :     } else {
     464           0 :         ticket = g_hash_table_lookup(scheduler->tickets, ticket_str);
     465             :     }
     466             : 
     467           0 :     if (ticket == NULL) {
     468           0 :         ticket = ticket_new(ticket_str, scheduler);
     469           0 :         if (ticket == NULL) {
     470           0 :             return;
     471             :         }
     472             :     }
     473             : 
     474           0 :     if (unpack_rsc_ticket_tags(xml_obj, &expanded_xml,
     475             :                                scheduler) != pcmk_rc_ok) {
     476           0 :         return;
     477             :     }
     478           0 :     if (expanded_xml != NULL) {
     479           0 :         orig_xml = xml_obj;
     480           0 :         xml_obj = expanded_xml;
     481             :     }
     482             : 
     483           0 :     for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL);
     484           0 :          set != NULL; set = pcmk__xe_next_same(set)) {
     485             : 
     486           0 :         const char *loss_policy = NULL;
     487             : 
     488           0 :         any_sets = true;
     489           0 :         set = expand_idref(set, scheduler->input);
     490           0 :         loss_policy = crm_element_value(xml_obj, PCMK_XA_LOSS_POLICY);
     491             : 
     492           0 :         if ((set == NULL) // Configuration error, message already logged
     493           0 :             || (unpack_rsc_ticket_set(set, ticket, loss_policy,
     494             :                                       scheduler) != pcmk_rc_ok)) {
     495           0 :             if (expanded_xml != NULL) {
     496           0 :                 free_xml(expanded_xml);
     497             :             }
     498           0 :             return;
     499             :         }
     500             :     }
     501             : 
     502           0 :     if (expanded_xml) {
     503           0 :         free_xml(expanded_xml);
     504           0 :         xml_obj = orig_xml;
     505             :     }
     506             : 
     507           0 :     if (!any_sets) {
     508           0 :         unpack_simple_rsc_ticket(xml_obj, scheduler);
     509             :     }
     510             : }
     511             : 
     512             : /*!
     513             :  * \internal
     514             :  * \brief Ban resource from a node if it doesn't have a promotion ticket
     515             :  *
     516             :  * If a resource has tickets for the promoted role, and the ticket is either not
     517             :  * granted or set to standby, then ban the resource from all nodes.
     518             :  *
     519             :  * \param[in,out] rsc  Resource to check
     520             :  */
     521             : void
     522           0 : pcmk__require_promotion_tickets(pcmk_resource_t *rsc)
     523             : {
     524           0 :     for (GList *item = rsc->rsc_tickets; item != NULL; item = item->next) {
     525           0 :         rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) item->data;
     526             : 
     527           0 :         if ((rsc_ticket->role == pcmk_role_promoted)
     528           0 :             && (!rsc_ticket->ticket->granted || rsc_ticket->ticket->standby)) {
     529           0 :             resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
     530             :                               "__stateful_without_ticket__", rsc->cluster);
     531             :         }
     532             :     }
     533           0 : }

Generated by: LCOV version 1.14