pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
cluster.c
Go to the documentation of this file.
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 #include <dlfcn.h>
12 
13 #include <inttypes.h> // PRIu32
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <time.h>
20 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h> // uname()
23 
24 #include <glib.h> // gboolean
25 
26 #include <crm/crm.h>
27 
28 #include <crm/common/ipc.h>
29 #include <crm/common/xml.h>
30 #include <crm/cluster/internal.h>
31 #include "crmcluster_private.h"
32 
33 CRM_TRACE_INIT_DATA(cluster);
34 
43 const char *
45 {
46  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
47 
48  if (node == NULL) {
49  return NULL;
50  }
51  if (node->xml_id != NULL) {
52  return node->xml_id;
53  }
54 
55  switch (cluster_layer) {
56 #if SUPPORT_COROSYNC
58  node->xml_id = pcmk__corosync_uuid(node);
59  return node->xml_id;
60 #endif // SUPPORT_COROSYNC
61 
62  default:
63  crm_err("Unsupported cluster layer %s",
64  pcmk_cluster_layer_text(cluster_layer));
65  return NULL;
66  }
67 }
68 
77 int
79 {
80  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
81  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
82 
83  if (cluster == NULL) {
84  return EINVAL;
85  }
86 
87  // cts-lab looks for this message
88  crm_notice("Connecting to %s cluster layer", cluster_layer_s);
89 
90  switch (cluster_layer) {
91 #if SUPPORT_COROSYNC
93  return pcmk__corosync_connect(cluster);
94 #endif // SUPPORT_COROSYNC
95 
96  default:
97  break;
98  }
99 
100  crm_err("Failed to connect to unsupported cluster layer %s",
101  cluster_layer_s);
102  return EPROTONOSUPPORT;
103 }
104 
112 int
114 {
115  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
116  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
117 
118  crm_info("Disconnecting from %s cluster layer", cluster_layer_s);
119 
120  switch (cluster_layer) {
121 #if SUPPORT_COROSYNC
123  pcmk__corosync_disconnect(cluster);
125  return pcmk_rc_ok;
126 #endif // SUPPORT_COROSYNC
127 
128  default:
129  break;
130  }
131 
132  crm_err("Failed to disconnect from unsupported cluster layer %s",
133  cluster_layer_s);
134  return EPROTONOSUPPORT;
135 }
136 
146 {
147  pcmk_cluster_t *cluster = pcmk__assert_alloc(1, sizeof(pcmk_cluster_t));
148 
149  cluster->priv = pcmk__assert_alloc(1, sizeof(pcmk__cluster_private_t));
151  return cluster;
152 }
153 
159 void
161 {
162  if (cluster == NULL) {
163  return;
164  }
165  election_fini(cluster);
166  free(cluster->priv->node_name);
167  free(cluster->priv);
168  free(cluster);
169 }
170 
179 int
180 pcmk_cluster_set_destroy_fn(pcmk_cluster_t *cluster, void (*fn)(gpointer))
181 {
182  if (cluster == NULL) {
183  return EINVAL;
184  }
185  cluster->destroy = fn;
186  return pcmk_rc_ok;
187 }
188 
199 bool
201  enum pcmk_ipc_server service, const xmlNode *data)
202 {
203  // @TODO Return standard Pacemaker return code
204  switch (pcmk_get_cluster_layer()) {
205 #if SUPPORT_COROSYNC
207  return pcmk__cpg_send_xml(data, node, service);
208 #endif // SUPPORT_COROSYNC
209 
210  default:
211  break;
212  }
213  return false;
214 }
215 
232 char *
233 pcmk__cluster_node_name(uint32_t nodeid)
234 {
235  char *name = NULL;
236  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
237  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
238 
239  switch (cluster_layer) {
240 #if SUPPORT_COROSYNC
242  name = pcmk__corosync_name(0, nodeid);
243  if (name != NULL) {
244  return name;
245  }
246  break;
247 #endif // SUPPORT_COROSYNC
248 
249  default:
250  crm_err("Unsupported cluster layer: %s", cluster_layer_s);
251  break;
252  }
253 
254  if (nodeid == 0) {
255  struct utsname hostinfo;
256 
257  crm_notice("Could not get local node name from %s cluster layer, "
258  "defaulting to local hostname",
259  cluster_layer_s);
260 
261  if (uname(&hostinfo) < 0) {
262  // @TODO Maybe let the caller decide what to do
263  crm_err("Failed to get the local hostname");
265  }
266  return pcmk__str_copy(hostinfo.nodename);
267  }
268 
269  crm_notice("Could not obtain a node name for node with "
270  PCMK_XA_ID "=" PRIu32,
271  nodeid);
272  return NULL;
273 }
274 
288 const char *
290 {
291  // @TODO Refactor to avoid trivially leaking name at exit
292  static char *name = NULL;
293 
294  if (name == NULL) {
296  }
297  return name;
298 }
299 
310 const char *
311 pcmk__node_name_from_uuid(const char *uuid)
312 {
313  /* @TODO There are too many functions in libcrmcluster that look up a node
314  * from the node caches (possibly creating a cache entry if none exists).
315  * There are at least the following:
316  * * pcmk__cluster_lookup_remote_node()
317  * * pcmk__get_node()
318  * * pcmk__node_name_from_uuid()
319  * * pcmk__search_node_caches()
320  *
321  * There's a lot of duplication among them, but they all do slightly
322  * different things. We should try to clean them up and consolidate them to
323  * the extent possible, likely with new helper functions.
324  */
325  GHashTableIter iter;
326  pcmk__node_status_t *node = NULL;
327 
328  CRM_CHECK(uuid != NULL, return NULL);
329 
330  // Remote nodes have the same uname and uuid
331  if (g_hash_table_lookup(pcmk__remote_peer_cache, uuid)) {
332  return uuid;
333  }
334 
335  g_hash_table_iter_init(&iter, pcmk__peer_cache);
336  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
337  if (pcmk__str_eq(node->xml_id, uuid, pcmk__str_casei)) {
338  return node->name;
339  }
340  }
341  return NULL;
342 }
343 
351 const char *
353 {
354  switch (layer) {
356  return "corosync";
358  return "unknown";
360  return "invalid";
361  default:
362  crm_err("Invalid cluster layer: %d", layer);
363  return "invalid";
364  }
365 }
366 
380 {
381  static enum pcmk_cluster_layer cluster_layer = pcmk_cluster_layer_unknown;
382  const char *cluster = NULL;
383 
384  // Cluster layer is stable once set
385  if (cluster_layer != pcmk_cluster_layer_unknown) {
386  return cluster_layer;
387  }
388 
390 
391  if (cluster != NULL) {
392  crm_info("Verifying configured cluster layer '%s'", cluster);
393  cluster_layer = pcmk_cluster_layer_invalid;
394 
395 #if SUPPORT_COROSYNC
396  if (pcmk__str_eq(cluster, PCMK_VALUE_COROSYNC, pcmk__str_casei)) {
397  cluster_layer = pcmk_cluster_layer_corosync;
398  }
399 #endif // SUPPORT_COROSYNC
400 
401  if (cluster_layer == pcmk_cluster_layer_invalid) {
402  crm_notice("This installation does not support the '%s' cluster "
403  "infrastructure: terminating",
404  cluster);
406  }
407  crm_info("Assuming an active '%s' cluster", cluster);
408 
409  } else {
410  // Nothing configured, so test supported cluster layers
411 #if SUPPORT_COROSYNC
412  crm_debug("Testing with Corosync");
413  if (pcmk__corosync_is_active()) {
414  cluster_layer = pcmk_cluster_layer_corosync;
415  }
416 #endif // SUPPORT_COROSYNC
417 
418  if (cluster_layer == pcmk_cluster_layer_unknown) {
419  crm_notice("Could not determine the current cluster layer");
420  } else {
421  crm_info("Detected an active '%s' cluster",
422  pcmk_cluster_layer_text(cluster_layer));
423  }
424  }
425 
426  return cluster_layer;
427 }
428 
429 // Deprecated functions kept only for backward API compatibility
430 // LCOV_EXCL_START
431 
432 #include <crm/cluster/compat.h>
433 
434 gboolean
436 {
437  if (cluster == NULL) {
438  return FALSE;
439  }
440  if (cluster->priv == NULL) {
441  /* sbd (as of at least 1.5.2) doesn't call pcmk_cluster_new() to
442  * allocate the pcmk_cluster_t
443  */
444  cluster->priv = pcmk__assert_alloc(1, sizeof(pcmk__cluster_private_t));
445  }
446  return pcmk_cluster_connect(cluster) == pcmk_rc_ok;
447 }
448 
449 const char *
451 {
452  switch (type) {
454  return "corosync";
456  return "unknown";
458  return "invalid";
459  }
460  crm_err("Invalid cluster type: %d", type);
461  return "invalid";
462 }
463 
464 enum cluster_type_e
466 {
467  return (enum cluster_type_e) pcmk_get_cluster_layer();
468 }
469 
470 // LCOV_EXCL_STOP
471 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:365
#define PCMK_VALUE_COROSYNC
Definition: options.h:138
char data[0]
Definition: cpg.c:58
int pcmk_cluster_disconnect(pcmk_cluster_t *cluster)
Disconnect from the cluster layer.
Definition: cluster.c:113
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:1044
Implementation of pcmk__cluster_private_t.
Definition: internal.h:91
Corosync Cluster Engine.
Definition: cluster.h:75
cluster_type_e
Definition: compat.h:39
const char * name
Definition: cib.c:26
enum pcmk_ipc_server type
Definition: cpg.c:51
char * pcmk__corosync_name(uint64_t cmap_handle, uint32_t nodeid)
Definition: corosync.c:101
enum cluster_type_e get_cluster_type(void)
Definition: cluster.c:465
int pcmk_cluster_connect(pcmk_cluster_t *cluster)
Definition: cluster.c:78
gboolean crm_cluster_connect(pcmk_cluster_t *cluster)
Definition: cluster.c:435
pcmk_cluster_t * pcmk_cluster_new(void)
Allocate a new pcmk_cluster_t object.
Definition: cluster.c:145
const char * pcmk_cluster_layer_text(enum pcmk_cluster_layer layer)
Get a log-friendly string equivalent of a cluster layer.
Definition: cluster.c:352
char * crm_system_name
Definition: utils.c:44
bool pcmk__cpg_send_xml(const xmlNode *msg, const pcmk__node_status_t *node, enum pcmk_ipc_server dest)
Definition: cpg.c:1042
char * node_name
Local node name at cluster layer.
Definition: internal.h:93
const char * pcmk__env_option(const char *option)
Definition: options.c:1075
enum pcmk_ipc_server server
Server this connection is for (if any)
Definition: internal.h:92
G_GNUC_INTERNAL void election_fini(pcmk_cluster_t *cluster)
Definition: election.c:156
const char * pcmk__node_name_from_uuid(const char *uuid)
Definition: cluster.c:311
pcmk_ipc_server
Available IPC interfaces.
Definition: ipc.h:48
void(* destroy)(gpointer)
Definition: cluster.h:40
#define crm_debug(fmt, args...)
Definition: logging.h:370
int pcmk__corosync_connect(pcmk_cluster_t *cluster)
Definition: corosync.c:459
const char * name_for_cluster_type(enum cluster_type_e type)
Definition: cluster.c:450
char * pcmk__corosync_uuid(const pcmk__node_status_t *node)
Definition: corosync.c:53
Wrappers for and extensions to libxml2.
CRM_TRACE_INIT_DATA(cluster)
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition: servers.c:178
int pcmk_cluster_set_destroy_fn(pcmk_cluster_t *cluster, void(*fn)(gpointer))
Set the destroy function for a cluster object.
Definition: cluster.c:180
#define PCMK_XA_ID
Definition: xml_names.h:301
#define PCMK__ENV_CLUSTER_TYPE
#define pcmk__str_copy(str)
const char * pcmk__cluster_local_node_name(void)
Definition: cluster.c:289
Deprecated Pacemaker cluster API.
GHashTable * pcmk__remote_peer_cache
Definition: membership.c:55
enum pcmk_cluster_layer pcmk_get_cluster_layer(void)
Get and validate the local cluster layer.
Definition: cluster.c:379
bool pcmk__cluster_send_message(const pcmk__node_status_t *node, enum pcmk_ipc_server service, const xmlNode *data)
Definition: cluster.c:200
void pcmk__cluster_destroy_node_caches(void)
Definition: membership.c:582
#define crm_err(fmt, args...)
Definition: logging.h:359
const char * pcmk__cluster_node_uuid(pcmk__node_status_t *node)
Definition: cluster.c:44
GHashTable * pcmk__peer_cache
Definition: membership.c:37
Invalid cluster layer.
Definition: cluster.h:74
void pcmk_cluster_free(pcmk_cluster_t *cluster)
Free a pcmk_cluster_t object and its dynamically allocated members.
Definition: cluster.c:160
char uname[MAX_NAME]
Definition: cpg.c:53
pcmk_cluster_layer
Types of cluster layer.
Definition: cluster.h:72
IPC interface to Pacemaker daemons.
char * pcmk__cluster_node_name(uint32_t nodeid)
Definition: cluster.c:233
Unknown cluster layer.
Definition: cluster.h:73
bool pcmk__corosync_is_active(void)
Definition: corosync.c:506
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
#define crm_info(fmt, args...)
Definition: logging.h:367
Do not respawn.
Definition: results.h:262
pcmk__cluster_private_t * priv
Definition: cluster.h:36
Node status data (may be a cluster node or a Pacemaker Remote node)
Definition: internal.h:112
void pcmk__corosync_disconnect(pcmk_cluster_t *cluster)
Definition: corosync.c:223