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     pcmk__node_status_t *local_node = NULL;
 464     int rc = pcmk_rc_ok;
 465 
 466     pcmk__cluster_init_node_caches();
 467 
 468     if (cluster_layer != pcmk_cluster_layer_corosync) {
 469         crm_err("Invalid cluster layer: %s " QB_XS " cluster_layer=%d",
 470                 cluster_layer_s, cluster_layer);
 471         return EINVAL;
 472     }
 473 
 474     rc = pcmk__cpg_connect(cluster);
 475     if (rc != pcmk_rc_ok) {
 476         // Error message was logged by pcmk__cpg_connect()
 477         return rc;
 478     }
 479     crm_info("Connection to %s established", cluster_layer_s);
 480 
 481     cluster->priv->node_id = pcmk__cpg_local_nodeid(0);
 482     if (cluster->priv->node_id == 0) {
 483         crm_err("Could not determine local node ID");
 484         return ENXIO;
 485     }
 486 
 487     cluster->priv->node_name = pcmk__cluster_node_name(0);
 488     if (cluster->priv->node_name == NULL) {
 489         crm_err("Could not determine local node name");
 490         return ENXIO;
 491     }
 492 
 493     // Ensure local node always exists in peer cache
 494     local_node = pcmk__get_node(cluster->priv->node_id,
 495                                 cluster->priv->node_name, NULL,
 496                                 pcmk__node_search_cluster_member);
 497 
 498     cluster->priv->node_xml_id = pcmk__corosync_uuid(local_node);
 499     CRM_LOG_ASSERT(cluster->priv->node_xml_id != NULL);
 500 
 501     return pcmk_rc_ok;
 502 }
 503 
 504 /*!
 505  * \internal
 506  * \brief Check whether a Corosync cluster is active
 507  *
 508  * \return \c true if Corosync is found active, or \c false otherwise
 509  */
 510 bool
 511 pcmk__corosync_is_active(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 512 {
 513     cmap_handle_t handle;
 514     int rc = pcmk__init_cmap(&handle);
 515 
 516     if (rc == CS_OK) {
 517         cmap_finalize(handle);
 518         return true;
 519     }
 520 
 521     crm_info("Failed to initialize the cmap API: %s (%d)",
 522              pcmk__cs_err_str(rc), rc);
 523     return false;
 524 }
 525 
 526 /*!
 527  * \internal
 528  * \brief Check whether a Corosync cluster peer is active
 529  *
 530  * \param[in] node  Node to check
 531  *
 532  * \return \c true if \p node is an active Corosync peer, or \c false otherwise
 533  */
 534 bool
 535 pcmk__corosync_is_peer_active(const pcmk__node_status_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 536 {
 537     if (node == NULL) {
 538         crm_trace("Corosync peer inactive: NULL");
 539         return false;
 540     }
 541     if (!pcmk__str_eq(node->state, PCMK_VALUE_MEMBER, pcmk__str_none)) {
 542         crm_trace("Corosync peer %s inactive: state=%s",
 543                   node->name, node->state);
 544         return false;
 545     }
 546     if (!pcmk_is_set(node->processes, crm_proc_cpg)) {
 547         crm_trace("Corosync peer %s inactive " QB_XS " processes=%.16" PRIx32,
 548                   node->name, node->processes);
 549         return false;
 550     }
 551     return true;
 552 }
 553 
 554 /*!
 555  * \internal
 556  * \brief Load Corosync node list (via CMAP) into peer cache and optionally XML
 557  *
 558  * \param[in,out] xml_parent  If not NULL, add <node> entry here for each node
 559  *
 560  * \return true if any nodes were found, false otherwise
 561  */
 562 bool
 563 pcmk__corosync_add_nodes(xmlNode *xml_parent)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565     int lpc = 0;
 566     cs_error_t rc = CS_OK;
 567     int retries = 0;
 568     bool any = false;
 569     cmap_handle_t cmap_handle;
 570     int fd = -1;
 571     uid_t found_uid = 0;
 572     gid_t found_gid = 0;
 573     pid_t found_pid = 0;
 574     int rv;
 575 
 576     do {
 577         rc = pcmk__init_cmap(&cmap_handle);
 578         if (rc != CS_OK) {
 579             retries++;
 580             crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
 581                       retries);
 582             sleep(retries);
 583         }
 584 
 585     } while (retries < 5 && rc != CS_OK);
 586 
 587     if (rc != CS_OK) {
 588         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
 589         return false;
 590     }
 591 
 592     rc = cmap_fd_get(cmap_handle, &fd);
 593     if (rc != CS_OK) {
 594         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 595                 cs_strerror(rc), rc);
 596         goto bail;
 597     }
 598 
 599     /* CMAP provider run as root (in given user namespace, anyway)? */
 600     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 601                                             &found_uid, &found_gid))) {
 602         crm_err("CMAP provider is not authentic:"
 603                 " process %lld (uid: %lld, gid: %lld)",
 604                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 605                 (long long) found_uid, (long long) found_gid);
 606         goto bail;
 607     } else if (rv < 0) {
 608         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 609                 strerror(-rv), -rv);
 610         goto bail;
 611     }
 612 
 613     pcmk__cluster_init_node_caches();
 614     crm_trace("Initializing Corosync node list");
 615     for (lpc = 0; TRUE; lpc++) {
 616         uint32_t nodeid = 0;
 617         char *name = NULL;
 618         char *key = NULL;
 619 
 620         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
 621         rc = cmap_get_uint32(cmap_handle, key, &nodeid);
 622         free(key);
 623 
 624         if (rc != CS_OK) {
 625             break;
 626         }
 627 
 628         name = pcmk__corosync_name(cmap_handle, nodeid);
 629         if (name != NULL) {
 630             GHashTableIter iter;
 631             pcmk__node_status_t *node = NULL;
 632 
 633             g_hash_table_iter_init(&iter, pcmk__peer_cache);
 634             while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 635                 if ((node != NULL)
 636                     && (node->cluster_layer_id > 0)
 637                     && (node->cluster_layer_id != nodeid)
 638                     && pcmk__str_eq(node->name, name, pcmk__str_casei)) {
 639 
 640                     crm_crit("Nodes %" PRIu32 " and %" PRIu32 " share the "
 641                              "same name '%s': shutting down",
 642                              node->cluster_layer_id, nodeid, name);
 643                     crm_exit(CRM_EX_FATAL);
 644                 }
 645             }
 646         }
 647 
 648         if (nodeid > 0 || name != NULL) {
 649             crm_trace("Initializing node[%d] %u = %s", lpc, nodeid, name);
 650             pcmk__get_node(nodeid, name, NULL, pcmk__node_search_cluster_member);
 651         }
 652 
 653         if (nodeid > 0 && name != NULL) {
 654             any = true;
 655 
 656             if (xml_parent) {
 657                 xmlNode *node = pcmk__xe_create(xml_parent, PCMK_XE_NODE);
 658 
 659                 crm_xml_add_ll(node, PCMK_XA_ID, (long long) nodeid);
 660                 crm_xml_add(node, PCMK_XA_UNAME, name);
 661             }
 662         }
 663 
 664         free(name);
 665     }
 666 bail:
 667     cmap_finalize(cmap_handle);
 668     return any;
 669 }
 670 
 671 /*!
 672  * \internal
 673  * \brief Get cluster name from Corosync configuration (via CMAP)
 674  *
 675  * \return Newly allocated string with cluster name if configured, or NULL
 676  */
 677 char *
 678 pcmk__corosync_cluster_name(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 679 {
 680     cmap_handle_t handle;
 681     char *cluster_name = NULL;
 682     cs_error_t rc = CS_OK;
 683     int fd = -1;
 684     uid_t found_uid = 0;
 685     gid_t found_gid = 0;
 686     pid_t found_pid = 0;
 687     int rv;
 688 
 689     rc = pcmk__init_cmap(&handle);
 690     if (rc != CS_OK) {
 691         crm_info("Failed to initialize the cmap API: %s (%d)",
 692                  cs_strerror(rc), rc);
 693         return NULL;
 694     }
 695 
 696     rc = cmap_fd_get(handle, &fd);
 697     if (rc != CS_OK) {
 698         crm_err("Could not obtain the CMAP API connection: %s (%d)",
 699                 cs_strerror(rc), rc);
 700         goto bail;
 701     }
 702 
 703     /* CMAP provider run as root (in given user namespace, anyway)? */
 704     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 705                                             &found_uid, &found_gid))) {
 706         crm_err("CMAP provider is not authentic:"
 707                 " process %lld (uid: %lld, gid: %lld)",
 708                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 709                 (long long) found_uid, (long long) found_gid);
 710         goto bail;
 711     } else if (rv < 0) {
 712         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
 713                 strerror(-rv), -rv);
 714         goto bail;
 715     }
 716 
 717     rc = cmap_get_string(handle, "totem.cluster_name", &cluster_name);
 718     if (rc != CS_OK) {
 719         crm_info("Cannot get totem.cluster_name: %s (%d)", cs_strerror(rc), rc);
 720 
 721     } else {
 722         crm_debug("cmap totem.cluster_name = '%s'", cluster_name);
 723     }
 724 
 725 bail:
 726     cmap_finalize(handle);
 727     return cluster_name;
 728 }
 729 
 730 /*!
 731  * \internal
 732  * \brief Check (via CMAP) whether Corosync configuration has a node list
 733  *
 734  * \return true if Corosync has node list, otherwise false
 735  */
 736 bool
 737 pcmk__corosync_has_nodelist(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 738 {
 739     cs_error_t cs_rc = CS_OK;
 740     int retries = 0;
 741     cmap_handle_t cmap_handle;
 742     cmap_iter_handle_t iter_handle;
 743     char key_name[CMAP_KEYNAME_MAXLEN + 1];
 744     int fd = -1;
 745     uid_t found_uid = 0;
 746     gid_t found_gid = 0;
 747     pid_t found_pid = 0;
 748     int rc = pcmk_ok;
 749 
 750     static bool got_result = false;
 751     static bool result = false;
 752 
 753     if (got_result) {
 754         return result;
 755     }
 756 
 757     // Connect to CMAP
 758     do {
 759         cs_rc = pcmk__init_cmap(&cmap_handle);
 760         if (cs_rc != CS_OK) {
 761             retries++;
 762             crm_debug("CMAP connection failed: %s (rc=%d, retrying in %ds)",
 763                       cs_strerror(cs_rc), cs_rc, retries);
 764             sleep(retries);
 765         }
 766     } while ((retries < 5) && (cs_rc != CS_OK));
 767     if (cs_rc != CS_OK) {
 768         crm_warn("Assuming Corosync does not have node list: "
 769                  "CMAP connection failed (%s) " QB_XS " rc=%d",
 770                  cs_strerror(cs_rc), cs_rc);
 771         return false;
 772     }
 773 
 774     // Get CMAP connection file descriptor
 775     cs_rc = cmap_fd_get(cmap_handle, &fd);
 776     if (cs_rc != CS_OK) {
 777         crm_warn("Assuming Corosync does not have node list: "
 778                  "CMAP unusable (%s) " QB_XS " rc=%d",
 779                  cs_strerror(cs_rc), cs_rc);
 780         goto bail;
 781     }
 782 
 783     // Check whether CMAP connection is authentic (i.e. provided by root)
 784     rc = crm_ipc_is_authentic_process(fd, (uid_t) 0, (gid_t) 0,
 785                                       &found_pid, &found_uid, &found_gid);
 786     if (rc == 0) {
 787         crm_warn("Assuming Corosync does not have node list: "
 788                  "CMAP provider is inauthentic "
 789                  QB_XS " pid=%lld uid=%lld gid=%lld",
 790                  (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 791                  (long long) found_uid, (long long) found_gid);
 792         goto bail;
 793     } else if (rc < 0) {
 794         crm_warn("Assuming Corosync does not have node list: "
 795                  "Could not verify CMAP authenticity (%s) " QB_XS " rc=%d",
 796                   pcmk_strerror(rc), rc);
 797         goto bail;
 798     }
 799 
 800     // Check whether nodelist section is presetn
 801     cs_rc = cmap_iter_init(cmap_handle, "nodelist", &iter_handle);
 802     if (cs_rc != CS_OK) {
 803         crm_warn("Assuming Corosync does not have node list: "
 804                  "CMAP not readable (%s) " QB_XS " rc=%d",
 805                  cs_strerror(cs_rc), cs_rc);
 806         goto bail;
 807     }
 808 
 809     cs_rc = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL);
 810     if (cs_rc == CS_OK) {
 811         result = true;
 812     }
 813 
 814     cmap_iter_finalize(cmap_handle, iter_handle);
 815     got_result = true;
 816     crm_debug("Corosync %s node list", (result? "has" : "does not have"));
 817 
 818 bail:
 819     cmap_finalize(cmap_handle);
 820     return result;
 821 }

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