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. set_cluster_type
  11. get_cluster_type
  12. is_corosync_cluster
  13. node_name_is_valid

   1 /*
   2  * Copyright 2004-2020 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 
  27 CRM_TRACE_INIT_DATA(cluster);
  28 
  29 const char *
  30 crm_peer_uuid(crm_node_t *peer)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32     char *uuid = NULL;
  33     enum cluster_type_e type = get_cluster_type();
  34 
  35     // Check simple cases first, to avoid any calls that might block
  36     if(peer == NULL) {
  37         return NULL;
  38 
  39     } else if (peer->uuid) {
  40         return peer->uuid;
  41     }
  42 
  43     switch (type) {
  44         case pcmk_cluster_corosync:
  45 #if SUPPORT_COROSYNC
  46             uuid = get_corosync_uuid(peer);
  47 #endif
  48             break;
  49 
  50         case pcmk_cluster_unknown:
  51         case pcmk_cluster_invalid:
  52             crm_err("Unsupported cluster type");
  53             break;
  54     }
  55 
  56     peer->uuid = uuid;
  57     return peer->uuid;
  58 }
  59 
  60 gboolean
  61 crm_cluster_connect(crm_cluster_t * cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63     enum cluster_type_e type = get_cluster_type();
  64 
  65     crm_notice("Connecting to cluster infrastructure: %s",
  66                name_for_cluster_type(type));
  67     switch (type) {
  68         case pcmk_cluster_corosync:
  69 #if SUPPORT_COROSYNC
  70             if (is_corosync_cluster()) {
  71                 crm_peer_init();
  72                 return init_cs_connection(cluster);
  73             }
  74 #endif
  75             break;
  76         default:
  77             break;
  78     }
  79     return FALSE;
  80 }
  81 
  82 void
  83 crm_cluster_disconnect(crm_cluster_t * cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     enum cluster_type_e type = get_cluster_type();
  86 
  87     crm_info("Disconnecting from cluster infrastructure: %s",
  88              name_for_cluster_type(type));
  89     switch (type) {
  90         case pcmk_cluster_corosync:
  91 #if SUPPORT_COROSYNC
  92             if (is_corosync_cluster()) {
  93                 crm_peer_destroy();
  94                 terminate_cs_connection(cluster);
  95             }
  96 #endif
  97             break;
  98         default:
  99             break;
 100     }
 101 }
 102 
 103 gboolean
 104 send_cluster_message(crm_node_t * node, enum crm_ais_msg_types service, xmlNode * data,
     /* [previous][next][first][last][top][bottom][index][help] */
 105                      gboolean ordered)
 106 {
 107     switch (get_cluster_type()) {
 108         case pcmk_cluster_corosync:
 109 #if SUPPORT_COROSYNC
 110             return send_cluster_message_cs(data, FALSE, node, service);
 111 #endif
 112             break;
 113         default:
 114             break;
 115     }
 116     return FALSE;
 117 }
 118 
 119 const char *
 120 get_local_node_name(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122     static char *name = NULL;
 123 
 124     if(name) {
 125         return name;
 126     }
 127     name = get_node_name(0);
 128     return name;
 129 }
 130 
 131 char *
 132 get_node_name(uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     char *name = NULL;
 135     enum cluster_type_e stack;
 136 
 137     stack = get_cluster_type();
 138     switch (stack) {
 139 #  if SUPPORT_COROSYNC
 140         case pcmk_cluster_corosync:
 141             name = corosync_node_name(0, nodeid);
 142             break;
 143 #  endif
 144 
 145         default:
 146             crm_err("Unknown cluster type: %s (%d)", name_for_cluster_type(stack), stack);
 147     }
 148 
 149     if(name == NULL && nodeid == 0) {
 150         name = pcmk_hostname();
 151         if (name == NULL) {
 152             crm_err("Could not obtain the local %s node name",
 153                     name_for_cluster_type(stack));
 154             crm_exit(CRM_EX_FATAL);
 155         }
 156         crm_notice("Defaulting to uname -n for the local %s node name",
 157                    name_for_cluster_type(stack));
 158     }
 159 
 160     if (name == NULL) {
 161         crm_notice("Could not obtain a node name for %s nodeid %u",
 162                    name_for_cluster_type(stack), nodeid);
 163     }
 164     return name;
 165 }
 166 
 167 /*!
 168  * \brief Get the node name corresponding to a node UUID
 169  *
 170  * \param[in] uuid  UUID of desired node
 171  *
 172  * \return name of desired node
 173  *
 174  * \note This relies on the remote peer cache being populated with all
 175  *       remote nodes in the cluster, so callers should maintain that cache.
 176  */
 177 const char *
 178 crm_peer_uname(const char *uuid)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180     GHashTableIter iter;
 181     crm_node_t *node = NULL;
 182 
 183     CRM_CHECK(uuid != NULL, return NULL);
 184 
 185     /* remote nodes have the same uname and uuid */
 186     if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) {
 187         return uuid;
 188     }
 189 
 190     /* avoid blocking calls where possible */
 191     g_hash_table_iter_init(&iter, crm_peer_cache);
 192     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 193         if(node->uuid && strcasecmp(node->uuid, uuid) == 0) {
 194             if(node->uname) {
 195                 return node->uname;
 196             }
 197             break;
 198         }
 199     }
 200     node = NULL;
 201 
 202 #if SUPPORT_COROSYNC
 203     if (is_corosync_cluster()) {
 204         uint32_t id = (uint32_t) crm_parse_ll(uuid, NULL);
 205 
 206         if (id != 0) {
 207             node = crm_find_peer(id, NULL);
 208         } else {
 209             crm_err("Invalid node id: %s", uuid);
 210         }
 211 
 212         if (node) {
 213             crm_info("Setting uuid for node %s[%u] to '%s'", node->uname, node->id, uuid);
 214             node->uuid = strdup(uuid);
 215             if(node->uname) {
 216                 return node->uname;
 217             }
 218         }
 219         return NULL;
 220     }
 221 #endif
 222 
 223     return NULL;
 224 }
 225 
 226 void
 227 set_uuid(xmlNode *xml, const char *attr, crm_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 228 {
 229     const char *uuid_calc = crm_peer_uuid(node);
 230 
 231     crm_xml_add(xml, attr, uuid_calc);
 232     return;
 233 }
 234 
 235 const char *
 236 name_for_cluster_type(enum cluster_type_e type)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238     switch (type) {
 239         case pcmk_cluster_corosync:
 240             return "corosync";
 241         case pcmk_cluster_unknown:
 242             return "unknown";
 243         case pcmk_cluster_invalid:
 244             return "invalid";
 245     }
 246     crm_err("Invalid cluster type: %d", type);
 247     return "invalid";
 248 }
 249 
 250 /* Do not expose these two */
 251 int set_cluster_type(enum cluster_type_e type);
 252 static enum cluster_type_e cluster_type = pcmk_cluster_unknown;
 253 
 254 int
 255 set_cluster_type(enum cluster_type_e type)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257     if (cluster_type == pcmk_cluster_unknown) {
 258         crm_info("Cluster type set to: %s", name_for_cluster_type(type));
 259         cluster_type = type;
 260         return 0;
 261 
 262     } else if (cluster_type == type) {
 263         return 0;
 264 
 265     } else if (pcmk_cluster_unknown == type) {
 266         cluster_type = type;
 267         return 0;
 268     }
 269 
 270     crm_err("Cluster type already set to %s, ignoring %s",
 271             name_for_cluster_type(cluster_type), name_for_cluster_type(type));
 272     return -1;
 273 }
 274 enum cluster_type_e
 275 get_cluster_type(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277     bool detected = FALSE;
 278     const char *cluster = NULL;
 279 
 280     /* Return the previous calculation, if any */
 281     if (cluster_type != pcmk_cluster_unknown) {
 282         return cluster_type;
 283     }
 284 
 285     cluster = pcmk__env_option("cluster_type");
 286 
 287 #if SUPPORT_COROSYNC
 288     /* If nothing is defined in the environment, try corosync (if supported) */
 289     if(cluster == NULL) {
 290         crm_debug("Testing with Corosync");
 291         cluster_type = find_corosync_variant();
 292         if (cluster_type != pcmk_cluster_unknown) {
 293             detected = TRUE;
 294             goto done;
 295         }
 296     }
 297 #endif
 298 
 299     /* Something was defined in the environment, test it against what we support */
 300     crm_info("Verifying cluster type: '%s'", cluster?cluster:"-unspecified-");
 301     if (cluster == NULL) {
 302 
 303 #if SUPPORT_COROSYNC
 304     } else if (pcmk__str_eq(cluster, "corosync", pcmk__str_casei)) {
 305         cluster_type = pcmk_cluster_corosync;
 306 #endif
 307 
 308     } else {
 309         cluster_type = pcmk_cluster_invalid;
 310         goto done; /* Keep the compiler happy when no stacks are supported */
 311     }
 312 
 313   done:
 314     if (cluster_type == pcmk_cluster_unknown) {
 315         crm_notice("Could not determine the current cluster type");
 316 
 317     } else if (cluster_type == pcmk_cluster_invalid) {
 318         crm_notice("This installation does not support the '%s' cluster infrastructure: terminating.",
 319                    cluster);
 320         crm_exit(CRM_EX_FATAL);
 321 
 322     } else {
 323         crm_info("%s an active '%s' cluster", detected?"Detected":"Assuming", name_for_cluster_type(cluster_type));
 324     }
 325 
 326     return cluster_type;
 327 }
 328 
 329 gboolean
 330 is_corosync_cluster(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332     return get_cluster_type() == pcmk_cluster_corosync;
 333 }
 334 
 335 gboolean
 336 node_name_is_valid(const char *key, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 337 {
 338     int octet;
 339 
 340     if (name == NULL) {
 341         crm_trace("%s is empty", key);
 342         return FALSE;
 343 
 344     } else if (sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
 345         crm_trace("%s contains an ipv4 address, ignoring: %s", key, name);
 346         return FALSE;
 347 
 348     } else if (strstr(name, ":") != NULL) {
 349         crm_trace("%s contains an ipv6 address, ignoring: %s", key, name);
 350         return FALSE;
 351     }
 352     crm_trace("%s is valid", key);
 353     return TRUE;
 354 }

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