root/lib/cluster/cluster.c

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

DEFINITIONS

This source file includes following definitions.
  1. crm_peer_uuid
  2. crm_cluster_connect
  3. crm_cluster_disconnect
  4. send_cluster_message
  5. get_local_node_name
  6. get_node_name
  7. crm_peer_uname
  8. set_uuid
  9. name_for_cluster_type
  10. get_cluster_type
  11. is_corosync_cluster

   1 /*
   2  * Copyright 2004-2021 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 #include <dlfcn.h>
  12 
  13 #include <stdio.h>
  14 #include <unistd.h>
  15 #include <string.h>
  16 #include <stdlib.h>
  17 #include <time.h>
  18 #include <sys/param.h>
  19 #include <sys/types.h>
  20 
  21 #include <crm/crm.h>
  22 #include <crm/msg_xml.h>
  23 
  24 #include <crm/common/ipc.h>
  25 #include <crm/cluster/internal.h>
  26 #include "crmcluster_private.h"
  27 
  28 CRM_TRACE_INIT_DATA(cluster);
  29 
  30 /*!
  31  * \brief Get (and set if needed) a node's UUID
  32  *
  33  * \param[in] peer  Node to check
  34  *
  35  * \return Node UUID of \p peer, or NULL if unknown
  36  */
  37 const char *
  38 crm_peer_uuid(crm_node_t *peer)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40     char *uuid = NULL;
  41 
  42     // Check simple cases first, to avoid any calls that might block
  43     if (peer == NULL) {
  44         return NULL;
  45     }
  46     if (peer->uuid != NULL) {
  47         return peer->uuid;
  48     }
  49 
  50     switch (get_cluster_type()) {
  51         case pcmk_cluster_corosync:
  52 #if SUPPORT_COROSYNC
  53             uuid = pcmk__corosync_uuid(peer);
  54 #endif
  55             break;
  56 
  57         case pcmk_cluster_unknown:
  58         case pcmk_cluster_invalid:
  59             crm_err("Unsupported cluster type");
  60             break;
  61     }
  62 
  63     peer->uuid = uuid;
  64     return peer->uuid;
  65 }
  66 
  67 /*!
  68  * \brief Connect to the cluster layer
  69  *
  70  * \param[in] Initialized cluster object to connect
  71  *
  72  * \return TRUE on success, otherwise FALSE
  73  */
  74 gboolean
  75 crm_cluster_connect(crm_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     enum cluster_type_e type = get_cluster_type();
  78 
  79     crm_notice("Connecting to %s cluster infrastructure",
  80                name_for_cluster_type(type));
  81     switch (type) {
  82         case pcmk_cluster_corosync:
  83 #if SUPPORT_COROSYNC
  84             if (is_corosync_cluster()) {
  85                 crm_peer_init();
  86                 return pcmk__corosync_connect(cluster);
  87             }
  88 #endif
  89             break;
  90         default:
  91             break;
  92     }
  93     return FALSE;
  94 }
  95 
  96 /*!
  97  * \brief Disconnect from the cluster layer
  98  *
  99  * \param[in] cluster  Cluster object to disconnect
 100  */
 101 void
 102 crm_cluster_disconnect(crm_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104     enum cluster_type_e type = get_cluster_type();
 105 
 106     crm_info("Disconnecting from %s cluster infrastructure",
 107              name_for_cluster_type(type));
 108     switch (type) {
 109         case pcmk_cluster_corosync:
 110 #if SUPPORT_COROSYNC
 111             if (is_corosync_cluster()) {
 112                 crm_peer_destroy();
 113                 pcmk__corosync_disconnect(cluster);
 114             }
 115 #endif
 116             break;
 117         default:
 118             break;
 119     }
 120 }
 121 
 122 /*!
 123  * \brief Send an XML message via the cluster messaging layer
 124  *
 125  * \param[in] node     Cluster node to send message to
 126  * \param[in] service  Message type to use in message host info
 127  * \param[in] data     XML message to send
 128  * \param[in] ordered  Ignored for currently supported messaging layers
 129  *
 130  * \return TRUE on success, otherwise FALSE
 131  */
 132 gboolean
 133 send_cluster_message(crm_node_t *node, enum crm_ais_msg_types service,
     /* [previous][next][first][last][top][bottom][index][help] */
 134                      xmlNode *data, gboolean ordered)
 135 {
 136     switch (get_cluster_type()) {
 137         case pcmk_cluster_corosync:
 138 #if SUPPORT_COROSYNC
 139             return pcmk__cpg_send_xml(data, node, service);
 140 #endif
 141             break;
 142         default:
 143             break;
 144     }
 145     return FALSE;
 146 }
 147 
 148 /*!
 149  * \brief Get the local node's name
 150  *
 151  * \return Local node's name
 152  * \note This will fatally exit if local node name cannot be known.
 153  */
 154 const char *
 155 get_local_node_name(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157     static char *name = NULL;
 158 
 159     if (name == NULL) {
 160         name = get_node_name(0);
 161     }
 162     return name;
 163 }
 164 
 165 /*!
 166  * \brief Get the node name corresponding to a cluster node ID
 167  *
 168  * \param[in] nodeid  Node ID to check (or 0 for local node)
 169  *
 170  * \return Node name corresponding to \p nodeid
 171  * \note This will fatally exit if \p nodeid is 0 and local node name cannot be
 172  *       known.
 173  */
 174 char *
 175 get_node_name(uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177     char *name = NULL;
 178     enum cluster_type_e stack = get_cluster_type();
 179 
 180     switch (stack) {
 181 #  if SUPPORT_COROSYNC
 182         case pcmk_cluster_corosync:
 183             name = pcmk__corosync_name(0, nodeid);
 184             break;
 185 #  endif
 186 
 187         default:
 188             crm_err("Unknown cluster type: %s (%d)", name_for_cluster_type(stack), stack);
 189     }
 190 
 191     if ((name == NULL) && (nodeid == 0)) {
 192         name = pcmk_hostname();
 193         if (name == NULL) {
 194             // @TODO Maybe let the caller decide what to do
 195             crm_err("Could not obtain the local %s node name",
 196                     name_for_cluster_type(stack));
 197             crm_exit(CRM_EX_FATAL);
 198         }
 199         crm_notice("Defaulting to uname -n for the local %s node name",
 200                    name_for_cluster_type(stack));
 201     }
 202 
 203     if (name == NULL) {
 204         crm_notice("Could not obtain a node name for %s node with id %u",
 205                    name_for_cluster_type(stack), nodeid);
 206     }
 207     return name;
 208 }
 209 
 210 /*!
 211  * \brief Get the node name corresponding to a node UUID
 212  *
 213  * \param[in] uuid  UUID of desired node
 214  *
 215  * \return name of desired node
 216  *
 217  * \note This relies on the remote peer cache being populated with all
 218  *       remote nodes in the cluster, so callers should maintain that cache.
 219  */
 220 const char *
 221 crm_peer_uname(const char *uuid)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223     GHashTableIter iter;
 224     crm_node_t *node = NULL;
 225 
 226     CRM_CHECK(uuid != NULL, return NULL);
 227 
 228     /* remote nodes have the same uname and uuid */
 229     if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) {
 230         return uuid;
 231     }
 232 
 233     /* avoid blocking calls where possible */
 234     g_hash_table_iter_init(&iter, crm_peer_cache);
 235     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 236         if (pcmk__str_eq(node->uuid, uuid, pcmk__str_casei)) {
 237             if (node->uname != NULL) {
 238                 return node->uname;
 239             }
 240             break;
 241         }
 242     }
 243     node = NULL;
 244 
 245 #if SUPPORT_COROSYNC
 246     if (is_corosync_cluster()) {
 247         long long id;
 248 
 249         if ((pcmk__scan_ll(uuid, &id, 0LL) != pcmk_rc_ok)
 250             || (id < 1LL) || (id > UINT32_MAX))  {
 251             crm_err("Invalid Corosync node ID '%s'", uuid);
 252             return NULL;
 253         }
 254 
 255         node = pcmk__search_cluster_node_cache((uint32_t) id, NULL);
 256         if (node != NULL) {
 257             crm_info("Setting uuid for node %s[%u] to %s",
 258                      node->uname, node->id, uuid);
 259             node->uuid = strdup(uuid);
 260             return node->uname;
 261         }
 262         return NULL;
 263     }
 264 #endif
 265 
 266     return NULL;
 267 }
 268 
 269 /*!
 270  * \brief Add a node's UUID as an XML attribute
 271  *
 272  * \param[in,out] xml   XML element to add UUID to
 273  * \param[in]     attr  XML attribute name to set
 274  * \param[in]     node  Node whose UUID should be used as attribute value
 275  */
 276 void
 277 set_uuid(xmlNode *xml, const char *attr, crm_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279     crm_xml_add(xml, attr, crm_peer_uuid(node));
 280 }
 281 
 282 /*!
 283  * \brief  Get a log-friendly string equivalent of a cluster type
 284  *
 285  * \param[in] type  Cluster type
 286  *
 287  * \return Log-friendly string corresponding to \p type
 288  */
 289 const char *
 290 name_for_cluster_type(enum cluster_type_e type)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292     switch (type) {
 293         case pcmk_cluster_corosync:
 294             return "corosync";
 295         case pcmk_cluster_unknown:
 296             return "unknown";
 297         case pcmk_cluster_invalid:
 298             return "invalid";
 299     }
 300     crm_err("Invalid cluster type: %d", type);
 301     return "invalid";
 302 }
 303 
 304 /*!
 305  * \brief Get (and validate) the local cluster type
 306  *
 307  * \return Local cluster type
 308  * \note This will fatally exit if the local cluster type is invalid.
 309  */
 310 enum cluster_type_e
 311 get_cluster_type(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 312 {
 313     bool detected = false;
 314     const char *cluster = NULL;
 315     static enum cluster_type_e cluster_type = pcmk_cluster_unknown;
 316 
 317     /* Return the previous calculation, if any */
 318     if (cluster_type != pcmk_cluster_unknown) {
 319         return cluster_type;
 320     }
 321 
 322     cluster = pcmk__env_option("cluster_type");
 323 
 324 #if SUPPORT_COROSYNC
 325     /* If nothing is defined in the environment, try corosync (if supported) */
 326     if (cluster == NULL) {
 327         crm_debug("Testing with Corosync");
 328         cluster_type = pcmk__corosync_detect();
 329         if (cluster_type != pcmk_cluster_unknown) {
 330             detected = true;
 331             goto done;
 332         }
 333     }
 334 #endif
 335 
 336     /* Something was defined in the environment, test it against what we support */
 337     crm_info("Verifying cluster type: '%s'",
 338              ((cluster == NULL)? "-unspecified-" : cluster));
 339     if (cluster == NULL) {
 340 
 341 #if SUPPORT_COROSYNC
 342     } else if (pcmk__str_eq(cluster, "corosync", pcmk__str_casei)) {
 343         cluster_type = pcmk_cluster_corosync;
 344 #endif
 345 
 346     } else {
 347         cluster_type = pcmk_cluster_invalid;
 348         goto done; /* Keep the compiler happy when no stacks are supported */
 349     }
 350 
 351   done:
 352     if (cluster_type == pcmk_cluster_unknown) {
 353         crm_notice("Could not determine the current cluster type");
 354 
 355     } else if (cluster_type == pcmk_cluster_invalid) {
 356         crm_notice("This installation does not support the '%s' cluster infrastructure: terminating.",
 357                    cluster);
 358         crm_exit(CRM_EX_FATAL);
 359 
 360     } else {
 361         crm_info("%s an active '%s' cluster",
 362                  (detected? "Detected" : "Assuming"),
 363                  name_for_cluster_type(cluster_type));
 364     }
 365 
 366     return cluster_type;
 367 }
 368 
 369 /*!
 370  * \brief Check whether the local cluster is a Corosync cluster
 371  *
 372  * \return TRUE if the local cluster is a Corosync cluster, otherwise FALSE
 373  */
 374 gboolean
 375 is_corosync_cluster(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377     return get_cluster_type() == pcmk_cluster_corosync;
 378 }

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