root/lib/cluster/corosync.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__corosync_uuid
  2. node_name_is_valid
  3. pcmk__corosync_name
  4. pcmk__corosync_disconnect
  5. quorum_dispatch_cb
  6. quorum_notification_cb
  7. pcmk__corosync_quorum_connect
  8. pcmk__corosync_connect
  9. pcmk__corosync_is_active
  10. pcmk__corosync_is_peer_active
  11. pcmk__corosync_add_nodes
  12. pcmk__corosync_cluster_name
  13. pcmk__corosync_has_nodelist
  14. crm_is_corosync_peer_active

   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 <arpa/inet.h>
  13 #include <inttypes.h>                   // PRIu64, PRIx32
  14 #include <netdb.h>
  15 #include <netinet/in.h>
  16 #include <stdbool.h>
  17 #include <sys/socket.h>
  18 #include <sys/utsname.h>
  19 
  20 #include <bzlib.h>
  21 #include <corosync/cfg.h>
  22 #include <corosync/cmap.h>
  23 #include <corosync/corodefs.h>
  24 #include <corosync/corotypes.h>
  25 #include <corosync/hdb.h>
  26 #include <corosync/quorum.h>
  27 #include <qb/qbipcc.h>
  28 #include <qb/qbutil.h>
  29 
  30 #include <crm/cluster/internal.h>
  31 #include <crm/common/ipc.h>
  32 #include <crm/common/ipc_internal.h>    // PCMK__SPECIAL_PID
  33 #include <crm/common/mainloop.h>
  34 #include <crm/common/xml.h>
  35 
  36 #include "crmcluster_private.h"
  37 
  38 static quorum_handle_t pcmk_quorum_handle = 0;
  39 
  40 static gboolean (*quorum_app_callback)(unsigned long long seq,
  41                                        gboolean quorate) = NULL;
  42 
  43 /*!
  44  * \internal
  45  * \brief Get the Corosync UUID associated with a Pacemaker node
  46  *
  47  * \param[in] node  Pacemaker node
  48  *
  49  * \return Newly allocated string with node's Corosync UUID, or NULL if unknown
  50  * \note It is the caller's responsibility to free the result with free().
  51  */
  52 char *
  53 pcmk__corosync_uuid(const crm_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55     pcmk__assert(pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync);
  56 
  57     if (node != NULL) {
  58         if (node->id > 0) {
  59             return crm_strdup_printf("%u", node->id);
  60         } else {
  61             crm_info("Node %s is not yet known by Corosync", node->uname);
  62         }
  63     }
  64     return NULL;
  65 }
  66 
  67 static bool
  68 node_name_is_valid(const char *key, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70     int octet;
  71 
  72     if (name == NULL) {
  73         crm_trace("%s is empty", key);
  74         return false;
  75 
  76     } else if (sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
  77         crm_trace("%s contains an IPv4 address (%s), ignoring", key, name);
  78         return false;
  79 
  80     } else if (strstr(name, ":") != NULL) {
  81         crm_trace("%s contains an IPv6 address (%s), ignoring", key, name);
  82         return false;
  83     }
  84     crm_trace("'%s: %s' is valid", key, name);
  85     return true;
  86 }
  87 
  88 /*
  89  * \internal
  90  * \brief Get Corosync node name corresponding to a node ID
  91  *
  92  * \param[in] cmap_handle  Connection to Corosync CMAP
  93  * \param[in] nodeid       Node ID to check
  94  *
  95  * \return Newly allocated string with name or (if no name) IP address
  96  *         associated with first address assigned to a Corosync node ID (or NULL
  97  *         if unknown)
  98  * \note It is the caller's responsibility to free the result with free().
  99  */
 100 char *
 101 pcmk__corosync_name(uint64_t /*cmap_handle_t */ cmap_handle, uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103     // Originally based on corosync-quorumtool.c:node_name()
 104 
 105     int lpc = 0;
 106     cs_error_t rc = CS_OK;
 107     int retries = 0;
 108     char *name = NULL;
 109     cmap_handle_t local_handle = 0;
 110     int fd = -1;
 111     uid_t found_uid = 0;
 112     gid_t found_gid = 0;
 113     pid_t found_pid = 0;
 114     int rv;
 115 
 116     if (nodeid == 0) {
 117         nodeid = pcmk__cpg_local_nodeid(0);
 118     }
 119 
 120     if (cmap_handle == 0 && local_handle == 0) {
 121         retries = 0;
 122         crm_trace("Initializing CMAP connection");
 123         do {
 124             rc = pcmk__init_cmap(&local_handle);
 125             if (rc != CS_OK) {
 126                 retries++;
 127                 crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
 128                           retries);
 129                 sleep(retries);
 130             }
 131 
 132         } while (retries < 5 && rc != CS_OK);
 133 
 134         if (rc != CS_OK) {
 135             crm_warn("Could not connect to Cluster Configuration Database API, error %s",
 136                      cs_strerror(rc));
 137             local_handle = 0;
 138         }
 139     }
 140 
 141     if (cmap_handle == 0) {
 142         cmap_handle = local_handle;
 143 
 144         rc = cmap_fd_get(cmap_handle, &fd);
 145         if (rc != CS_OK) {
 146             crm_err("Could not obtain the CMAP API connection: %s (%d)",
 147                     cs_strerror(rc), rc);
 148             goto bail;
 149         }
 150 
 151         /* CMAP provider run as root (in given user namespace, anyway)? */
 152         if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 153                                                 &found_uid, &found_gid))) {
 154             crm_err("CMAP provider is not authentic:"
 155                     " process %lld (uid: %lld, gid: %lld)",
 156                     (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 157                     (long long) found_uid, (long long) found_gid);
 158             goto bail;
 159         } else if (rv < 0) {
 160             crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 161                     strerror(-rv), -rv);
 162             goto bail;
 163         }
 164     }
 165 
 166     while (name == NULL && cmap_handle != 0) {
 167         uint32_t id = 0;
 168         char *key = NULL;
 169 
 170         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
 171         rc = cmap_get_uint32(cmap_handle, key, &id);
 172         crm_trace("Checking %u vs %u from %s", nodeid, id, key);
 173         free(key);
 174 
 175         if (rc != CS_OK) {
 176             break;
 177         }
 178 
 179         if (nodeid == id) {
 180             crm_trace("Searching for node name for %u in nodelist.node.%d %s",
 181                       nodeid, lpc, pcmk__s(name, "<null>"));
 182             if (name == NULL) {
 183                 key = crm_strdup_printf("nodelist.node.%d.name", lpc);
 184                 cmap_get_string(cmap_handle, key, &name);
 185                 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
 186                 free(key);
 187             }
 188             if (name == NULL) {
 189                 key = crm_strdup_printf("nodelist.node.%d.ring0_addr", lpc);
 190                 cmap_get_string(cmap_handle, key, &name);
 191                 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
 192 
 193                 if (!node_name_is_valid(key, name)) {
 194                     free(name);
 195                     name = NULL;
 196                 }
 197                 free(key);
 198             }
 199             break;
 200         }
 201 
 202         lpc++;
 203     }
 204 
 205 bail:
 206     if(local_handle) {
 207         cmap_finalize(local_handle);
 208     }
 209 
 210     if (name == NULL) {
 211         crm_info("Unable to get node name for nodeid %u", nodeid);
 212     }
 213     return name;
 214 }
 215 
 216 /*!
 217  * \internal
 218  * \brief Disconnect from Corosync cluster
 219  *
 220  * \param[in,out] cluster  Cluster object to disconnect
 221  */
 222 void
 223 pcmk__corosync_disconnect(pcmk_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225     pcmk__cpg_disconnect(cluster);
 226 
 227     if (pcmk_quorum_handle != 0) {
 228         quorum_finalize(pcmk_quorum_handle);
 229         pcmk_quorum_handle = 0;
 230     }
 231     crm_notice("Disconnected from Corosync");
 232 }
 233 
 234 /*!
 235  * \internal
 236  * \brief Dispatch function for quorum connection file descriptor
 237  *
 238  * \param[in] user_data  Ignored
 239  *
 240  * \return 0 on success, -1 on error (per mainloop_io_t interface)
 241  */
 242 static int
 243 quorum_dispatch_cb(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245     int rc = quorum_dispatch(pcmk_quorum_handle, CS_DISPATCH_ALL);
 246 
 247     if (rc < 0) {
 248         crm_err("Connection to the Quorum API failed: %d", rc);
 249         quorum_finalize(pcmk_quorum_handle);
 250         pcmk_quorum_handle = 0;
 251         return -1;
 252     }
 253     return 0;
 254 }
 255 
 256 /*!
 257  * \internal
 258  * \brief Notification callback for Corosync quorum connection
 259  *
 260  * \param[in] handle             Corosync quorum connection
 261  * \param[in] quorate            Whether cluster is quorate
 262  * \param[in] ring_id            Corosync ring ID
 263  * \param[in] view_list_entries  Number of entries in \p view_list
 264  * \param[in] view_list          Corosync node IDs in membership
 265  */
 266 static void
 267 quorum_notification_cb(quorum_handle_t handle, uint32_t quorate,
     /* [previous][next][first][last][top][bottom][index][help] */
 268                        uint64_t ring_id, uint32_t view_list_entries,
 269                        uint32_t *view_list)
 270 {
 271     int i;
 272     GHashTableIter iter;
 273     crm_node_t *node = NULL;
 274     static gboolean init_phase = TRUE;
 275 
 276     if (quorate != crm_have_quorum) {
 277         if (quorate) {
 278             crm_notice("Quorum acquired " CRM_XS " membership=%" PRIu64 " members=%lu",
 279                        ring_id, (long unsigned int)view_list_entries);
 280         } else {
 281             crm_warn("Quorum lost " CRM_XS " membership=%" PRIu64 " members=%lu",
 282                      ring_id, (long unsigned int)view_list_entries);
 283         }
 284         crm_have_quorum = quorate;
 285 
 286     } else {
 287         crm_info("Quorum %s " CRM_XS " membership=%" PRIu64 " members=%lu",
 288                  (quorate? "retained" : "still lost"), ring_id,
 289                  (long unsigned int)view_list_entries);
 290     }
 291 
 292     if (view_list_entries == 0 && init_phase) {
 293         crm_info("Corosync membership is still forming, ignoring");
 294         return;
 295     }
 296 
 297     init_phase = FALSE;
 298 
 299     /* Reset last_seen for all cached nodes so we can tell which ones aren't
 300      * in the view list */
 301     g_hash_table_iter_init(&iter, crm_peer_cache);
 302     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 303         node->last_seen = 0;
 304     }
 305 
 306     /* Update the peer cache for each node in view list */
 307     for (i = 0; i < view_list_entries; i++) {
 308         uint32_t id = view_list[i];
 309 
 310         crm_debug("Member[%d] %u ", i, id);
 311 
 312         /* Get this node's peer cache entry (adding one if not already there) */
 313         node = pcmk__get_node(id, NULL, NULL, pcmk__node_search_cluster_member);
 314         if (node->uname == NULL) {
 315             char *name = pcmk__corosync_name(0, id);
 316 
 317             crm_info("Obtaining name for new node %u", id);
 318             node = pcmk__get_node(id, name, NULL,
 319                                   pcmk__node_search_cluster_member);
 320             free(name);
 321         }
 322 
 323         /* Update the node state (including updating last_seen to ring_id) */
 324         pcmk__update_peer_state(__func__, node, CRM_NODE_MEMBER, ring_id);
 325     }
 326 
 327     /* Remove any peer cache entries we didn't update */
 328     pcmk__reap_unseen_nodes(ring_id);
 329 
 330     if (quorum_app_callback) {
 331         quorum_app_callback(ring_id, quorate);
 332     }
 333 }
 334 
 335 /*!
 336  * \internal
 337  * \brief Connect to Corosync quorum service
 338  *
 339  * \param[in] dispatch   Connection dispatch callback
 340  * \param[in] destroy    Connection destroy callback
 341  */
 342 void
 343 pcmk__corosync_quorum_connect(gboolean (*dispatch)(unsigned long long,
     /* [previous][next][first][last][top][bottom][index][help] */
 344                                                    gboolean),
 345                               void (*destroy)(gpointer))
 346 {
 347     cs_error_t rc;
 348     int fd = 0;
 349     int quorate = 0;
 350     uint32_t quorum_type = 0;
 351     struct mainloop_fd_callbacks quorum_fd_callbacks;
 352     uid_t found_uid = 0;
 353     gid_t found_gid = 0;
 354     pid_t found_pid = 0;
 355     int rv;
 356 
 357     quorum_fd_callbacks.dispatch = quorum_dispatch_cb;
 358     quorum_fd_callbacks.destroy = destroy;
 359 
 360     crm_debug("Configuring Pacemaker to obtain quorum from Corosync");
 361 
 362     {
 363 #if 0
 364         // New way but not supported by all Corosync 2 versions
 365         quorum_model_v0_data_t quorum_model_data = {
 366             .model = QUORUM_MODEL_V0,
 367             .quorum_notify_fn = quorum_notification_cb,
 368         };
 369 
 370         rc = quorum_model_initialize(&pcmk_quorum_handle, QUORUM_MODEL_V0,
 371                                      (quorum_model_data_t *) &quorum_model_data,
 372                                      &quorum_type, NULL);
 373 #else
 374         quorum_callbacks_t quorum_callbacks = {
 375             .quorum_notify_fn = quorum_notification_cb,
 376         };
 377 
 378         rc = quorum_initialize(&pcmk_quorum_handle, &quorum_callbacks,
 379                                &quorum_type);
 380 #endif
 381     }
 382 
 383     if (rc != CS_OK) {
 384         crm_err("Could not connect to the Quorum API: %s (%d)",
 385                 cs_strerror(rc), rc);
 386         goto bail;
 387 
 388     } else if (quorum_type != QUORUM_SET) {
 389         crm_err("Corosync quorum is not configured");
 390         goto bail;
 391     }
 392 
 393     rc = quorum_fd_get(pcmk_quorum_handle, &fd);
 394     if (rc != CS_OK) {
 395         crm_err("Could not obtain the Quorum API connection: %s (%d)",
 396                 strerror(rc), rc);
 397         goto bail;
 398     }
 399 
 400     /* Quorum provider run as root (in given user namespace, anyway)? */
 401     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 402                                             &found_uid, &found_gid))) {
 403         crm_err("Quorum provider is not authentic:"
 404                 " process %lld (uid: %lld, gid: %lld)",
 405                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 406                 (long long) found_uid, (long long) found_gid);
 407         rc = CS_ERR_ACCESS;
 408         goto bail;
 409     } else if (rv < 0) {
 410         crm_err("Could not verify authenticity of Quorum provider: %s (%d)",
 411                 strerror(-rv), -rv);
 412         rc = CS_ERR_ACCESS;
 413         goto bail;
 414     }
 415 
 416     rc = quorum_getquorate(pcmk_quorum_handle, &quorate);
 417     if (rc != CS_OK) {
 418         crm_err("Could not obtain the current Quorum API state: %d", rc);
 419         goto bail;
 420     }
 421 
 422     if (quorate) {
 423         crm_notice("Quorum acquired");
 424     } else {
 425         crm_warn("No quorum");
 426     }
 427     quorum_app_callback = dispatch;
 428     crm_have_quorum = quorate;
 429 
 430     rc = quorum_trackstart(pcmk_quorum_handle, CS_TRACK_CHANGES | CS_TRACK_CURRENT);
 431     if (rc != CS_OK) {
 432         crm_err("Could not setup Quorum API notifications: %d", rc);
 433         goto bail;
 434     }
 435 
 436     mainloop_add_fd("quorum", G_PRIORITY_HIGH, fd, dispatch, &quorum_fd_callbacks);
 437 
 438     pcmk__corosync_add_nodes(NULL);
 439 
 440   bail:
 441     if (rc != CS_OK) {
 442         quorum_finalize(pcmk_quorum_handle);
 443     }
 444 }
 445 
 446 /*!
 447  * \internal
 448  * \brief Connect to Corosync cluster layer
 449  *
 450  * \param[in,out] cluster  Initialized cluster object to connect
 451  *
 452  * \return Standard Pacemaker return code
 453  */
 454 int
 455 pcmk__corosync_connect(pcmk_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {
 457     crm_node_t *peer = NULL;
 458     const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
 459     const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
 460     int rc = pcmk_rc_ok;
 461 
 462     pcmk__cluster_init_node_caches();
 463 
 464     if (cluster_layer != pcmk_cluster_layer_corosync) {
 465         crm_err("Invalid cluster layer: %s " CRM_XS " cluster_layer=%d",
 466                 cluster_layer_s, cluster_layer);
 467         return EINVAL;
 468     }
 469 
 470     rc = pcmk__cpg_connect(cluster);
 471     if (rc != pcmk_rc_ok) {
 472         // Error message was logged by pcmk__cpg_connect()
 473         return rc;
 474     }
 475     crm_info("Connection to %s established", cluster_layer_s);
 476 
 477     cluster->nodeid = pcmk__cpg_local_nodeid(0);
 478     if (cluster->nodeid == 0) {
 479         crm_err("Could not determine local node ID");
 480         return ENXIO;
 481     }
 482 
 483     cluster->uname = pcmk__cluster_node_name(0);
 484     if (cluster->uname == NULL) {
 485         crm_err("Could not determine local node name");
 486         return ENXIO;
 487     }
 488 
 489     // Ensure local node always exists in peer cache
 490     peer = pcmk__get_node(cluster->nodeid, cluster->uname, NULL,
 491                           pcmk__node_search_cluster_member);
 492     cluster->uuid = pcmk__corosync_uuid(peer);
 493 
 494     return pcmk_rc_ok;
 495 }
 496 
 497 /*!
 498  * \internal
 499  * \brief Check whether a Corosync cluster is active
 500  *
 501  * \return \c true if Corosync is found active, or \c false otherwise
 502  */
 503 bool
 504 pcmk__corosync_is_active(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506     cmap_handle_t handle;
 507     int rc = pcmk__init_cmap(&handle);
 508 
 509     if (rc == CS_OK) {
 510         cmap_finalize(handle);
 511         return true;
 512     }
 513 
 514     crm_info("Failed to initialize the cmap API: %s (%d)",
 515              pcmk__cs_err_str(rc), rc);
 516     return false;
 517 }
 518 
 519 /*!
 520  * \internal
 521  * \brief Check whether a Corosync cluster peer is active
 522  *
 523  * \param[in] node  Node to check
 524  *
 525  * \return \c true if \p node is an active Corosync peer, or \c false otherwise
 526  */
 527 bool
 528 pcmk__corosync_is_peer_active(const crm_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530     if (node == NULL) {
 531         crm_trace("Corosync peer inactive: NULL");
 532         return false;
 533     }
 534     if (!pcmk__str_eq(node->state, CRM_NODE_MEMBER, pcmk__str_none)) {
 535         crm_trace("Corosync peer %s inactive: state=%s",
 536                   node->uname, node->state);
 537         return false;
 538     }
 539     if (!pcmk_is_set(node->processes, crm_proc_cpg)) {
 540         crm_trace("Corosync peer %s inactive " CRM_XS " processes=%.16" PRIx32,
 541                   node->uname, node->processes);
 542         return false;
 543     }
 544     return true;
 545 }
 546 
 547 /*!
 548  * \internal
 549  * \brief Load Corosync node list (via CMAP) into peer cache and optionally XML
 550  *
 551  * \param[in,out] xml_parent  If not NULL, add <node> entry here for each node
 552  *
 553  * \return true if any nodes were found, false otherwise
 554  */
 555 bool
 556 pcmk__corosync_add_nodes(xmlNode *xml_parent)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558     int lpc = 0;
 559     cs_error_t rc = CS_OK;
 560     int retries = 0;
 561     bool any = false;
 562     cmap_handle_t cmap_handle;
 563     int fd = -1;
 564     uid_t found_uid = 0;
 565     gid_t found_gid = 0;
 566     pid_t found_pid = 0;
 567     int rv;
 568 
 569     do {
 570         rc = pcmk__init_cmap(&cmap_handle);
 571         if (rc != CS_OK) {
 572             retries++;
 573             crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
 574                       retries);
 575             sleep(retries);
 576         }
 577 
 578     } while (retries < 5 && rc != CS_OK);
 579 
 580     if (rc != CS_OK) {
 581         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
 582         return false;
 583     }
 584 
 585     rc = cmap_fd_get(cmap_handle, &fd);
 586     if (rc != CS_OK) {
 587         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 588                 cs_strerror(rc), rc);
 589         goto bail;
 590     }
 591 
 592     /* CMAP provider run as root (in given user namespace, anyway)? */
 593     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 594                                             &found_uid, &found_gid))) {
 595         crm_err("CMAP provider is not authentic:"
 596                 " process %lld (uid: %lld, gid: %lld)",
 597                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 598                 (long long) found_uid, (long long) found_gid);
 599         goto bail;
 600     } else if (rv < 0) {
 601         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 602                 strerror(-rv), -rv);
 603         goto bail;
 604     }
 605 
 606     pcmk__cluster_init_node_caches();
 607     crm_trace("Initializing Corosync node list");
 608     for (lpc = 0; TRUE; lpc++) {
 609         uint32_t nodeid = 0;
 610         char *name = NULL;
 611         char *key = NULL;
 612 
 613         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
 614         rc = cmap_get_uint32(cmap_handle, key, &nodeid);
 615         free(key);
 616 
 617         if (rc != CS_OK) {
 618             break;
 619         }
 620 
 621         name = pcmk__corosync_name(cmap_handle, nodeid);
 622         if (name != NULL) {
 623             GHashTableIter iter;
 624             crm_node_t *node = NULL;
 625 
 626             g_hash_table_iter_init(&iter, crm_peer_cache);
 627             while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 628                 if(node && node->uname && strcasecmp(node->uname, name) == 0) {
 629                     if (node->id && node->id != nodeid) {
 630                         crm_crit("Nodes %u and %u share the same name '%s': shutting down", node->id,
 631                                  nodeid, name);
 632                         crm_exit(CRM_EX_FATAL);
 633                     }
 634                 }
 635             }
 636         }
 637 
 638         if (nodeid > 0 || name != NULL) {
 639             crm_trace("Initializing node[%d] %u = %s", lpc, nodeid, name);
 640             pcmk__get_node(nodeid, name, NULL, pcmk__node_search_cluster_member);
 641         }
 642 
 643         if (nodeid > 0 && name != NULL) {
 644             any = true;
 645 
 646             if (xml_parent) {
 647                 xmlNode *node = pcmk__xe_create(xml_parent, PCMK_XE_NODE);
 648 
 649                 crm_xml_add_ll(node, PCMK_XA_ID, (long long) nodeid);
 650                 crm_xml_add(node, PCMK_XA_UNAME, name);
 651             }
 652         }
 653 
 654         free(name);
 655     }
 656 bail:
 657     cmap_finalize(cmap_handle);
 658     return any;
 659 }
 660 
 661 /*!
 662  * \internal
 663  * \brief Get cluster name from Corosync configuration (via CMAP)
 664  *
 665  * \return Newly allocated string with cluster name if configured, or NULL
 666  */
 667 char *
 668 pcmk__corosync_cluster_name(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 669 {
 670     cmap_handle_t handle;
 671     char *cluster_name = NULL;
 672     cs_error_t rc = CS_OK;
 673     int fd = -1;
 674     uid_t found_uid = 0;
 675     gid_t found_gid = 0;
 676     pid_t found_pid = 0;
 677     int rv;
 678 
 679     rc = pcmk__init_cmap(&handle);
 680     if (rc != CS_OK) {
 681         crm_info("Failed to initialize the cmap API: %s (%d)",
 682                  cs_strerror(rc), rc);
 683         return NULL;
 684     }
 685 
 686     rc = cmap_fd_get(handle, &fd);
 687     if (rc != CS_OK) {
 688         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 689                 cs_strerror(rc), rc);
 690         goto bail;
 691     }
 692 
 693     /* CMAP provider run as root (in given user namespace, anyway)? */
 694     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 695                                             &found_uid, &found_gid))) {
 696         crm_err("CMAP provider is not authentic:"
 697                 " process %lld (uid: %lld, gid: %lld)",
 698                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 699                 (long long) found_uid, (long long) found_gid);
 700         goto bail;
 701     } else if (rv < 0) {
 702         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 703                 strerror(-rv), -rv);
 704         goto bail;
 705     }
 706 
 707     rc = cmap_get_string(handle, "totem.cluster_name", &cluster_name);
 708     if (rc != CS_OK) {
 709         crm_info("Cannot get totem.cluster_name: %s (%d)", cs_strerror(rc), rc);
 710 
 711     } else {
 712         crm_debug("cmap totem.cluster_name = '%s'", cluster_name);
 713     }
 714 
 715 bail:
 716     cmap_finalize(handle);
 717     return cluster_name;
 718 }
 719 
 720 /*!
 721  * \internal
 722  * \brief Check (via CMAP) whether Corosync configuration has a node list
 723  *
 724  * \return true if Corosync has node list, otherwise false
 725  */
 726 bool
 727 pcmk__corosync_has_nodelist(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729     cs_error_t cs_rc = CS_OK;
 730     int retries = 0;
 731     cmap_handle_t cmap_handle;
 732     cmap_iter_handle_t iter_handle;
 733     char key_name[CMAP_KEYNAME_MAXLEN + 1];
 734     int fd = -1;
 735     uid_t found_uid = 0;
 736     gid_t found_gid = 0;
 737     pid_t found_pid = 0;
 738     int rc = pcmk_ok;
 739 
 740     static bool got_result = false;
 741     static bool result = false;
 742 
 743     if (got_result) {
 744         return result;
 745     }
 746 
 747     // Connect to CMAP
 748     do {
 749         cs_rc = pcmk__init_cmap(&cmap_handle);
 750         if (cs_rc != CS_OK) {
 751             retries++;
 752             crm_debug("CMAP connection failed: %s (rc=%d, retrying in %ds)",
 753                       cs_strerror(cs_rc), cs_rc, retries);
 754             sleep(retries);
 755         }
 756     } while ((retries < 5) && (cs_rc != CS_OK));
 757     if (cs_rc != CS_OK) {
 758         crm_warn("Assuming Corosync does not have node list: "
 759                  "CMAP connection failed (%s) " CRM_XS " rc=%d",
 760                  cs_strerror(cs_rc), cs_rc);
 761         return false;
 762     }
 763 
 764     // Get CMAP connection file descriptor
 765     cs_rc = cmap_fd_get(cmap_handle, &fd);
 766     if (cs_rc != CS_OK) {
 767         crm_warn("Assuming Corosync does not have node list: "
 768                  "CMAP unusable (%s) " CRM_XS " rc=%d",
 769                  cs_strerror(cs_rc), cs_rc);
 770         goto bail;
 771     }
 772 
 773     // Check whether CMAP connection is authentic (i.e. provided by root)
 774     rc = crm_ipc_is_authentic_process(fd, (uid_t) 0, (gid_t) 0,
 775                                       &found_pid, &found_uid, &found_gid);
 776     if (rc == 0) {
 777         crm_warn("Assuming Corosync does not have node list: "
 778                  "CMAP provider is inauthentic "
 779                  CRM_XS " pid=%lld uid=%lld gid=%lld",
 780                  (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 781                  (long long) found_uid, (long long) found_gid);
 782         goto bail;
 783     } else if (rc < 0) {
 784         crm_warn("Assuming Corosync does not have node list: "
 785                  "Could not verify CMAP authenticity (%s) " CRM_XS " rc=%d",
 786                   pcmk_strerror(rc), rc);
 787         goto bail;
 788     }
 789 
 790     // Check whether nodelist section is presetn
 791     cs_rc = cmap_iter_init(cmap_handle, "nodelist", &iter_handle);
 792     if (cs_rc != CS_OK) {
 793         crm_warn("Assuming Corosync does not have node list: "
 794                  "CMAP not readable (%s) " CRM_XS " rc=%d",
 795                  cs_strerror(cs_rc), cs_rc);
 796         goto bail;
 797     }
 798 
 799     cs_rc = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL);
 800     if (cs_rc == CS_OK) {
 801         result = true;
 802     }
 803 
 804     cmap_iter_finalize(cmap_handle, iter_handle);
 805     got_result = true;
 806     crm_debug("Corosync %s node list", (result? "has" : "does not have"));
 807 
 808 bail:
 809     cmap_finalize(cmap_handle);
 810     return result;
 811 }
 812 
 813 // Deprecated functions kept only for backward API compatibility
 814 // LCOV_EXCL_START
 815 
 816 #include <crm/cluster/compat.h>
 817 
 818 gboolean
 819 crm_is_corosync_peer_active(const crm_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 820 {
 821     return pcmk__corosync_is_peer_active(node);
 822 }
 823 
 824 // LCOV_EXCL_STOP
 825 // End deprecated API

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