pacemaker  1.1.14-70404b0
Scalable High-Availability cluster resource manager
membership.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include <crm_internal.h>
19 
20 #ifndef _GNU_SOURCE
21 # define _GNU_SOURCE
22 #endif
23 
24 #include <sys/param.h>
25 #include <sys/types.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <glib.h>
30 #include <crm/common/ipc.h>
31 #include <crm/cluster/internal.h>
32 #include <crm/msg_xml.h>
33 #include <crm/stonith-ng.h>
34 
35 GHashTable *crm_peer_cache = NULL;
36 GHashTable *crm_remote_peer_cache = NULL;
37 unsigned long long crm_peer_seq = 0;
38 gboolean crm_have_quorum = FALSE;
39 static gboolean crm_autoreap = TRUE;
40 
41 int
43 {
44  if (crm_remote_peer_cache == NULL) {
45  return 0;
46  }
47  return g_hash_table_size(crm_remote_peer_cache);
48 }
49 
50 void
51 crm_remote_peer_cache_add(const char *node_name)
52 {
53  crm_node_t *node = g_hash_table_lookup(crm_remote_peer_cache, node_name);
54 
55  if (node == NULL) {
56  crm_trace("added %s to remote cache", node_name);
57  node = calloc(1, sizeof(crm_node_t));
58  node->flags = crm_remote_node;
59  CRM_ASSERT(node);
60  node->uname = strdup(node_name);
61  node->uuid = strdup(node_name);
62  node->state = strdup(CRM_NODE_MEMBER);
63  g_hash_table_replace(crm_remote_peer_cache, node->uname, node);
64  }
65 }
66 
67 void
68 crm_remote_peer_cache_remove(const char *node_name)
69 {
70  g_hash_table_remove(crm_remote_peer_cache, node_name);
71 }
72 
73 static void
74 remote_cache_refresh_helper(xmlNode *cib, const char *xpath, const char *field)
75 {
76  const char *remote = NULL;
77  crm_node_t *node = NULL;
78  xmlXPathObjectPtr xpathObj = NULL;
79  int max = 0;
80  int lpc = 0;
81 
82  xpathObj = xpath_search(cib, xpath);
83  max = numXpathResults(xpathObj);
84  for (lpc = 0; lpc < max; lpc++) {
85  xmlNode *xml = getXpathResult(xpathObj, lpc);
86 
87  CRM_LOG_ASSERT(xml != NULL);
88  if(xml != NULL) {
89  remote = crm_element_value(xml, field);
90  }
91 
92  if (remote) {
93  crm_trace("added %s to remote cache", remote);
94  node = calloc(1, sizeof(crm_node_t));
95  node->flags = crm_remote_node;
96  CRM_ASSERT(node);
97  node->uname = strdup(remote);
98  node->uuid = strdup(remote);
99  node->state = strdup(CRM_NODE_MEMBER);
100  g_hash_table_replace(crm_remote_peer_cache, node->uname, node);
101  }
102  }
103  freeXpathObject(xpathObj);
104 }
105 
106 /* search string to find CIB resources entries for guest nodes */
107 #define XPATH_GUEST_NODE_CONFIG \
108  "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \
109  "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR \
110  "[@name='" XML_RSC_ATTR_REMOTE_NODE "']"
111 
112 /* search string to find CIB resources entries for remote nodes */
113 #define XPATH_REMOTE_NODE_CONFIG \
114  "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \
115  "[@type='remote'][@provider='pacemaker']"
116 
117 /* search string to find CIB node status entries for pacemaker_remote nodes */
118 #define XPATH_REMOTE_NODE_STATUS \
119  "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \
120  "[@" XML_NODE_IS_REMOTE "='true']"
121 
128 {
129  g_hash_table_remove_all(crm_remote_peer_cache);
130 
131  /* remote nodes associated with a cluster resource */
132  remote_cache_refresh_helper(cib, XPATH_GUEST_NODE_CONFIG, "value");
133 
134  /* baremetal nodes defined by connection resources*/
135  remote_cache_refresh_helper(cib, XPATH_REMOTE_NODE_CONFIG, "id");
136 
137  /* baremetal nodes we have seen in the config that may or may not have connection
138  * resources associated with them anymore */
139  remote_cache_refresh_helper(cib, XPATH_REMOTE_NODE_STATUS, "id");
140 }
141 
142 gboolean
144 {
145  if(node == NULL) {
146  return FALSE;
147  }
148 
149  if (is_set(node->flags, crm_remote_node)) {
150  /* remote nodes are never considered active members. This
151  * guarantees they will never be considered for DC membership.*/
152  return FALSE;
153  }
154 #if SUPPORT_COROSYNC
155  if (is_openais_cluster()) {
156  return crm_is_corosync_peer_active(node);
157  }
158 #endif
159 #if SUPPORT_HEARTBEAT
160  if (is_heartbeat_cluster()) {
161  return crm_is_heartbeat_peer_active(node);
162  }
163 #endif
164  crm_err("Unhandled cluster type: %s", name_for_cluster_type(get_cluster_type()));
165  return FALSE;
166 }
167 
168 static gboolean
169 crm_reap_dead_member(gpointer key, gpointer value, gpointer user_data)
170 {
171  crm_node_t *node = value;
172  crm_node_t *search = user_data;
173 
174  if (search == NULL) {
175  return FALSE;
176 
177  } else if (search->id && node->id != search->id) {
178  return FALSE;
179 
180  } else if (search->id == 0 && safe_str_neq(node->uname, search->uname)) {
181  return FALSE;
182 
183  } else if (crm_is_peer_active(value) == FALSE) {
184  crm_notice("Removing %s/%u from the membership list", node->uname, node->id);
185  return TRUE;
186  }
187  return FALSE;
188 }
189 
198 guint
199 reap_crm_member(uint32_t id, const char *name)
200 {
201  int matches = 0;
202  crm_node_t search;
203 
204  if (crm_peer_cache == NULL) {
205  crm_trace("Nothing to do, cache not initialized");
206  return 0;
207  }
208 
209  search.id = id;
210  search.uname = name ? strdup(name) : NULL;
211  matches = g_hash_table_foreach_remove(crm_peer_cache, crm_reap_dead_member, &search);
212  if(matches) {
213  crm_notice("Purged %d peers with id=%u and/or uname=%s from the membership cache",
214  matches, search.id, search.uname);
215 
216  } else {
217  crm_info("No peers with id=%u and/or uname=%s exist", id, name);
218  }
219 
220  free(search.uname);
221  return matches;
222 }
223 
224 static void
225 crm_count_peer(gpointer key, gpointer value, gpointer user_data)
226 {
227  guint *count = user_data;
228  crm_node_t *node = value;
229 
230  if (crm_is_peer_active(node)) {
231  *count = *count + 1;
232  }
233 }
234 
235 guint
237 {
238  guint count = 0;
239 
240  if (crm_peer_cache) {
241  g_hash_table_foreach(crm_peer_cache, crm_count_peer, &count);
242  }
243  return count;
244 }
245 
246 static void
247 destroy_crm_node(gpointer data)
248 {
249  crm_node_t *node = data;
250 
251  crm_trace("Destroying entry for node %u: %s", node->id, node->uname);
252 
253  free(node->addr);
254  free(node->uname);
255  free(node->state);
256  free(node->uuid);
257  free(node->expected);
258  free(node);
259 }
260 
261 void
263 {
264  if (crm_peer_cache == NULL) {
265  crm_peer_cache = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, free, destroy_crm_node);
266  }
267 
268  if (crm_remote_peer_cache == NULL) {
269  crm_remote_peer_cache = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, NULL, destroy_crm_node);
270  }
271 }
272 
273 void
275 {
276  if (crm_peer_cache != NULL) {
277  crm_trace("Destroying peer cache with %d members", g_hash_table_size(crm_peer_cache));
278  g_hash_table_destroy(crm_peer_cache);
279  crm_peer_cache = NULL;
280  }
281 
282  if (crm_remote_peer_cache != NULL) {
283  crm_trace("Destroying remote peer cache with %d members", g_hash_table_size(crm_remote_peer_cache));
284  g_hash_table_destroy(crm_remote_peer_cache);
285  crm_remote_peer_cache = NULL;
286  }
287 }
288 
289 void (*crm_status_callback) (enum crm_status_type, crm_node_t *, const void *) = NULL;
290 
301 void
303 {
305 }
306 
318 void
319 crm_set_autoreap(gboolean autoreap)
320 {
321  crm_autoreap = autoreap;
322 }
323 
324 static void crm_dump_peer_hash(int level, const char *caller)
325 {
326  GHashTableIter iter;
327  const char *id = NULL;
328  crm_node_t *node = NULL;
329 
330  g_hash_table_iter_init(&iter, crm_peer_cache);
331  while (g_hash_table_iter_next(&iter, (gpointer *) &id, (gpointer *) &node)) {
332  do_crm_log(level, "%s: Node %u/%s = %p - %s", caller, node->id, node->uname, node, id);
333  }
334 }
335 
336 static gboolean crm_hash_find_by_data(gpointer key, gpointer value, gpointer user_data)
337 {
338  if(value == user_data) {
339  return TRUE;
340  }
341  return FALSE;
342 }
343 
344 crm_node_t *
345 crm_find_peer_full(unsigned int id, const char *uname, int flags)
346 {
347  crm_node_t *node = NULL;
348 
349  CRM_ASSERT(id > 0 || uname != NULL);
350 
351  crm_peer_init();
352 
353  if (flags & CRM_GET_PEER_REMOTE) {
354  node = g_hash_table_lookup(crm_remote_peer_cache, uname);
355  }
356 
357  if (node == NULL && (flags & CRM_GET_PEER_CLUSTER)) {
358  node = crm_find_peer(id, uname);
359  }
360  return node;
361 }
362 
363 crm_node_t *
364 crm_get_peer_full(unsigned int id, const char *uname, int flags)
365 {
366  crm_node_t *node = NULL;
367 
368  CRM_ASSERT(id > 0 || uname != NULL);
369 
370  crm_peer_init();
371 
372  if (flags & CRM_GET_PEER_REMOTE) {
373  node = g_hash_table_lookup(crm_remote_peer_cache, uname);
374  }
375 
376  if (node == NULL && (flags & CRM_GET_PEER_CLUSTER)) {
377  node = crm_get_peer(id, uname);
378  }
379  return node;
380 }
381 
382 crm_node_t *
383 crm_find_peer(unsigned int id, const char *uname)
384 {
385  GHashTableIter iter;
386  crm_node_t *node = NULL;
387  crm_node_t *by_id = NULL;
388  crm_node_t *by_name = NULL;
389 
390  CRM_ASSERT(id > 0 || uname != NULL);
391 
392  crm_peer_init();
393 
394  if (uname != NULL) {
395  g_hash_table_iter_init(&iter, crm_peer_cache);
396  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
397  if(node->uname && strcasecmp(node->uname, uname) == 0) {
398  crm_trace("Name match: %s = %p", node->uname, node);
399  by_name = node;
400  break;
401  }
402  }
403  }
404 
405  if (id > 0) {
406  g_hash_table_iter_init(&iter, crm_peer_cache);
407  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
408  if(node->id == id) {
409  crm_trace("ID match: %u = %p", node->id, node);
410  by_id = node;
411  break;
412  }
413  }
414  }
415 
416  node = by_id; /* Good default */
417  if(by_id == by_name) {
418  /* Nothing to do if they match (both NULL counts) */
419  crm_trace("Consistent: %p for %u/%s", by_id, id, uname);
420 
421  } else if(by_id == NULL && by_name) {
422  crm_trace("Only one: %p for %u/%s", by_name, id, uname);
423 
424  if(id && by_name->id) {
425  crm_dump_peer_hash(LOG_WARNING, __FUNCTION__);
426  crm_crit("Node %u and %u share the same name '%s'",
427  id, by_name->id, uname);
428  node = NULL; /* Create a new one */
429 
430  } else {
431  node = by_name;
432  }
433 
434  } else if(by_name == NULL && by_id) {
435  crm_trace("Only one: %p for %u/%s", by_id, id, uname);
436 
437  if(uname && by_id->uname) {
438  crm_dump_peer_hash(LOG_WARNING, __FUNCTION__);
439  crm_crit("Node '%s' and '%s' share the same cluster nodeid %u: assuming '%s' is correct",
440  uname, by_id->uname, id, uname);
441  }
442 
443  } else if(uname && by_id->uname) {
444  if(safe_str_eq(uname, by_id->uname)) {
445  crm_notice("Node '%s' has changed its ID from %u to %u", by_id->uname, by_name->id, by_id->id);
446  g_hash_table_foreach_remove(crm_peer_cache, crm_hash_find_by_data, by_name);
447 
448  } else {
449  crm_warn("Node '%s' and '%s' share the same cluster nodeid: %u %s", by_id->uname, by_name->uname, id, uname);
450  crm_dump_peer_hash(LOG_INFO, __FUNCTION__);
451  crm_abort(__FILE__, __FUNCTION__, __LINE__, "member weirdness", TRUE, TRUE);
452  }
453 
454  } else if(id && by_name->id) {
455  crm_warn("Node %u and %u share the same name: '%s'", by_id->id, by_name->id, uname);
456 
457  } else {
458  /* Simple merge */
459 
460  /* Only corosync based clusters use nodeid's
461  *
462  * The functions that call crm_update_peer_state() only know nodeid
463  * so 'by_id' is authorative when merging
464  *
465  * Same for crm_update_peer_proc()
466  */
467  crm_dump_peer_hash(LOG_DEBUG, __FUNCTION__);
468 
469  crm_info("Merging %p into %p", by_name, by_id);
470  g_hash_table_foreach_remove(crm_peer_cache, crm_hash_find_by_data, by_name);
471  }
472 
473  return node;
474 }
475 
476 #if SUPPORT_COROSYNC
477 static guint
478 crm_remove_conflicting_peer(crm_node_t *node)
479 {
480  int matches = 0;
481  GHashTableIter iter;
482  crm_node_t *existing_node = NULL;
483 
484  if (node->id == 0 || node->uname == NULL) {
485  return 0;
486  }
487 
488 # if !SUPPORT_PLUGIN
489  if (corosync_cmap_has_config("nodelist") != 0) {
490  return 0;
491  }
492 # endif
493 
494  g_hash_table_iter_init(&iter, crm_peer_cache);
495  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &existing_node)) {
496  if (existing_node->id > 0
497  && existing_node->id != node->id
498  && existing_node->uname != NULL
499  && strcasecmp(existing_node->uname, node->uname) == 0) {
500 
501  if (crm_is_peer_active(existing_node)) {
502  continue;
503  }
504 
505  crm_warn("Removing cached offline node %u/%s which has conflicting uname with %u",
506  existing_node->id, existing_node->uname, node->id);
507 
508  g_hash_table_iter_remove(&iter);
509  matches++;
510  }
511  }
512 
513  return matches;
514 }
515 #endif
516 
517 /* coverity[-alloc] Memory is referenced in one or both hashtables */
518 crm_node_t *
519 crm_get_peer(unsigned int id, const char *uname)
520 {
521  crm_node_t *node = NULL;
522  char *uname_lookup = NULL;
523 
524  CRM_ASSERT(id > 0 || uname != NULL);
525 
526  crm_peer_init();
527 
528  node = crm_find_peer(id, uname);
529 
530  /* if uname wasn't provided, and find_peer did not turn up a uname based on id.
531  * we need to do a lookup of the node name using the id in the cluster membership. */
532  if ((node == NULL || node->uname == NULL) && (uname == NULL)) {
533  uname_lookup = get_node_name(id);
534  }
535 
536  if (uname_lookup) {
537  uname = uname_lookup;
538  crm_trace("Inferred a name of '%s' for node %u", uname, id);
539 
540  /* try to turn up the node one more time now that we know the uname. */
541  if (node == NULL) {
542  node = crm_find_peer(id, uname);
543  }
544  }
545 
546 
547  if (node == NULL) {
548  char *uniqueid = crm_generate_uuid();
549 
550  node = calloc(1, sizeof(crm_node_t));
551  CRM_ASSERT(node);
552 
553  crm_info("Created entry %s/%p for node %s/%u (%d total)",
554  uniqueid, node, uname, id, 1 + g_hash_table_size(crm_peer_cache));
555  g_hash_table_replace(crm_peer_cache, uniqueid, node);
556  }
557 
558  if(id > 0 && uname && (node->id == 0 || node->uname == NULL)) {
559  crm_info("Node %u is now known as %s", id, uname);
560  }
561 
562  if(id > 0 && node->id == 0) {
563  node->id = id;
564  }
565 
566  if (uname && (node->uname == NULL)) {
567  crm_update_peer_uname(node, uname);
568  }
569 
570  if(node->uuid == NULL) {
571  const char *uuid = crm_peer_uuid(node);
572 
573  if (uuid) {
574  crm_info("Node %u has uuid %s", id, uuid);
575 
576  } else {
577  crm_info("Cannot obtain a UUID for node %u/%s", id, node->uname);
578  }
579  }
580 
581  free(uname_lookup);
582 
583  return node;
584 }
585 
597 crm_node_t *
598 crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes,
599  uint32_t children, const char *uuid, const char *uname, const char *addr,
600  const char *state)
601 {
602 #if SUPPORT_PLUGIN
603  gboolean addr_changed = FALSE;
604  gboolean votes_changed = FALSE;
605 #endif
606  crm_node_t *node = NULL;
607 
608  id = get_corosync_id(id, uuid);
609  node = crm_get_peer(id, uname);
610 
611  CRM_ASSERT(node != NULL);
612 
613  if (node->uuid == NULL) {
614  if (is_openais_cluster()) {
615  /* Yes, overrule whatever was passed in */
616  crm_peer_uuid(node);
617 
618  } else if (uuid != NULL) {
619  node->uuid = strdup(uuid);
620  }
621  }
622 
623  if (children > 0) {
624  if (crm_update_peer_proc(source, node, children, state) == NULL) {
625  return NULL;
626  }
627  }
628 
629  if (state != NULL) {
630  if (crm_update_peer_state(source, node, state, seen) == NULL) {
631  return NULL;
632  }
633  }
634 #if SUPPORT_HEARTBEAT
635  if (born != 0) {
636  node->born = born;
637  }
638 #endif
639 
640 #if SUPPORT_PLUGIN
641  /* These were only used by the plugin */
642  if (born != 0) {
643  node->born = born;
644  }
645 
646  if (votes > 0 && node->votes != votes) {
647  votes_changed = TRUE;
648  node->votes = votes;
649  }
650 
651  if (addr != NULL) {
652  if (node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) {
653  addr_changed = TRUE;
654  free(node->addr);
655  node->addr = strdup(addr);
656  }
657  }
658  if (addr_changed || votes_changed) {
659  crm_info("%s: Node %s: id=%u state=%s addr=%s%s votes=%d%s born=" U64T " seen=" U64T
660  " proc=%.32x", source, node->uname, node->id, node->state,
661  node->addr, addr_changed ? " (new)" : "", node->votes,
662  votes_changed ? " (new)" : "", node->born, node->last_seen, node->processes);
663  }
664 #endif
665 
666  return node;
667 }
668 
680 void
682 {
683  int i, len = strlen(uname);
684 
685  for (i = 0; i < len; i++) {
686  if (uname[i] >= 'A' && uname[i] <= 'Z') {
687  crm_warn("Node names with capitals are discouraged, consider changing '%s'",
688  uname);
689  break;
690  }
691  }
692 
693  free(node->uname);
694  node->uname = strdup(uname);
695  if (crm_status_callback) {
697  }
698 
699 #if SUPPORT_COROSYNC
700  if (is_openais_cluster() && !is_set(node->flags, crm_remote_node)) {
701  crm_remove_conflicting_peer(node);
702  }
703 #endif
704 }
705 
722 crm_node_t *
723 crm_update_peer_proc(const char *source, crm_node_t * node, uint32_t flag, const char *status)
724 {
725  uint32_t last = 0;
726  gboolean changed = FALSE;
727 
728  CRM_CHECK(node != NULL, crm_err("%s: Could not set %s to %s for NULL",
729  source, peer2text(flag), status); return NULL);
730 
731  /* Pacemaker doesn't spawn processes on remote nodes */
732  if (is_set(node->flags, crm_remote_node)) {
733  return node;
734  }
735 
736  last = node->processes;
737  if (status == NULL) {
738  node->processes = flag;
739  if (node->processes != last) {
740  changed = TRUE;
741  }
742 
743  } else if (safe_str_eq(status, ONLINESTATUS)) {
744  if ((node->processes & flag) != flag) {
745  set_bit(node->processes, flag);
746  changed = TRUE;
747  }
748 #if SUPPORT_PLUGIN
749  } else if (safe_str_eq(status, CRM_NODE_MEMBER)) {
750  if (flag > 0 && node->processes != flag) {
751  node->processes = flag;
752  changed = TRUE;
753  }
754 #endif
755 
756  } else if (node->processes & flag) {
757  clear_bit(node->processes, flag);
758  changed = TRUE;
759  }
760 
761  if (changed) {
762  if (status == NULL && flag <= crm_proc_none) {
763  crm_info("%s: Node %s[%u] - all processes are now offline", source, node->uname,
764  node->id);
765  } else {
766  crm_info("%s: Node %s[%u] - %s is now %s", source, node->uname, node->id,
767  peer2text(flag), status);
768  }
769 
770  /* Call the client callback first, then update the peer state,
771  * in case the node will be reaped
772  */
773  if (crm_status_callback) {
775  }
776 
777  /* The client callback shouldn't touch the peer caches,
778  * but as a safety net, bail if the peer cache was destroyed.
779  */
780  if (crm_peer_cache == NULL) {
781  return NULL;
782  }
783 
784  if (crm_autoreap) {
785  node = crm_update_peer_state(__FUNCTION__, node,
786  is_set(node->processes, crm_get_cluster_proc())?
788  }
789  } else {
790  crm_trace("%s: Node %s[%u] - %s is unchanged (%s)", source, node->uname, node->id,
791  peer2text(flag), status);
792  }
793  return node;
794 }
795 
796 void
797 crm_update_peer_expected(const char *source, crm_node_t * node, const char *expected)
798 {
799  char *last = NULL;
800  gboolean changed = FALSE;
801 
802  CRM_CHECK(node != NULL, crm_err("%s: Could not set 'expected' to %s", source, expected);
803  return);
804 
805  /* Remote nodes don't participate in joins */
806  if (is_set(node->flags, crm_remote_node)) {
807  return;
808  }
809 
810  last = node->expected;
811  if (expected != NULL && safe_str_neq(node->expected, expected)) {
812  node->expected = strdup(expected);
813  changed = TRUE;
814  }
815 
816  if (changed) {
817  crm_info("%s: Node %s[%u] - expected state is now %s (was %s)", source, node->uname, node->id,
818  expected, last);
819  free(last);
820  } else {
821  crm_trace("%s: Node %s[%u] - expected state is unchanged (%s)", source, node->uname,
822  node->id, expected);
823  }
824 }
825 
842 static crm_node_t *
843 crm_update_peer_state_iter(const char *source, crm_node_t * node, const char *state, int membership, GHashTableIter *iter)
844 {
845  gboolean is_member;
846 
847  CRM_CHECK(node != NULL, crm_err("%s: Could not set 'state' to %s", source, state);
848  return NULL);
849 
850  is_member = safe_str_eq(state, CRM_NODE_MEMBER);
851  if (membership && is_member) {
852  node->last_seen = membership;
853  }
854 
855  if (state && safe_str_neq(node->state, state)) {
856  char *last = node->state;
857  enum crm_status_type status_type = is_set(node->flags, crm_remote_node)?
859 
860  node->state = strdup(state);
861  crm_notice("%s: Node %s[%u] - state is now %s (was %s)",
862  source, node->uname, node->id, state, last);
863  if (crm_status_callback) {
864  crm_status_callback(status_type, node, last);
865  }
866  free(last);
867 
868  if (crm_autoreap && !is_member && !is_set(node->flags, crm_remote_node)) {
869  /* We only autoreap from the peer cache, not the remote peer cache,
870  * because the latter should be managed only by
871  * crm_remote_peer_cache_refresh().
872  */
873  if(iter) {
874  crm_notice("Purged 1 peer with id=%u and/or uname=%s from the membership cache", node->id, node->uname);
875  g_hash_table_iter_remove(iter);
876 
877  } else {
878  reap_crm_member(node->id, node->uname);
879  }
880  node = NULL;
881  }
882 
883  } else {
884  crm_trace("%s: Node %s[%u] - state is unchanged (%s)", source, node->uname, node->id,
885  state);
886  }
887  return node;
888 }
889 
905 crm_node_t *
906 crm_update_peer_state(const char *source, crm_node_t * node, const char *state, int membership)
907 {
908  return crm_update_peer_state_iter(source, node, state, membership, NULL);
909 }
910 
917 void
918 crm_reap_unseen_nodes(uint64_t membership)
919 {
920  GHashTableIter iter;
921  crm_node_t *node = NULL;
922 
923  crm_trace("Reaping unseen nodes...");
924  g_hash_table_iter_init(&iter, crm_peer_cache);
925  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&node)) {
926  if (node->last_seen != membership) {
927  if (node->state) {
928  /*
929  * Calling crm_update_peer_state_iter() allows us to
930  * remove the node from crm_peer_cache without
931  * invalidating our iterator
932  */
933  crm_update_peer_state_iter(__FUNCTION__, node, CRM_NODE_LOST, membership, &iter);
934 
935  } else {
936  crm_info("State of node %s[%u] is still unknown",
937  node->uname, node->id);
938  }
939  }
940  }
941 }
942 
943 int
944 crm_terminate_member(int nodeid, const char *uname, void *unused)
945 {
946  /* Always use the synchronous, non-mainloop version */
947  return stonith_api_kick(nodeid, uname, 120, TRUE);
948 }
949 
950 int
951 crm_terminate_member_no_mainloop(int nodeid, const char *uname, int *connection)
952 {
953  return stonith_api_kick(nodeid, uname, 120, TRUE);
954 }
uint32_t votes
Definition: internal.h:50
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
void crm_remote_peer_cache_add(const char *node_name)
Definition: membership.c:51
void crm_reap_unseen_nodes(uint64_t membership)
Definition: membership.c:918
#define crm_notice(fmt, args...)
Definition: logging.h:250
#define CRM_NODE_LOST
Definition: cluster.h:43
#define XPATH_REMOTE_NODE_STATUS
Definition: membership.c:118
GHashTable * crm_peer_cache
Definition: membership.c:35
gboolean is_openais_cluster(void)
Definition: cluster.c:619
#define crm_crit(fmt, args...)
Definition: logging.h:247
gboolean safe_str_neq(const char *a, const char *b)
Definition: utils.c:668
char * crm_generate_uuid(void)
Definition: utils.c:2314
uint64_t flags
Definition: cluster.h:73
void crm_peer_destroy(void)
Definition: membership.c:274
uint32_t id
Definition: cluster.h:70
gboolean is_heartbeat_cluster(void)
Definition: cluster.c:634
uint64_t born
Definition: cluster.h:71
char * uuid
Definition: cluster.h:80
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:2562
crm_node_t * crm_find_peer(unsigned int id, const char *uname)
Definition: membership.c:383
int get_corosync_id(int id, const char *uuid)
Definition: cluster.c:96
gboolean crm_have_quorum
Definition: membership.c:38
crm_node_t * crm_find_peer_full(unsigned int id, const char *uname, int flags)
Definition: membership.c:345
GHashTable * crm_remote_peer_cache
Definition: membership.c:36
char * addr
Definition: cluster.h:84
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:150
#define clear_bit(word, bit)
Definition: crm_internal.h:199
unsigned long long crm_peer_seq
Definition: membership.c:37
char * get_node_name(uint32_t nodeid)
Definition: cluster.c:301
void crm_set_autoreap(gboolean autoreap)
Tell the library whether to automatically reap lost nodes.
Definition: membership.c:319
void crm_peer_init(void)
Definition: membership.c:262
void crm_remote_peer_cache_remove(const char *node_name)
Definition: membership.c:68
gboolean crm_is_corosync_peer_active(const crm_node_t *node)
Definition: corosync.c:456
char uname[MAX_NAME]
Definition: internal.h:53
int crm_remote_peer_cache_size(void)
Definition: membership.c:42
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define set_bit(word, bit)
Definition: crm_internal.h:198
uint32_t processes
Definition: cluster.h:76
crm_node_t * crm_get_peer_full(unsigned int id, const char *uname, int flags)
Definition: membership.c:364
crm_node_t * crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes, uint32_t children, const char *uuid, const char *uname, const char *addr, const char *state)
Definition: membership.c:598
guint reap_crm_member(uint32_t id, const char *name)
Remove all peer cache entries matching a node ID and/or uname.
Definition: membership.c:199
gboolean crm_is_peer_active(const crm_node_t *node)
Definition: membership.c:143
uint32_t id
Definition: internal.h:48
uint64_t flags
Definition: remote.c:121
guint crm_strcase_hash(gconstpointer v)
Definition: utils.c:2243
#define XPATH_GUEST_NODE_CONFIG
Definition: membership.c:107
crm_status_type
Definition: cluster.h:194
void crm_update_peer_expected(const char *source, crm_node_t *node, const char *expected)
Definition: membership.c:797
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:129
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5839
int corosync_cmap_has_config(const char *prefix)
Definition: corosync.c:585
#define CRM_NODE_MEMBER
Definition: cluster.h:44
void crm_update_peer_uname(crm_node_t *node, const char *uname)
Definition: membership.c:681
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: utils.c:1415
void crm_set_status_callback(void(*dispatch)(enum crm_status_type, crm_node_t *, const void *))
Set a client function that will be called after peer status changes.
Definition: membership.c:302
const char * name_for_cluster_type(enum cluster_type_e type)
Definition: cluster.c:457
int crm_terminate_member(int nodeid, const char *uname, void *unused)
Definition: membership.c:944
char * expected
Definition: cluster.h:82
void(* crm_status_callback)(enum crm_status_type, crm_node_t *, const void *)
Definition: membership.c:289
void crm_remote_peer_cache_refresh(xmlNode *cib)
Repopulate the remote peer cache based on CIB XML.
Definition: membership.c:127
guint crm_active_peers(void)
Definition: membership.c:236
#define crm_err(fmt, args...)
Definition: logging.h:248
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:145
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:64
#define uint32_t
Definition: stdint.in.h:158
int crm_terminate_member_no_mainloop(int nodeid, const char *uname, int *connection)
Definition: membership.c:951
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
char * state
Definition: cluster.h:81
#define U64T
Definition: config.h:628
Wrappers for and extensions to libqb IPC.
crm_node_t * crm_update_peer_proc(const char *source, crm_node_t *node, uint32_t flag, const char *status)
Definition: membership.c:723
int32_t votes
Definition: cluster.h:75
char * uname
Definition: cluster.h:79
uint64_t last_seen
Definition: cluster.h:72
#define safe_str_eq(a, b)
Definition: util.h:74
#define ONLINESTATUS
Definition: util.h:48
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
Definition: utils.c:1126
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:45
crm_node_t * crm_get_peer(unsigned int id, const char *uname)
Definition: membership.c:519
#define XPATH_REMOTE_NODE_CONFIG
Definition: membership.c:113
#define crm_info(fmt, args...)
Definition: logging.h:251
const char * crm_peer_uuid(crm_node_t *node)
Definition: cluster.c:135
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:73
#define int32_t
Definition: stdint.in.h:157
enum cluster_type_e get_cluster_type(void)
Definition: cluster.c:502
crm_node_t * crm_update_peer_state(const char *source, crm_node_t *node, const char *state, int membership)
Update a node&#39;s state and membership information.
Definition: membership.c:906