LCOV - code coverage report
Current view: top level - cluster - corosync.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 353 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 13 0.0 %

          Line data    Source code
       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           0 : pcmk__corosync_uuid(const crm_node_t *node)
      54             : {
      55           0 :     CRM_ASSERT(pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync);
      56             : 
      57           0 :     if (node != NULL) {
      58           0 :         if (node->id > 0) {
      59           0 :             return crm_strdup_printf("%u", node->id);
      60             :         } else {
      61           0 :             crm_info("Node %s is not yet known by Corosync", node->uname);
      62             :         }
      63             :     }
      64           0 :     return NULL;
      65             : }
      66             : 
      67             : static bool
      68           0 : node_name_is_valid(const char *key, const char *name)
      69             : {
      70             :     int octet;
      71             : 
      72           0 :     if (name == NULL) {
      73           0 :         crm_trace("%s is empty", key);
      74           0 :         return false;
      75             : 
      76           0 :     } else if (sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
      77           0 :         crm_trace("%s contains an IPv4 address (%s), ignoring", key, name);
      78           0 :         return false;
      79             : 
      80           0 :     } else if (strstr(name, ":") != NULL) {
      81           0 :         crm_trace("%s contains an IPv6 address (%s), ignoring", key, name);
      82           0 :         return false;
      83             :     }
      84           0 :     crm_trace("'%s: %s' is valid", key, name);
      85           0 :     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           0 : pcmk__corosync_name(uint64_t /*cmap_handle_t */ cmap_handle, uint32_t nodeid)
     102             : {
     103             :     // Originally based on corosync-quorumtool.c:node_name()
     104             : 
     105           0 :     int lpc = 0;
     106           0 :     cs_error_t rc = CS_OK;
     107           0 :     int retries = 0;
     108           0 :     char *name = NULL;
     109           0 :     cmap_handle_t local_handle = 0;
     110           0 :     int fd = -1;
     111           0 :     uid_t found_uid = 0;
     112           0 :     gid_t found_gid = 0;
     113           0 :     pid_t found_pid = 0;
     114             :     int rv;
     115             : 
     116           0 :     if (nodeid == 0) {
     117           0 :         nodeid = pcmk__cpg_local_nodeid(0);
     118             :     }
     119             : 
     120           0 :     if (cmap_handle == 0 && local_handle == 0) {
     121           0 :         retries = 0;
     122           0 :         crm_trace("Initializing CMAP connection");
     123             :         do {
     124           0 :             rc = pcmk__init_cmap(&local_handle);
     125           0 :             if (rc != CS_OK) {
     126           0 :                 retries++;
     127           0 :                 crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
     128             :                           retries);
     129           0 :                 sleep(retries);
     130             :             }
     131             : 
     132           0 :         } while (retries < 5 && rc != CS_OK);
     133             : 
     134           0 :         if (rc != CS_OK) {
     135           0 :             crm_warn("Could not connect to Cluster Configuration Database API, error %s",
     136             :                      cs_strerror(rc));
     137           0 :             local_handle = 0;
     138             :         }
     139             :     }
     140             : 
     141           0 :     if (cmap_handle == 0) {
     142           0 :         cmap_handle = local_handle;
     143             : 
     144           0 :         rc = cmap_fd_get(cmap_handle, &fd);
     145           0 :         if (rc != CS_OK) {
     146           0 :             crm_err("Could not obtain the CMAP API connection: %s (%d)",
     147             :                     cs_strerror(rc), rc);
     148           0 :             goto bail;
     149             :         }
     150             : 
     151             :         /* CMAP provider run as root (in given user namespace, anyway)? */
     152           0 :         if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
     153             :                                                 &found_uid, &found_gid))) {
     154           0 :             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           0 :             goto bail;
     159           0 :         } else if (rv < 0) {
     160           0 :             crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
     161             :                     strerror(-rv), -rv);
     162           0 :             goto bail;
     163             :         }
     164             :     }
     165             : 
     166           0 :     while (name == NULL && cmap_handle != 0) {
     167           0 :         uint32_t id = 0;
     168           0 :         char *key = NULL;
     169             : 
     170           0 :         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
     171           0 :         rc = cmap_get_uint32(cmap_handle, key, &id);
     172           0 :         crm_trace("Checking %u vs %u from %s", nodeid, id, key);
     173           0 :         free(key);
     174             : 
     175           0 :         if (rc != CS_OK) {
     176           0 :             break;
     177             :         }
     178             : 
     179           0 :         if (nodeid == id) {
     180           0 :             crm_trace("Searching for node name for %u in nodelist.node.%d %s",
     181             :                       nodeid, lpc, pcmk__s(name, "<null>"));
     182           0 :             if (name == NULL) {
     183           0 :                 key = crm_strdup_printf("nodelist.node.%d.name", lpc);
     184           0 :                 cmap_get_string(cmap_handle, key, &name);
     185           0 :                 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
     186           0 :                 free(key);
     187             :             }
     188           0 :             if (name == NULL) {
     189           0 :                 key = crm_strdup_printf("nodelist.node.%d.ring0_addr", lpc);
     190           0 :                 cmap_get_string(cmap_handle, key, &name);
     191           0 :                 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
     192             : 
     193           0 :                 if (!node_name_is_valid(key, name)) {
     194           0 :                     free(name);
     195           0 :                     name = NULL;
     196             :                 }
     197           0 :                 free(key);
     198             :             }
     199           0 :             break;
     200             :         }
     201             : 
     202           0 :         lpc++;
     203             :     }
     204             : 
     205           0 : bail:
     206           0 :     if(local_handle) {
     207           0 :         cmap_finalize(local_handle);
     208             :     }
     209             : 
     210           0 :     if (name == NULL) {
     211           0 :         crm_info("Unable to get node name for nodeid %u", nodeid);
     212             :     }
     213           0 :     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           0 : pcmk__corosync_disconnect(pcmk_cluster_t *cluster)
     224             : {
     225           0 :     pcmk__cpg_disconnect(cluster);
     226             : 
     227           0 :     if (pcmk_quorum_handle != 0) {
     228           0 :         quorum_finalize(pcmk_quorum_handle);
     229           0 :         pcmk_quorum_handle = 0;
     230             :     }
     231           0 :     crm_notice("Disconnected from Corosync");
     232           0 : }
     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           0 : quorum_dispatch_cb(gpointer user_data)
     244             : {
     245           0 :     int rc = quorum_dispatch(pcmk_quorum_handle, CS_DISPATCH_ALL);
     246             : 
     247           0 :     if (rc < 0) {
     248           0 :         crm_err("Connection to the Quorum API failed: %d", rc);
     249           0 :         quorum_finalize(pcmk_quorum_handle);
     250           0 :         pcmk_quorum_handle = 0;
     251           0 :         return -1;
     252             :     }
     253           0 :     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           0 : quorum_notification_cb(quorum_handle_t handle, uint32_t quorate,
     268             :                        uint64_t ring_id, uint32_t view_list_entries,
     269             :                        uint32_t *view_list)
     270             : {
     271             :     int i;
     272             :     GHashTableIter iter;
     273           0 :     crm_node_t *node = NULL;
     274             :     static gboolean init_phase = TRUE;
     275             : 
     276           0 :     if (quorate != crm_have_quorum) {
     277           0 :         if (quorate) {
     278           0 :             crm_notice("Quorum acquired " CRM_XS " membership=%" PRIu64 " members=%lu",
     279             :                        ring_id, (long unsigned int)view_list_entries);
     280             :         } else {
     281           0 :             crm_warn("Quorum lost " CRM_XS " membership=%" PRIu64 " members=%lu",
     282             :                      ring_id, (long unsigned int)view_list_entries);
     283             :         }
     284           0 :         crm_have_quorum = quorate;
     285             : 
     286             :     } else {
     287           0 :         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           0 :     if (view_list_entries == 0 && init_phase) {
     293           0 :         crm_info("Corosync membership is still forming, ignoring");
     294           0 :         return;
     295             :     }
     296             : 
     297           0 :     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           0 :     g_hash_table_iter_init(&iter, crm_peer_cache);
     302           0 :     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
     303           0 :         node->last_seen = 0;
     304             :     }
     305             : 
     306             :     /* Update the peer cache for each node in view list */
     307           0 :     for (i = 0; i < view_list_entries; i++) {
     308           0 :         uint32_t id = view_list[i];
     309             : 
     310           0 :         crm_debug("Member[%d] %u ", i, id);
     311             : 
     312             :         /* Get this node's peer cache entry (adding one if not already there) */
     313           0 :         node = pcmk__get_node(id, NULL, NULL, pcmk__node_search_cluster_member);
     314           0 :         if (node->uname == NULL) {
     315           0 :             char *name = pcmk__corosync_name(0, id);
     316             : 
     317           0 :             crm_info("Obtaining name for new node %u", id);
     318           0 :             node = pcmk__get_node(id, name, NULL,
     319             :                                   pcmk__node_search_cluster_member);
     320           0 :             free(name);
     321             :         }
     322             : 
     323             :         /* Update the node state (including updating last_seen to ring_id) */
     324           0 :         pcmk__update_peer_state(__func__, node, CRM_NODE_MEMBER, ring_id);
     325             :     }
     326             : 
     327             :     /* Remove any peer cache entries we didn't update */
     328           0 :     pcmk__reap_unseen_nodes(ring_id);
     329             : 
     330           0 :     if (quorum_app_callback) {
     331           0 :         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           0 : pcmk__corosync_quorum_connect(gboolean (*dispatch)(unsigned long long,
     344             :                                                    gboolean),
     345             :                               void (*destroy)(gpointer))
     346             : {
     347             :     cs_error_t rc;
     348           0 :     int fd = 0;
     349           0 :     int quorate = 0;
     350           0 :     uint32_t quorum_type = 0;
     351             :     struct mainloop_fd_callbacks quorum_fd_callbacks;
     352           0 :     uid_t found_uid = 0;
     353           0 :     gid_t found_gid = 0;
     354           0 :     pid_t found_pid = 0;
     355             :     int rv;
     356             : 
     357           0 :     quorum_fd_callbacks.dispatch = quorum_dispatch_cb;
     358           0 :     quorum_fd_callbacks.destroy = destroy;
     359             : 
     360           0 :     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           0 :         quorum_callbacks_t quorum_callbacks = {
     375             :             .quorum_notify_fn = quorum_notification_cb,
     376             :         };
     377             : 
     378           0 :         rc = quorum_initialize(&pcmk_quorum_handle, &quorum_callbacks,
     379             :                                &quorum_type);
     380             : #endif
     381             :     }
     382             : 
     383           0 :     if (rc != CS_OK) {
     384           0 :         crm_err("Could not connect to the Quorum API: %s (%d)",
     385             :                 cs_strerror(rc), rc);
     386           0 :         goto bail;
     387             : 
     388           0 :     } else if (quorum_type != QUORUM_SET) {
     389           0 :         crm_err("Corosync quorum is not configured");
     390           0 :         goto bail;
     391             :     }
     392             : 
     393           0 :     rc = quorum_fd_get(pcmk_quorum_handle, &fd);
     394           0 :     if (rc != CS_OK) {
     395           0 :         crm_err("Could not obtain the Quorum API connection: %s (%d)",
     396             :                 strerror(rc), rc);
     397           0 :         goto bail;
     398             :     }
     399             : 
     400             :     /* Quorum provider run as root (in given user namespace, anyway)? */
     401           0 :     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
     402             :                                             &found_uid, &found_gid))) {
     403           0 :         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           0 :         rc = CS_ERR_ACCESS;
     408           0 :         goto bail;
     409           0 :     } else if (rv < 0) {
     410           0 :         crm_err("Could not verify authenticity of Quorum provider: %s (%d)",
     411             :                 strerror(-rv), -rv);
     412           0 :         rc = CS_ERR_ACCESS;
     413           0 :         goto bail;
     414             :     }
     415             : 
     416           0 :     rc = quorum_getquorate(pcmk_quorum_handle, &quorate);
     417           0 :     if (rc != CS_OK) {
     418           0 :         crm_err("Could not obtain the current Quorum API state: %d", rc);
     419           0 :         goto bail;
     420             :     }
     421             : 
     422           0 :     if (quorate) {
     423           0 :         crm_notice("Quorum acquired");
     424             :     } else {
     425           0 :         crm_warn("No quorum");
     426             :     }
     427           0 :     quorum_app_callback = dispatch;
     428           0 :     crm_have_quorum = quorate;
     429             : 
     430           0 :     rc = quorum_trackstart(pcmk_quorum_handle, CS_TRACK_CHANGES | CS_TRACK_CURRENT);
     431           0 :     if (rc != CS_OK) {
     432           0 :         crm_err("Could not setup Quorum API notifications: %d", rc);
     433           0 :         goto bail;
     434             :     }
     435             : 
     436           0 :     mainloop_add_fd("quorum", G_PRIORITY_HIGH, fd, dispatch, &quorum_fd_callbacks);
     437             : 
     438           0 :     pcmk__corosync_add_nodes(NULL);
     439             : 
     440           0 :   bail:
     441           0 :     if (rc != CS_OK) {
     442           0 :         quorum_finalize(pcmk_quorum_handle);
     443             :     }
     444           0 : }
     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           0 : pcmk__corosync_connect(pcmk_cluster_t *cluster)
     456             : {
     457           0 :     crm_node_t *peer = NULL;
     458           0 :     const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
     459           0 :     const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
     460           0 :     int rc = pcmk_rc_ok;
     461             : 
     462           0 :     pcmk__cluster_init_node_caches();
     463             : 
     464           0 :     if (cluster_layer != pcmk_cluster_layer_corosync) {
     465           0 :         crm_err("Invalid cluster layer: %s " CRM_XS " cluster_layer=%d",
     466             :                 cluster_layer_s, cluster_layer);
     467           0 :         return EINVAL;
     468             :     }
     469             : 
     470           0 :     rc = pcmk__cpg_connect(cluster);
     471           0 :     if (rc != pcmk_rc_ok) {
     472             :         // Error message was logged by pcmk__cpg_connect()
     473           0 :         return rc;
     474             :     }
     475           0 :     crm_info("Connection to %s established", cluster_layer_s);
     476             : 
     477           0 :     cluster->nodeid = pcmk__cpg_local_nodeid(0);
     478           0 :     if (cluster->nodeid == 0) {
     479           0 :         crm_err("Could not determine local node ID");
     480           0 :         return ENXIO;
     481             :     }
     482             : 
     483           0 :     cluster->uname = pcmk__cluster_node_name(0);
     484           0 :     if (cluster->uname == NULL) {
     485           0 :         crm_err("Could not determine local node name");
     486           0 :         return ENXIO;
     487             :     }
     488             : 
     489             :     // Ensure local node always exists in peer cache
     490           0 :     peer = pcmk__get_node(cluster->nodeid, cluster->uname, NULL,
     491             :                           pcmk__node_search_cluster_member);
     492           0 :     cluster->uuid = pcmk__corosync_uuid(peer);
     493             : 
     494           0 :     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           0 : pcmk__corosync_is_active(void)
     505             : {
     506             :     cmap_handle_t handle;
     507           0 :     int rc = pcmk__init_cmap(&handle);
     508             : 
     509           0 :     if (rc == CS_OK) {
     510           0 :         cmap_finalize(handle);
     511           0 :         return true;
     512             :     }
     513             : 
     514           0 :     crm_info("Failed to initialize the cmap API: %s (%d)",
     515             :              pcmk__cs_err_str(rc), rc);
     516           0 :     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           0 : pcmk__corosync_is_peer_active(const crm_node_t *node)
     529             : {
     530           0 :     if (node == NULL) {
     531           0 :         crm_trace("Corosync peer inactive: NULL");
     532           0 :         return false;
     533             :     }
     534           0 :     if (!pcmk__str_eq(node->state, CRM_NODE_MEMBER, pcmk__str_none)) {
     535           0 :         crm_trace("Corosync peer %s inactive: state=%s",
     536             :                   node->uname, node->state);
     537           0 :         return false;
     538             :     }
     539           0 :     if (!pcmk_is_set(node->processes, crm_proc_cpg)) {
     540           0 :         crm_trace("Corosync peer %s inactive " CRM_XS " processes=%.16" PRIx32,
     541             :                   node->uname, node->processes);
     542           0 :         return false;
     543             :     }
     544           0 :     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           0 : pcmk__corosync_add_nodes(xmlNode *xml_parent)
     557             : {
     558           0 :     int lpc = 0;
     559           0 :     cs_error_t rc = CS_OK;
     560           0 :     int retries = 0;
     561           0 :     bool any = false;
     562             :     cmap_handle_t cmap_handle;
     563           0 :     int fd = -1;
     564           0 :     uid_t found_uid = 0;
     565           0 :     gid_t found_gid = 0;
     566           0 :     pid_t found_pid = 0;
     567             :     int rv;
     568             : 
     569             :     do {
     570           0 :         rc = pcmk__init_cmap(&cmap_handle);
     571           0 :         if (rc != CS_OK) {
     572           0 :             retries++;
     573           0 :             crm_debug("API connection setup failed: %s.  Retrying in %ds", cs_strerror(rc),
     574             :                       retries);
     575           0 :             sleep(retries);
     576             :         }
     577             : 
     578           0 :     } while (retries < 5 && rc != CS_OK);
     579             : 
     580           0 :     if (rc != CS_OK) {
     581           0 :         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
     582           0 :         return false;
     583             :     }
     584             : 
     585           0 :     rc = cmap_fd_get(cmap_handle, &fd);
     586           0 :     if (rc != CS_OK) {
     587           0 :         crm_err("Could not obtain the CMAP API connection: %s (%d)",
     588             :                 cs_strerror(rc), rc);
     589           0 :         goto bail;
     590             :     }
     591             : 
     592             :     /* CMAP provider run as root (in given user namespace, anyway)? */
     593           0 :     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
     594             :                                             &found_uid, &found_gid))) {
     595           0 :         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           0 :         goto bail;
     600           0 :     } else if (rv < 0) {
     601           0 :         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
     602             :                 strerror(-rv), -rv);
     603           0 :         goto bail;
     604             :     }
     605             : 
     606           0 :     pcmk__cluster_init_node_caches();
     607           0 :     crm_trace("Initializing Corosync node list");
     608           0 :     for (lpc = 0; TRUE; lpc++) {
     609           0 :         uint32_t nodeid = 0;
     610           0 :         char *name = NULL;
     611           0 :         char *key = NULL;
     612             : 
     613           0 :         key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
     614           0 :         rc = cmap_get_uint32(cmap_handle, key, &nodeid);
     615           0 :         free(key);
     616             : 
     617           0 :         if (rc != CS_OK) {
     618           0 :             break;
     619             :         }
     620             : 
     621           0 :         name = pcmk__corosync_name(cmap_handle, nodeid);
     622           0 :         if (name != NULL) {
     623             :             GHashTableIter iter;
     624           0 :             crm_node_t *node = NULL;
     625             : 
     626           0 :             g_hash_table_iter_init(&iter, crm_peer_cache);
     627           0 :             while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
     628           0 :                 if(node && node->uname && strcasecmp(node->uname, name) == 0) {
     629           0 :                     if (node->id && node->id != nodeid) {
     630           0 :                         crm_crit("Nodes %u and %u share the same name '%s': shutting down", node->id,
     631             :                                  nodeid, name);
     632           0 :                         crm_exit(CRM_EX_FATAL);
     633             :                     }
     634             :                 }
     635             :             }
     636             :         }
     637             : 
     638           0 :         if (nodeid > 0 || name != NULL) {
     639           0 :             crm_trace("Initializing node[%d] %u = %s", lpc, nodeid, name);
     640           0 :             pcmk__get_node(nodeid, name, NULL, pcmk__node_search_cluster_member);
     641             :         }
     642             : 
     643           0 :         if (nodeid > 0 && name != NULL) {
     644           0 :             any = true;
     645             : 
     646           0 :             if (xml_parent) {
     647           0 :                 xmlNode *node = pcmk__xe_create(xml_parent, PCMK_XE_NODE);
     648             : 
     649           0 :                 crm_xml_set_id(node, "%u", nodeid);
     650           0 :                 crm_xml_add(node, PCMK_XA_UNAME, name);
     651             :             }
     652             :         }
     653             : 
     654           0 :         free(name);
     655             :     }
     656           0 : bail:
     657           0 :     cmap_finalize(cmap_handle);
     658           0 :     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           0 : pcmk__corosync_cluster_name(void)
     669             : {
     670             :     cmap_handle_t handle;
     671           0 :     char *cluster_name = NULL;
     672           0 :     cs_error_t rc = CS_OK;
     673           0 :     int fd = -1;
     674           0 :     uid_t found_uid = 0;
     675           0 :     gid_t found_gid = 0;
     676           0 :     pid_t found_pid = 0;
     677             :     int rv;
     678             : 
     679           0 :     rc = pcmk__init_cmap(&handle);
     680           0 :     if (rc != CS_OK) {
     681           0 :         crm_info("Failed to initialize the cmap API: %s (%d)",
     682             :                  cs_strerror(rc), rc);
     683           0 :         return NULL;
     684             :     }
     685             : 
     686           0 :     rc = cmap_fd_get(handle, &fd);
     687           0 :     if (rc != CS_OK) {
     688           0 :         crm_err("Could not obtain the CMAP API connection: %s (%d)",
     689             :                 cs_strerror(rc), rc);
     690           0 :         goto bail;
     691             :     }
     692             : 
     693             :     /* CMAP provider run as root (in given user namespace, anyway)? */
     694           0 :     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
     695             :                                             &found_uid, &found_gid))) {
     696           0 :         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           0 :         goto bail;
     701           0 :     } else if (rv < 0) {
     702           0 :         crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
     703             :                 strerror(-rv), -rv);
     704           0 :         goto bail;
     705             :     }
     706             : 
     707           0 :     rc = cmap_get_string(handle, "totem.cluster_name", &cluster_name);
     708           0 :     if (rc != CS_OK) {
     709           0 :         crm_info("Cannot get totem.cluster_name: %s (%d)", cs_strerror(rc), rc);
     710             : 
     711             :     } else {
     712           0 :         crm_debug("cmap totem.cluster_name = '%s'", cluster_name);
     713             :     }
     714             : 
     715           0 : bail:
     716           0 :     cmap_finalize(handle);
     717           0 :     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           0 : pcmk__corosync_has_nodelist(void)
     728             : {
     729           0 :     cs_error_t cs_rc = CS_OK;
     730           0 :     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           0 :     int fd = -1;
     735           0 :     uid_t found_uid = 0;
     736           0 :     gid_t found_gid = 0;
     737           0 :     pid_t found_pid = 0;
     738           0 :     int rc = pcmk_ok;
     739             : 
     740             :     static bool got_result = false;
     741             :     static bool result = false;
     742             : 
     743           0 :     if (got_result) {
     744           0 :         return result;
     745             :     }
     746             : 
     747             :     // Connect to CMAP
     748             :     do {
     749           0 :         cs_rc = pcmk__init_cmap(&cmap_handle);
     750           0 :         if (cs_rc != CS_OK) {
     751           0 :             retries++;
     752           0 :             crm_debug("CMAP connection failed: %s (rc=%d, retrying in %ds)",
     753             :                       cs_strerror(cs_rc), cs_rc, retries);
     754           0 :             sleep(retries);
     755             :         }
     756           0 :     } while ((retries < 5) && (cs_rc != CS_OK));
     757           0 :     if (cs_rc != CS_OK) {
     758           0 :         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           0 :         return false;
     762             :     }
     763             : 
     764             :     // Get CMAP connection file descriptor
     765           0 :     cs_rc = cmap_fd_get(cmap_handle, &fd);
     766           0 :     if (cs_rc != CS_OK) {
     767           0 :         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           0 :         goto bail;
     771             :     }
     772             : 
     773             :     // Check whether CMAP connection is authentic (i.e. provided by root)
     774           0 :     rc = crm_ipc_is_authentic_process(fd, (uid_t) 0, (gid_t) 0,
     775             :                                       &found_pid, &found_uid, &found_gid);
     776           0 :     if (rc == 0) {
     777           0 :         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           0 :         goto bail;
     783           0 :     } else if (rc < 0) {
     784           0 :         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           0 :         goto bail;
     788             :     }
     789             : 
     790             :     // Check whether nodelist section is presetn
     791           0 :     cs_rc = cmap_iter_init(cmap_handle, "nodelist", &iter_handle);
     792           0 :     if (cs_rc != CS_OK) {
     793           0 :         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           0 :         goto bail;
     797             :     }
     798             : 
     799           0 :     cs_rc = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL);
     800           0 :     if (cs_rc == CS_OK) {
     801           0 :         result = true;
     802             :     }
     803             : 
     804           0 :     cmap_iter_finalize(cmap_handle, iter_handle);
     805           0 :     got_result = true;
     806           0 :     crm_debug("Corosync %s node list", (result? "has" : "does not have"));
     807             : 
     808           0 : bail:
     809           0 :     cmap_finalize(cmap_handle);
     810           0 :     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)
     820             : {
     821             :     return pcmk__corosync_is_peer_active(node);
     822             : }
     823             : 
     824             : // LCOV_EXCL_STOP
     825             : // End deprecated API

Generated by: LCOV version 1.14