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

   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, etc.
  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 pcmk__node_status_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->cluster_layer_id > 0) {
  59             return crm_strdup_printf("%" PRIu32, node->cluster_layer_id);
  60         } else {
  61             crm_info("Node %s is not yet known by Corosync", node->name);
  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     pcmk__node_status_t *node = NULL;
 274     static gboolean init_phase = TRUE;
 275 
 276     bool is_quorate = (quorate != 0);
 277     bool was_quorate = pcmk__cluster_has_quorum();
 278 
 279     if (is_quorate && !was_quorate) {
 280         crm_notice("Quorum acquired " QB_XS " membership=%" PRIu64
 281                    " members=%" PRIu32,
 282                    ring_id, view_list_entries);
 283         pcmk__cluster_set_quorum(true);
 284 
 285     } else if (!is_quorate && was_quorate) {
 286         crm_warn("Quorum lost " QB_XS " membership=%" PRIu64 " members=" PRIu32,
 287                  ring_id, view_list_entries);
 288         pcmk__cluster_set_quorum(false);
 289 
 290     } else {
 291         crm_info("Quorum %s " QB_XS " membership=%" PRIu64 " members=%" PRIu32,
 292                  (is_quorate? "retained" : "still lost"), ring_id,
 293                  view_list_entries);
 294     }
 295 
 296     if (view_list_entries == 0 && init_phase) {
 297         crm_info("Corosync membership is still forming, ignoring");
 298         return;
 299     }
 300 
 301     init_phase = FALSE;
 302 
 303     /* Reset membership_id for all cached nodes so we can tell which ones aren't
 304      * in the view list */
 305     g_hash_table_iter_init(&iter, pcmk__peer_cache);
 306     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 307         node->membership_id = 0;
 308     }
 309 
 310     /* Update the peer cache for each node in view list */
 311     for (i = 0; i < view_list_entries; i++) {
 312         uint32_t id = view_list[i];
 313 
 314         crm_debug("Member[%d] %u ", i, id);
 315 
 316         /* Get this node's peer cache entry (adding one if not already there) */
 317         node = pcmk__get_node(id, NULL, NULL, pcmk__node_search_cluster_member);
 318         if (node->name == NULL) {
 319             char *name = pcmk__corosync_name(0, id);
 320 
 321             crm_info("Obtaining name for new node %u", id);
 322             node = pcmk__get_node(id, name, NULL,
 323                                   pcmk__node_search_cluster_member);
 324             free(name);
 325         }
 326 
 327         // Update the node state (including updating membership_id to ring_id)
 328         pcmk__update_peer_state(__func__, node, PCMK_VALUE_MEMBER, ring_id);
 329     }
 330 
 331     /* Remove any peer cache entries we didn't update */
 332     pcmk__reap_unseen_nodes(ring_id);
 333 
 334     if (quorum_app_callback) {
 335         quorum_app_callback(ring_id, is_quorate);
 336     }
 337 }
 338 
 339 /*!
 340  * \internal
 341  * \brief Connect to Corosync quorum service
 342  *
 343  * \param[in] dispatch   Connection dispatch callback
 344  * \param[in] destroy    Connection destroy callback
 345  */
 346 void
 347 pcmk__corosync_quorum_connect(gboolean (*dispatch)(unsigned long long,
     /* [previous][next][first][last][top][bottom][index][help] */
 348                                                    gboolean),
 349                               void (*destroy)(gpointer))
 350 {
 351     cs_error_t rc;
 352     int fd = 0;
 353     int quorate = 0;
 354     uint32_t quorum_type = 0;
 355     struct mainloop_fd_callbacks quorum_fd_callbacks;
 356     uid_t found_uid = 0;
 357     gid_t found_gid = 0;
 358     pid_t found_pid = 0;
 359     int rv;
 360 
 361     quorum_fd_callbacks.dispatch = quorum_dispatch_cb;
 362     quorum_fd_callbacks.destroy = destroy;
 363 
 364     crm_debug("Configuring Pacemaker to obtain quorum from Corosync");
 365 
 366     {
 367 #if 0
 368         // New way but not supported by all Corosync 2 versions
 369         quorum_model_v0_data_t quorum_model_data = {
 370             .model = QUORUM_MODEL_V0,
 371             .quorum_notify_fn = quorum_notification_cb,
 372         };
 373 
 374         rc = quorum_model_initialize(&pcmk_quorum_handle, QUORUM_MODEL_V0,
 375                                      (quorum_model_data_t *) &quorum_model_data,
 376                                      &quorum_type, NULL);
 377 #else
 378         quorum_callbacks_t quorum_callbacks = {
 379             .quorum_notify_fn = quorum_notification_cb,
 380         };
 381 
 382         rc = quorum_initialize(&pcmk_quorum_handle, &quorum_callbacks,
 383                                &quorum_type);
 384 #endif
 385     }
 386 
 387     if (rc != CS_OK) {
 388         crm_err("Could not connect to the Quorum API: %s (%d)",
 389                 cs_strerror(rc), rc);
 390         goto bail;
 391 
 392     } else if (quorum_type != QUORUM_SET) {
 393         crm_err("Corosync quorum is not configured");
 394         goto bail;
 395     }
 396 
 397     rc = quorum_fd_get(pcmk_quorum_handle, &fd);
 398     if (rc != CS_OK) {
 399         crm_err("Could not obtain the Quorum API connection: %s (%d)",
 400                 strerror(rc), rc);
 401         goto bail;
 402     }
 403 
 404     /* Quorum provider run as root (in given user namespace, anyway)? */
 405     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 406                                             &found_uid, &found_gid))) {
 407         crm_err("Quorum provider is not authentic:"
 408                 " process %lld (uid: %lld, gid: %lld)",
 409                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 410                 (long long) found_uid, (long long) found_gid);
 411         rc = CS_ERR_ACCESS;
 412         goto bail;
 413     } else if (rv < 0) {
 414         crm_err("Could not verify authenticity of Quorum provider: %s (%d)",
 415                 strerror(-rv), -rv);
 416         rc = CS_ERR_ACCESS;
 417         goto bail;
 418     }
 419 
 420     rc = quorum_getquorate(pcmk_quorum_handle, &quorate);
 421     if (rc != CS_OK) {
 422         crm_err("Could not obtain the current Quorum API state: %d", rc);
 423         goto bail;
 424     }
 425 
 426     if (quorate) {
 427         crm_notice("Quorum acquired");
 428     } else {
 429         crm_warn("No quorum");
 430     }
 431     quorum_app_callback = dispatch;
 432     pcmk__cluster_set_quorum(quorate != 0);
 433 
 434     rc = quorum_trackstart(pcmk_quorum_handle, CS_TRACK_CHANGES | CS_TRACK_CURRENT);
 435     if (rc != CS_OK) {
 436         crm_err("Could not setup Quorum API notifications: %d", rc);
 437         goto bail;
 438     }
 439 
 440     mainloop_add_fd("quorum", G_PRIORITY_HIGH, fd, dispatch, &quorum_fd_callbacks);
 441 
 442     pcmk__corosync_add_nodes(NULL);
 443 
 444   bail:
 445     if (rc != CS_OK) {
 446         quorum_finalize(pcmk_quorum_handle);
 447     }
 448 }
 449 
 450 /*!
 451  * \internal
 452  * \brief Connect to Corosync cluster layer
 453  *
 454  * \param[in,out] cluster  Initialized cluster object to connect
 455  *
 456  * \return Standard Pacemaker return code
 457  */
 458 int
 459 pcmk__corosync_connect(pcmk_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461     const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
 462     const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
 463     int rc = pcmk_rc_ok;
 464 
 465     pcmk__cluster_init_node_caches();
 466 
 467     if (cluster_layer != pcmk_cluster_layer_corosync) {
 468         crm_err("Invalid cluster layer: %s " QB_XS " cluster_layer=%d",
 469                 cluster_layer_s, cluster_layer);
 470         return EINVAL;
 471     }
 472 
 473     rc = pcmk__cpg_connect(cluster);
 474     if (rc != pcmk_rc_ok) {
 475         // Error message was logged by pcmk__cpg_connect()
 476         return rc;
 477     }
 478     crm_info("Connection to %s established", cluster_layer_s);
 479 
 480     cluster->priv->node_id = pcmk__cpg_local_nodeid(0);
 481     if (cluster->priv->node_id == 0) {
 482         crm_err("Could not determine local node ID");
 483         return ENXIO;
 484     }
 485 
 486     cluster->priv->node_name = pcmk__cluster_node_name(0);
 487     if (cluster->priv->node_name == NULL) {
 488         crm_err("Could not determine local node name");
 489         return ENXIO;
 490     }
 491 
 492     // Ensure local node always exists in peer cache
 493     pcmk__get_node(cluster->priv->node_id, cluster->priv->node_name, NULL,
 494                    pcmk__node_search_cluster_member);
 495 
 496     return pcmk_rc_ok;
 497 }
 498 
 499 /*!
 500  * \internal
 501  * \brief Check whether a Corosync cluster is active
 502  *
 503  * \return \c true if Corosync is found active, or \c false otherwise
 504  */
 505 bool
 506 pcmk__corosync_is_active(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508     cmap_handle_t handle;
 509     int rc = pcmk__init_cmap(&handle);
 510 
 511     if (rc == CS_OK) {
 512         cmap_finalize(handle);
 513         return true;
 514     }
 515 
 516     crm_info("Failed to initialize the cmap API: %s (%d)",
 517              pcmk__cs_err_str(rc), rc);
 518     return false;
 519 }
 520 
 521 /*!
 522  * \internal
 523  * \brief Check whether a Corosync cluster peer is active
 524  *
 525  * \param[in] node  Node to check
 526  *
 527  * \return \c true if \p node is an active Corosync peer, or \c false otherwise
 528  */
 529 bool
 530 pcmk__corosync_is_peer_active(const pcmk__node_status_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 531 {
 532     if (node == NULL) {
 533         crm_trace("Corosync peer inactive: NULL");
 534         return false;
 535     }
 536     if (!pcmk__str_eq(node->state, PCMK_VALUE_MEMBER, pcmk__str_none)) {
 537         crm_trace("Corosync peer %s inactive: state=%s",
 538                   node->name, node->state);
 539         return false;
 540     }
 541     if (!pcmk_is_set(node->processes, crm_proc_cpg)) {
 542         crm_trace("Corosync peer %s inactive " QB_XS " processes=%.16" PRIx32,
 543                   node->name, node->processes);
 544         return false;
 545     }
 546     return true;
 547 }
 548 
 549 /*!
 550  * \internal
 551  * \brief Load Corosync node list (via CMAP) into peer cache and optionally XML
 552  *
 553  * \param[in,out] xml_parent  If not NULL, add <node> entry here for each node
 554  *
 555  * \return true if any nodes were found, false otherwise
 556  */
 557 bool
 558 pcmk__corosync_add_nodes(xmlNode *xml_parent)
     /* [previous][next][first][last][top][bottom][index][help] */
 559 {
 560     int lpc = 0;
 561     cs_error_t rc = CS_OK;
 562     int retries = 0;
 563     bool any = false;
 564     cmap_handle_t cmap_handle;
 565     int fd = -1;
 566     uid_t found_uid = 0;
 567     gid_t found_gid = 0;
 568     pid_t found_pid = 0;
 569     int rv;
 570 
 571     do {
 572         rc = pcmk__init_cmap(&cmap_handle);
 573         if (rc != CS_OK) {
 574             retries++;
 575             crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
 576                       retries);
 577             sleep(retries);
 578         }
 579 
 580     } while (retries < 5 && rc != CS_OK);
 581 
 582     if (rc != CS_OK) {
 583         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
 584         return false;
 585     }
 586 
 587     rc = cmap_fd_get(cmap_handle, &fd);
 588     if (rc != CS_OK) {
 589         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 590                 cs_strerror(rc), rc);
 591         goto bail;
 592     }
 593 
 594     /* CMAP provider run as root (in given user namespace, anyway)? */
 595     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 596                                             &found_uid, &found_gid))) {
 597         crm_err("CMAP provider is not authentic:"
 598                 " process %lld (uid: %lld, gid: %lld)",
 599                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 600                 (long long) found_uid, (long long) found_gid);
 601         goto bail;
 602     } else if (rv < 0) {
 603         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 604                 strerror(-rv), -rv);
 605         goto bail;
 606     }
 607 
 608     pcmk__cluster_init_node_caches();
 609     crm_trace("Initializing Corosync node list");
 610     for (lpc = 0; TRUE; lpc++) {
 611         uint32_t nodeid = 0;
 612         char *name = NULL;
 613         char *key = NULL;
 614 
 615         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
 616         rc = cmap_get_uint32(cmap_handle, key, &nodeid);
 617         free(key);
 618 
 619         if (rc != CS_OK) {
 620             break;
 621         }
 622 
 623         name = pcmk__corosync_name(cmap_handle, nodeid);
 624         if (name != NULL) {
 625             GHashTableIter iter;
 626             pcmk__node_status_t *node = NULL;
 627 
 628             g_hash_table_iter_init(&iter, pcmk__peer_cache);
 629             while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 630                 if ((node != NULL)
 631                     && (node->cluster_layer_id > 0)
 632                     && (node->cluster_layer_id != nodeid)
 633                     && pcmk__str_eq(node->name, name, pcmk__str_casei)) {
 634 
 635                     crm_crit("Nodes %" PRIu32 " and %" PRIu32 " share the "
 636                              "same name '%s': shutting down",
 637                              node->cluster_layer_id, nodeid, name);
 638                     crm_exit(CRM_EX_FATAL);
 639                 }
 640             }
 641         }
 642 
 643         if (nodeid > 0 || name != NULL) {
 644             crm_trace("Initializing node[%d] %u = %s", lpc, nodeid, name);
 645             pcmk__get_node(nodeid, name, NULL, pcmk__node_search_cluster_member);
 646         }
 647 
 648         if (nodeid > 0 && name != NULL) {
 649             any = true;
 650 
 651             if (xml_parent) {
 652                 xmlNode *node = pcmk__xe_create(xml_parent, PCMK_XE_NODE);
 653 
 654                 crm_xml_add_ll(node, PCMK_XA_ID, (long long) nodeid);
 655                 crm_xml_add(node, PCMK_XA_UNAME, name);
 656             }
 657         }
 658 
 659         free(name);
 660     }
 661 bail:
 662     cmap_finalize(cmap_handle);
 663     return any;
 664 }
 665 
 666 /*!
 667  * \internal
 668  * \brief Get cluster name from Corosync configuration (via CMAP)
 669  *
 670  * \return Newly allocated string with cluster name if configured, or NULL
 671  */
 672 char *
 673 pcmk__corosync_cluster_name(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 674 {
 675     cmap_handle_t handle;
 676     char *cluster_name = NULL;
 677     cs_error_t rc = CS_OK;
 678     int fd = -1;
 679     uid_t found_uid = 0;
 680     gid_t found_gid = 0;
 681     pid_t found_pid = 0;
 682     int rv;
 683 
 684     rc = pcmk__init_cmap(&handle);
 685     if (rc != CS_OK) {
 686         crm_info("Failed to initialize the cmap API: %s (%d)",
 687                  cs_strerror(rc), rc);
 688         return NULL;
 689     }
 690 
 691     rc = cmap_fd_get(handle, &fd);
 692     if (rc != CS_OK) {
 693         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 694                 cs_strerror(rc), rc);
 695         goto bail;
 696     }
 697 
 698     /* CMAP provider run as root (in given user namespace, anyway)? */
 699     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 700                                             &found_uid, &found_gid))) {
 701         crm_err("CMAP provider is not authentic:"
 702                 " process %lld (uid: %lld, gid: %lld)",
 703                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 704                 (long long) found_uid, (long long) found_gid);
 705         goto bail;
 706     } else if (rv < 0) {
 707         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 708                 strerror(-rv), -rv);
 709         goto bail;
 710     }
 711 
 712     rc = cmap_get_string(handle, "totem.cluster_name", &cluster_name);
 713     if (rc != CS_OK) {
 714         crm_info("Cannot get totem.cluster_name: %s (%d)", cs_strerror(rc), rc);
 715 
 716     } else {
 717         crm_debug("cmap totem.cluster_name = '%s'", cluster_name);
 718     }
 719 
 720 bail:
 721     cmap_finalize(handle);
 722     return cluster_name;
 723 }
 724 
 725 /*!
 726  * \internal
 727  * \brief Check (via CMAP) whether Corosync configuration has a node list
 728  *
 729  * \return true if Corosync has node list, otherwise false
 730  */
 731 bool
 732 pcmk__corosync_has_nodelist(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 733 {
 734     cs_error_t cs_rc = CS_OK;
 735     int retries = 0;
 736     cmap_handle_t cmap_handle;
 737     cmap_iter_handle_t iter_handle;
 738     char key_name[CMAP_KEYNAME_MAXLEN + 1];
 739     int fd = -1;
 740     uid_t found_uid = 0;
 741     gid_t found_gid = 0;
 742     pid_t found_pid = 0;
 743     int rc = pcmk_ok;
 744 
 745     static bool got_result = false;
 746     static bool result = false;
 747 
 748     if (got_result) {
 749         return result;
 750     }
 751 
 752     // Connect to CMAP
 753     do {
 754         cs_rc = pcmk__init_cmap(&cmap_handle);
 755         if (cs_rc != CS_OK) {
 756             retries++;
 757             crm_debug("CMAP connection failed: %s (rc=%d, retrying in %ds)",
 758                       cs_strerror(cs_rc), cs_rc, retries);
 759             sleep(retries);
 760         }
 761     } while ((retries < 5) && (cs_rc != CS_OK));
 762     if (cs_rc != CS_OK) {
 763         crm_warn("Assuming Corosync does not have node list: "
 764                  "CMAP connection failed (%s) " QB_XS " rc=%d",
 765                  cs_strerror(cs_rc), cs_rc);
 766         return false;
 767     }
 768 
 769     // Get CMAP connection file descriptor
 770     cs_rc = cmap_fd_get(cmap_handle, &fd);
 771     if (cs_rc != CS_OK) {
 772         crm_warn("Assuming Corosync does not have node list: "
 773                  "CMAP unusable (%s) " QB_XS " rc=%d",
 774                  cs_strerror(cs_rc), cs_rc);
 775         goto bail;
 776     }
 777 
 778     // Check whether CMAP connection is authentic (i.e. provided by root)
 779     rc = crm_ipc_is_authentic_process(fd, (uid_t) 0, (gid_t) 0,
 780                                       &found_pid, &found_uid, &found_gid);
 781     if (rc == 0) {
 782         crm_warn("Assuming Corosync does not have node list: "
 783                  "CMAP provider is inauthentic "
 784                  QB_XS " pid=%lld uid=%lld gid=%lld",
 785                  (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 786                  (long long) found_uid, (long long) found_gid);
 787         goto bail;
 788     } else if (rc < 0) {
 789         crm_warn("Assuming Corosync does not have node list: "
 790                  "Could not verify CMAP authenticity (%s) " QB_XS " rc=%d",
 791                   pcmk_strerror(rc), rc);
 792         goto bail;
 793     }
 794 
 795     // Check whether nodelist section is presetn
 796     cs_rc = cmap_iter_init(cmap_handle, "nodelist", &iter_handle);
 797     if (cs_rc != CS_OK) {
 798         crm_warn("Assuming Corosync does not have node list: "
 799                  "CMAP not readable (%s) " QB_XS " rc=%d",
 800                  cs_strerror(cs_rc), cs_rc);
 801         goto bail;
 802     }
 803 
 804     cs_rc = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL);
 805     if (cs_rc == CS_OK) {
 806         result = true;
 807     }
 808 
 809     cmap_iter_finalize(cmap_handle, iter_handle);
 810     got_result = true;
 811     crm_debug("Corosync %s node list", (result? "has" : "does not have"));
 812 
 813 bail:
 814     cmap_finalize(cmap_handle);
 815     return result;
 816 }

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