LCOV - code coverage report
Current view: top level - pengine - pe_digest.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 186 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 13 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 <glib.h>
      13             : #include <stdbool.h>
      14             : 
      15             : #include <crm/crm.h>
      16             : #include <crm/common/xml.h>
      17             : #include <crm/common/xml_internal.h>
      18             : #include <crm/pengine/internal.h>
      19             : #include "pe_status_private.h"
      20             : 
      21             : extern bool pcmk__is_daemon;
      22             : 
      23             : /*!
      24             :  * \internal
      25             :  * \brief Free an operation digest cache entry
      26             :  *
      27             :  * \param[in,out] ptr  Pointer to cache entry to free
      28             :  *
      29             :  * \note The argument is a gpointer so this can be used as a hash table
      30             :  *       free function.
      31             :  */
      32             : void
      33           0 : pe__free_digests(gpointer ptr)
      34             : {
      35           0 :     pcmk__op_digest_t *data = ptr;
      36             : 
      37           0 :     if (data != NULL) {
      38           0 :         free_xml(data->params_all);
      39           0 :         free_xml(data->params_secure);
      40           0 :         free_xml(data->params_restart);
      41             : 
      42           0 :         free(data->digest_all_calc);
      43           0 :         free(data->digest_restart_calc);
      44           0 :         free(data->digest_secure_calc);
      45             : 
      46           0 :         free(data);
      47             :     }
      48           0 : }
      49             : 
      50             : // Return true if XML attribute name is not substring of a given string
      51             : static bool
      52           0 : attr_not_in_string(xmlAttrPtr a, void *user_data)
      53             : {
      54           0 :     bool filter = false;
      55           0 :     char *name = crm_strdup_printf(" %s ", (const char *) a->name);
      56             : 
      57           0 :     if (strstr((const char *) user_data, name) == NULL) {
      58           0 :         crm_trace("Filtering %s (not found in '%s')",
      59             :                   (const char *) a->name, (const char *) user_data);
      60           0 :         filter = true;
      61             :     }
      62           0 :     free(name);
      63           0 :     return filter;
      64             : }
      65             : 
      66             : // Return true if XML attribute name is substring of a given string
      67             : static bool
      68           0 : attr_in_string(xmlAttrPtr a, void *user_data)
      69             : {
      70           0 :     bool filter = false;
      71           0 :     char *name = crm_strdup_printf(" %s ", (const char *) a->name);
      72             : 
      73           0 :     if (strstr((const char *) user_data, name) != NULL) {
      74           0 :         crm_trace("Filtering %s (found in '%s')",
      75             :                   (const char *) a->name, (const char *) user_data);
      76           0 :         filter = true;
      77             :     }
      78           0 :     free(name);
      79           0 :     return filter;
      80             : }
      81             : 
      82             : /*!
      83             :  * \internal
      84             :  * \brief Add digest of all parameters to a digest cache entry
      85             :  *
      86             :  * \param[out]    data         Digest cache entry to modify
      87             :  * \param[in,out] rsc          Resource that action was for
      88             :  * \param[in]     node         Node action was performed on
      89             :  * \param[in]     params       Resource parameters evaluated for node
      90             :  * \param[in]     task         Name of action performed
      91             :  * \param[in,out] interval_ms  Action's interval (will be reset if in overrides)
      92             :  * \param[in]     xml_op       Unused
      93             :  * \param[in]     op_version   CRM feature set to use for digest calculation
      94             :  * \param[in]     overrides    Key/value table to override resource parameters
      95             :  * \param[in,out] scheduler    Scheduler data
      96             :  */
      97             : static void
      98           0 : calculate_main_digest(pcmk__op_digest_t *data, pcmk_resource_t *rsc,
      99             :                       const pcmk_node_t *node, GHashTable *params,
     100             :                       const char *task, guint *interval_ms,
     101             :                       const xmlNode *xml_op, const char *op_version,
     102             :                       GHashTable *overrides, pcmk_scheduler_t *scheduler)
     103             : {
     104           0 :     xmlNode *action_config = NULL;
     105             : 
     106           0 :     data->params_all = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
     107             : 
     108             :     /* REMOTE_CONTAINER_HACK: Allow Pacemaker Remote nodes to run containers
     109             :      * that themselves are Pacemaker Remote nodes
     110             :      */
     111           0 :     (void) pe__add_bundle_remote_name(rsc, data->params_all,
     112             :                                       PCMK_REMOTE_RA_ADDR);
     113             : 
     114           0 :     if (overrides != NULL) {
     115             :         // If interval was overridden, reset it
     116           0 :         const char *meta_name = CRM_META "_" PCMK_META_INTERVAL;
     117           0 :         const char *interval_s = g_hash_table_lookup(overrides, meta_name);
     118             : 
     119           0 :         if (interval_s != NULL) {
     120             :             long long value_ll;
     121             : 
     122           0 :             if ((pcmk__scan_ll(interval_s, &value_ll, 0LL) == pcmk_rc_ok)
     123           0 :                 && (value_ll >= 0) && (value_ll <= G_MAXUINT)) {
     124           0 :                 *interval_ms = (guint) value_ll;
     125             :             }
     126             :         }
     127             : 
     128             :         // Add overrides to list of all parameters
     129           0 :         g_hash_table_foreach(overrides, hash2field, data->params_all);
     130             :     }
     131             : 
     132             :     // Add provided instance parameters
     133           0 :     g_hash_table_foreach(params, hash2field, data->params_all);
     134             : 
     135             :     // Find action configuration XML in CIB
     136           0 :     action_config = pcmk__find_action_config(rsc, task, *interval_ms, true);
     137             : 
     138             :     /* Add action-specific resource instance attributes to the digest list.
     139             :      *
     140             :      * If this is a one-time action with action-specific instance attributes,
     141             :      * enforce a restart instead of reload-agent in case the main digest doesn't
     142             :      * match, even if the restart digest does. This ensures any changes of the
     143             :      * action-specific parameters get applied for this specific action, and
     144             :      * digests calculated for the resulting history will be correct. Default the
     145             :      * result to RSC_DIGEST_RESTART for the case where the main digest doesn't
     146             :      * match.
     147             :      */
     148           0 :     params = pcmk__unpack_action_rsc_params(action_config, node->details->attrs,
     149             :                                             scheduler);
     150           0 :     if ((*interval_ms == 0) && (g_hash_table_size(params) > 0)) {
     151           0 :         data->rc = pcmk__digest_restart;
     152             :     }
     153           0 :     g_hash_table_foreach(params, hash2field, data->params_all);
     154           0 :     g_hash_table_destroy(params);
     155             : 
     156             :     // Add action meta-attributes
     157           0 :     params = pcmk__unpack_action_meta(rsc, node, task, *interval_ms,
     158             :                                       action_config);
     159           0 :     g_hash_table_foreach(params, hash2metafield, data->params_all);
     160           0 :     g_hash_table_destroy(params);
     161             : 
     162           0 :     pcmk__filter_op_for_digest(data->params_all);
     163             : 
     164           0 :     data->digest_all_calc = calculate_operation_digest(data->params_all,
     165             :                                                        op_version);
     166           0 : }
     167             : 
     168             : // Return true if XML attribute name is a Pacemaker-defined fencing parameter
     169             : static bool
     170           0 : is_fence_param(xmlAttrPtr attr, void *user_data)
     171             : {
     172           0 :     return pcmk_stonith_param((const char *) attr->name);
     173             : }
     174             : 
     175             : /*!
     176             :  * \internal
     177             :  * \brief Add secure digest to a digest cache entry
     178             :  *
     179             :  * \param[out] data        Digest cache entry to modify
     180             :  * \param[in]  rsc         Resource that action was for
     181             :  * \param[in]  params      Resource parameters evaluated for node
     182             :  * \param[in]  xml_op      XML of operation in CIB status (if available)
     183             :  * \param[in]  op_version  CRM feature set to use for digest calculation
     184             :  * \param[in]  overrides   Key/value hash table to override resource parameters
     185             :  */
     186             : static void
     187           0 : calculate_secure_digest(pcmk__op_digest_t *data, const pcmk_resource_t *rsc,
     188             :                         GHashTable *params, const xmlNode *xml_op,
     189             :                         const char *op_version, GHashTable *overrides)
     190             : {
     191           0 :     const char *class = crm_element_value(rsc->xml, PCMK_XA_CLASS);
     192           0 :     const char *secure_list = NULL;
     193           0 :     bool old_version = (compare_version(op_version, "3.16.0") < 0);
     194             : 
     195           0 :     if (xml_op == NULL) {
     196           0 :         secure_list = " passwd password user ";
     197             :     } else {
     198           0 :         secure_list = crm_element_value(xml_op, PCMK__XA_OP_SECURE_PARAMS);
     199             :     }
     200             : 
     201           0 :     if (old_version) {
     202           0 :         data->params_secure = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
     203           0 :         if (overrides != NULL) {
     204           0 :             g_hash_table_foreach(overrides, hash2field, data->params_secure);
     205             :         }
     206             : 
     207           0 :         g_hash_table_foreach(params, hash2field, data->params_secure);
     208             : 
     209             :     } else {
     210             :         // Start with a copy of all parameters
     211           0 :         data->params_secure = pcmk__xml_copy(NULL, data->params_all);
     212             :     }
     213             : 
     214           0 :     if (secure_list != NULL) {
     215           0 :         pcmk__xe_remove_matching_attrs(data->params_secure, attr_in_string,
     216             :                                        (void *) secure_list);
     217             :     }
     218           0 :     if (old_version
     219           0 :         && pcmk_is_set(pcmk_get_ra_caps(class),
     220             :                        pcmk_ra_cap_fence_params)) {
     221             :         /* For stonith resources, Pacemaker adds special parameters,
     222             :          * but these are not listed in fence agent meta-data, so with older
     223             :          * versions of DC, the controller will not hash them. That means we have
     224             :          * to filter them out before calculating our hash for comparison.
     225             :          */
     226           0 :         pcmk__xe_remove_matching_attrs(data->params_secure, is_fence_param,
     227             :                                        NULL);
     228             :     }
     229           0 :     pcmk__filter_op_for_digest(data->params_secure);
     230             : 
     231             :     /* CRM_meta_timeout *should* be part of a digest for recurring operations.
     232             :      * However, with older versions of DC, the controller does not add timeout
     233             :      * to secure digests, because it only includes parameters declared by the
     234             :      * resource agent.
     235             :      * Remove any timeout that made it this far, to match.
     236             :      */
     237           0 :     if (old_version) {
     238           0 :         pcmk__xe_remove_attr(data->params_secure,
     239             :                              CRM_META "_" PCMK_META_TIMEOUT);
     240             :     }
     241             : 
     242           0 :     data->digest_secure_calc = calculate_operation_digest(data->params_secure,
     243             :                                                           op_version);
     244           0 : }
     245             : 
     246             : /*!
     247             :  * \internal
     248             :  * \brief Add restart digest to a digest cache entry
     249             :  *
     250             :  * \param[out] data        Digest cache entry to modify
     251             :  * \param[in]  xml_op      XML of operation in CIB status (if available)
     252             :  * \param[in]  op_version  CRM feature set to use for digest calculation
     253             :  *
     254             :  * \note This function doesn't need to handle overrides because it starts with
     255             :  *       data->params_all, which already has overrides applied.
     256             :  */
     257             : static void
     258           0 : calculate_restart_digest(pcmk__op_digest_t *data, const xmlNode *xml_op,
     259             :                          const char *op_version)
     260             : {
     261           0 :     const char *value = NULL;
     262             : 
     263             :     // We must have XML of resource operation history
     264           0 :     if (xml_op == NULL) {
     265           0 :         return;
     266             :     }
     267             : 
     268             :     // And the history must have a restart digest to compare against
     269           0 :     if (crm_element_value(xml_op, PCMK__XA_OP_RESTART_DIGEST) == NULL) {
     270           0 :         return;
     271             :     }
     272             : 
     273             :     // Start with a copy of all parameters
     274           0 :     data->params_restart = pcmk__xml_copy(NULL, data->params_all);
     275             : 
     276             :     // Then filter out reloadable parameters, if any
     277           0 :     value = crm_element_value(xml_op, PCMK__XA_OP_FORCE_RESTART);
     278           0 :     if (value != NULL) {
     279           0 :         pcmk__xe_remove_matching_attrs(data->params_restart, attr_not_in_string,
     280             :                                        (void *) value);
     281             :     }
     282             : 
     283           0 :     value = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
     284           0 :     data->digest_restart_calc = calculate_operation_digest(data->params_restart,
     285             :                                                            value);
     286             : }
     287             : 
     288             : /*!
     289             :  * \internal
     290             :  * \brief Create a new digest cache entry with calculated digests
     291             :  *
     292             :  * \param[in,out] rsc          Resource that action was for
     293             :  * \param[in]     task         Name of action performed
     294             :  * \param[in,out] interval_ms  Action's interval (will be reset if in overrides)
     295             :  * \param[in]     node         Node action was performed on
     296             :  * \param[in]     xml_op       XML of operation in CIB status (if available)
     297             :  * \param[in]     overrides    Key/value table to override resource parameters
     298             :  * \param[in]     calc_secure  Whether to calculate secure digest
     299             :  * \param[in,out] scheduler    Scheduler data
     300             :  *
     301             :  * \return Pointer to new digest cache entry (or NULL on memory error)
     302             :  * \note It is the caller's responsibility to free the result using
     303             :  *       pe__free_digests().
     304             :  */
     305             : pcmk__op_digest_t *
     306           0 : pe__calculate_digests(pcmk_resource_t *rsc, const char *task,
     307             :                       guint *interval_ms, const pcmk_node_t *node,
     308             :                       const xmlNode *xml_op, GHashTable *overrides,
     309             :                       bool calc_secure, pcmk_scheduler_t *scheduler)
     310             : {
     311           0 :     pcmk__op_digest_t *data = NULL;
     312           0 :     const char *op_version = NULL;
     313           0 :     GHashTable *params = NULL;
     314             : 
     315           0 :     CRM_CHECK(scheduler != NULL, return NULL);
     316             : 
     317           0 :     data = calloc(1, sizeof(pcmk__op_digest_t));
     318           0 :     if (data == NULL) {
     319           0 :         pcmk__sched_err("Could not allocate memory for operation digest");
     320           0 :         return NULL;
     321             :     }
     322             : 
     323           0 :     data->rc = pcmk__digest_match;
     324             : 
     325           0 :     if (xml_op != NULL) {
     326           0 :         op_version = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
     327             :     }
     328             : 
     329           0 :     if ((op_version == NULL) && (scheduler->input != NULL)) {
     330           0 :         op_version = crm_element_value(scheduler->input,
     331             :                                        PCMK_XA_CRM_FEATURE_SET);
     332             :     }
     333             : 
     334           0 :     if (op_version == NULL) {
     335           0 :         op_version = CRM_FEATURE_SET;
     336             :     }
     337             : 
     338           0 :     params = pe_rsc_params(rsc, node, scheduler);
     339           0 :     calculate_main_digest(data, rsc, node, params, task, interval_ms, xml_op,
     340             :                           op_version, overrides, scheduler);
     341           0 :     if (calc_secure) {
     342           0 :         calculate_secure_digest(data, rsc, params, xml_op, op_version,
     343             :                                 overrides);
     344             :     }
     345           0 :     calculate_restart_digest(data, xml_op, op_version);
     346           0 :     return data;
     347             : }
     348             : 
     349             : /*!
     350             :  * \internal
     351             :  * \brief Calculate action digests and store in node's digest cache
     352             :  *
     353             :  * \param[in,out] rsc          Resource that action was for
     354             :  * \param[in]     task         Name of action performed
     355             :  * \param[in]     interval_ms  Action's interval
     356             :  * \param[in,out] node         Node action was performed on
     357             :  * \param[in]     xml_op       XML of operation in CIB status (if available)
     358             :  * \param[in]     calc_secure  Whether to calculate secure digest
     359             :  * \param[in,out] scheduler    Scheduler data
     360             :  *
     361             :  * \return Pointer to node's digest cache entry
     362             :  */
     363             : static pcmk__op_digest_t *
     364           0 : rsc_action_digest(pcmk_resource_t *rsc, const char *task, guint interval_ms,
     365             :                   pcmk_node_t *node, const xmlNode *xml_op,
     366             :                   bool calc_secure, pcmk_scheduler_t *scheduler)
     367             : {
     368           0 :     pcmk__op_digest_t *data = NULL;
     369           0 :     char *key = pcmk__op_key(rsc->id, task, interval_ms);
     370             : 
     371           0 :     data = g_hash_table_lookup(node->details->digest_cache, key);
     372           0 :     if (data == NULL) {
     373           0 :         data = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
     374             :                                      NULL, calc_secure, scheduler);
     375           0 :         CRM_ASSERT(data != NULL);
     376           0 :         g_hash_table_insert(node->details->digest_cache, strdup(key), data);
     377             :     }
     378           0 :     free(key);
     379           0 :     return data;
     380             : }
     381             : 
     382             : /*!
     383             :  * \internal
     384             :  * \brief Calculate operation digests and compare against an XML history entry
     385             :  *
     386             :  * \param[in,out] rsc        Resource to check
     387             :  * \param[in]     xml_op     Resource history XML
     388             :  * \param[in,out] node       Node to use for digest calculation
     389             :  * \param[in,out] scheduler  Scheduler data
     390             :  *
     391             :  * \return Pointer to node's digest cache entry, with comparison result set
     392             :  */
     393             : pcmk__op_digest_t *
     394           0 : rsc_action_digest_cmp(pcmk_resource_t *rsc, const xmlNode *xml_op,
     395             :                       pcmk_node_t *node, pcmk_scheduler_t *scheduler)
     396             : {
     397           0 :     pcmk__op_digest_t *data = NULL;
     398           0 :     guint interval_ms = 0;
     399             : 
     400             :     const char *op_version;
     401           0 :     const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
     402             :     const char *digest_all;
     403             :     const char *digest_restart;
     404             : 
     405           0 :     CRM_ASSERT(node != NULL);
     406             : 
     407           0 :     op_version = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
     408           0 :     digest_all = crm_element_value(xml_op, PCMK__XA_OP_DIGEST);
     409           0 :     digest_restart = crm_element_value(xml_op, PCMK__XA_OP_RESTART_DIGEST);
     410             : 
     411           0 :     crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
     412           0 :     data = rsc_action_digest(rsc, task, interval_ms, node, xml_op,
     413           0 :                              pcmk_is_set(scheduler->flags,
     414             :                                          pcmk_sched_sanitized),
     415             :                              scheduler);
     416             : 
     417           0 :     if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
     418           0 :         pcmk__rsc_info(rsc,
     419             :                        "Parameters to %ums-interval %s action for %s on %s "
     420             :                        "changed: hash was %s vs. now %s (restart:%s) %s",
     421             :                        interval_ms, task, rsc->id, pcmk__node_name(node),
     422             :                        pcmk__s(digest_restart, "missing"),
     423             :                        data->digest_restart_calc, op_version,
     424             :                        crm_element_value(xml_op, PCMK__XA_TRANSITION_MAGIC));
     425           0 :         data->rc = pcmk__digest_restart;
     426             : 
     427           0 :     } else if (digest_all == NULL) {
     428             :         /* it is unknown what the previous op digest was */
     429           0 :         data->rc = pcmk__digest_unknown;
     430             : 
     431           0 :     } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
     432             :         /* Given a non-recurring operation with extra parameters configured,
     433             :          * in case that the main digest doesn't match, even if the restart
     434             :          * digest matches, enforce a restart rather than a reload-agent anyway.
     435             :          * So that it ensures any changes of the extra parameters get applied
     436             :          * for this specific operation, and the digests calculated for the
     437             :          * resulting PCMK__XE_LRM_RSC_OP will be correct.
     438             :          * Preserve the implied rc pcmk__digest_restart for the case that the
     439             :          * main digest doesn't match.
     440             :          */
     441           0 :         if ((interval_ms == 0) && (data->rc == pcmk__digest_restart)) {
     442           0 :             pcmk__rsc_info(rsc,
     443             :                            "Parameters containing extra ones to %ums-interval"
     444             :                            " %s action for %s on %s "
     445             :                            "changed: hash was %s vs. now %s (restart:%s) %s",
     446             :                            interval_ms, task, rsc->id, pcmk__node_name(node),
     447             :                            pcmk__s(digest_all, "missing"),
     448             :                            data->digest_all_calc, op_version,
     449             :                            crm_element_value(xml_op,
     450             :                                              PCMK__XA_TRANSITION_MAGIC));
     451             : 
     452             :         } else {
     453           0 :             pcmk__rsc_info(rsc,
     454             :                            "Parameters to %ums-interval %s action for %s on %s "
     455             :                            "changed: hash was %s vs. now %s (%s:%s) %s",
     456             :                            interval_ms, task, rsc->id, pcmk__node_name(node),
     457             :                            pcmk__s(digest_all, "missing"),
     458             :                            data->digest_all_calc,
     459             :                            (interval_ms > 0)? "reschedule" : "reload",
     460             :                            op_version,
     461             :                            crm_element_value(xml_op,
     462             :                                              PCMK__XA_TRANSITION_MAGIC));
     463           0 :             data->rc = pcmk__digest_mismatch;
     464             :         }
     465             : 
     466             :     } else {
     467           0 :         data->rc = pcmk__digest_match;
     468             :     }
     469           0 :     return data;
     470             : }
     471             : 
     472             : /*!
     473             :  * \internal
     474             :  * \brief Create an unfencing summary for use in special node attribute
     475             :  *
     476             :  * Create a string combining a fence device's resource ID, agent type, and
     477             :  * parameter digest (whether for all parameters or just non-private parameters).
     478             :  * This can be stored in a special node attribute, allowing us to detect changes
     479             :  * in either the agent type or parameters, to know whether unfencing must be
     480             :  * redone or can be safely skipped when the device's history is cleaned.
     481             :  *
     482             :  * \param[in] rsc_id        Fence device resource ID
     483             :  * \param[in] agent_type    Fence device agent
     484             :  * \param[in] param_digest  Fence device parameter digest
     485             :  *
     486             :  * \return Newly allocated string with unfencing digest
     487             :  * \note The caller is responsible for freeing the result.
     488             :  */
     489             : static inline char *
     490           0 : create_unfencing_summary(const char *rsc_id, const char *agent_type,
     491             :                          const char *param_digest)
     492             : {
     493           0 :     return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
     494             : }
     495             : 
     496             : /*!
     497             :  * \internal
     498             :  * \brief Check whether a node can skip unfencing
     499             :  *
     500             :  * Check whether a fence device's current definition matches a node's
     501             :  * stored summary of when it was last unfenced by the device.
     502             :  *
     503             :  * \param[in] rsc_id        Fence device's resource ID
     504             :  * \param[in] agent         Fence device's agent type
     505             :  * \param[in] digest_calc   Fence device's current parameter digest
     506             :  * \param[in] node_summary  Value of node's special unfencing node attribute
     507             :  *                          (a comma-separated list of unfencing summaries for
     508             :  *                          all devices that have unfenced this node)
     509             :  *
     510             :  * \return TRUE if digest matches, FALSE otherwise
     511             :  */
     512             : static bool
     513           0 : unfencing_digest_matches(const char *rsc_id, const char *agent,
     514             :                          const char *digest_calc, const char *node_summary)
     515             : {
     516           0 :     bool matches = FALSE;
     517             : 
     518           0 :     if (rsc_id && agent && digest_calc && node_summary) {
     519           0 :         char *search_secure = create_unfencing_summary(rsc_id, agent,
     520             :                                                        digest_calc);
     521             : 
     522             :         /* The digest was calculated including the device ID and agent,
     523             :          * so there is no risk of collision using strstr().
     524             :          */
     525           0 :         matches = (strstr(node_summary, search_secure) != NULL);
     526           0 :         crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
     527             :                   search_secure, matches? "" : "not ", node_summary);
     528           0 :         free(search_secure);
     529             :     }
     530           0 :     return matches;
     531             : }
     532             : 
     533             : /* Magic string to use as action name for digest cache entries used for
     534             :  * unfencing checks. This is not a real action name (i.e. "on"), so
     535             :  * pcmk__check_action_config() won't confuse these entries with real actions.
     536             :  */
     537             : #define STONITH_DIGEST_TASK "stonith-on"
     538             : 
     539             : /*!
     540             :  * \internal
     541             :  * \brief Calculate fence device digests and digest comparison result
     542             :  *
     543             :  * \param[in,out] rsc        Fence device resource
     544             :  * \param[in]     agent      Fence device's agent type
     545             :  * \param[in,out] node       Node with digest cache to use
     546             :  * \param[in,out] scheduler  Scheduler data
     547             :  *
     548             :  * \return Node's digest cache entry
     549             :  */
     550             : pcmk__op_digest_t *
     551           0 : pe__compare_fencing_digest(pcmk_resource_t *rsc, const char *agent,
     552             :                            pcmk_node_t *node, pcmk_scheduler_t *scheduler)
     553             : {
     554           0 :     const char *node_summary = NULL;
     555             : 
     556             :     // Calculate device's current parameter digests
     557           0 :     pcmk__op_digest_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, 0U,
     558             :                                                 node, NULL, TRUE, scheduler);
     559             : 
     560             :     // Check whether node has special unfencing summary node attribute
     561           0 :     node_summary = pcmk__node_attr(node, CRM_ATTR_DIGESTS_ALL, NULL,
     562             :                                    pcmk__rsc_node_current);
     563           0 :     if (node_summary == NULL) {
     564           0 :         data->rc = pcmk__digest_unknown;
     565           0 :         return data;
     566             :     }
     567             : 
     568             :     // Check whether full parameter digest matches
     569           0 :     if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
     570             :                                  node_summary)) {
     571           0 :         data->rc = pcmk__digest_match;
     572           0 :         return data;
     573             :     }
     574             : 
     575             :     // Check whether secure parameter digest matches
     576           0 :     node_summary = pcmk__node_attr(node, CRM_ATTR_DIGESTS_SECURE, NULL,
     577             :                                    pcmk__rsc_node_current);
     578           0 :     if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
     579             :                                  node_summary)) {
     580           0 :         data->rc = pcmk__digest_match;
     581           0 :         if (!pcmk__is_daemon && scheduler->priv != NULL) {
     582           0 :             pcmk__output_t *out = scheduler->priv;
     583           0 :             out->info(out, "Only 'private' parameters to %s "
     584             :                       "for unfencing %s changed", rsc->id,
     585             :                       pcmk__node_name(node));
     586             :         }
     587           0 :         return data;
     588             :     }
     589             : 
     590             :     // Parameters don't match
     591           0 :     data->rc = pcmk__digest_mismatch;
     592           0 :     if (pcmk_is_set(scheduler->flags, pcmk_sched_sanitized)
     593           0 :         && (data->digest_secure_calc != NULL)) {
     594             : 
     595           0 :         if (scheduler->priv != NULL) {
     596           0 :             pcmk__output_t *out = scheduler->priv;
     597           0 :             char *digest = create_unfencing_summary(rsc->id, agent,
     598           0 :                                                     data->digest_secure_calc);
     599             : 
     600           0 :             out->info(out, "Parameters to %s for unfencing "
     601             :                       "%s changed, try '%s'", rsc->id,
     602             :                       pcmk__node_name(node), digest);
     603           0 :             free(digest);
     604           0 :         } else if (!pcmk__is_daemon) {
     605           0 :             char *digest = create_unfencing_summary(rsc->id, agent,
     606           0 :                                                     data->digest_secure_calc);
     607             : 
     608           0 :             printf("Parameters to %s for unfencing %s changed, try '%s'\n",
     609             :                    rsc->id, pcmk__node_name(node), digest);
     610           0 :             free(digest);
     611             :         }
     612             :     }
     613           0 :     return data;
     614             : }

Generated by: LCOV version 1.14