This source file includes following definitions.
- pcmk__cluster_num_remote_nodes
- pcmk__cluster_lookup_remote_node
- pcmk__cluster_forget_remote_node
- remote_state_from_cib
- remote_cache_refresh_helper
- mark_dirty
- is_dirty
- refresh_remote_nodes
- pcmk__cluster_is_node_active
- should_forget_cluster_node
- pcmk__cluster_forget_cluster_node
- count_peer
- pcmk__cluster_num_active_nodes
- destroy_crm_node
- pcmk__cluster_init_node_caches
- pcmk__cluster_destroy_node_caches
- pcmk__cluster_set_status_callback
- pcmk__cluster_set_autoreap
- dump_peer_hash
- hash_find_by_data
- search_cluster_member_cache
- pcmk__search_node_caches
- pcmk__purge_node_from_cache
- remove_conflicting_peer
- pcmk__get_node
- update_peer_uname
- proc2text
- crm_update_peer_proc
- pcmk__update_peer_expected
- update_peer_state_iter
- pcmk__update_peer_state
- pcmk__reap_unseen_nodes
- find_cib_cluster_node
- cluster_node_cib_cache_refresh_helper
- refresh_cluster_node_cib_cache
- pcmk__refresh_node_caches_from_cib
- crm_terminate_member
- crm_terminate_member_no_mainloop
- crm_get_peer
- crm_get_peer_full
- crm_remote_peer_cache_size
- crm_remote_peer_cache_refresh
- crm_remote_peer_get
- crm_remote_peer_cache_remove
- crm_is_peer_active
- crm_active_peers
- reap_crm_member
- crm_peer_init
- crm_peer_destroy
- crm_set_autoreap
- crm_set_status_callback
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <inttypes.h>
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <crm/common/ipc.h>
24 #include <crm/common/xml_internal.h>
25 #include <crm/cluster/internal.h>
26 #include <crm/common/xml.h>
27 #include <crm/stonith-ng.h>
28 #include "crmcluster_private.h"
29
30
31
32
33
34
35
36
37
38
39
40 GHashTable *crm_peer_cache = NULL;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 GHashTable *crm_remote_peer_cache = NULL;
58
59
60
61
62
63
64
65 static GHashTable *cluster_node_cib_cache = NULL;
66
67 unsigned long long crm_peer_seq = 0;
68 gboolean crm_have_quorum = FALSE;
69 static bool autoreap = true;
70
71
72
73 #define set_peer_flags(peer, flags_to_set) do { \
74 (peer)->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
75 "Peer", (peer)->uname, \
76 (peer)->flags, (flags_to_set), \
77 #flags_to_set); \
78 } while (0)
79
80 #define clear_peer_flags(peer, flags_to_clear) do { \
81 (peer)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
82 LOG_TRACE, \
83 "Peer", (peer)->uname, \
84 (peer)->flags, (flags_to_clear), \
85 #flags_to_clear); \
86 } while (0)
87
88 static void update_peer_uname(crm_node_t *node, const char *uname);
89 static crm_node_t *find_cib_cluster_node(const char *id, const char *uname);
90
91
92
93
94
95
96
97 unsigned int
98 pcmk__cluster_num_remote_nodes(void)
99 {
100 if (crm_remote_peer_cache == NULL) {
101 return 0U;
102 }
103 return g_hash_table_size(crm_remote_peer_cache);
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 crm_node_t *
122 pcmk__cluster_lookup_remote_node(const char *node_name)
123 {
124 crm_node_t *node;
125 char *node_name_copy = NULL;
126
127 if (node_name == NULL) {
128 errno = EINVAL;
129 return NULL;
130 }
131
132
133
134
135
136
137 node = pcmk__search_node_caches(0, node_name,
138 pcmk__node_search_cluster_member);
139 if ((node != NULL) && (node->uuid == NULL)) {
140
141
142
143 node_name_copy = strdup(node_name);
144 if (node_name_copy == NULL) {
145 errno = ENOMEM;
146 return NULL;
147 }
148 node_name = node_name_copy;
149 pcmk__cluster_forget_cluster_node(0, node_name);
150 }
151
152
153 node = g_hash_table_lookup(crm_remote_peer_cache, node_name);
154 if (node) {
155 free(node_name_copy);
156 return node;
157 }
158
159
160 node = calloc(1, sizeof(crm_node_t));
161 if (node == NULL) {
162 free(node_name_copy);
163 return NULL;
164 }
165
166
167 set_peer_flags(node, crm_remote_node);
168 node->uuid = strdup(node_name);
169 if (node->uuid == NULL) {
170 free(node);
171 errno = ENOMEM;
172 free(node_name_copy);
173 return NULL;
174 }
175
176
177 g_hash_table_replace(crm_remote_peer_cache, node->uuid, node);
178 crm_trace("added %s to remote cache", node_name);
179
180
181 update_peer_uname(node, node_name);
182 free(node_name_copy);
183 return node;
184 }
185
186
187
188
189
190
191
192
193
194
195 void
196 pcmk__cluster_forget_remote_node(const char *node_name)
197 {
198
199
200
201 if (g_hash_table_lookup(crm_remote_peer_cache, node_name) != NULL) {
202 crm_trace("Removing %s from Pacemaker Remote node cache", node_name);
203 g_hash_table_remove(crm_remote_peer_cache, node_name);
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 static const char *
219 remote_state_from_cib(const xmlNode *node_state)
220 {
221 bool status = false;
222
223 if ((pcmk__xe_get_bool_attr(node_state, PCMK__XA_IN_CCM,
224 &status) == pcmk_rc_ok) && !status) {
225 return CRM_NODE_LOST;
226 } else {
227 return CRM_NODE_MEMBER;
228 }
229 }
230
231
232 struct refresh_data {
233 const char *field;
234 gboolean has_state;
235 };
236
237
238
239
240
241
242
243
244 static void
245 remote_cache_refresh_helper(xmlNode *result, void *user_data)
246 {
247 const struct refresh_data *data = user_data;
248 const char *remote = crm_element_value(result, data->field);
249 const char *state = NULL;
250 crm_node_t *node;
251
252 CRM_CHECK(remote != NULL, return);
253
254
255 if (data->has_state) {
256 state = remote_state_from_cib(result);
257 }
258
259
260 node = g_hash_table_lookup(crm_remote_peer_cache, remote);
261
262 if (node == NULL) {
263
264 node = pcmk__cluster_lookup_remote_node(remote);
265 CRM_ASSERT(node);
266 if (state) {
267 pcmk__update_peer_state(__func__, node, state, 0);
268 }
269
270 } else if (pcmk_is_set(node->flags, crm_node_dirty)) {
271
272 clear_peer_flags(node, crm_node_dirty);
273 if (state) {
274 pcmk__update_peer_state(__func__, node, state, 0);
275 }
276 }
277 }
278
279 static void
280 mark_dirty(gpointer key, gpointer value, gpointer user_data)
281 {
282 set_peer_flags((crm_node_t *) value, crm_node_dirty);
283 }
284
285 static gboolean
286 is_dirty(gpointer key, gpointer value, gpointer user_data)
287 {
288 return pcmk_is_set(((crm_node_t*)value)->flags, crm_node_dirty);
289 }
290
291
292
293
294
295
296
297 static void
298 refresh_remote_nodes(xmlNode *cib)
299 {
300 struct refresh_data data;
301
302 pcmk__cluster_init_node_caches();
303
304
305
306
307
308 g_hash_table_foreach(crm_remote_peer_cache, mark_dirty, NULL);
309
310
311 data.field = PCMK_XA_ID;
312 data.has_state = TRUE;
313 crm_foreach_xpath_result(cib, PCMK__XP_REMOTE_NODE_STATUS,
314 remote_cache_refresh_helper, &data);
315
316
317
318
319
320
321
322 data.field = PCMK_XA_VALUE;
323 data.has_state = FALSE;
324 crm_foreach_xpath_result(cib, PCMK__XP_GUEST_NODE_CONFIG,
325 remote_cache_refresh_helper, &data);
326 data.field = PCMK_XA_ID;
327 data.has_state = FALSE;
328 crm_foreach_xpath_result(cib, PCMK__XP_REMOTE_NODE_CONFIG,
329 remote_cache_refresh_helper, &data);
330
331
332 g_hash_table_foreach_remove(crm_remote_peer_cache, is_dirty, NULL);
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346 bool
347 pcmk__cluster_is_node_active(const crm_node_t *node)
348 {
349 const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
350
351 if ((node == NULL) || pcmk_is_set(node->flags, crm_remote_node)) {
352 return false;
353 }
354
355 switch (cluster_layer) {
356 case pcmk_cluster_layer_corosync:
357 #if SUPPORT_COROSYNC
358 return pcmk__corosync_is_peer_active(node);
359 #else
360 break;
361 #endif
362 default:
363 break;
364 }
365
366 crm_err("Unhandled cluster layer: %s",
367 pcmk_cluster_layer_text(cluster_layer));
368 return false;
369 }
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396 static gboolean
397 should_forget_cluster_node(gpointer key, gpointer value, gpointer user_data)
398 {
399 crm_node_t *node = value;
400 crm_node_t *search = user_data;
401
402 if (search == NULL) {
403 return FALSE;
404 }
405 if ((search->id != 0) && (node->id != search->id)) {
406 return FALSE;
407 }
408 if ((search->id == 0)
409 && !pcmk__str_eq(node->uname, search->uname, pcmk__str_casei)) {
410
411 return FALSE;
412 }
413 if (pcmk__cluster_is_node_active(value)) {
414 return FALSE;
415 }
416
417 crm_info("Removing node with name %s and " PCMK_XA_ID " %u from membership "
418 "cache",
419 pcmk__s(node->uname, "(unknown)"), node->id);
420 return TRUE;
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 void
442 pcmk__cluster_forget_cluster_node(uint32_t id, const char *node_name)
443 {
444 crm_node_t search = { 0, };
445 char *criterion = NULL;
446 guint matches = 0;
447
448 if (crm_peer_cache == NULL) {
449 crm_trace("Membership cache not initialized, ignoring removal request");
450 return;
451 }
452
453 search.id = id;
454 search.uname = pcmk__str_copy(node_name);
455
456 if (id > 0) {
457 criterion = crm_strdup_printf(PCMK_XA_ID "=%" PRIu32, id);
458
459 } else if (node_name != NULL) {
460 criterion = crm_strdup_printf(PCMK_XA_UNAME "=%s", node_name);
461 }
462
463 matches = g_hash_table_foreach_remove(crm_peer_cache,
464 should_forget_cluster_node, &search);
465 if (matches > 0) {
466 if (criterion != NULL) {
467 crm_notice("Removed %u inactive node%s with %s from the membership "
468 "cache",
469 matches, pcmk__plural_s(matches), criterion);
470 } else {
471 crm_notice("Removed all (%u) inactive cluster nodes from the "
472 "membership cache",
473 matches);
474 }
475
476 } else {
477 crm_info("No inactive cluster nodes%s%s to remove from the membership "
478 "cache",
479 ((criterion != NULL)? " with " : ""), pcmk__s(criterion, ""));
480 }
481
482 free(search.uname);
483 free(criterion);
484 }
485
486 static void
487 count_peer(gpointer key, gpointer value, gpointer user_data)
488 {
489 unsigned int *count = user_data;
490 crm_node_t *node = value;
491
492 if (pcmk__cluster_is_node_active(node)) {
493 *count = *count + 1;
494 }
495 }
496
497
498
499
500
501
502
503
504
505
506 unsigned int
507 pcmk__cluster_num_active_nodes(void)
508 {
509 unsigned int count = 0;
510
511 if (crm_peer_cache != NULL) {
512 g_hash_table_foreach(crm_peer_cache, count_peer, &count);
513 }
514 return count;
515 }
516
517 static void
518 destroy_crm_node(gpointer data)
519 {
520 crm_node_t *node = data;
521
522 crm_trace("Destroying entry for node %u: %s", node->id, node->uname);
523
524 free(node->uname);
525 free(node->state);
526 free(node->uuid);
527 free(node->expected);
528 free(node->conn_host);
529 free(node);
530 }
531
532
533
534
535
536 void
537 pcmk__cluster_init_node_caches(void)
538 {
539 if (crm_peer_cache == NULL) {
540 crm_peer_cache = pcmk__strikey_table(free, destroy_crm_node);
541 }
542
543 if (crm_remote_peer_cache == NULL) {
544 crm_remote_peer_cache = pcmk__strikey_table(NULL, destroy_crm_node);
545 }
546
547 if (cluster_node_cib_cache == NULL) {
548 cluster_node_cib_cache = pcmk__strikey_table(free, destroy_crm_node);
549 }
550 }
551
552
553
554
555
556 void
557 pcmk__cluster_destroy_node_caches(void)
558 {
559 if (crm_peer_cache != NULL) {
560 crm_trace("Destroying peer cache with %d members",
561 g_hash_table_size(crm_peer_cache));
562 g_hash_table_destroy(crm_peer_cache);
563 crm_peer_cache = NULL;
564 }
565
566 if (crm_remote_peer_cache != NULL) {
567 crm_trace("Destroying remote peer cache with %d members",
568 pcmk__cluster_num_remote_nodes());
569 g_hash_table_destroy(crm_remote_peer_cache);
570 crm_remote_peer_cache = NULL;
571 }
572
573 if (cluster_node_cib_cache != NULL) {
574 crm_trace("Destroying configured cluster node cache with %d members",
575 g_hash_table_size(cluster_node_cib_cache));
576 g_hash_table_destroy(cluster_node_cib_cache);
577 cluster_node_cib_cache = NULL;
578 }
579 }
580
581 static void (*peer_status_callback)(enum crm_status_type, crm_node_t *,
582 const void *) = NULL;
583
584
585
586
587
588
589
590
591
592
593 void
594 pcmk__cluster_set_status_callback(void (*dispatch)(enum crm_status_type,
595 crm_node_t *, const void *))
596 {
597
598 peer_status_callback = dispatch;
599 }
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615 void
616 pcmk__cluster_set_autoreap(bool enable)
617 {
618 autoreap = enable;
619 }
620
621 static void
622 dump_peer_hash(int level, const char *caller)
623 {
624 GHashTableIter iter;
625 const char *id = NULL;
626 crm_node_t *node = NULL;
627
628 g_hash_table_iter_init(&iter, crm_peer_cache);
629 while (g_hash_table_iter_next(&iter, (gpointer *) &id, (gpointer *) &node)) {
630 do_crm_log(level, "%s: Node %u/%s = %p - %s", caller, node->id, node->uname, node, id);
631 }
632 }
633
634 static gboolean
635 hash_find_by_data(gpointer key, gpointer value, gpointer user_data)
636 {
637 return value == user_data;
638 }
639
640
641
642
643
644
645
646
647
648
649
650
651 static crm_node_t *
652 search_cluster_member_cache(unsigned int id, const char *uname,
653 const char *uuid)
654 {
655 GHashTableIter iter;
656 crm_node_t *node = NULL;
657 crm_node_t *by_id = NULL;
658 crm_node_t *by_name = NULL;
659
660 CRM_ASSERT(id > 0 || uname != NULL);
661
662 pcmk__cluster_init_node_caches();
663
664 if (uname != NULL) {
665 g_hash_table_iter_init(&iter, crm_peer_cache);
666 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
667 if(node->uname && strcasecmp(node->uname, uname) == 0) {
668 crm_trace("Name match: %s = %p", node->uname, node);
669 by_name = node;
670 break;
671 }
672 }
673 }
674
675 if (id > 0) {
676 g_hash_table_iter_init(&iter, crm_peer_cache);
677 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
678 if(node->id == id) {
679 crm_trace("ID match: %u = %p", node->id, node);
680 by_id = node;
681 break;
682 }
683 }
684
685 } else if (uuid != NULL) {
686 g_hash_table_iter_init(&iter, crm_peer_cache);
687 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
688 if (pcmk__str_eq(node->uuid, uuid, pcmk__str_casei)) {
689 crm_trace("UUID match: %s = %p", node->uuid, node);
690 by_id = node;
691 break;
692 }
693 }
694 }
695
696 node = by_id;
697 if(by_id == by_name) {
698
699 crm_trace("Consistent: %p for %u/%s", by_id, id, uname);
700
701 } else if(by_id == NULL && by_name) {
702 crm_trace("Only one: %p for %u/%s", by_name, id, uname);
703
704 if(id && by_name->id) {
705 dump_peer_hash(LOG_WARNING, __func__);
706 crm_crit("Node %u and %u share the same name '%s'",
707 id, by_name->id, uname);
708 node = NULL;
709
710 } else {
711 node = by_name;
712 }
713
714 } else if(by_name == NULL && by_id) {
715 crm_trace("Only one: %p for %u/%s", by_id, id, uname);
716
717 if(uname && by_id->uname) {
718 dump_peer_hash(LOG_WARNING, __func__);
719 crm_crit("Node '%s' and '%s' share the same cluster nodeid %u: assuming '%s' is correct",
720 uname, by_id->uname, id, uname);
721 }
722
723 } else if(uname && by_id->uname) {
724 if(pcmk__str_eq(uname, by_id->uname, pcmk__str_casei)) {
725 crm_notice("Node '%s' has changed its ID from %u to %u", by_id->uname, by_name->id, by_id->id);
726 g_hash_table_foreach_remove(crm_peer_cache, hash_find_by_data, by_name);
727
728 } else {
729 crm_warn("Node '%s' and '%s' share the same cluster nodeid: %u %s", by_id->uname, by_name->uname, id, uname);
730 dump_peer_hash(LOG_INFO, __func__);
731 crm_abort(__FILE__, __func__, __LINE__, "member weirdness", TRUE,
732 TRUE);
733 }
734
735 } else if(id && by_name->id) {
736 crm_warn("Node %u and %u share the same name: '%s'", by_id->id, by_name->id, uname);
737
738 } else {
739
740
741
742
743
744
745 dump_peer_hash(LOG_DEBUG, __func__);
746
747 crm_info("Merging %p into %p", by_name, by_id);
748 g_hash_table_foreach_remove(crm_peer_cache, hash_find_by_data, by_name);
749 }
750
751 return node;
752 }
753
754
755
756
757
758
759
760
761
762
763
764 crm_node_t *
765 pcmk__search_node_caches(unsigned int id, const char *uname, uint32_t flags)
766 {
767 crm_node_t *node = NULL;
768
769 CRM_ASSERT(id > 0 || uname != NULL);
770
771 pcmk__cluster_init_node_caches();
772
773 if ((uname != NULL) && pcmk_is_set(flags, pcmk__node_search_remote)) {
774 node = g_hash_table_lookup(crm_remote_peer_cache, uname);
775 }
776
777 if ((node == NULL)
778 && pcmk_is_set(flags, pcmk__node_search_cluster_member)) {
779
780 node = search_cluster_member_cache(id, uname, NULL);
781 }
782
783 if ((node == NULL) && pcmk_is_set(flags, pcmk__node_search_cluster_cib)) {
784 char *id_str = (id == 0)? NULL : crm_strdup_printf("%u", id);
785
786 node = find_cib_cluster_node(id_str, uname);
787 free(id_str);
788 }
789
790 return node;
791 }
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807 void
808 pcmk__purge_node_from_cache(const char *node_name, uint32_t node_id)
809 {
810 char *node_name_copy = NULL;
811
812 if ((node_name == NULL) && (node_id == 0U)) {
813 return;
814 }
815
816
817 if ((node_name != NULL)
818 && (g_hash_table_lookup(crm_remote_peer_cache, node_name) != NULL)) {
819
820
821
822 node_name_copy = pcmk__str_copy(node_name);
823 node_name = node_name_copy;
824
825 crm_trace("Purging %s from Pacemaker Remote node cache", node_name);
826 g_hash_table_remove(crm_remote_peer_cache, node_name);
827 }
828
829 pcmk__cluster_forget_cluster_node(node_id, node_name);
830 free(node_name_copy);
831 }
832
833 #if SUPPORT_COROSYNC
834 static guint
835 remove_conflicting_peer(crm_node_t *node)
836 {
837 int matches = 0;
838 GHashTableIter iter;
839 crm_node_t *existing_node = NULL;
840
841 if (node->id == 0 || node->uname == NULL) {
842 return 0;
843 }
844
845 if (!pcmk__corosync_has_nodelist()) {
846 return 0;
847 }
848
849 g_hash_table_iter_init(&iter, crm_peer_cache);
850 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &existing_node)) {
851 if (existing_node->id > 0
852 && existing_node->id != node->id
853 && existing_node->uname != NULL
854 && strcasecmp(existing_node->uname, node->uname) == 0) {
855
856 if (pcmk__cluster_is_node_active(existing_node)) {
857 continue;
858 }
859
860 crm_warn("Removing cached offline node %u/%s which has conflicting uname with %u",
861 existing_node->id, existing_node->uname, node->id);
862
863 g_hash_table_iter_remove(&iter);
864 matches++;
865 }
866 }
867
868 return matches;
869 }
870 #endif
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889 crm_node_t *
890 pcmk__get_node(unsigned int id, const char *uname, const char *uuid,
891 uint32_t flags)
892 {
893 crm_node_t *node = NULL;
894 char *uname_lookup = NULL;
895
896 CRM_ASSERT(id > 0 || uname != NULL);
897
898 pcmk__cluster_init_node_caches();
899
900
901 if (pcmk_is_set(flags, pcmk__node_search_remote)) {
902 node = g_hash_table_lookup(crm_remote_peer_cache, uname);
903 if (node != NULL) {
904 return node;
905 }
906 }
907
908 if (!pcmk_is_set(flags, pcmk__node_search_cluster_member)) {
909 return NULL;
910 }
911
912 node = search_cluster_member_cache(id, uname, uuid);
913
914
915
916 if ((node == NULL || node->uname == NULL) && (uname == NULL)) {
917 uname_lookup = pcmk__cluster_node_name(id);
918 }
919
920 if (uname_lookup) {
921 uname = uname_lookup;
922 crm_trace("Inferred a name of '%s' for node %u", uname, id);
923
924
925 if (node == NULL) {
926 node = search_cluster_member_cache(id, uname, uuid);
927 }
928 }
929
930 if (node == NULL) {
931 char *uniqueid = crm_generate_uuid();
932
933 node = pcmk__assert_alloc(1, sizeof(crm_node_t));
934
935 crm_info("Created entry %s/%p for node %s/%u (%d total)",
936 uniqueid, node, uname, id, 1 + g_hash_table_size(crm_peer_cache));
937 g_hash_table_replace(crm_peer_cache, uniqueid, node);
938 }
939
940 if(id > 0 && uname && (node->id == 0 || node->uname == NULL)) {
941 crm_info("Node %u is now known as %s", id, uname);
942 }
943
944 if(id > 0 && node->id == 0) {
945 node->id = id;
946 }
947
948 if (uname && (node->uname == NULL)) {
949 update_peer_uname(node, uname);
950 }
951
952 if(node->uuid == NULL) {
953 if (uuid == NULL) {
954 uuid = pcmk__cluster_node_uuid(node);
955 }
956
957 if (uuid) {
958 crm_info("Node %u has uuid %s", id, uuid);
959
960 } else {
961 crm_info("Cannot obtain a UUID for node %u/%s", id, node->uname);
962 }
963 }
964
965 free(uname_lookup);
966
967 return node;
968 }
969
970
971
972
973
974
975
976
977
978
979
980
981 static void
982 update_peer_uname(crm_node_t *node, const char *uname)
983 {
984 CRM_CHECK(uname != NULL,
985 crm_err("Bug: can't update node name without name"); return);
986 CRM_CHECK(node != NULL,
987 crm_err("Bug: can't update node name to %s without node", uname);
988 return);
989
990 if (pcmk__str_eq(uname, node->uname, pcmk__str_casei)) {
991 crm_debug("Node uname '%s' did not change", uname);
992 return;
993 }
994
995 for (const char *c = uname; *c; ++c) {
996 if ((*c >= 'A') && (*c <= 'Z')) {
997 crm_warn("Node names with capitals are discouraged, consider changing '%s'",
998 uname);
999 break;
1000 }
1001 }
1002
1003 pcmk__str_update(&node->uname, uname);
1004
1005 if (peer_status_callback != NULL) {
1006 peer_status_callback(crm_status_uname, node, NULL);
1007 }
1008
1009 #if SUPPORT_COROSYNC
1010 if ((pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync)
1011 && !pcmk_is_set(node->flags, crm_remote_node)) {
1012
1013 remove_conflicting_peer(node);
1014 }
1015 #endif
1016 }
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 static inline const char *
1027 proc2text(enum crm_proc_flag proc)
1028 {
1029 const char *text = "unknown";
1030
1031 switch (proc) {
1032 case crm_proc_none:
1033 text = "none";
1034 break;
1035 case crm_proc_cpg:
1036 text = "corosync-cpg";
1037 break;
1038 }
1039 return text;
1040 }
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 crm_node_t *
1059 crm_update_peer_proc(const char *source, crm_node_t * node, uint32_t flag, const char *status)
1060 {
1061 uint32_t last = 0;
1062 gboolean changed = FALSE;
1063
1064 CRM_CHECK(node != NULL, crm_err("%s: Could not set %s to %s for NULL",
1065 source, proc2text(flag), status);
1066 return NULL);
1067
1068
1069 if (pcmk_is_set(node->flags, crm_remote_node)) {
1070 return node;
1071 }
1072
1073 last = node->processes;
1074 if (status == NULL) {
1075 node->processes = flag;
1076 if (node->processes != last) {
1077 changed = TRUE;
1078 }
1079
1080 } else if (pcmk__str_eq(status, PCMK_VALUE_ONLINE, pcmk__str_casei)) {
1081 if ((node->processes & flag) != flag) {
1082 node->processes = pcmk__set_flags_as(__func__, __LINE__,
1083 LOG_TRACE, "Peer process",
1084 node->uname, node->processes,
1085 flag, "processes");
1086 changed = TRUE;
1087 }
1088
1089 } else if (node->processes & flag) {
1090 node->processes = pcmk__clear_flags_as(__func__, __LINE__,
1091 LOG_TRACE, "Peer process",
1092 node->uname, node->processes,
1093 flag, "processes");
1094 changed = TRUE;
1095 }
1096
1097 if (changed) {
1098 if (status == NULL && flag <= crm_proc_none) {
1099 crm_info("%s: Node %s[%u] - all processes are now offline", source, node->uname,
1100 node->id);
1101 } else {
1102 crm_info("%s: Node %s[%u] - %s is now %s", source, node->uname, node->id,
1103 proc2text(flag), status);
1104 }
1105
1106 if (pcmk_is_set(node->processes, crm_get_cluster_proc())) {
1107 node->when_online = time(NULL);
1108
1109 } else {
1110 node->when_online = 0;
1111 }
1112
1113
1114
1115
1116 if (peer_status_callback != NULL) {
1117 peer_status_callback(crm_status_processes, node, &last);
1118 }
1119
1120
1121
1122
1123 if (crm_peer_cache == NULL) {
1124 return NULL;
1125 }
1126
1127 if (autoreap) {
1128 const char *peer_state = NULL;
1129
1130 if (pcmk_is_set(node->processes, crm_get_cluster_proc())) {
1131 peer_state = CRM_NODE_MEMBER;
1132 } else {
1133 peer_state = CRM_NODE_LOST;
1134 }
1135 node = pcmk__update_peer_state(__func__, node, peer_state, 0);
1136 }
1137 } else {
1138 crm_trace("%s: Node %s[%u] - %s is unchanged (%s)", source, node->uname, node->id,
1139 proc2text(flag), status);
1140 }
1141 return node;
1142 }
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152 void
1153 pcmk__update_peer_expected(const char *source, crm_node_t *node,
1154 const char *expected)
1155 {
1156 char *last = NULL;
1157 gboolean changed = FALSE;
1158
1159 CRM_CHECK(node != NULL, crm_err("%s: Could not set 'expected' to %s", source, expected);
1160 return);
1161
1162
1163 if (pcmk_is_set(node->flags, crm_remote_node)) {
1164 return;
1165 }
1166
1167 last = node->expected;
1168 if (expected != NULL && !pcmk__str_eq(node->expected, expected, pcmk__str_casei)) {
1169 node->expected = strdup(expected);
1170 changed = TRUE;
1171 }
1172
1173 if (changed) {
1174 crm_info("%s: Node %s[%u] - expected state is now %s (was %s)", source, node->uname, node->id,
1175 expected, last);
1176 free(last);
1177 } else {
1178 crm_trace("%s: Node %s[%u] - expected state is unchanged (%s)", source, node->uname,
1179 node->id, expected);
1180 }
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199 static crm_node_t *
1200 update_peer_state_iter(const char *source, crm_node_t *node, const char *state,
1201 uint64_t membership, GHashTableIter *iter)
1202 {
1203 gboolean is_member;
1204
1205 CRM_CHECK(node != NULL,
1206 crm_err("Could not set state for unknown host to %s"
1207 CRM_XS " source=%s", state, source);
1208 return NULL);
1209
1210 is_member = pcmk__str_eq(state, CRM_NODE_MEMBER, pcmk__str_casei);
1211 if (is_member) {
1212 node->when_lost = 0;
1213 if (membership) {
1214 node->last_seen = membership;
1215 }
1216 }
1217
1218 if (state && !pcmk__str_eq(node->state, state, pcmk__str_casei)) {
1219 char *last = node->state;
1220
1221 if (is_member) {
1222 node->when_member = time(NULL);
1223
1224 } else {
1225 node->when_member = 0;
1226 }
1227
1228 node->state = strdup(state);
1229 crm_notice("Node %s state is now %s " CRM_XS
1230 " nodeid=%u previous=%s source=%s", node->uname, state,
1231 node->id, (last? last : "unknown"), source);
1232 if (peer_status_callback != NULL) {
1233 peer_status_callback(crm_status_nstate, node, last);
1234 }
1235 free(last);
1236
1237 if (autoreap && !is_member
1238 && !pcmk_is_set(node->flags, crm_remote_node)) {
1239
1240
1241
1242
1243 if(iter) {
1244 crm_notice("Purged 1 peer with " PCMK_XA_ID
1245 "=%u and/or uname=%s from the membership cache",
1246 node->id, node->uname);
1247 g_hash_table_iter_remove(iter);
1248
1249 } else {
1250 pcmk__cluster_forget_cluster_node(node->id, node->uname);
1251 }
1252 node = NULL;
1253 }
1254
1255 } else {
1256 crm_trace("Node %s state is unchanged (%s) " CRM_XS
1257 " nodeid=%u source=%s", node->uname, state, node->id, source);
1258 }
1259 return node;
1260 }
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277 crm_node_t *
1278 pcmk__update_peer_state(const char *source, crm_node_t *node,
1279 const char *state, uint64_t membership)
1280 {
1281 return update_peer_state_iter(source, node, state, membership, NULL);
1282 }
1283
1284
1285
1286
1287
1288
1289
1290 void
1291 pcmk__reap_unseen_nodes(uint64_t membership)
1292 {
1293 GHashTableIter iter;
1294 crm_node_t *node = NULL;
1295
1296 crm_trace("Reaping unseen nodes...");
1297 g_hash_table_iter_init(&iter, crm_peer_cache);
1298 while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&node)) {
1299 if (node->last_seen != membership) {
1300 if (node->state) {
1301
1302
1303
1304
1305
1306 update_peer_state_iter(__func__, node, CRM_NODE_LOST,
1307 membership, &iter);
1308
1309 } else {
1310 crm_info("State of node %s[%u] is still unknown",
1311 node->uname, node->id);
1312 }
1313 }
1314 }
1315 }
1316
1317 static crm_node_t *
1318 find_cib_cluster_node(const char *id, const char *uname)
1319 {
1320 GHashTableIter iter;
1321 crm_node_t *node = NULL;
1322 crm_node_t *by_id = NULL;
1323 crm_node_t *by_name = NULL;
1324
1325 if (uname) {
1326 g_hash_table_iter_init(&iter, cluster_node_cib_cache);
1327 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
1328 if (node->uname && strcasecmp(node->uname, uname) == 0) {
1329 crm_trace("Name match: %s = %p", node->uname, node);
1330 by_name = node;
1331 break;
1332 }
1333 }
1334 }
1335
1336 if (id) {
1337 g_hash_table_iter_init(&iter, cluster_node_cib_cache);
1338 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
1339 if(strcasecmp(node->uuid, id) == 0) {
1340 crm_trace("ID match: %s= %p", id, node);
1341 by_id = node;
1342 break;
1343 }
1344 }
1345 }
1346
1347 node = by_id;
1348 if (by_id == by_name) {
1349
1350 crm_trace("Consistent: %p for %s/%s", by_id, id, uname);
1351
1352 } else if (by_id == NULL && by_name) {
1353 crm_trace("Only one: %p for %s/%s", by_name, id, uname);
1354
1355 if (id) {
1356 node = NULL;
1357
1358 } else {
1359 node = by_name;
1360 }
1361
1362 } else if (by_name == NULL && by_id) {
1363 crm_trace("Only one: %p for %s/%s", by_id, id, uname);
1364
1365 if (uname) {
1366 node = NULL;
1367 }
1368
1369 } else if (uname && by_id->uname
1370 && pcmk__str_eq(uname, by_id->uname, pcmk__str_casei)) {
1371
1372
1373
1374 } else if (id && by_name->uuid
1375 && pcmk__str_eq(id, by_name->uuid, pcmk__str_casei)) {
1376
1377
1378 node = by_name;
1379
1380 } else {
1381 node = NULL;
1382 }
1383
1384 if (node == NULL) {
1385 crm_debug("Couldn't find node%s%s%s%s",
1386 id? " " : "",
1387 id? id : "",
1388 uname? " with name " : "",
1389 uname? uname : "");
1390 }
1391
1392 return node;
1393 }
1394
1395 static void
1396 cluster_node_cib_cache_refresh_helper(xmlNode *xml_node, void *user_data)
1397 {
1398 const char *id = crm_element_value(xml_node, PCMK_XA_ID);
1399 const char *uname = crm_element_value(xml_node, PCMK_XA_UNAME);
1400 crm_node_t * node = NULL;
1401
1402 CRM_CHECK(id != NULL && uname !=NULL, return);
1403 node = find_cib_cluster_node(id, uname);
1404
1405 if (node == NULL) {
1406 char *uniqueid = crm_generate_uuid();
1407
1408 node = pcmk__assert_alloc(1, sizeof(crm_node_t));
1409
1410 node->uname = pcmk__str_copy(uname);
1411 node->uuid = pcmk__str_copy(id);
1412
1413 g_hash_table_replace(cluster_node_cib_cache, uniqueid, node);
1414
1415 } else if (pcmk_is_set(node->flags, crm_node_dirty)) {
1416 pcmk__str_update(&node->uname, uname);
1417
1418
1419 clear_peer_flags(node, crm_node_dirty);
1420 }
1421
1422 }
1423
1424 static void
1425 refresh_cluster_node_cib_cache(xmlNode *cib)
1426 {
1427 pcmk__cluster_init_node_caches();
1428
1429 g_hash_table_foreach(cluster_node_cib_cache, mark_dirty, NULL);
1430
1431 crm_foreach_xpath_result(cib, PCMK__XP_MEMBER_NODE_CONFIG,
1432 cluster_node_cib_cache_refresh_helper, NULL);
1433
1434
1435 g_hash_table_foreach_remove(cluster_node_cib_cache, is_dirty, NULL);
1436 }
1437
1438 void
1439 pcmk__refresh_node_caches_from_cib(xmlNode *cib)
1440 {
1441 refresh_remote_nodes(cib);
1442 refresh_cluster_node_cib_cache(cib);
1443 }
1444
1445
1446
1447
1448 #include <crm/cluster/compat.h>
1449
1450 int
1451 crm_terminate_member(int nodeid, const char *uname, void *unused)
1452 {
1453 return stonith_api_kick(nodeid, uname, 120, TRUE);
1454 }
1455
1456 int
1457 crm_terminate_member_no_mainloop(int nodeid, const char *uname, int *connection)
1458 {
1459 return stonith_api_kick(nodeid, uname, 120, TRUE);
1460 }
1461
1462 crm_node_t *
1463 crm_get_peer(unsigned int id, const char *uname)
1464 {
1465 return pcmk__get_node(id, uname, NULL, pcmk__node_search_cluster_member);
1466 }
1467
1468 crm_node_t *
1469 crm_get_peer_full(unsigned int id, const char *uname, int flags)
1470 {
1471 return pcmk__get_node(id, uname, NULL, flags);
1472 }
1473
1474 int
1475 crm_remote_peer_cache_size(void)
1476 {
1477 unsigned int count = pcmk__cluster_num_remote_nodes();
1478
1479 return QB_MIN(count, INT_MAX);
1480 }
1481
1482 void
1483 crm_remote_peer_cache_refresh(xmlNode *cib)
1484 {
1485 refresh_remote_nodes(cib);
1486 }
1487
1488 crm_node_t *
1489 crm_remote_peer_get(const char *node_name)
1490 {
1491 return pcmk__cluster_lookup_remote_node(node_name);
1492 }
1493
1494 void
1495 crm_remote_peer_cache_remove(const char *node_name)
1496 {
1497 pcmk__cluster_forget_remote_node(node_name);
1498 }
1499
1500 gboolean
1501 crm_is_peer_active(const crm_node_t * node)
1502 {
1503 return pcmk__cluster_is_node_active(node);
1504 }
1505
1506 guint
1507 crm_active_peers(void)
1508 {
1509 return pcmk__cluster_num_active_nodes();
1510 }
1511
1512 guint
1513 reap_crm_member(uint32_t id, const char *name)
1514 {
1515 int matches = 0;
1516 crm_node_t search = { 0, };
1517
1518 if (crm_peer_cache == NULL) {
1519 crm_trace("Membership cache not initialized, ignoring purge request");
1520 return 0;
1521 }
1522
1523 search.id = id;
1524 search.uname = pcmk__str_copy(name);
1525 matches = g_hash_table_foreach_remove(crm_peer_cache,
1526 should_forget_cluster_node, &search);
1527 if(matches) {
1528 crm_notice("Purged %d peer%s with " PCMK_XA_ID
1529 "=%u%s%s from the membership cache",
1530 matches, pcmk__plural_s(matches), search.id,
1531 (search.uname? " and/or uname=" : ""),
1532 (search.uname? search.uname : ""));
1533
1534 } else {
1535 crm_info("No peers with " PCMK_XA_ID
1536 "=%u%s%s to purge from the membership cache",
1537 search.id, (search.uname? " and/or uname=" : ""),
1538 (search.uname? search.uname : ""));
1539 }
1540
1541 free(search.uname);
1542 return matches;
1543 }
1544
1545 void
1546 crm_peer_init(void)
1547 {
1548 pcmk__cluster_init_node_caches();
1549 }
1550
1551 void
1552 crm_peer_destroy(void)
1553 {
1554 pcmk__cluster_destroy_node_caches();
1555 }
1556
1557 void
1558 crm_set_autoreap(gboolean enable)
1559 {
1560 pcmk__cluster_set_autoreap(enable);
1561 }
1562
1563 void
1564 crm_set_status_callback(void (*dispatch) (enum crm_status_type, crm_node_t *, const void *))
1565 {
1566 pcmk__cluster_set_status_callback(dispatch);
1567 }
1568
1569
1570