This source file includes following definitions.
- pcmk__corosync_uuid
- node_name_is_valid
- pcmk__corosync_name
- pcmk__corosync_disconnect
- quorum_dispatch_cb
- quorum_notification_cb
- pcmk__corosync_quorum_connect
- pcmk__corosync_connect
- pcmk__corosync_is_active
- pcmk__corosync_is_peer_active
- pcmk__corosync_add_nodes
- pcmk__corosync_cluster_name
- pcmk__corosync_has_nodelist
- crm_is_corosync_peer_active
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <arpa/inet.h>
13 #include <inttypes.h>
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>
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
45
46
47
48
49
50
51
52 char *
53 pcmk__corosync_uuid(const crm_node_t *node)
54 {
55 pcmk__assert(pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync);
56
57 if (node != NULL) {
58 if (node->id > 0) {
59 return crm_strdup_printf("%u", node->id);
60 } else {
61 crm_info("Node %s is not yet known by Corosync", node->uname);
62 }
63 }
64 return NULL;
65 }
66
67 static bool
68 node_name_is_valid(const char *key, const char *name)
69 {
70 int octet;
71
72 if (name == NULL) {
73 crm_trace("%s is empty", key);
74 return false;
75
76 } else if (sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
77 crm_trace("%s contains an IPv4 address (%s), ignoring", key, name);
78 return false;
79
80 } else if (strstr(name, ":") != NULL) {
81 crm_trace("%s contains an IPv6 address (%s), ignoring", key, name);
82 return false;
83 }
84 crm_trace("'%s: %s' is valid", key, name);
85 return true;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100 char *
101 pcmk__corosync_name(uint64_t cmap_handle, uint32_t nodeid)
102 {
103
104
105 int lpc = 0;
106 cs_error_t rc = CS_OK;
107 int retries = 0;
108 char *name = NULL;
109 cmap_handle_t local_handle = 0;
110 int fd = -1;
111 uid_t found_uid = 0;
112 gid_t found_gid = 0;
113 pid_t found_pid = 0;
114 int rv;
115
116 if (nodeid == 0) {
117 nodeid = pcmk__cpg_local_nodeid(0);
118 }
119
120 if (cmap_handle == 0 && local_handle == 0) {
121 retries = 0;
122 crm_trace("Initializing CMAP connection");
123 do {
124 rc = pcmk__init_cmap(&local_handle);
125 if (rc != CS_OK) {
126 retries++;
127 crm_debug("API connection setup failed: %s. Retrying in %ds", cs_strerror(rc),
128 retries);
129 sleep(retries);
130 }
131
132 } while (retries < 5 && rc != CS_OK);
133
134 if (rc != CS_OK) {
135 crm_warn("Could not connect to Cluster Configuration Database API, error %s",
136 cs_strerror(rc));
137 local_handle = 0;
138 }
139 }
140
141 if (cmap_handle == 0) {
142 cmap_handle = local_handle;
143
144 rc = cmap_fd_get(cmap_handle, &fd);
145 if (rc != CS_OK) {
146 crm_err("Could not obtain the CMAP API connection: %s (%d)",
147 cs_strerror(rc), rc);
148 goto bail;
149 }
150
151
152 if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
153 &found_uid, &found_gid))) {
154 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 goto bail;
159 } else if (rv < 0) {
160 crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
161 strerror(-rv), -rv);
162 goto bail;
163 }
164 }
165
166 while (name == NULL && cmap_handle != 0) {
167 uint32_t id = 0;
168 char *key = NULL;
169
170 key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
171 rc = cmap_get_uint32(cmap_handle, key, &id);
172 crm_trace("Checking %u vs %u from %s", nodeid, id, key);
173 free(key);
174
175 if (rc != CS_OK) {
176 break;
177 }
178
179 if (nodeid == id) {
180 crm_trace("Searching for node name for %u in nodelist.node.%d %s",
181 nodeid, lpc, pcmk__s(name, "<null>"));
182 if (name == NULL) {
183 key = crm_strdup_printf("nodelist.node.%d.name", lpc);
184 cmap_get_string(cmap_handle, key, &name);
185 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
186 free(key);
187 }
188 if (name == NULL) {
189 key = crm_strdup_printf("nodelist.node.%d.ring0_addr", lpc);
190 cmap_get_string(cmap_handle, key, &name);
191 crm_trace("%s = %s", key, pcmk__s(name, "<null>"));
192
193 if (!node_name_is_valid(key, name)) {
194 free(name);
195 name = NULL;
196 }
197 free(key);
198 }
199 break;
200 }
201
202 lpc++;
203 }
204
205 bail:
206 if(local_handle) {
207 cmap_finalize(local_handle);
208 }
209
210 if (name == NULL) {
211 crm_info("Unable to get node name for nodeid %u", nodeid);
212 }
213 return name;
214 }
215
216
217
218
219
220
221
222 void
223 pcmk__corosync_disconnect(pcmk_cluster_t *cluster)
224 {
225 pcmk__cpg_disconnect(cluster);
226
227 if (pcmk_quorum_handle != 0) {
228 quorum_finalize(pcmk_quorum_handle);
229 pcmk_quorum_handle = 0;
230 }
231 crm_notice("Disconnected from Corosync");
232 }
233
234
235
236
237
238
239
240
241
242 static int
243 quorum_dispatch_cb(gpointer user_data)
244 {
245 int rc = quorum_dispatch(pcmk_quorum_handle, CS_DISPATCH_ALL);
246
247 if (rc < 0) {
248 crm_err("Connection to the Quorum API failed: %d", rc);
249 quorum_finalize(pcmk_quorum_handle);
250 pcmk_quorum_handle = 0;
251 return -1;
252 }
253 return 0;
254 }
255
256
257
258
259
260
261
262
263
264
265
266 static void
267 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 crm_node_t *node = NULL;
274 static gboolean init_phase = TRUE;
275
276 if (quorate != crm_have_quorum) {
277 if (quorate) {
278 crm_notice("Quorum acquired " CRM_XS " membership=%" PRIu64 " members=%lu",
279 ring_id, (long unsigned int)view_list_entries);
280 } else {
281 crm_warn("Quorum lost " CRM_XS " membership=%" PRIu64 " members=%lu",
282 ring_id, (long unsigned int)view_list_entries);
283 }
284 crm_have_quorum = quorate;
285
286 } else {
287 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 if (view_list_entries == 0 && init_phase) {
293 crm_info("Corosync membership is still forming, ignoring");
294 return;
295 }
296
297 init_phase = FALSE;
298
299
300
301 g_hash_table_iter_init(&iter, crm_peer_cache);
302 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
303 node->last_seen = 0;
304 }
305
306
307 for (i = 0; i < view_list_entries; i++) {
308 uint32_t id = view_list[i];
309
310 crm_debug("Member[%d] %u ", i, id);
311
312
313 node = pcmk__get_node(id, NULL, NULL, pcmk__node_search_cluster_member);
314 if (node->uname == NULL) {
315 char *name = pcmk__corosync_name(0, id);
316
317 crm_info("Obtaining name for new node %u", id);
318 node = pcmk__get_node(id, name, NULL,
319 pcmk__node_search_cluster_member);
320 free(name);
321 }
322
323
324 pcmk__update_peer_state(__func__, node, CRM_NODE_MEMBER, ring_id);
325 }
326
327
328 pcmk__reap_unseen_nodes(ring_id);
329
330 if (quorum_app_callback) {
331 quorum_app_callback(ring_id, quorate);
332 }
333 }
334
335
336
337
338
339
340
341
342 void
343 pcmk__corosync_quorum_connect(gboolean (*dispatch)(unsigned long long,
344 gboolean),
345 void (*destroy)(gpointer))
346 {
347 cs_error_t rc;
348 int fd = 0;
349 int quorate = 0;
350 uint32_t quorum_type = 0;
351 struct mainloop_fd_callbacks quorum_fd_callbacks;
352 uid_t found_uid = 0;
353 gid_t found_gid = 0;
354 pid_t found_pid = 0;
355 int rv;
356
357 quorum_fd_callbacks.dispatch = quorum_dispatch_cb;
358 quorum_fd_callbacks.destroy = destroy;
359
360 crm_debug("Configuring Pacemaker to obtain quorum from Corosync");
361
362 {
363 #if 0
364
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 quorum_callbacks_t quorum_callbacks = {
375 .quorum_notify_fn = quorum_notification_cb,
376 };
377
378 rc = quorum_initialize(&pcmk_quorum_handle, &quorum_callbacks,
379 &quorum_type);
380 #endif
381 }
382
383 if (rc != CS_OK) {
384 crm_err("Could not connect to the Quorum API: %s (%d)",
385 cs_strerror(rc), rc);
386 goto bail;
387
388 } else if (quorum_type != QUORUM_SET) {
389 crm_err("Corosync quorum is not configured");
390 goto bail;
391 }
392
393 rc = quorum_fd_get(pcmk_quorum_handle, &fd);
394 if (rc != CS_OK) {
395 crm_err("Could not obtain the Quorum API connection: %s (%d)",
396 strerror(rc), rc);
397 goto bail;
398 }
399
400
401 if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
402 &found_uid, &found_gid))) {
403 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 rc = CS_ERR_ACCESS;
408 goto bail;
409 } else if (rv < 0) {
410 crm_err("Could not verify authenticity of Quorum provider: %s (%d)",
411 strerror(-rv), -rv);
412 rc = CS_ERR_ACCESS;
413 goto bail;
414 }
415
416 rc = quorum_getquorate(pcmk_quorum_handle, &quorate);
417 if (rc != CS_OK) {
418 crm_err("Could not obtain the current Quorum API state: %d", rc);
419 goto bail;
420 }
421
422 if (quorate) {
423 crm_notice("Quorum acquired");
424 } else {
425 crm_warn("No quorum");
426 }
427 quorum_app_callback = dispatch;
428 crm_have_quorum = quorate;
429
430 rc = quorum_trackstart(pcmk_quorum_handle, CS_TRACK_CHANGES | CS_TRACK_CURRENT);
431 if (rc != CS_OK) {
432 crm_err("Could not setup Quorum API notifications: %d", rc);
433 goto bail;
434 }
435
436 mainloop_add_fd("quorum", G_PRIORITY_HIGH, fd, dispatch, &quorum_fd_callbacks);
437
438 pcmk__corosync_add_nodes(NULL);
439
440 bail:
441 if (rc != CS_OK) {
442 quorum_finalize(pcmk_quorum_handle);
443 }
444 }
445
446
447
448
449
450
451
452
453
454 int
455 pcmk__corosync_connect(pcmk_cluster_t *cluster)
456 {
457 crm_node_t *peer = NULL;
458 const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
459 const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
460 int rc = pcmk_rc_ok;
461
462 pcmk__cluster_init_node_caches();
463
464 if (cluster_layer != pcmk_cluster_layer_corosync) {
465 crm_err("Invalid cluster layer: %s " CRM_XS " cluster_layer=%d",
466 cluster_layer_s, cluster_layer);
467 return EINVAL;
468 }
469
470 rc = pcmk__cpg_connect(cluster);
471 if (rc != pcmk_rc_ok) {
472
473 return rc;
474 }
475 crm_info("Connection to %s established", cluster_layer_s);
476
477 cluster->nodeid = pcmk__cpg_local_nodeid(0);
478 if (cluster->nodeid == 0) {
479 crm_err("Could not determine local node ID");
480 return ENXIO;
481 }
482
483 cluster->uname = pcmk__cluster_node_name(0);
484 if (cluster->uname == NULL) {
485 crm_err("Could not determine local node name");
486 return ENXIO;
487 }
488
489
490 peer = pcmk__get_node(cluster->nodeid, cluster->uname, NULL,
491 pcmk__node_search_cluster_member);
492 cluster->uuid = pcmk__corosync_uuid(peer);
493
494 return pcmk_rc_ok;
495 }
496
497
498
499
500
501
502
503 bool
504 pcmk__corosync_is_active(void)
505 {
506 cmap_handle_t handle;
507 int rc = pcmk__init_cmap(&handle);
508
509 if (rc == CS_OK) {
510 cmap_finalize(handle);
511 return true;
512 }
513
514 crm_info("Failed to initialize the cmap API: %s (%d)",
515 pcmk__cs_err_str(rc), rc);
516 return false;
517 }
518
519
520
521
522
523
524
525
526
527 bool
528 pcmk__corosync_is_peer_active(const crm_node_t *node)
529 {
530 if (node == NULL) {
531 crm_trace("Corosync peer inactive: NULL");
532 return false;
533 }
534 if (!pcmk__str_eq(node->state, CRM_NODE_MEMBER, pcmk__str_none)) {
535 crm_trace("Corosync peer %s inactive: state=%s",
536 node->uname, node->state);
537 return false;
538 }
539 if (!pcmk_is_set(node->processes, crm_proc_cpg)) {
540 crm_trace("Corosync peer %s inactive " CRM_XS " processes=%.16" PRIx32,
541 node->uname, node->processes);
542 return false;
543 }
544 return true;
545 }
546
547
548
549
550
551
552
553
554
555 bool
556 pcmk__corosync_add_nodes(xmlNode *xml_parent)
557 {
558 int lpc = 0;
559 cs_error_t rc = CS_OK;
560 int retries = 0;
561 bool any = false;
562 cmap_handle_t cmap_handle;
563 int fd = -1;
564 uid_t found_uid = 0;
565 gid_t found_gid = 0;
566 pid_t found_pid = 0;
567 int rv;
568
569 do {
570 rc = pcmk__init_cmap(&cmap_handle);
571 if (rc != CS_OK) {
572 retries++;
573 crm_debug("API connection setup failed: %s. Retrying in %ds", cs_strerror(rc),
574 retries);
575 sleep(retries);
576 }
577
578 } while (retries < 5 && rc != CS_OK);
579
580 if (rc != CS_OK) {
581 crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
582 return false;
583 }
584
585 rc = cmap_fd_get(cmap_handle, &fd);
586 if (rc != CS_OK) {
587 crm_err("Could not obtain the CMAP API connection: %s (%d)",
588 cs_strerror(rc), rc);
589 goto bail;
590 }
591
592
593 if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
594 &found_uid, &found_gid))) {
595 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 goto bail;
600 } else if (rv < 0) {
601 crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
602 strerror(-rv), -rv);
603 goto bail;
604 }
605
606 pcmk__cluster_init_node_caches();
607 crm_trace("Initializing Corosync node list");
608 for (lpc = 0; TRUE; lpc++) {
609 uint32_t nodeid = 0;
610 char *name = NULL;
611 char *key = NULL;
612
613 key = crm_strdup_printf("nodelist.node.%d.nodeid", lpc);
614 rc = cmap_get_uint32(cmap_handle, key, &nodeid);
615 free(key);
616
617 if (rc != CS_OK) {
618 break;
619 }
620
621 name = pcmk__corosync_name(cmap_handle, nodeid);
622 if (name != NULL) {
623 GHashTableIter iter;
624 crm_node_t *node = NULL;
625
626 g_hash_table_iter_init(&iter, crm_peer_cache);
627 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
628 if(node && node->uname && strcasecmp(node->uname, name) == 0) {
629 if (node->id && node->id != nodeid) {
630 crm_crit("Nodes %u and %u share the same name '%s': shutting down", node->id,
631 nodeid, name);
632 crm_exit(CRM_EX_FATAL);
633 }
634 }
635 }
636 }
637
638 if (nodeid > 0 || name != NULL) {
639 crm_trace("Initializing node[%d] %u = %s", lpc, nodeid, name);
640 pcmk__get_node(nodeid, name, NULL, pcmk__node_search_cluster_member);
641 }
642
643 if (nodeid > 0 && name != NULL) {
644 any = true;
645
646 if (xml_parent) {
647 xmlNode *node = pcmk__xe_create(xml_parent, PCMK_XE_NODE);
648
649 crm_xml_add_ll(node, PCMK_XA_ID, (long long) nodeid);
650 crm_xml_add(node, PCMK_XA_UNAME, name);
651 }
652 }
653
654 free(name);
655 }
656 bail:
657 cmap_finalize(cmap_handle);
658 return any;
659 }
660
661
662
663
664
665
666
667 char *
668 pcmk__corosync_cluster_name(void)
669 {
670 cmap_handle_t handle;
671 char *cluster_name = NULL;
672 cs_error_t rc = CS_OK;
673 int fd = -1;
674 uid_t found_uid = 0;
675 gid_t found_gid = 0;
676 pid_t found_pid = 0;
677 int rv;
678
679 rc = pcmk__init_cmap(&handle);
680 if (rc != CS_OK) {
681 crm_info("Failed to initialize the cmap API: %s (%d)",
682 cs_strerror(rc), rc);
683 return NULL;
684 }
685
686 rc = cmap_fd_get(handle, &fd);
687 if (rc != CS_OK) {
688 crm_err("Could not obtain the CMAP API connection: %s (%d)",
689 cs_strerror(rc), rc);
690 goto bail;
691 }
692
693
694 if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
695 &found_uid, &found_gid))) {
696 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 goto bail;
701 } else if (rv < 0) {
702 crm_err("Could not verify authenticity of CMAP provider: %s (%d)",
703 strerror(-rv), -rv);
704 goto bail;
705 }
706
707 rc = cmap_get_string(handle, "totem.cluster_name", &cluster_name);
708 if (rc != CS_OK) {
709 crm_info("Cannot get totem.cluster_name: %s (%d)", cs_strerror(rc), rc);
710
711 } else {
712 crm_debug("cmap totem.cluster_name = '%s'", cluster_name);
713 }
714
715 bail:
716 cmap_finalize(handle);
717 return cluster_name;
718 }
719
720
721
722
723
724
725
726 bool
727 pcmk__corosync_has_nodelist(void)
728 {
729 cs_error_t cs_rc = CS_OK;
730 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 int fd = -1;
735 uid_t found_uid = 0;
736 gid_t found_gid = 0;
737 pid_t found_pid = 0;
738 int rc = pcmk_ok;
739
740 static bool got_result = false;
741 static bool result = false;
742
743 if (got_result) {
744 return result;
745 }
746
747
748 do {
749 cs_rc = pcmk__init_cmap(&cmap_handle);
750 if (cs_rc != CS_OK) {
751 retries++;
752 crm_debug("CMAP connection failed: %s (rc=%d, retrying in %ds)",
753 cs_strerror(cs_rc), cs_rc, retries);
754 sleep(retries);
755 }
756 } while ((retries < 5) && (cs_rc != CS_OK));
757 if (cs_rc != CS_OK) {
758 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 return false;
762 }
763
764
765 cs_rc = cmap_fd_get(cmap_handle, &fd);
766 if (cs_rc != CS_OK) {
767 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 goto bail;
771 }
772
773
774 rc = crm_ipc_is_authentic_process(fd, (uid_t) 0, (gid_t) 0,
775 &found_pid, &found_uid, &found_gid);
776 if (rc == 0) {
777 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 goto bail;
783 } else if (rc < 0) {
784 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 goto bail;
788 }
789
790
791 cs_rc = cmap_iter_init(cmap_handle, "nodelist", &iter_handle);
792 if (cs_rc != CS_OK) {
793 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 goto bail;
797 }
798
799 cs_rc = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL);
800 if (cs_rc == CS_OK) {
801 result = true;
802 }
803
804 cmap_iter_finalize(cmap_handle, iter_handle);
805 got_result = true;
806 crm_debug("Corosync %s node list", (result? "has" : "does not have"));
807
808 bail:
809 cmap_finalize(cmap_handle);
810 return result;
811 }
812
813
814
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
825