root/daemons/fenced/fenced_cib.c

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

DEFINITIONS

This source file includes following definitions.
  1. node_has_attr
  2. add_topology_level
  3. topology_remove_helper
  4. remove_topology_level
  5. register_fencing_topology
  6. fencing_topology_init
  7. remove_cib_device
  8. update_stonith_watchdog_timeout_ms
  9. cib_devices_update
  10. update_cib_stonith_devices_v1
  11. update_cib_stonith_devices_v2
  12. update_cib_stonith_devices
  13. watchdog_device_update
  14. fenced_query_cib
  15. remove_fencing_topology
  16. update_fencing_topology
  17. update_cib_cache_cb
  18. init_cib_cache_cb
  19. cib_connection_destroy
  20. fenced_cib_cleanup
  21. setup_cib

   1 /*
   2  * Copyright 2009-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8 */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdbool.h>
  13 #include <stdio.h>
  14 #include <libxml/tree.h>
  15 #include <libxml/xpath.h>
  16 
  17 #include <crm/crm.h>
  18 #include <crm/common/xml.h>
  19 
  20 #include <crm/cluster/internal.h>
  21 
  22 #include <crm/cib.h>
  23 #include <crm/cib/internal.h>
  24 
  25 #include <pacemaker-fenced.h>
  26 
  27 static xmlNode *local_cib = NULL;
  28 static cib_t *cib_api = NULL;
  29 static bool have_cib_devices = FALSE;
  30 
  31 /*!
  32  * \internal
  33  * \brief Check whether a node has a specific attribute name/value
  34  *
  35  * \param[in] node    Name of node to check
  36  * \param[in] name    Name of an attribute to look for
  37  * \param[in] value   The value the named attribute needs to be set to in order to be considered a match
  38  *
  39  * \return TRUE if the locally cached CIB has the specified node attribute
  40  */
  41 gboolean
  42 node_has_attr(const char *node, const char *name, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44     GString *xpath = NULL;
  45     xmlNode *match;
  46 
  47     CRM_CHECK((local_cib != NULL) && (node != NULL) && (name != NULL)
  48               && (value != NULL), return FALSE);
  49 
  50     /* Search for the node's attributes in the CIB. While the schema allows
  51      * multiple sets of instance attributes, and allows instance attributes to
  52      * use id-ref to reference values elsewhere, that is intended for resources,
  53      * so we ignore that here.
  54      */
  55     xpath = g_string_sized_new(256);
  56     pcmk__g_strcat(xpath,
  57                    "//" PCMK_XE_NODES "/" PCMK_XE_NODE
  58                    "[@" PCMK_XA_UNAME "='", node, "']"
  59                    "/" PCMK_XE_INSTANCE_ATTRIBUTES
  60                    "/" PCMK_XE_NVPAIR
  61                    "[@" PCMK_XA_NAME "='", name, "' "
  62                    "and @" PCMK_XA_VALUE "='", value, "']", NULL);
  63 
  64     match = get_xpath_object((const char *) xpath->str, local_cib, LOG_NEVER);
  65 
  66     g_string_free(xpath, TRUE);
  67     return (match != NULL);
  68 }
  69 
  70 static void
  71 add_topology_level(xmlNode *match)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73     char *desc = NULL;
  74     pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
  75 
  76     CRM_CHECK(match != NULL, return);
  77 
  78     fenced_register_level(match, &desc, &result);
  79     fenced_send_config_notification(STONITH_OP_LEVEL_ADD, &result, desc);
  80     pcmk__reset_result(&result);
  81     free(desc);
  82 }
  83 
  84 static void
  85 topology_remove_helper(const char *node, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87     char *desc = NULL;
  88     pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
  89     xmlNode *data = pcmk__xe_create(NULL, PCMK_XE_FENCING_LEVEL);
  90 
  91     crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
  92     crm_xml_add_int(data, PCMK_XA_INDEX, level);
  93     crm_xml_add(data, PCMK_XA_TARGET, node);
  94 
  95     fenced_unregister_level(data, &desc, &result);
  96     fenced_send_config_notification(STONITH_OP_LEVEL_DEL, &result, desc);
  97     pcmk__reset_result(&result);
  98     free_xml(data);
  99     free(desc);
 100 }
 101 
 102 static void
 103 remove_topology_level(xmlNode *match)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105     int index = 0;
 106     char *key = NULL;
 107 
 108     CRM_CHECK(match != NULL, return);
 109 
 110     key = stonith_level_key(match, fenced_target_by_unknown);
 111     crm_element_value_int(match, PCMK_XA_INDEX, &index);
 112     topology_remove_helper(key, index);
 113     free(key);
 114 }
 115 
 116 static void
 117 register_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119     int max = numXpathResults(xpathObj), lpc = 0;
 120 
 121     for (lpc = 0; lpc < max; lpc++) {
 122         xmlNode *match = getXpathResult(xpathObj, lpc);
 123 
 124         remove_topology_level(match);
 125         add_topology_level(match);
 126     }
 127 }
 128 
 129 /* Fencing
 130 <diff crm_feature_set="3.0.6">
 131   <diff-removed>
 132     <fencing-topology>
 133       <fencing-level id="f-p1.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="removed:top"/>
 134       <fencing-level id="f-p1.2" target="pcmk-1" index="2" devices="power" __crm_diff_marker__="removed:top"/>
 135       <fencing-level devices="disk,network" id="f-p2.1"/>
 136     </fencing-topology>
 137   </diff-removed>
 138   <diff-added>
 139     <fencing-topology>
 140       <fencing-level id="f-p.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="added:top"/>
 141       <fencing-level id="f-p2.1" target="pcmk-2" index="1" devices="disk,something"/>
 142       <fencing-level id="f-p3.1" target="pcmk-2" index="2" devices="power" __crm_diff_marker__="added:top"/>
 143     </fencing-topology>
 144   </diff-added>
 145 </diff>
 146 */
 147 
 148 void
 149 fencing_topology_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151     xmlXPathObjectPtr xpathObj = NULL;
 152     const char *xpath = "//" PCMK_XE_FENCING_LEVEL;
 153 
 154     crm_trace("Full topology refresh");
 155     free_topology_list();
 156     init_topology_list();
 157 
 158     /* Grab everything */
 159     xpathObj = xpath_search(local_cib, xpath);
 160     register_fencing_topology(xpathObj);
 161 
 162     freeXpathObject(xpathObj);
 163 }
 164 
 165 static void
 166 remove_cib_device(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     int max = numXpathResults(xpathObj), lpc = 0;
 169 
 170     for (lpc = 0; lpc < max; lpc++) {
 171         const char *rsc_id = NULL;
 172         const char *standard = NULL;
 173         xmlNode *match = getXpathResult(xpathObj, lpc);
 174 
 175         CRM_LOG_ASSERT(match != NULL);
 176         if(match != NULL) {
 177             standard = crm_element_value(match, PCMK_XA_CLASS);
 178         }
 179 
 180         if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 181             continue;
 182         }
 183 
 184         rsc_id = crm_element_value(match, PCMK_XA_ID);
 185 
 186         stonith_device_remove(rsc_id, true);
 187     }
 188 }
 189 
 190 #define XPATH_WATCHDOG_TIMEOUT "//" PCMK_XE_NVPAIR      \
 191                                "[@" PCMK_XA_NAME "='"   \
 192                                     PCMK_OPT_STONITH_WATCHDOG_TIMEOUT "']"
 193 
 194 static void
 195 update_stonith_watchdog_timeout_ms(xmlNode *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197     long long timeout_ms = 0;
 198     xmlNode *stonith_watchdog_xml = NULL;
 199     const char *value = NULL;
 200 
 201     stonith_watchdog_xml = get_xpath_object(XPATH_WATCHDOG_TIMEOUT, cib,
 202                                             LOG_NEVER);
 203     if (stonith_watchdog_xml) {
 204         value = crm_element_value(stonith_watchdog_xml, PCMK_XA_VALUE);
 205     }
 206     if (value) {
 207         timeout_ms = crm_get_msec(value);
 208     }
 209 
 210     if (timeout_ms < 0) {
 211         timeout_ms = pcmk__auto_stonith_watchdog_timeout();
 212     }
 213 
 214     stonith_watchdog_timeout_ms = timeout_ms;
 215 }
 216 
 217 /*!
 218  * \internal
 219  * \brief Update all STONITH device definitions based on current CIB
 220  */
 221 static void
 222 cib_devices_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     GHashTableIter iter;
 225     stonith_device_t *device = NULL;
 226 
 227     crm_info("Updating devices to version %s.%s.%s",
 228              crm_element_value(local_cib, PCMK_XA_ADMIN_EPOCH),
 229              crm_element_value(local_cib, PCMK_XA_EPOCH),
 230              crm_element_value(local_cib, PCMK_XA_NUM_UPDATES));
 231 
 232     g_hash_table_iter_init(&iter, device_list);
 233     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 234         if (device->cib_registered) {
 235             device->dirty = TRUE;
 236         }
 237     }
 238 
 239     /* have list repopulated if cib has a watchdog-fencing-resource
 240        TODO: keep a cached list for queries happening while we are refreshing
 241      */
 242     g_list_free_full(stonith_watchdog_targets, free);
 243     stonith_watchdog_targets = NULL;
 244 
 245     fenced_scheduler_run(local_cib);
 246 
 247     g_hash_table_iter_init(&iter, device_list);
 248     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 249         if (device->dirty) {
 250             g_hash_table_iter_remove(&iter);
 251         }
 252     }
 253 }
 254 
 255 static void
 256 update_cib_stonith_devices_v1(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258     const char *reason = "none";
 259     gboolean needs_update = FALSE;
 260     xmlXPathObjectPtr xpath_obj = NULL;
 261 
 262     /* process new constraints */
 263     xpath_obj = xpath_search(msg,
 264                              "//" PCMK__XE_CIB_UPDATE_RESULT
 265                              "//" PCMK_XE_RSC_LOCATION);
 266     if (numXpathResults(xpath_obj) > 0) {
 267         int max = numXpathResults(xpath_obj), lpc = 0;
 268 
 269         /* Safest and simplest to always recompute */
 270         needs_update = TRUE;
 271         reason = "new location constraint";
 272 
 273         for (lpc = 0; lpc < max; lpc++) {
 274             xmlNode *match = getXpathResult(xpath_obj, lpc);
 275 
 276             crm_log_xml_trace(match, "new constraint");
 277         }
 278     }
 279     freeXpathObject(xpath_obj);
 280 
 281     /* process deletions */
 282     xpath_obj = xpath_search(msg,
 283                              "//" PCMK__XE_CIB_UPDATE_RESULT
 284                              "//" PCMK__XE_DIFF_REMOVED
 285                              "//" PCMK_XE_PRIMITIVE);
 286     if (numXpathResults(xpath_obj) > 0) {
 287         remove_cib_device(xpath_obj);
 288     }
 289     freeXpathObject(xpath_obj);
 290 
 291     /* process additions */
 292     xpath_obj = xpath_search(msg,
 293                              "//" PCMK__XE_CIB_UPDATE_RESULT
 294                              "//" PCMK__XE_DIFF_ADDED
 295                              "//" PCMK_XE_PRIMITIVE);
 296     if (numXpathResults(xpath_obj) > 0) {
 297         int max = numXpathResults(xpath_obj), lpc = 0;
 298 
 299         for (lpc = 0; lpc < max; lpc++) {
 300             const char *rsc_id = NULL;
 301             const char *standard = NULL;
 302             xmlNode *match = getXpathResult(xpath_obj, lpc);
 303 
 304             rsc_id = crm_element_value(match, PCMK_XA_ID);
 305             standard = crm_element_value(match, PCMK_XA_CLASS);
 306 
 307             if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 308                 continue;
 309             }
 310 
 311             crm_trace("Fencing resource %s was added or modified", rsc_id);
 312             reason = "new resource";
 313             needs_update = TRUE;
 314         }
 315     }
 316     freeXpathObject(xpath_obj);
 317 
 318     if(needs_update) {
 319         crm_info("Updating device list from CIB: %s", reason);
 320         cib_devices_update();
 321     }
 322 }
 323 
 324 static void
 325 update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327     xmlNode *change = NULL;
 328     char *reason = NULL;
 329     xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
 330                                             NULL, NULL);
 331     xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 332 
 333     for (change = pcmk__xe_first_child(patchset, NULL, NULL, NULL);
 334          change != NULL; change = pcmk__xe_next(change)) {
 335 
 336         const char *op = crm_element_value(change, PCMK_XA_OPERATION);
 337         const char *xpath = crm_element_value(change, PCMK_XA_PATH);
 338         const char *shortpath = NULL;
 339 
 340         if (pcmk__str_eq(op, PCMK_VALUE_MOVE, pcmk__str_null_matches)
 341             || (strstr(xpath, "/" PCMK_XE_STATUS) != NULL)) {
 342             continue;
 343         }
 344 
 345         if (pcmk__str_eq(op, PCMK_VALUE_DELETE, pcmk__str_none)
 346             && (strstr(xpath, "/" PCMK_XE_PRIMITIVE) != NULL)) {
 347             const char *rsc_id = NULL;
 348             char *search = NULL;
 349             char *mutable = NULL;
 350 
 351             if ((strstr(xpath, PCMK_XE_INSTANCE_ATTRIBUTES) != NULL)
 352                 || (strstr(xpath, PCMK_XE_META_ATTRIBUTES) != NULL)) {
 353 
 354                 reason = pcmk__str_copy("(meta) attribute deleted from "
 355                                         "resource");
 356                 break;
 357             }
 358             mutable = pcmk__str_copy(xpath);
 359             rsc_id = strstr(mutable, PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
 360             if (rsc_id != NULL) {
 361                 rsc_id += strlen(PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
 362                 search = strchr(rsc_id, '\'');
 363             }
 364             if (search != NULL) {
 365                 *search = 0;
 366                 stonith_device_remove(rsc_id, true);
 367                 /* watchdog_device_update called afterwards
 368                    to fall back to implicit definition if needed */
 369             } else {
 370                 crm_warn("Ignoring malformed CIB update (resource deletion)");
 371             }
 372             free(mutable);
 373 
 374         } else if (strstr(xpath, "/" PCMK_XE_RESOURCES)
 375                    || strstr(xpath, "/" PCMK_XE_CONSTRAINTS)
 376                    || strstr(xpath, "/" PCMK_XE_RSC_DEFAULTS)) {
 377             shortpath = strrchr(xpath, '/');
 378             pcmk__assert(shortpath != NULL);
 379             reason = crm_strdup_printf("%s %s", op, shortpath+1);
 380             break;
 381         }
 382     }
 383 
 384     if (reason != NULL) {
 385         crm_info("Updating device list from CIB: %s", reason);
 386         cib_devices_update();
 387         free(reason);
 388     } else {
 389         crm_trace("No updates for device list found in CIB");
 390     }
 391 }
 392 
 393 static void
 394 update_cib_stonith_devices(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396     int format = 1;
 397     xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
 398                                             NULL, NULL);
 399     xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 400 
 401     pcmk__assert(patchset != NULL);
 402     crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
 403     switch(format) {
 404         case 1:
 405             update_cib_stonith_devices_v1(event, msg);
 406             break;
 407         case 2:
 408             update_cib_stonith_devices_v2(event, msg);
 409             break;
 410         default:
 411             crm_warn("Unknown patch format: %d", format);
 412     }
 413 }
 414 
 415 static void
 416 watchdog_device_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418     if (stonith_watchdog_timeout_ms > 0) {
 419         if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
 420             !stonith_watchdog_targets) {
 421             /* getting here watchdog-fencing enabled, no device there yet
 422                and reason isn't stonith_watchdog_targets preventing that
 423              */
 424             int rc;
 425             xmlNode *xml;
 426 
 427             xml = create_device_registration_xml(
 428                     STONITH_WATCHDOG_ID,
 429                     st_namespace_internal,
 430                     STONITH_WATCHDOG_AGENT,
 431                     NULL, /* stonith_device_register will add our
 432                              own name as PCMK_STONITH_HOST_LIST param
 433                              so we can skip that here
 434                            */
 435                     NULL);
 436             rc = stonith_device_register(xml, TRUE);
 437             free_xml(xml);
 438             if (rc != pcmk_ok) {
 439                 rc = pcmk_legacy2rc(rc);
 440                 exit_code = CRM_EX_FATAL;
 441                 crm_crit("Cannot register watchdog pseudo fence agent: %s",
 442                          pcmk_rc_str(rc));
 443                 stonith_shutdown(0);
 444             }
 445         }
 446 
 447     } else if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) != NULL) {
 448         /* be silent if no device - todo parameter to stonith_device_remove */
 449         stonith_device_remove(STONITH_WATCHDOG_ID, true);
 450     }
 451 }
 452 
 453 /*!
 454  * \internal
 455  * \brief Query the full CIB
 456  *
 457  * \return Standard Pacemaker return code
 458  */
 459 static int
 460 fenced_query_cib(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 461 {
 462     int rc = pcmk_ok;
 463 
 464     crm_trace("Re-requesting full CIB");
 465     rc = cib_api->cmds->query(cib_api, NULL, &local_cib,
 466                               cib_scope_local|cib_sync_call);
 467     rc = pcmk_legacy2rc(rc);
 468     if (rc == pcmk_rc_ok) {
 469         pcmk__assert(local_cib != NULL);
 470     } else {
 471         crm_err("Couldn't retrieve the CIB: %s " CRM_XS " rc=%d",
 472                 pcmk_rc_str(rc), rc);
 473     }
 474     return rc;
 475 }
 476 
 477 static void
 478 remove_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480     int max = numXpathResults(xpathObj), lpc = 0;
 481 
 482     for (lpc = 0; lpc < max; lpc++) {
 483         xmlNode *match = getXpathResult(xpathObj, lpc);
 484 
 485         CRM_LOG_ASSERT(match != NULL);
 486         if (match && crm_element_value(match, PCMK__XA_CRM_DIFF_MARKER)) {
 487             /* Deletion */
 488             int index = 0;
 489             char *target = stonith_level_key(match, fenced_target_by_unknown);
 490 
 491             crm_element_value_int(match, PCMK_XA_INDEX, &index);
 492             if (target == NULL) {
 493                 crm_err("Invalid fencing target in element %s",
 494                         pcmk__xe_id(match));
 495 
 496             } else if (index <= 0) {
 497                 crm_err("Invalid level for %s in element %s",
 498                         target, pcmk__xe_id(match));
 499 
 500             } else {
 501                 topology_remove_helper(target, index);
 502             }
 503             /* } else { Deal with modifications during the 'addition' stage */
 504         }
 505     }
 506 }
 507 
 508 static void
 509 update_fencing_topology(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 510 {
 511     int format = 1;
 512     const char *xpath;
 513     xmlXPathObjectPtr xpathObj = NULL;
 514     xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
 515                                             NULL, NULL);
 516     xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 517 
 518     pcmk__assert(patchset != NULL);
 519     crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
 520 
 521     if(format == 1) {
 522         /* Process deletions (only) */
 523         xpath = "//" PCMK__XE_CIB_UPDATE_RESULT
 524                 "//" PCMK__XE_DIFF_REMOVED
 525                 "//" PCMK_XE_FENCING_LEVEL;
 526         xpathObj = xpath_search(msg, xpath);
 527 
 528         remove_fencing_topology(xpathObj);
 529         freeXpathObject(xpathObj);
 530 
 531         /* Process additions and changes */
 532         xpath = "//" PCMK__XE_CIB_UPDATE_RESULT
 533                 "//" PCMK__XE_DIFF_ADDED
 534                 "//" PCMK_XE_FENCING_LEVEL;
 535         xpathObj = xpath_search(msg, xpath);
 536 
 537         register_fencing_topology(xpathObj);
 538         freeXpathObject(xpathObj);
 539 
 540     } else if(format == 2) {
 541         xmlNode *change = NULL;
 542         int add[] = { 0, 0, 0 };
 543         int del[] = { 0, 0, 0 };
 544 
 545         xml_patch_versions(patchset, add, del);
 546 
 547         for (change = pcmk__xe_first_child(patchset, NULL, NULL, NULL);
 548              change != NULL; change = pcmk__xe_next(change)) {
 549 
 550             const char *op = crm_element_value(change, PCMK_XA_OPERATION);
 551             const char *xpath = crm_element_value(change, PCMK_XA_PATH);
 552 
 553             if(op == NULL) {
 554                 continue;
 555 
 556             } else if(strstr(xpath, "/" PCMK_XE_FENCING_LEVEL) != NULL) {
 557                 /* Change to a specific entry */
 558 
 559                 crm_trace("Handling %s operation %d.%d.%d for %s", op, add[0], add[1], add[2], xpath);
 560                 if (strcmp(op, PCMK_VALUE_MOVE) == 0) {
 561                     continue;
 562 
 563                 } else if (strcmp(op, PCMK_VALUE_CREATE) == 0) {
 564                     add_topology_level(change->children);
 565 
 566                 } else if (strcmp(op, PCMK_VALUE_MODIFY) == 0) {
 567                     xmlNode *match = pcmk__xe_first_child(change,
 568                                                           PCMK_XE_CHANGE_RESULT,
 569                                                           NULL, NULL);
 570 
 571                     if(match) {
 572                         remove_topology_level(match->children);
 573                         add_topology_level(match->children);
 574                     }
 575 
 576                 } else if (strcmp(op, PCMK_VALUE_DELETE) == 0) {
 577                     /* Nuclear option, all we have is the path and an id... not enough to remove a specific entry */
 578                     crm_info("Re-initializing fencing topology after %s operation %d.%d.%d for %s",
 579                              op, add[0], add[1], add[2], xpath);
 580                     fencing_topology_init();
 581                     return;
 582                 }
 583 
 584             } else if (strstr(xpath, "/" PCMK_XE_FENCING_TOPOLOGY) != NULL) {
 585                 /* Change to the topology in general */
 586                 crm_info("Re-initializing fencing topology after top-level %s operation  %d.%d.%d for %s",
 587                          op, add[0], add[1], add[2], xpath);
 588                 fencing_topology_init();
 589                 return;
 590 
 591             } else if (strstr(xpath, "/" PCMK_XE_CONFIGURATION)) {
 592                 /* Changes to the whole config section, possibly including the topology as a whild */
 593                 if (pcmk__xe_first_child(change, PCMK_XE_FENCING_TOPOLOGY, NULL,
 594                                          NULL) == NULL) {
 595                     crm_trace("Nothing for us in %s operation %d.%d.%d for %s.",
 596                               op, add[0], add[1], add[2], xpath);
 597 
 598                 } else if (pcmk__str_any_of(op,
 599                                             PCMK_VALUE_DELETE,
 600                                             PCMK_VALUE_CREATE, NULL)) {
 601                     crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s.",
 602                              op, add[0], add[1], add[2], xpath);
 603                     fencing_topology_init();
 604                     return;
 605                 }
 606 
 607             } else {
 608                 crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
 609                           op, add[0], add[1], add[2], xpath);
 610             }
 611         }
 612 
 613     } else {
 614         crm_warn("Unknown patch format: %d", format);
 615     }
 616 }
 617 
 618 static void
 619 update_cib_cache_cb(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 620 {
 621     long long timeout_ms_saved = stonith_watchdog_timeout_ms;
 622     bool need_full_refresh = false;
 623 
 624     if(!have_cib_devices) {
 625         crm_trace("Skipping updates until we get a full dump");
 626         return;
 627 
 628     } else if(msg == NULL) {
 629         crm_trace("Missing %s update", event);
 630         return;
 631     }
 632 
 633     /* Maintain a local copy of the CIB so that we have full access
 634      * to device definitions, location constraints, and node attributes
 635      */
 636     if (local_cib != NULL) {
 637         int rc = pcmk_ok;
 638         xmlNode *wrapper = NULL;
 639         xmlNode *patchset = NULL;
 640 
 641         crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc);
 642         if (rc != pcmk_ok) {
 643             return;
 644         }
 645 
 646         wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT, NULL,
 647                                        NULL);
 648         patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 649 
 650         rc = xml_apply_patchset(local_cib, patchset, TRUE);
 651         switch (rc) {
 652             case pcmk_ok:
 653             case -pcmk_err_old_data:
 654                 break;
 655             case -pcmk_err_diff_resync:
 656             case -pcmk_err_diff_failed:
 657                 crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
 658                 free_xml(local_cib);
 659                 local_cib = NULL;
 660                 break;
 661             default:
 662                 crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
 663                 free_xml(local_cib);
 664                 local_cib = NULL;
 665         }
 666     }
 667 
 668     if (local_cib == NULL) {
 669         if (fenced_query_cib() != pcmk_rc_ok) {
 670             return;
 671         }
 672         need_full_refresh = true;
 673     }
 674 
 675     pcmk__refresh_node_caches_from_cib(local_cib);
 676     update_stonith_watchdog_timeout_ms(local_cib);
 677 
 678     if (timeout_ms_saved != stonith_watchdog_timeout_ms) {
 679         need_full_refresh = true;
 680     }
 681 
 682     if (need_full_refresh) {
 683         fencing_topology_init();
 684         cib_devices_update();
 685     } else {
 686         // Partial refresh
 687         update_fencing_topology(event, msg);
 688         update_cib_stonith_devices(event, msg);
 689     }
 690 
 691     watchdog_device_update();
 692 }
 693 
 694 static void
 695 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 696 {
 697     crm_info("Updating device list from CIB");
 698     have_cib_devices = TRUE;
 699     local_cib = pcmk__xml_copy(NULL, output);
 700 
 701     pcmk__refresh_node_caches_from_cib(local_cib);
 702     update_stonith_watchdog_timeout_ms(local_cib);
 703 
 704     fencing_topology_init();
 705     cib_devices_update();
 706     watchdog_device_update();
 707 }
 708 
 709 static void
 710 cib_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 711 {
 712     if (stonith_shutdown_flag) {
 713         crm_info("Connection to the CIB manager closed");
 714         return;
 715     } else {
 716         crm_crit("Lost connection to the CIB manager, shutting down");
 717     }
 718     if (cib_api) {
 719         cib_api->cmds->signoff(cib_api);
 720     }
 721     stonith_shutdown(0);
 722 }
 723 
 724 /*!
 725  * \internal
 726  * \brief Disconnect from CIB manager
 727  */
 728 void
 729 fenced_cib_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 730 {
 731     if (cib_api != NULL) {
 732         cib_api->cmds->del_notify_callback(cib_api, PCMK__VALUE_CIB_DIFF_NOTIFY,
 733                                            update_cib_cache_cb);
 734         cib__clean_up_connection(&cib_api);
 735     }
 736     free_xml(local_cib);
 737     local_cib = NULL;
 738 }
 739 
 740 void
 741 setup_cib(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 742 {
 743     int rc, retries = 0;
 744 
 745     cib_api = cib_new();
 746     if (cib_api == NULL) {
 747         crm_err("No connection to the CIB manager");
 748         return;
 749     }
 750 
 751     do {
 752         sleep(retries);
 753         rc = cib_api->cmds->signon(cib_api, CRM_SYSTEM_STONITHD, cib_command);
 754     } while (rc == -ENOTCONN && ++retries < 5);
 755 
 756     if (rc != pcmk_ok) {
 757         crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
 758         return;
 759     }
 760 
 761     rc = cib_api->cmds->add_notify_callback(cib_api,
 762                                             PCMK__VALUE_CIB_DIFF_NOTIFY,
 763                                             update_cib_cache_cb);
 764     if (rc != pcmk_ok) {
 765         crm_err("Could not set CIB notification callback");
 766         return;
 767     }
 768 
 769     rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_scope_local);
 770     cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL,
 771                                      "init_cib_cache_cb", init_cib_cache_cb);
 772     cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
 773     crm_info("Watching for fencing topology changes");
 774 }

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