pacemaker  2.1.8-3980678f03
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 
45 {
46  CRM_CHECK(text != NULL, return crm_msg_none);
47 
48  text = pcmk__message_name(text);
49 
50  if (pcmk__str_eq(text, "ais", pcmk__str_none)) {
51  return crm_msg_ais;
52  }
53  if (pcmk__str_eq(text, CRM_SYSTEM_CIB, pcmk__str_none)) {
54  return crm_msg_cib;
55  }
57  return crm_msg_crmd;
58  }
59  if (pcmk__str_eq(text, CRM_SYSTEM_TENGINE, pcmk__str_none)) {
60  return crm_msg_te;
61  }
62  if (pcmk__str_eq(text, CRM_SYSTEM_PENGINE, pcmk__str_none)) {
63  return crm_msg_pe;
64  }
65  if (pcmk__str_eq(text, CRM_SYSTEM_LRMD, pcmk__str_none)) {
66  return crm_msg_lrmd;
67  }
68  if (pcmk__str_eq(text, CRM_SYSTEM_STONITHD, pcmk__str_none)) {
69  return crm_msg_stonithd;
70  }
71  if (pcmk__str_eq(text, "stonith-ng", pcmk__str_none)) {
72  return crm_msg_stonith_ng;
73  }
74  if (pcmk__str_eq(text, "attrd", pcmk__str_none)) {
75  return crm_msg_attrd;
76  }
77  return crm_msg_none;
78 }
79 
88 const char *
90 {
91  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
92 
93  if (node == NULL) {
94  return NULL;
95  }
96  if (node->uuid != NULL) {
97  return node->uuid;
98  }
99 
100  switch (cluster_layer) {
101 #if SUPPORT_COROSYNC
103  node->uuid = pcmk__corosync_uuid(node);
104  return node->uuid;
105 #endif // SUPPORT_COROSYNC
106 
107  default:
108  crm_err("Unsupported cluster layer %s",
109  pcmk_cluster_layer_text(cluster_layer));
110  return NULL;
111  }
112 }
113 
122 int
124 {
125  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
126  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
127 
128  // cts-lab looks for this message
129  crm_notice("Connecting to %s cluster layer", cluster_layer_s);
130 
131  switch (cluster_layer) {
132 #if SUPPORT_COROSYNC
134  return pcmk__corosync_connect(cluster);
135 #endif // SUPPORT_COROSYNC
136 
137  default:
138  break;
139  }
140 
141  crm_err("Failed to connect to unsupported cluster layer %s",
142  cluster_layer_s);
143  return EPROTONOSUPPORT;
144 }
145 
153 int
155 {
156  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
157  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
158 
159  crm_info("Disconnecting from %s cluster layer", cluster_layer_s);
160 
161  switch (cluster_layer) {
162 #if SUPPORT_COROSYNC
164  pcmk__corosync_disconnect(cluster);
166  return pcmk_rc_ok;
167 #endif // SUPPORT_COROSYNC
168 
169  default:
170  break;
171  }
172 
173  crm_err("Failed to disconnect from unsupported cluster layer %s",
174  cluster_layer_s);
175  return EPROTONOSUPPORT;
176 }
177 
187 {
188  return (pcmk_cluster_t *) pcmk__assert_alloc(1, sizeof(pcmk_cluster_t));
189 }
190 
196 void
198 {
199  if (cluster == NULL) {
200  return;
201  }
202  free(cluster->uuid);
203  free(cluster->uname);
204  free(cluster);
205 }
206 
215 int
216 pcmk_cluster_set_destroy_fn(pcmk_cluster_t *cluster, void (*fn)(gpointer))
217 {
218  if (cluster == NULL) {
219  return EINVAL;
220  }
221  cluster->destroy = fn;
222  return pcmk_rc_ok;
223 }
224 
235 bool
237  enum crm_ais_msg_types service, const xmlNode *data)
238 {
239  // @TODO Return standard Pacemaker return code
240  switch (pcmk_get_cluster_layer()) {
241 #if SUPPORT_COROSYNC
243  return pcmk__cpg_send_xml(data, node, service);
244 #endif // SUPPORT_COROSYNC
245 
246  default:
247  break;
248  }
249  return false;
250 }
251 
268 char *
269 pcmk__cluster_node_name(uint32_t nodeid)
270 {
271  char *name = NULL;
272  const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
273  const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
274 
275  switch (cluster_layer) {
276 #if SUPPORT_COROSYNC
278  name = pcmk__corosync_name(0, nodeid);
279  if (name != NULL) {
280  return name;
281  }
282  break;
283 #endif // SUPPORT_COROSYNC
284 
285  default:
286  crm_err("Unsupported cluster layer: %s", cluster_layer_s);
287  break;
288  }
289 
290  if (nodeid == 0) {
291  struct utsname hostinfo;
292 
293  crm_notice("Could not get local node name from %s cluster layer, "
294  "defaulting to local hostname",
295  cluster_layer_s);
296 
297  if (uname(&hostinfo) < 0) {
298  // @TODO Maybe let the caller decide what to do
299  crm_err("Failed to get the local hostname");
301  }
302  return pcmk__str_copy(hostinfo.nodename);
303  }
304 
305  crm_notice("Could not obtain a node name for node with "
306  PCMK_XA_ID "=" PRIu32,
307  nodeid);
308  return NULL;
309 }
310 
324 const char *
326 {
327  // @TODO Refactor to avoid trivially leaking name at exit
328  static char *name = NULL;
329 
330  if (name == NULL) {
332  }
333  return name;
334 }
335 
346 const char *
347 pcmk__node_name_from_uuid(const char *uuid)
348 {
349  /* @TODO There are too many functions in libcrmcluster that look up a node
350  * from the node caches (possibly creating a cache entry if none exists).
351  * There are at least the following:
352  * * pcmk__cluster_lookup_remote_node()
353  * * pcmk__get_node()
354  * * pcmk__node_name_from_uuid()
355  * * pcmk__search_node_caches()
356  *
357  * There's a lot of duplication among them, but they all do slightly
358  * different things. We should try to clean them up and consolidate them to
359  * the extent possible, likely with new helper functions.
360  */
361  GHashTableIter iter;
362  crm_node_t *node = NULL;
363 
364  CRM_CHECK(uuid != NULL, return NULL);
365 
366  // Remote nodes have the same uname and uuid
367  if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) {
368  return uuid;
369  }
370 
371  g_hash_table_iter_init(&iter, crm_peer_cache);
372  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
373  if (pcmk__str_eq(node->uuid, uuid, pcmk__str_casei)) {
374  return node->uname;
375  }
376  }
377  return NULL;
378 }
379 
387 const char *
389 {
390  switch (layer) {
392  return "corosync";
394  return "unknown";
396  return "invalid";
397  default:
398  crm_err("Invalid cluster layer: %d", layer);
399  return "invalid";
400  }
401 }
402 
416 {
417  static enum pcmk_cluster_layer cluster_layer = pcmk_cluster_layer_unknown;
418  const char *cluster = NULL;
419 
420  // Cluster layer is stable once set
421  if (cluster_layer != pcmk_cluster_layer_unknown) {
422  return cluster_layer;
423  }
424 
426 
427  if (cluster != NULL) {
428  crm_info("Verifying configured cluster layer '%s'", cluster);
429  cluster_layer = pcmk_cluster_layer_invalid;
430 
431 #if SUPPORT_COROSYNC
432  if (pcmk__str_eq(cluster, PCMK_VALUE_COROSYNC, pcmk__str_casei)) {
433  cluster_layer = pcmk_cluster_layer_corosync;
434  }
435 #endif // SUPPORT_COROSYNC
436 
437  if (cluster_layer == pcmk_cluster_layer_invalid) {
438  crm_notice("This installation does not support the '%s' cluster "
439  "infrastructure: terminating",
440  cluster);
442  }
443  crm_info("Assuming an active '%s' cluster", cluster);
444 
445  } else {
446  // Nothing configured, so test supported cluster layers
447 #if SUPPORT_COROSYNC
448  crm_debug("Testing with Corosync");
449  if (pcmk__corosync_is_active()) {
450  cluster_layer = pcmk_cluster_layer_corosync;
451  }
452 #endif // SUPPORT_COROSYNC
453 
454  if (cluster_layer == pcmk_cluster_layer_unknown) {
455  crm_notice("Could not determine the current cluster layer");
456  } else {
457  crm_info("Detected an active '%s' cluster",
458  pcmk_cluster_layer_text(cluster_layer));
459  }
460  }
461 
462  return cluster_layer;
463 }
464 
465 // Deprecated functions kept only for backward API compatibility
466 // LCOV_EXCL_START
467 
468 #include <crm/cluster/compat.h>
469 
470 void
471 set_uuid(xmlNode *xml, const char *attr, crm_node_t *node)
472 {
473  crm_xml_add(xml, attr, pcmk__cluster_node_uuid(node));
474 }
475 
476 gboolean
478 {
479  return pcmk_cluster_connect(cluster) == pcmk_rc_ok;
480 }
481 
482 void
484 {
485  pcmk_cluster_disconnect(cluster);
486 }
487 
488 const char *
490 {
491  switch (type) {
493  return "corosync";
495  return "unknown";
497  return "invalid";
498  }
499  crm_err("Invalid cluster type: %d", type);
500  return "invalid";
501 }
502 
503 enum cluster_type_e
505 {
506  return (enum cluster_type_e) pcmk_get_cluster_layer();
507 }
508 
509 gboolean
511 {
513 }
514 
515 gboolean
517  const xmlNode *data, gboolean ordered)
518 {
519  return pcmk__cluster_send_message(node, service, data);
520 }
521 
522 const char *
524 {
525  return pcmk__cluster_node_uuid(peer);
526 }
527 
528 char *
529 get_node_name(uint32_t nodeid)
530 {
531  return pcmk__cluster_node_name(nodeid);
532 }
533 
534 const char *
536 {
538 }
539 
540 const char *
541 crm_peer_uname(const char *uuid)
542 {
543  return pcmk__node_name_from_uuid(uuid);
544 }
545 
546 // LCOV_EXCL_STOP
547 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:397
#define PCMK_VALUE_COROSYNC
Definition: options.h:138
char data[0]
Definition: cpg.c:58
crm_ais_msg_types
Definition: cluster.h:197
int pcmk_cluster_disconnect(pcmk_cluster_t *cluster)
Disconnect from the cluster layer.
Definition: cluster.c:154
gboolean send_cluster_message(const crm_node_t *node, enum crm_ais_msg_types service, const xmlNode *data, gboolean ordered)
Definition: cluster.c:516
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:936
Corosync Cluster Engine.
Definition: cluster.h:228
cluster_type_e
Definition: compat.h:135
const char * name
Definition: cib.c:26
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:504
char * uuid
Definition: cluster.h:107
int pcmk_cluster_connect(pcmk_cluster_t *cluster)
Definition: cluster.c:123
const char * crm_peer_uuid(crm_node_t *peer)
Definition: cluster.c:523
void(* destroy)(gpointer)
Definition: cluster.h:146
GHashTable * crm_remote_peer_cache
Definition: membership.c:57
gboolean crm_cluster_connect(pcmk_cluster_t *cluster)
Definition: cluster.c:477
pcmk_cluster_t * pcmk_cluster_new(void)
Allocate a new pcmk_cluster_t object.
Definition: cluster.c:186
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:301
bool pcmk__cpg_send_xml(const xmlNode *msg, const crm_node_t *node, enum crm_ais_msg_types dest)
Definition: cpg.c:1091
const char * pcmk_cluster_layer_text(enum pcmk_cluster_layer layer)
Get a log-friendly string equivalent of a cluster layer.
Definition: cluster.c:388
char * uuid
Definition: cluster.h:140
enum crm_ais_msg_types type
Definition: cpg.c:51
const char * get_local_node_name(void)
Definition: cluster.c:535
const char * pcmk__env_option(const char *option)
Definition: options.c:1088
enum crm_ais_msg_types pcmk__cluster_parse_msg_type(const char *text)
Definition: cluster.c:44
#define CRM_SYSTEM_DC
Definition: crm.h:87
gboolean is_corosync_cluster(void)
Definition: cluster.c:510
const char * pcmk__node_name_from_uuid(const char *uuid)
Definition: cluster.c:347
char * get_node_name(uint32_t nodeid)
Definition: cluster.c:529
#define crm_debug(fmt, args...)
Definition: logging.h:402
const char * crm_peer_uname(const char *uuid)
Definition: cluster.c:541
int pcmk__corosync_connect(pcmk_cluster_t *cluster)
Definition: corosync.c:455
const char * name_for_cluster_type(enum cluster_type_e type)
Definition: cluster.c:489
#define CRM_SYSTEM_PENGINE
Definition: crm.h:92
Wrappers for and extensions to libxml2.
CRM_TRACE_INIT_DATA(cluster)
int pcmk_cluster_set_destroy_fn(pcmk_cluster_t *cluster, void(*fn)(gpointer))
Set the destroy function for a cluster object.
Definition: cluster.c:216
#define PCMK_XA_ID
Definition: xml_names.h:296
#define PCMK__ENV_CLUSTER_TYPE
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1050
#define pcmk__str_copy(str)
const char * pcmk__cluster_local_node_name(void)
Definition: cluster.c:325
Deprecated Pacemaker cluster API.
const char * pcmk__message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: messages.c:171
#define CRM_SYSTEM_CRMD
Definition: crm.h:90
enum pcmk_cluster_layer pcmk_get_cluster_layer(void)
Get and validate the local cluster layer.
Definition: cluster.c:415
#define CRM_SYSTEM_STONITHD
Definition: crm.h:94
char * uname
Definition: cluster.h:141
#define CRM_SYSTEM_CIB
Definition: crm.h:89
#define CRM_SYSTEM_TENGINE
Definition: crm.h:93
void pcmk__cluster_destroy_node_caches(void)
Definition: membership.c:557
#define crm_err(fmt, args...)
Definition: logging.h:391
Invalid cluster layer.
Definition: cluster.h:227
#define CRM_SYSTEM_LRMD
Definition: crm.h:91
void pcmk_cluster_free(pcmk_cluster_t *cluster)
Free a pcmk_cluster_t object and its dynamically allocated members.
Definition: cluster.c:197
char uname[MAX_NAME]
Definition: cpg.c:53
pcmk_cluster_layer
Types of cluster layer.
Definition: cluster.h:225
void crm_cluster_disconnect(pcmk_cluster_t *cluster)
Definition: cluster.c:483
IPC interface to Pacemaker daemons.
void set_uuid(xmlNode *xml, const char *attr, crm_node_t *node)
Definition: cluster.c:471
char * pcmk__cluster_node_name(uint32_t nodeid)
Definition: cluster.c:269
Unknown cluster layer.
Definition: cluster.h:226
char * pcmk__corosync_uuid(const crm_node_t *node)
Definition: corosync.c:53
bool pcmk__corosync_is_active(void)
Definition: corosync.c:504
const char * pcmk__cluster_node_uuid(crm_node_t *node)
Definition: cluster.c:89
bool pcmk__cluster_send_message(const crm_node_t *node, enum crm_ais_msg_types service, const xmlNode *data)
Definition: cluster.c:236
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
GHashTable * crm_peer_cache
Definition: membership.c:40
#define crm_info(fmt, args...)
Definition: logging.h:399
Do not respawn.
Definition: results.h:286
void pcmk__corosync_disconnect(pcmk_cluster_t *cluster)
Definition: corosync.c:223