LCOV - code coverage report
Current view: top level - pengine - complex.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 523 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 23 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 Lesser General Public License
       7             :  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : 
      12             : #include <crm/pengine/rules.h>
      13             : #include <crm/pengine/internal.h>
      14             : #include <crm/common/xml.h>
      15             : #include <crm/common/xml_internal.h>
      16             : #include <crm/common/scheduler_internal.h>
      17             : 
      18             : #include "pe_status_private.h"
      19             : 
      20             : void populate_hash(xmlNode * nvpair_list, GHashTable * hash, const char **attrs, int attrs_length);
      21             : 
      22             : static pcmk_node_t *active_node(const pcmk_resource_t *rsc,
      23             :                                 unsigned int *count_all,
      24             :                                 unsigned int *count_clean);
      25             : 
      26             : pcmk_rsc_methods_t resource_class_functions[] = {
      27             :     {
      28             :          native_unpack,
      29             :          native_find_rsc,
      30             :          native_parameter,
      31             :          native_print,
      32             :          native_active,
      33             :          native_resource_state,
      34             :          native_location,
      35             :          native_free,
      36             :          pe__count_common,
      37             :          pe__native_is_filtered,
      38             :          active_node,
      39             :          pe__primitive_max_per_node,
      40             :     },
      41             :     {
      42             :          group_unpack,
      43             :          native_find_rsc,
      44             :          native_parameter,
      45             :          group_print,
      46             :          group_active,
      47             :          group_resource_state,
      48             :          native_location,
      49             :          group_free,
      50             :          pe__count_common,
      51             :          pe__group_is_filtered,
      52             :          active_node,
      53             :          pe__group_max_per_node,
      54             :     },
      55             :     {
      56             :          clone_unpack,
      57             :          native_find_rsc,
      58             :          native_parameter,
      59             :          clone_print,
      60             :          clone_active,
      61             :          clone_resource_state,
      62             :          native_location,
      63             :          clone_free,
      64             :          pe__count_common,
      65             :          pe__clone_is_filtered,
      66             :          active_node,
      67             :          pe__clone_max_per_node,
      68             :     },
      69             :     {
      70             :          pe__unpack_bundle,
      71             :          native_find_rsc,
      72             :          native_parameter,
      73             :          pe__print_bundle,
      74             :          pe__bundle_active,
      75             :          pe__bundle_resource_state,
      76             :          native_location,
      77             :          pe__free_bundle,
      78             :          pe__count_bundle,
      79             :          pe__bundle_is_filtered,
      80             :          pe__bundle_active_node,
      81             :          pe__bundle_max_per_node,
      82             :     }
      83             : };
      84             : 
      85             : static enum pe_obj_types
      86           0 : get_resource_type(const char *name)
      87             : {
      88           0 :     if (pcmk__str_eq(name, PCMK_XE_PRIMITIVE, pcmk__str_casei)) {
      89           0 :         return pcmk_rsc_variant_primitive;
      90             : 
      91           0 :     } else if (pcmk__str_eq(name, PCMK_XE_GROUP, pcmk__str_casei)) {
      92           0 :         return pcmk_rsc_variant_group;
      93             : 
      94           0 :     } else if (pcmk__str_eq(name, PCMK_XE_CLONE, pcmk__str_casei)) {
      95           0 :         return pcmk_rsc_variant_clone;
      96             : 
      97           0 :     } else if (pcmk__str_eq(name, PCMK__XE_PROMOTABLE_LEGACY,
      98             :                             pcmk__str_casei)) {
      99             :         // @COMPAT deprecated since 2.0.0
     100           0 :         return pcmk_rsc_variant_clone;
     101             : 
     102           0 :     } else if (pcmk__str_eq(name, PCMK_XE_BUNDLE, pcmk__str_casei)) {
     103           0 :         return pcmk_rsc_variant_bundle;
     104             :     }
     105             : 
     106           0 :     return pcmk_rsc_variant_unknown;
     107             : }
     108             : 
     109             : /*!
     110             :  * \internal
     111             :  * \brief Insert a meta-attribute if not already present
     112             :  *
     113             :  * \param[in]     key    Meta-attribute name
     114             :  * \param[in]     value  Meta-attribute value to add if not already present
     115             :  * \param[in,out] table  Meta-attribute hash table to insert into
     116             :  *
     117             :  * \note This is like pcmk__insert_meta() except it won't overwrite existing
     118             :  *       values.
     119             :  */
     120             : static void
     121           0 : dup_attr(gpointer key, gpointer value, gpointer user_data)
     122             : {
     123           0 :     GHashTable *table = user_data;
     124             : 
     125           0 :     CRM_CHECK((key != NULL) && (table != NULL), return);
     126           0 :     if (pcmk__str_eq((const char *) value, "#default", pcmk__str_casei)) {
     127             :         // @COMPAT Deprecated since 2.1.8
     128           0 :         pcmk__config_warn("Support for setting meta-attributes (such as %s) to "
     129             :                           "the explicit value '#default' is deprecated and "
     130             :                           "will be removed in a future release",
     131             :                           (const char *) key);
     132           0 :     } else if ((value != NULL) && (g_hash_table_lookup(table, key) == NULL)) {
     133           0 :         pcmk__insert_dup(table, (const char *) key, (const char *) value);
     134             :     }
     135             : }
     136             : 
     137             : static void
     138           0 : expand_parents_fixed_nvpairs(pcmk_resource_t *rsc,
     139             :                              pe_rule_eval_data_t *rule_data,
     140             :                              GHashTable *meta_hash, pcmk_scheduler_t *scheduler)
     141             : {
     142           0 :     GHashTable *parent_orig_meta = pcmk__strkey_table(free, free);
     143           0 :     pcmk_resource_t *p = rsc->parent;
     144             : 
     145           0 :     if (p == NULL) {
     146           0 :         return ;
     147             :     }
     148             : 
     149             :     /* Search all parent resources, get the fixed value of
     150             :      * PCMK_XE_META_ATTRIBUTES set only in the original xml, and stack it in the
     151             :      * hash table. The fixed value of the lower parent resource takes precedence
     152             :      * and is not overwritten.
     153             :      */
     154           0 :     while(p != NULL) {
     155             :         /* A hash table for comparison is generated, including the id-ref. */
     156           0 :         pe__unpack_dataset_nvpairs(p->xml, PCMK_XE_META_ATTRIBUTES, rule_data,
     157             :                                    parent_orig_meta, NULL, FALSE, scheduler);
     158           0 :         p = p->parent; 
     159             :     }
     160             : 
     161           0 :     if (parent_orig_meta != NULL) {
     162             :         // This will not overwrite any values already existing for child
     163           0 :         g_hash_table_foreach(parent_orig_meta, dup_attr, meta_hash);
     164             :     }
     165             : 
     166           0 :     if (parent_orig_meta != NULL) {
     167           0 :         g_hash_table_destroy(parent_orig_meta);
     168             :     }
     169             :     
     170           0 :     return ;
     171             : 
     172             : }
     173             : void
     174           0 : get_meta_attributes(GHashTable * meta_hash, pcmk_resource_t * rsc,
     175             :                     pcmk_node_t *node, pcmk_scheduler_t *scheduler)
     176             : {
     177           0 :     pe_rsc_eval_data_t rsc_rule_data = {
     178           0 :         .standard = crm_element_value(rsc->xml, PCMK_XA_CLASS),
     179           0 :         .provider = crm_element_value(rsc->xml, PCMK_XA_PROVIDER),
     180           0 :         .agent = crm_element_value(rsc->xml, PCMK_XA_TYPE)
     181             :     };
     182             : 
     183           0 :     pe_rule_eval_data_t rule_data = {
     184             :         .node_hash = NULL,
     185           0 :         .now = scheduler->now,
     186             :         .match_data = NULL,
     187             :         .rsc_data = &rsc_rule_data,
     188             :         .op_data = NULL
     189             :     };
     190             : 
     191           0 :     if (node) {
     192             :         /* @COMPAT Support for node attribute expressions in rules for
     193             :          * meta-attributes is deprecated. When we can break behavioral backward
     194             :          * compatibility, drop this block.
     195             :          */
     196           0 :         rule_data.node_hash = node->details->attrs;
     197             :     }
     198             : 
     199           0 :     for (xmlAttrPtr a = pcmk__xe_first_attr(rsc->xml); a != NULL; a = a->next) {
     200           0 :         if (a->children != NULL) {
     201           0 :             dup_attr((gpointer) a->name, (gpointer) a->children->content,
     202             :                      meta_hash);
     203             :         }
     204             :     }
     205             : 
     206           0 :     pe__unpack_dataset_nvpairs(rsc->xml, PCMK_XE_META_ATTRIBUTES, &rule_data,
     207             :                                meta_hash, NULL, FALSE, scheduler);
     208             : 
     209             :     /* Set the PCMK_XE_META_ATTRIBUTES explicitly set in the parent resource to
     210             :      * the hash table of the child resource. If it is already explicitly set as
     211             :      * a child, it will not be overwritten.
     212             :      */
     213           0 :     if (rsc->parent != NULL) {
     214           0 :         expand_parents_fixed_nvpairs(rsc, &rule_data, meta_hash, scheduler);
     215             :     }
     216             : 
     217             :     /* check the defaults */
     218           0 :     pe__unpack_dataset_nvpairs(scheduler->rsc_defaults, PCMK_XE_META_ATTRIBUTES,
     219             :                                &rule_data, meta_hash, NULL, FALSE, scheduler);
     220             : 
     221             :     /* If there is PCMK_XE_META_ATTRIBUTES that the parent resource has not
     222             :      * explicitly set, set a value that is not set from PCMK_XE_RSC_DEFAULTS
     223             :      * either. The values already set up to this point will not be overwritten.
     224             :      */
     225           0 :     if (rsc->parent) {
     226           0 :         g_hash_table_foreach(rsc->parent->meta, dup_attr, meta_hash);
     227             :     }
     228           0 : }
     229             : 
     230             : void
     231           0 : get_rsc_attributes(GHashTable *meta_hash, const pcmk_resource_t *rsc,
     232             :                    const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
     233             : {
     234           0 :     pe_rule_eval_data_t rule_data = {
     235             :         .node_hash = NULL,
     236           0 :         .now = scheduler->now,
     237             :         .match_data = NULL,
     238             :         .rsc_data = NULL,
     239             :         .op_data = NULL
     240             :     };
     241             : 
     242           0 :     if (node) {
     243           0 :         rule_data.node_hash = node->details->attrs;
     244             :     }
     245             : 
     246           0 :     pe__unpack_dataset_nvpairs(rsc->xml, PCMK_XE_INSTANCE_ATTRIBUTES,
     247             :                                &rule_data, meta_hash, NULL, FALSE, scheduler);
     248             : 
     249             :     /* set anything else based on the parent */
     250           0 :     if (rsc->parent != NULL) {
     251           0 :         get_rsc_attributes(meta_hash, rsc->parent, node, scheduler);
     252             : 
     253             :     } else {
     254           0 :         if (pcmk__xe_first_child(scheduler->rsc_defaults,
     255             :                                  PCMK_XE_INSTANCE_ATTRIBUTES, NULL,
     256             :                                  NULL) != NULL) {
     257             :             /* Not possible with schema validation enabled
     258             :              *
     259             :              * @COMPAT Drop support when we can break behavioral
     260             :              * backward compatibility
     261             :              */
     262           0 :             pcmk__warn_once(pcmk__wo_instance_defaults,
     263             :                             "Support for " PCMK_XE_INSTANCE_ATTRIBUTES " in "
     264             :                             PCMK_XE_RSC_DEFAULTS " is deprecated and will be "
     265             :                             "removed in a future release");
     266             :         }
     267             : 
     268             :         /* and finally check the defaults */
     269           0 :         pe__unpack_dataset_nvpairs(scheduler->rsc_defaults,
     270             :                                    PCMK_XE_INSTANCE_ATTRIBUTES, &rule_data,
     271             :                                    meta_hash, NULL, FALSE, scheduler);
     272             :     }
     273           0 : }
     274             : 
     275             : static char *
     276           0 : template_op_key(xmlNode * op)
     277             : {
     278           0 :     const char *name = crm_element_value(op, PCMK_XA_NAME);
     279           0 :     const char *role = crm_element_value(op, PCMK_XA_ROLE);
     280           0 :     char *key = NULL;
     281             : 
     282           0 :     if ((role == NULL)
     283           0 :         || pcmk__strcase_any_of(role, PCMK_ROLE_STARTED, PCMK_ROLE_UNPROMOTED,
     284             :                                 PCMK__ROLE_UNPROMOTED_LEGACY, NULL)) {
     285           0 :         role = PCMK__ROLE_UNKNOWN;
     286             :     }
     287             : 
     288           0 :     key = crm_strdup_printf("%s-%s", name, role);
     289           0 :     return key;
     290             : }
     291             : 
     292             : static gboolean
     293           0 : unpack_template(xmlNode *xml_obj, xmlNode **expanded_xml,
     294             :                 pcmk_scheduler_t *scheduler)
     295             : {
     296           0 :     xmlNode *cib_resources = NULL;
     297           0 :     xmlNode *template = NULL;
     298           0 :     xmlNode *new_xml = NULL;
     299           0 :     xmlNode *child_xml = NULL;
     300           0 :     xmlNode *rsc_ops = NULL;
     301           0 :     xmlNode *template_ops = NULL;
     302           0 :     const char *template_ref = NULL;
     303           0 :     const char *id = NULL;
     304             : 
     305           0 :     if (xml_obj == NULL) {
     306           0 :         pcmk__config_err("No resource object for template unpacking");
     307           0 :         return FALSE;
     308             :     }
     309             : 
     310           0 :     template_ref = crm_element_value(xml_obj, PCMK_XA_TEMPLATE);
     311           0 :     if (template_ref == NULL) {
     312           0 :         return TRUE;
     313             :     }
     314             : 
     315           0 :     id = pcmk__xe_id(xml_obj);
     316           0 :     if (id == NULL) {
     317           0 :         pcmk__config_err("'%s' object must have a id", xml_obj->name);
     318           0 :         return FALSE;
     319             :     }
     320             : 
     321           0 :     if (pcmk__str_eq(template_ref, id, pcmk__str_none)) {
     322           0 :         pcmk__config_err("The resource object '%s' should not reference itself",
     323             :                          id);
     324           0 :         return FALSE;
     325             :     }
     326             : 
     327           0 :     cib_resources = get_xpath_object("//" PCMK_XE_RESOURCES, scheduler->input,
     328             :                                      LOG_TRACE);
     329           0 :     if (cib_resources == NULL) {
     330           0 :         pcmk__config_err("No resources configured");
     331           0 :         return FALSE;
     332             :     }
     333             : 
     334           0 :     template = pcmk__xe_first_child(cib_resources, PCMK_XE_TEMPLATE,
     335             :                                     PCMK_XA_ID, template_ref);
     336           0 :     if (template == NULL) {
     337           0 :         pcmk__config_err("No template named '%s'", template_ref);
     338           0 :         return FALSE;
     339             :     }
     340             : 
     341           0 :     new_xml = pcmk__xml_copy(NULL, template);
     342           0 :     xmlNodeSetName(new_xml, xml_obj->name);
     343           0 :     crm_xml_add(new_xml, PCMK_XA_ID, id);
     344           0 :     crm_xml_add(new_xml, PCMK__META_CLONE,
     345             :                 crm_element_value(xml_obj, PCMK__META_CLONE));
     346             : 
     347           0 :     template_ops = pcmk__xe_first_child(new_xml, PCMK_XE_OPERATIONS, NULL,
     348             :                                         NULL);
     349             : 
     350           0 :     for (child_xml = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
     351           0 :          child_xml != NULL; child_xml = pcmk__xe_next(child_xml)) {
     352             : 
     353           0 :         xmlNode *new_child = pcmk__xml_copy(new_xml, child_xml);
     354             : 
     355           0 :         if (pcmk__xe_is(new_child, PCMK_XE_OPERATIONS)) {
     356           0 :             rsc_ops = new_child;
     357             :         }
     358             :     }
     359             : 
     360           0 :     if (template_ops && rsc_ops) {
     361           0 :         xmlNode *op = NULL;
     362           0 :         GHashTable *rsc_ops_hash = pcmk__strkey_table(free, NULL);
     363             : 
     364           0 :         for (op = pcmk__xe_first_child(rsc_ops, NULL, NULL, NULL); op != NULL;
     365           0 :              op = pcmk__xe_next(op)) {
     366             : 
     367           0 :             char *key = template_op_key(op);
     368             : 
     369           0 :             g_hash_table_insert(rsc_ops_hash, key, op);
     370             :         }
     371             : 
     372           0 :         for (op = pcmk__xe_first_child(template_ops, NULL, NULL, NULL);
     373           0 :              op != NULL; op = pcmk__xe_next(op)) {
     374             : 
     375           0 :             char *key = template_op_key(op);
     376             : 
     377           0 :             if (g_hash_table_lookup(rsc_ops_hash, key) == NULL) {
     378           0 :                 pcmk__xml_copy(rsc_ops, op);
     379             :             }
     380             : 
     381           0 :             free(key);
     382             :         }
     383             : 
     384           0 :         if (rsc_ops_hash) {
     385           0 :             g_hash_table_destroy(rsc_ops_hash);
     386             :         }
     387             : 
     388           0 :         free_xml(template_ops);
     389             :     }
     390             : 
     391             :     /*free_xml(*expanded_xml); */
     392           0 :     *expanded_xml = new_xml;
     393             : 
     394             : #if 0 /* Disable multi-level templates for now */
     395             :     if (!unpack_template(new_xml, expanded_xml, scheduler)) {
     396             :        free_xml(*expanded_xml);
     397             :        *expanded_xml = NULL;
     398             :        return FALSE;
     399             :     }
     400             : #endif
     401             : 
     402           0 :     return TRUE;
     403             : }
     404             : 
     405             : static gboolean
     406           0 : add_template_rsc(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
     407             : {
     408           0 :     const char *template_ref = NULL;
     409           0 :     const char *id = NULL;
     410             : 
     411           0 :     if (xml_obj == NULL) {
     412           0 :         pcmk__config_err("No resource object for processing resource list "
     413             :                          "of template");
     414           0 :         return FALSE;
     415             :     }
     416             : 
     417           0 :     template_ref = crm_element_value(xml_obj, PCMK_XA_TEMPLATE);
     418           0 :     if (template_ref == NULL) {
     419           0 :         return TRUE;
     420             :     }
     421             : 
     422           0 :     id = pcmk__xe_id(xml_obj);
     423           0 :     if (id == NULL) {
     424           0 :         pcmk__config_err("'%s' object must have a id", xml_obj->name);
     425           0 :         return FALSE;
     426             :     }
     427             : 
     428           0 :     if (pcmk__str_eq(template_ref, id, pcmk__str_none)) {
     429           0 :         pcmk__config_err("The resource object '%s' should not reference itself",
     430             :                          id);
     431           0 :         return FALSE;
     432             :     }
     433             : 
     434           0 :     if (add_tag_ref(scheduler->template_rsc_sets, template_ref, id) == FALSE) {
     435           0 :         return FALSE;
     436             :     }
     437             : 
     438           0 :     return TRUE;
     439             : }
     440             : 
     441             : static bool
     442           0 : detect_promotable(pcmk_resource_t *rsc)
     443             : {
     444           0 :     const char *promotable = g_hash_table_lookup(rsc->meta,
     445             :                                                  PCMK_META_PROMOTABLE);
     446             : 
     447           0 :     if (crm_is_true(promotable)) {
     448           0 :         return TRUE;
     449             :     }
     450             : 
     451             :     // @COMPAT deprecated since 2.0.0
     452           0 :     if (pcmk__xe_is(rsc->xml, PCMK__XE_PROMOTABLE_LEGACY)) {
     453           0 :         pcmk__warn_once(pcmk__wo_master_element,
     454             :                         "Support for <" PCMK__XE_PROMOTABLE_LEGACY "> (such "
     455             :                         "as in %s) is deprecated and will be removed in a "
     456             :                         "future release. Use <" PCMK_XE_CLONE "> with a "
     457             :                         PCMK_META_PROMOTABLE " meta-attribute instead.",
     458             :                         rsc->id);
     459           0 :         pcmk__insert_dup(rsc->meta, PCMK_META_PROMOTABLE, PCMK_VALUE_TRUE);
     460           0 :         return TRUE;
     461             :     }
     462           0 :     return FALSE;
     463             : }
     464             : 
     465             : static void
     466           0 : free_params_table(gpointer data)
     467             : {
     468           0 :     g_hash_table_destroy((GHashTable *) data);
     469           0 : }
     470             : 
     471             : /*!
     472             :  * \brief Get a table of resource parameters
     473             :  *
     474             :  * \param[in,out] rsc        Resource to query
     475             :  * \param[in]     node       Node for evaluating rules (NULL for defaults)
     476             :  * \param[in,out] scheduler  Scheduler data
     477             :  *
     478             :  * \return Hash table containing resource parameter names and values
     479             :  *         (or NULL if \p rsc or \p scheduler is NULL)
     480             :  * \note The returned table will be destroyed when the resource is freed, so
     481             :  *       callers should not destroy it.
     482             :  */
     483             : GHashTable *
     484           0 : pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node,
     485             :               pcmk_scheduler_t *scheduler)
     486             : {
     487           0 :     GHashTable *params_on_node = NULL;
     488             : 
     489             :     /* A NULL node is used to request the resource's default parameters
     490             :      * (not evaluated for node), but we always want something non-NULL
     491             :      * as a hash table key.
     492             :      */
     493           0 :     const char *node_name = "";
     494             : 
     495             :     // Sanity check
     496           0 :     if ((rsc == NULL) || (scheduler == NULL)) {
     497           0 :         return NULL;
     498             :     }
     499           0 :     if ((node != NULL) && (node->details->uname != NULL)) {
     500           0 :         node_name = node->details->uname;
     501             :     }
     502             : 
     503             :     // Find the parameter table for given node
     504           0 :     if (rsc->parameter_cache == NULL) {
     505           0 :         rsc->parameter_cache = pcmk__strikey_table(free, free_params_table);
     506             :     } else {
     507           0 :         params_on_node = g_hash_table_lookup(rsc->parameter_cache, node_name);
     508             :     }
     509             : 
     510             :     // If none exists yet, create one with parameters evaluated for node
     511           0 :     if (params_on_node == NULL) {
     512           0 :         params_on_node = pcmk__strkey_table(free, free);
     513           0 :         get_rsc_attributes(params_on_node, rsc, node, scheduler);
     514           0 :         g_hash_table_insert(rsc->parameter_cache, strdup(node_name),
     515             :                             params_on_node);
     516             :     }
     517           0 :     return params_on_node;
     518             : }
     519             : 
     520             : /*!
     521             :  * \internal
     522             :  * \brief Unpack a resource's \c PCMK_META_REQUIRES meta-attribute
     523             :  *
     524             :  * \param[in,out] rsc         Resource being unpacked
     525             :  * \param[in]     value       Value of \c PCMK_META_REQUIRES meta-attribute
     526             :  * \param[in]     is_default  Whether \p value was selected by default
     527             :  */
     528             : static void
     529           0 : unpack_requires(pcmk_resource_t *rsc, const char *value, bool is_default)
     530             : {
     531           0 :     if (pcmk__str_eq(value, PCMK_VALUE_NOTHING, pcmk__str_casei)) {
     532             : 
     533           0 :     } else if (pcmk__str_eq(value, PCMK_VALUE_QUORUM, pcmk__str_casei)) {
     534           0 :         pcmk__set_rsc_flags(rsc, pcmk_rsc_needs_quorum);
     535             : 
     536           0 :     } else if (pcmk__str_eq(value, PCMK_VALUE_FENCING, pcmk__str_casei)) {
     537           0 :         pcmk__set_rsc_flags(rsc, pcmk_rsc_needs_fencing);
     538           0 :         if (!pcmk_is_set(rsc->cluster->flags, pcmk_sched_fencing_enabled)) {
     539           0 :             pcmk__config_warn("%s requires fencing but fencing is disabled",
     540             :                               rsc->id);
     541             :         }
     542             : 
     543           0 :     } else if (pcmk__str_eq(value, PCMK_VALUE_UNFENCING, pcmk__str_casei)) {
     544           0 :         if (pcmk_is_set(rsc->flags, pcmk_rsc_fence_device)) {
     545           0 :             pcmk__config_warn("Resetting \"" PCMK_META_REQUIRES "\" for %s "
     546             :                               "to \"" PCMK_VALUE_QUORUM "\" because fencing "
     547             :                               "devices cannot require unfencing", rsc->id);
     548           0 :             unpack_requires(rsc, PCMK_VALUE_QUORUM, true);
     549           0 :             return;
     550             : 
     551           0 :         } else if (!pcmk_is_set(rsc->cluster->flags,
     552             :                                 pcmk_sched_fencing_enabled)) {
     553           0 :             pcmk__config_warn("Resetting \"" PCMK_META_REQUIRES "\" for %s "
     554             :                               "to \"" PCMK_VALUE_QUORUM "\" because fencing is "
     555             :                               "disabled", rsc->id);
     556           0 :             unpack_requires(rsc, PCMK_VALUE_QUORUM, true);
     557           0 :             return;
     558             : 
     559             :         } else {
     560           0 :             pcmk__set_rsc_flags(rsc, pcmk_rsc_needs_fencing
     561             :                                      |pcmk_rsc_needs_unfencing);
     562             :         }
     563             : 
     564             :     } else {
     565           0 :         const char *orig_value = value;
     566             : 
     567           0 :         if (pcmk_is_set(rsc->flags, pcmk_rsc_fence_device)) {
     568           0 :             value = PCMK_VALUE_QUORUM;
     569             : 
     570           0 :         } else if ((rsc->variant == pcmk_rsc_variant_primitive)
     571           0 :                    && xml_contains_remote_node(rsc->xml)) {
     572           0 :             value = PCMK_VALUE_QUORUM;
     573             : 
     574           0 :         } else if (pcmk_is_set(rsc->cluster->flags,
     575             :                                pcmk_sched_enable_unfencing)) {
     576           0 :             value = PCMK_VALUE_UNFENCING;
     577             : 
     578           0 :         } else if (pcmk_is_set(rsc->cluster->flags,
     579             :                                pcmk_sched_fencing_enabled)) {
     580           0 :             value = PCMK_VALUE_FENCING;
     581             : 
     582           0 :         } else if (rsc->cluster->no_quorum_policy == pcmk_no_quorum_ignore) {
     583           0 :             value = PCMK_VALUE_NOTHING;
     584             : 
     585             :         } else {
     586           0 :             value = PCMK_VALUE_QUORUM;
     587             :         }
     588             : 
     589           0 :         if (orig_value != NULL) {
     590           0 :             pcmk__config_err("Resetting '" PCMK_META_REQUIRES "' for %s "
     591             :                              "to '%s' because '%s' is not valid",
     592             :                               rsc->id, value, orig_value);
     593             :         }
     594           0 :         unpack_requires(rsc, value, true);
     595           0 :         return;
     596             :     }
     597             : 
     598           0 :     pcmk__rsc_trace(rsc, "\tRequired to start: %s%s", value,
     599             :                     (is_default? " (default)" : ""));
     600             : }
     601             : 
     602             : static void
     603           0 : warn_about_deprecated_classes(pcmk_resource_t *rsc)
     604             : {
     605           0 :     const char *std = crm_element_value(rsc->xml, PCMK_XA_CLASS);
     606             : 
     607           0 :     if (pcmk__str_eq(std, PCMK_RESOURCE_CLASS_UPSTART, pcmk__str_none)) {
     608           0 :         pcmk__warn_once(pcmk__wo_upstart,
     609             :                         "Support for Upstart resources (such as %s) is "
     610             :                         "deprecated and will be removed in a future release",
     611             :                         rsc->id);
     612             : 
     613           0 :     } else if (pcmk__str_eq(std, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_none)) {
     614           0 :         pcmk__warn_once(pcmk__wo_nagios,
     615             :                         "Support for Nagios resources (such as %s) is "
     616             :                         "deprecated and will be removed in a future release",
     617             :                         rsc->id);
     618             :     }
     619           0 : }
     620             : 
     621             : /*!
     622             :  * \internal
     623             :  * \brief Unpack configuration XML for a given resource
     624             :  *
     625             :  * Unpack the XML object containing a resource's configuration into a new
     626             :  * \c pcmk_resource_t object.
     627             :  *
     628             :  * \param[in]     xml_obj    XML node containing the resource's configuration
     629             :  * \param[out]    rsc        Where to store the unpacked resource information
     630             :  * \param[in]     parent     Resource's parent, if any
     631             :  * \param[in,out] scheduler  Scheduler data
     632             :  *
     633             :  * \return Standard Pacemaker return code
     634             :  * \note If pcmk_rc_ok is returned, \p *rsc is guaranteed to be non-NULL, and
     635             :  *       the caller is responsible for freeing it using its variant-specific
     636             :  *       free() method. Otherwise, \p *rsc is guaranteed to be NULL.
     637             :  */
     638             : int
     639           0 : pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc,
     640             :                     pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
     641             : {
     642           0 :     xmlNode *expanded_xml = NULL;
     643           0 :     xmlNode *ops = NULL;
     644           0 :     const char *value = NULL;
     645           0 :     const char *id = NULL;
     646           0 :     bool guest_node = false;
     647           0 :     bool remote_node = false;
     648             : 
     649           0 :     pe_rule_eval_data_t rule_data = {
     650             :         .node_hash = NULL,
     651             :         .now = NULL,
     652             :         .match_data = NULL,
     653             :         .rsc_data = NULL,
     654             :         .op_data = NULL
     655             :     };
     656             : 
     657           0 :     CRM_CHECK(rsc != NULL, return EINVAL);
     658           0 :     CRM_CHECK((xml_obj != NULL) && (scheduler != NULL),
     659             :               *rsc = NULL;
     660             :               return EINVAL);
     661             : 
     662           0 :     rule_data.now = scheduler->now;
     663             : 
     664           0 :     crm_log_xml_trace(xml_obj, "[raw XML]");
     665             : 
     666           0 :     id = crm_element_value(xml_obj, PCMK_XA_ID);
     667           0 :     if (id == NULL) {
     668           0 :         pcmk__config_err("Ignoring <%s> configuration without " PCMK_XA_ID,
     669             :                          xml_obj->name);
     670           0 :         return pcmk_rc_unpack_error;
     671             :     }
     672             : 
     673           0 :     if (unpack_template(xml_obj, &expanded_xml, scheduler) == FALSE) {
     674           0 :         return pcmk_rc_unpack_error;
     675             :     }
     676             : 
     677           0 :     *rsc = calloc(1, sizeof(pcmk_resource_t));
     678           0 :     if (*rsc == NULL) {
     679           0 :         pcmk__sched_err("Unable to allocate memory for resource '%s'", id);
     680           0 :         return ENOMEM;
     681             :     }
     682           0 :     (*rsc)->cluster = scheduler;
     683             : 
     684           0 :     if (expanded_xml) {
     685           0 :         crm_log_xml_trace(expanded_xml, "[expanded XML]");
     686           0 :         (*rsc)->xml = expanded_xml;
     687           0 :         (*rsc)->orig_xml = xml_obj;
     688             : 
     689             :     } else {
     690           0 :         (*rsc)->xml = xml_obj;
     691           0 :         (*rsc)->orig_xml = NULL;
     692             :     }
     693             : 
     694             :     /* Do not use xml_obj from here on, use (*rsc)->xml in case templates are involved */
     695             : 
     696           0 :     (*rsc)->parent = parent;
     697             : 
     698           0 :     ops = pcmk__xe_first_child((*rsc)->xml, PCMK_XE_OPERATIONS, NULL, NULL);
     699           0 :     (*rsc)->ops_xml = expand_idref(ops, scheduler->input);
     700             : 
     701           0 :     (*rsc)->variant = get_resource_type((const char *) (*rsc)->xml->name);
     702           0 :     if ((*rsc)->variant == pcmk_rsc_variant_unknown) {
     703           0 :         pcmk__config_err("Ignoring resource '%s' of unknown type '%s'",
     704             :                          id, (*rsc)->xml->name);
     705           0 :         common_free(*rsc);
     706           0 :         *rsc = NULL;
     707           0 :         return pcmk_rc_unpack_error;
     708             :     }
     709             : 
     710           0 :     (*rsc)->meta = pcmk__strkey_table(free, free);
     711           0 :     (*rsc)->allowed_nodes = pcmk__strkey_table(NULL, free);
     712           0 :     (*rsc)->known_on = pcmk__strkey_table(NULL, free);
     713             : 
     714           0 :     value = crm_element_value((*rsc)->xml, PCMK__META_CLONE);
     715           0 :     if (value) {
     716           0 :         (*rsc)->id = crm_strdup_printf("%s:%s", id, value);
     717           0 :         pcmk__insert_meta(*rsc, PCMK__META_CLONE, value);
     718             : 
     719             :     } else {
     720           0 :         (*rsc)->id = strdup(id);
     721             :     }
     722             : 
     723           0 :     warn_about_deprecated_classes(*rsc);
     724             : 
     725           0 :     (*rsc)->fns = &resource_class_functions[(*rsc)->variant];
     726             : 
     727           0 :     get_meta_attributes((*rsc)->meta, *rsc, NULL, scheduler);
     728           0 :     (*rsc)->parameters = pe_rsc_params(*rsc, NULL, scheduler); // \deprecated
     729             : 
     730           0 :     (*rsc)->flags = 0;
     731           0 :     pcmk__set_rsc_flags(*rsc, pcmk_rsc_runnable|pcmk_rsc_unassigned);
     732             : 
     733           0 :     if (!pcmk_is_set(scheduler->flags, pcmk_sched_in_maintenance)) {
     734           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_managed);
     735             :     }
     736             : 
     737           0 :     (*rsc)->rsc_cons = NULL;
     738           0 :     (*rsc)->rsc_tickets = NULL;
     739           0 :     (*rsc)->actions = NULL;
     740           0 :     (*rsc)->role = pcmk_role_stopped;
     741           0 :     (*rsc)->next_role = pcmk_role_unknown;
     742             : 
     743           0 :     (*rsc)->recovery_type = pcmk_multiply_active_restart;
     744           0 :     (*rsc)->stickiness = 0;
     745           0 :     (*rsc)->migration_threshold = PCMK_SCORE_INFINITY;
     746           0 :     (*rsc)->failure_timeout = 0;
     747             : 
     748           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_PRIORITY);
     749           0 :     (*rsc)->priority = char2score(value);
     750             : 
     751           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_CRITICAL);
     752           0 :     if ((value == NULL) || crm_is_true(value)) {
     753           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_critical);
     754             :     }
     755             : 
     756           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_NOTIFY);
     757           0 :     if (crm_is_true(value)) {
     758           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_notify);
     759             :     }
     760             : 
     761           0 :     if (xml_contains_remote_node((*rsc)->xml)) {
     762           0 :         (*rsc)->is_remote_node = TRUE;
     763           0 :         if (g_hash_table_lookup((*rsc)->meta, PCMK__META_CONTAINER)) {
     764           0 :             guest_node = true;
     765             :         } else {
     766           0 :             remote_node = true;
     767             :         }
     768             :     }
     769             : 
     770           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_ALLOW_MIGRATE);
     771           0 :     if (crm_is_true(value)) {
     772           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_migratable);
     773           0 :     } else if ((value == NULL) && remote_node) {
     774             :         /* By default, we want remote nodes to be able
     775             :          * to float around the cluster without having to stop all the
     776             :          * resources within the remote-node before moving. Allowing
     777             :          * migration support enables this feature. If this ever causes
     778             :          * problems, migration support can be explicitly turned off with
     779             :          * PCMK_META_ALLOW_MIGRATE=false.
     780             :          */
     781           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_migratable);
     782             :     }
     783             : 
     784           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_IS_MANAGED);
     785           0 :     if (value != NULL) {
     786           0 :         if (pcmk__str_eq(PCMK_VALUE_DEFAULT, value, pcmk__str_casei)) {
     787             :             // @COMPAT Deprecated since 2.1.8
     788           0 :             pcmk__config_warn("Support for setting " PCMK_META_IS_MANAGED
     789             :                               " to the explicit value '" PCMK_VALUE_DEFAULT
     790             :                               "' is deprecated and will be removed in a "
     791             :                               "future release (just leave it unset)");
     792           0 :         } else if (crm_is_true(value)) {
     793           0 :             pcmk__set_rsc_flags(*rsc, pcmk_rsc_managed);
     794             :         } else {
     795           0 :             pcmk__clear_rsc_flags(*rsc, pcmk_rsc_managed);
     796             :         }
     797             :     }
     798             : 
     799           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_MAINTENANCE);
     800           0 :     if (crm_is_true(value)) {
     801           0 :         pcmk__clear_rsc_flags(*rsc, pcmk_rsc_managed);
     802           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_maintenance);
     803             :     }
     804           0 :     if (pcmk_is_set(scheduler->flags, pcmk_sched_in_maintenance)) {
     805           0 :         pcmk__clear_rsc_flags(*rsc, pcmk_rsc_managed);
     806           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_maintenance);
     807             :     }
     808             : 
     809           0 :     if (pcmk__is_clone(pe__const_top_resource(*rsc, false))) {
     810           0 :         value = g_hash_table_lookup((*rsc)->meta, PCMK_META_GLOBALLY_UNIQUE);
     811           0 :         if (crm_is_true(value)) {
     812           0 :             pcmk__set_rsc_flags(*rsc, pcmk_rsc_unique);
     813             :         }
     814           0 :         if (detect_promotable(*rsc)) {
     815           0 :             pcmk__set_rsc_flags(*rsc, pcmk_rsc_promotable);
     816             :         }
     817             :     } else {
     818           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_unique);
     819             :     }
     820             : 
     821             :     // @COMPAT Deprecated meta-attribute
     822           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK__META_RESTART_TYPE);
     823           0 :     if (pcmk__str_eq(value, PCMK_VALUE_RESTART, pcmk__str_casei)) {
     824           0 :         (*rsc)->restart_type = pe_restart_restart;
     825           0 :         pcmk__rsc_trace(*rsc, "%s dependency restart handling: restart",
     826             :                         (*rsc)->id);
     827           0 :         pcmk__warn_once(pcmk__wo_restart_type,
     828             :                         "Support for " PCMK__META_RESTART_TYPE " is deprecated "
     829             :                         "and will be removed in a future release");
     830             : 
     831             :     } else {
     832           0 :         (*rsc)->restart_type = pe_restart_ignore;
     833           0 :         pcmk__rsc_trace(*rsc, "%s dependency restart handling: ignore",
     834             :                         (*rsc)->id);
     835             :     }
     836             : 
     837           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_MULTIPLE_ACTIVE);
     838           0 :     if (pcmk__str_eq(value, PCMK_VALUE_STOP_ONLY, pcmk__str_casei)) {
     839           0 :         (*rsc)->recovery_type = pcmk_multiply_active_stop;
     840           0 :         pcmk__rsc_trace(*rsc, "%s multiple running resource recovery: stop only",
     841             :                         (*rsc)->id);
     842             : 
     843           0 :     } else if (pcmk__str_eq(value, PCMK_VALUE_BLOCK, pcmk__str_casei)) {
     844           0 :         (*rsc)->recovery_type = pcmk_multiply_active_block;
     845           0 :         pcmk__rsc_trace(*rsc, "%s multiple running resource recovery: block",
     846             :                         (*rsc)->id);
     847             : 
     848           0 :     } else if (pcmk__str_eq(value, PCMK_VALUE_STOP_UNEXPECTED,
     849             :                             pcmk__str_casei)) {
     850           0 :         (*rsc)->recovery_type = pcmk_multiply_active_unexpected;
     851           0 :         pcmk__rsc_trace(*rsc,
     852             :                         "%s multiple running resource recovery: "
     853             :                         "stop unexpected instances",
     854             :                         (*rsc)->id);
     855             : 
     856             :     } else { // PCMK_VALUE_STOP_START
     857           0 :         if (!pcmk__str_eq(value, PCMK_VALUE_STOP_START,
     858             :                           pcmk__str_casei|pcmk__str_null_matches)) {
     859           0 :             pcmk__config_warn("%s is not a valid value for "
     860             :                               PCMK_META_MULTIPLE_ACTIVE
     861             :                               ", using default of "
     862             :                               "\"" PCMK_VALUE_STOP_START "\"",
     863             :                               value);
     864             :         }
     865           0 :         (*rsc)->recovery_type = pcmk_multiply_active_restart;
     866           0 :         pcmk__rsc_trace(*rsc,
     867             :                         "%s multiple running resource recovery: stop/start",
     868             :                         (*rsc)->id);
     869             :     }
     870             : 
     871           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_RESOURCE_STICKINESS);
     872           0 :     if (value != NULL) {
     873           0 :         if (pcmk__str_eq(PCMK_VALUE_DEFAULT, value, pcmk__str_casei)) {
     874             :             // @COMPAT Deprecated since 2.1.8
     875           0 :             pcmk__config_warn("Support for setting "
     876             :                               PCMK_META_RESOURCE_STICKINESS
     877             :                               " to the explicit value '" PCMK_VALUE_DEFAULT
     878             :                               "' is deprecated and will be removed in a "
     879             :                               "future release (just leave it unset)");
     880             :         } else {
     881           0 :             (*rsc)->stickiness = char2score(value);
     882             :         }
     883             :     }
     884             : 
     885           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_MIGRATION_THRESHOLD);
     886           0 :     if (value != NULL) {
     887           0 :         if (pcmk__str_eq(PCMK_VALUE_DEFAULT, value, pcmk__str_casei)) {
     888             :             // @COMPAT Deprecated since 2.1.8
     889           0 :             pcmk__config_warn("Support for setting "
     890             :                               PCMK_META_MIGRATION_THRESHOLD
     891             :                               " to the explicit value '" PCMK_VALUE_DEFAULT
     892             :                               "' is deprecated and will be removed in a "
     893             :                               "future release (just leave it unset)");
     894             :         } else {
     895           0 :             (*rsc)->migration_threshold = char2score(value);
     896           0 :             if ((*rsc)->migration_threshold < 0) {
     897             :                 /* @COMPAT We use 1 here to preserve previous behavior, but this
     898             :                  * should probably use the default (INFINITY) or 0 (to disable)
     899             :                  * instead.
     900             :                  */
     901           0 :                 pcmk__warn_once(pcmk__wo_neg_threshold,
     902             :                                 PCMK_META_MIGRATION_THRESHOLD
     903             :                                 " must be non-negative, using 1 instead");
     904           0 :                 (*rsc)->migration_threshold = 1;
     905             :             }
     906             :         }
     907             :     }
     908             : 
     909           0 :     if (pcmk__str_eq(crm_element_value((*rsc)->xml, PCMK_XA_CLASS),
     910             :                      PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
     911           0 :         pcmk__set_scheduler_flags(scheduler, pcmk_sched_have_fencing);
     912           0 :         pcmk__set_rsc_flags(*rsc, pcmk_rsc_fence_device);
     913             :     }
     914             : 
     915           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_REQUIRES);
     916           0 :     unpack_requires(*rsc, value, false);
     917             : 
     918           0 :     value = g_hash_table_lookup((*rsc)->meta, PCMK_META_FAILURE_TIMEOUT);
     919           0 :     if (value != NULL) {
     920           0 :         guint interval_ms = 0U;
     921             : 
     922             :         // Stored as seconds
     923           0 :         pcmk_parse_interval_spec(value, &interval_ms);
     924           0 :         (*rsc)->failure_timeout = (int) (interval_ms / 1000);
     925             :     }
     926             : 
     927           0 :     if (remote_node) {
     928           0 :         GHashTable *params = pe_rsc_params(*rsc, NULL, scheduler);
     929             : 
     930             :         /* Grabbing the value now means that any rules based on node attributes
     931             :          * will evaluate to false, so such rules should not be used with
     932             :          * PCMK_REMOTE_RA_RECONNECT_INTERVAL.
     933             :          *
     934             :          * @TODO Evaluate per node before using
     935             :          */
     936           0 :         value = g_hash_table_lookup(params, PCMK_REMOTE_RA_RECONNECT_INTERVAL);
     937           0 :         if (value) {
     938             :             /* reconnect delay works by setting failure_timeout and preventing the
     939             :              * connection from starting until the failure is cleared. */
     940           0 :             pcmk_parse_interval_spec(value, &((*rsc)->remote_reconnect_ms));
     941             : 
     942             :             /* We want to override any default failure_timeout in use when remote
     943             :              * PCMK_REMOTE_RA_RECONNECT_INTERVAL is in use.
     944             :              */
     945           0 :             (*rsc)->failure_timeout = (*rsc)->remote_reconnect_ms / 1000;
     946             :         }
     947             :     }
     948             : 
     949           0 :     get_target_role(*rsc, &((*rsc)->next_role));
     950           0 :     pcmk__rsc_trace(*rsc, "%s desired next state: %s", (*rsc)->id,
     951             :                     ((*rsc)->next_role == pcmk_role_unknown)?
     952             :                         "default" : pcmk_role_text((*rsc)->next_role));
     953             : 
     954           0 :     if ((*rsc)->fns->unpack(*rsc, scheduler) == FALSE) {
     955           0 :         (*rsc)->fns->free(*rsc);
     956           0 :         *rsc = NULL;
     957           0 :         return pcmk_rc_unpack_error;
     958             :     }
     959             : 
     960           0 :     if (pcmk_is_set(scheduler->flags, pcmk_sched_symmetric_cluster)) {
     961             :         // This tag must stay exactly the same because it is tested elsewhere
     962           0 :         resource_location(*rsc, NULL, 0, "symmetric_default", scheduler);
     963           0 :     } else if (guest_node) {
     964             :         /* remote resources tied to a container resource must always be allowed
     965             :          * to opt-in to the cluster. Whether the connection resource is actually
     966             :          * allowed to be placed on a node is dependent on the container resource */
     967           0 :         resource_location(*rsc, NULL, 0, "remote_connection_default",
     968             :                           scheduler);
     969             :     }
     970             : 
     971           0 :     pcmk__rsc_trace(*rsc, "%s action notification: %s", (*rsc)->id,
     972             :                     pcmk_is_set((*rsc)->flags, pcmk_rsc_notify)? "required" : "not required");
     973             : 
     974           0 :     (*rsc)->utilization = pcmk__strkey_table(free, free);
     975             : 
     976           0 :     pe__unpack_dataset_nvpairs((*rsc)->xml, PCMK_XE_UTILIZATION, &rule_data,
     977           0 :                                (*rsc)->utilization, NULL, FALSE, scheduler);
     978             : 
     979           0 :     if (expanded_xml) {
     980           0 :         if (add_template_rsc(xml_obj, scheduler) == FALSE) {
     981           0 :             (*rsc)->fns->free(*rsc);
     982           0 :             *rsc = NULL;
     983           0 :             return pcmk_rc_unpack_error;
     984             :         }
     985             :     }
     986           0 :     return pcmk_rc_ok;
     987             : }
     988             : 
     989             : gboolean
     990           0 : is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
     991             : {
     992           0 :     pcmk_resource_t *parent = child;
     993             : 
     994           0 :     if (parent == NULL || rsc == NULL) {
     995           0 :         return FALSE;
     996             :     }
     997           0 :     while (parent->parent != NULL) {
     998           0 :         if (parent->parent == rsc) {
     999           0 :             return TRUE;
    1000             :         }
    1001           0 :         parent = parent->parent;
    1002             :     }
    1003           0 :     return FALSE;
    1004             : }
    1005             : 
    1006             : pcmk_resource_t *
    1007           0 : uber_parent(pcmk_resource_t *rsc)
    1008             : {
    1009           0 :     pcmk_resource_t *parent = rsc;
    1010             : 
    1011           0 :     if (parent == NULL) {
    1012           0 :         return NULL;
    1013             :     }
    1014           0 :     while ((parent->parent != NULL)
    1015           0 :            && (parent->parent->variant != pcmk_rsc_variant_bundle)) {
    1016           0 :         parent = parent->parent;
    1017             :     }
    1018           0 :     return parent;
    1019             : }
    1020             : 
    1021             : /*!
    1022             :  * \internal
    1023             :  * \brief Get the topmost parent of a resource as a const pointer
    1024             :  *
    1025             :  * \param[in] rsc             Resource to check
    1026             :  * \param[in] include_bundle  If true, go all the way to bundle
    1027             :  *
    1028             :  * \return \p NULL if \p rsc is NULL, \p rsc if \p rsc has no parent,
    1029             :  *         the bundle if \p rsc is bundled and \p include_bundle is true,
    1030             :  *         otherwise the topmost parent of \p rsc up to a clone
    1031             :  */
    1032             : const pcmk_resource_t *
    1033           0 : pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
    1034             : {
    1035           0 :     const pcmk_resource_t *parent = rsc;
    1036             : 
    1037           0 :     if (parent == NULL) {
    1038           0 :         return NULL;
    1039             :     }
    1040           0 :     while (parent->parent != NULL) {
    1041           0 :         if (!include_bundle
    1042           0 :             && (parent->parent->variant == pcmk_rsc_variant_bundle)) {
    1043           0 :             break;
    1044             :         }
    1045           0 :         parent = parent->parent;
    1046             :     }
    1047           0 :     return parent;
    1048             : }
    1049             : 
    1050             : void
    1051           0 : common_free(pcmk_resource_t * rsc)
    1052             : {
    1053           0 :     if (rsc == NULL) {
    1054           0 :         return;
    1055             :     }
    1056             : 
    1057           0 :     pcmk__rsc_trace(rsc, "Freeing %s %d", rsc->id, rsc->variant);
    1058             : 
    1059           0 :     g_list_free(rsc->rsc_cons);
    1060           0 :     g_list_free(rsc->rsc_cons_lhs);
    1061           0 :     g_list_free(rsc->rsc_tickets);
    1062           0 :     g_list_free(rsc->dangling_migrations);
    1063             : 
    1064           0 :     if (rsc->parameter_cache != NULL) {
    1065           0 :         g_hash_table_destroy(rsc->parameter_cache);
    1066             :     }
    1067           0 :     if (rsc->meta != NULL) {
    1068           0 :         g_hash_table_destroy(rsc->meta);
    1069             :     }
    1070           0 :     if (rsc->utilization != NULL) {
    1071           0 :         g_hash_table_destroy(rsc->utilization);
    1072             :     }
    1073             : 
    1074           0 :     if ((rsc->parent == NULL)
    1075           0 :         && pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
    1076             : 
    1077           0 :         free_xml(rsc->xml);
    1078           0 :         rsc->xml = NULL;
    1079           0 :         free_xml(rsc->orig_xml);
    1080           0 :         rsc->orig_xml = NULL;
    1081             : 
    1082             :         /* if rsc->orig_xml, then rsc->xml is an expanded xml from a template */
    1083           0 :     } else if (rsc->orig_xml) {
    1084           0 :         free_xml(rsc->xml);
    1085           0 :         rsc->xml = NULL;
    1086             :     }
    1087           0 :     if (rsc->running_on) {
    1088           0 :         g_list_free(rsc->running_on);
    1089           0 :         rsc->running_on = NULL;
    1090             :     }
    1091           0 :     if (rsc->known_on) {
    1092           0 :         g_hash_table_destroy(rsc->known_on);
    1093           0 :         rsc->known_on = NULL;
    1094             :     }
    1095           0 :     if (rsc->actions) {
    1096           0 :         g_list_free(rsc->actions);
    1097           0 :         rsc->actions = NULL;
    1098             :     }
    1099           0 :     if (rsc->allowed_nodes) {
    1100           0 :         g_hash_table_destroy(rsc->allowed_nodes);
    1101           0 :         rsc->allowed_nodes = NULL;
    1102             :     }
    1103           0 :     g_list_free(rsc->fillers);
    1104           0 :     g_list_free(rsc->rsc_location);
    1105           0 :     pcmk__rsc_trace(rsc, "Resource freed");
    1106           0 :     free(rsc->id);
    1107           0 :     free(rsc->clone_name);
    1108           0 :     free(rsc->allocated_to);
    1109           0 :     free(rsc->variant_opaque);
    1110           0 :     free(rsc->pending_task);
    1111           0 :     free(rsc);
    1112             : }
    1113             : 
    1114             : /*!
    1115             :  * \internal
    1116             :  * \brief Count a node and update most preferred to it as appropriate
    1117             :  *
    1118             :  * \param[in]     rsc          An active resource
    1119             :  * \param[in]     node         A node that \p rsc is active on
    1120             :  * \param[in,out] active       This will be set to \p node if \p node is more
    1121             :  *                             preferred than the current value
    1122             :  * \param[in,out] count_all    If not NULL, this will be incremented
    1123             :  * \param[in,out] count_clean  If not NULL, this will be incremented if \p node
    1124             :  *                             is online and clean
    1125             :  *
    1126             :  * \return true if the count should continue, or false if sufficiently known
    1127             :  */
    1128             : bool
    1129           0 : pe__count_active_node(const pcmk_resource_t *rsc, pcmk_node_t *node,
    1130             :                       pcmk_node_t **active, unsigned int *count_all,
    1131             :                       unsigned int *count_clean)
    1132             : {
    1133           0 :     bool keep_looking = false;
    1134           0 :     bool is_happy = false;
    1135             : 
    1136           0 :     CRM_CHECK((rsc != NULL) && (node != NULL) && (active != NULL),
    1137             :               return false);
    1138             : 
    1139           0 :     is_happy = node->details->online && !node->details->unclean;
    1140             : 
    1141           0 :     if (count_all != NULL) {
    1142           0 :         ++*count_all;
    1143             :     }
    1144           0 :     if ((count_clean != NULL) && is_happy) {
    1145           0 :         ++*count_clean;
    1146             :     }
    1147           0 :     if ((count_all != NULL) || (count_clean != NULL)) {
    1148           0 :         keep_looking = true; // We're counting, so go through entire list
    1149             :     }
    1150             : 
    1151           0 :     if (rsc->partial_migration_source != NULL) {
    1152           0 :         if (pcmk__same_node(node, rsc->partial_migration_source)) {
    1153           0 :             *active = node; // This is the migration source
    1154             :         } else {
    1155           0 :             keep_looking = true;
    1156             :         }
    1157           0 :     } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_needs_fencing)) {
    1158           0 :         if (is_happy && ((*active == NULL) || !(*active)->details->online
    1159           0 :                          || (*active)->details->unclean)) {
    1160           0 :             *active = node; // This is the first clean node
    1161             :         } else {
    1162           0 :             keep_looking = true;
    1163             :         }
    1164             :     }
    1165           0 :     if (*active == NULL) {
    1166           0 :         *active = node; // This is the first node checked
    1167             :     }
    1168           0 :     return keep_looking;
    1169             : }
    1170             : 
    1171             : // Shared implementation of pcmk_rsc_methods_t:active_node()
    1172             : static pcmk_node_t *
    1173           0 : active_node(const pcmk_resource_t *rsc, unsigned int *count_all,
    1174             :             unsigned int *count_clean)
    1175             : {
    1176           0 :     pcmk_node_t *active = NULL;
    1177             : 
    1178           0 :     if (count_all != NULL) {
    1179           0 :         *count_all = 0;
    1180             :     }
    1181           0 :     if (count_clean != NULL) {
    1182           0 :         *count_clean = 0;
    1183             :     }
    1184           0 :     if (rsc == NULL) {
    1185           0 :         return NULL;
    1186             :     }
    1187           0 :     for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
    1188           0 :         if (!pe__count_active_node(rsc, (pcmk_node_t *) iter->data, &active,
    1189             :                                    count_all, count_clean)) {
    1190           0 :             break; // Don't waste time iterating if we don't have to
    1191             :         }
    1192             :     }
    1193           0 :     return active;
    1194             : }
    1195             : 
    1196             : /*!
    1197             :  * \brief
    1198             :  * \internal Find and count active nodes according to \c PCMK_META_REQUIRES
    1199             :  *
    1200             :  * \param[in]  rsc    Resource to check
    1201             :  * \param[out] count  If not NULL, will be set to count of active nodes
    1202             :  *
    1203             :  * \return An active node (or NULL if resource is not active anywhere)
    1204             :  *
    1205             :  * \note This is a convenience wrapper for active_node() where the count of all
    1206             :  *       active nodes or only clean active nodes is desired according to the
    1207             :  *       \c PCMK_META_REQUIRES meta-attribute.
    1208             :  */
    1209             : pcmk_node_t *
    1210           0 : pe__find_active_requires(const pcmk_resource_t *rsc, unsigned int *count)
    1211             : {
    1212           0 :     if (rsc == NULL) {
    1213           0 :         if (count != NULL) {
    1214           0 :             *count = 0;
    1215             :         }
    1216           0 :         return NULL;
    1217             : 
    1218           0 :     } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_fencing)) {
    1219           0 :         return rsc->fns->active_node(rsc, count, NULL);
    1220             : 
    1221             :     } else {
    1222           0 :         return rsc->fns->active_node(rsc, NULL, count);
    1223             :     }
    1224             : }
    1225             : 
    1226             : void
    1227           0 : pe__count_common(pcmk_resource_t *rsc)
    1228             : {
    1229           0 :     if (rsc->children != NULL) {
    1230           0 :         for (GList *item = rsc->children; item != NULL; item = item->next) {
    1231           0 :             ((pcmk_resource_t *) item->data)->fns->count(item->data);
    1232             :         }
    1233             : 
    1234           0 :     } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_removed)
    1235           0 :                || (rsc->role > pcmk_role_stopped)) {
    1236           0 :         rsc->cluster->ninstances++;
    1237           0 :         if (pe__resource_is_disabled(rsc)) {
    1238           0 :             rsc->cluster->disabled_resources++;
    1239             :         }
    1240           0 :         if (pcmk_is_set(rsc->flags, pcmk_rsc_blocked)) {
    1241           0 :             rsc->cluster->blocked_resources++;
    1242             :         }
    1243             :     }
    1244           0 : }
    1245             : 
    1246             : /*!
    1247             :  * \internal
    1248             :  * \brief Update a resource's next role
    1249             :  *
    1250             :  * \param[in,out] rsc   Resource to be updated
    1251             :  * \param[in]     role  Resource's new next role
    1252             :  * \param[in]     why   Human-friendly reason why role is changing (for logs)
    1253             :  */
    1254             : void
    1255           0 : pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
    1256             : {
    1257           0 :     CRM_ASSERT((rsc != NULL) && (why != NULL));
    1258           0 :     if (rsc->next_role != role) {
    1259           0 :         pcmk__rsc_trace(rsc, "Resetting next role for %s from %s to %s (%s)",
    1260             :                         rsc->id, pcmk_role_text(rsc->next_role),
    1261             :                         pcmk_role_text(role), why);
    1262           0 :         rsc->next_role = role;
    1263             :     }
    1264           0 : }

Generated by: LCOV version 1.14