root/lib/pengine/pe_digest.c

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

DEFINITIONS

This source file includes following definitions.
  1. pe__free_digests
  2. attr_not_in_string
  3. attr_in_string
  4. calculate_main_digest
  5. is_fence_param
  6. calculate_secure_digest
  7. calculate_restart_digest
  8. pe__calculate_digests
  9. rsc_action_digest
  10. rsc_action_digest_cmp
  11. create_unfencing_summary
  12. unfencing_digest_matches
  13. pe__compare_fencing_digest

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

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