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_in_string
  3. attr_not_in_string
  4. append_versioned_params
  5. append_all_versioned_params
  6. calculate_main_digest
  7. is_fence_param
  8. calculate_secure_digest
  9. calculate_restart_digest
  10. pe__calculate_digests
  11. rsc_action_digest
  12. rsc_action_digest_cmp
  13. create_unfencing_summary
  14. unfencing_digest_matches
  15. pe__compare_fencing_digest

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

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