16 #include <sys/param.h>
17 #include <sys/types.h>
61 static GHashTable *known_node_cache = NULL;
65 static gboolean crm_autoreap = TRUE;
69 #define set_peer_flags(peer, flags_to_set) do { \
70 (peer)->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
71 "Peer", (peer)->uname, \
72 (peer)->flags, (flags_to_set), \
76 #define clear_peer_flags(peer, flags_to_clear) do { \
77 (peer)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
79 "Peer", (peer)->uname, \
80 (peer)->flags, (flags_to_clear), \
111 if (node_name == NULL) {
130 node->
uuid = strdup(node_name);
131 if (node->
uuid == NULL) {
139 crm_trace(
"added %s to remote cache", node_name);
142 update_peer_uname(node, node_name);
150 crm_trace(
"removed %s from remote peer cache", node_name);
166 remote_state_from_cib(xmlNode *node_state)
180 struct refresh_data {
193 remote_cache_refresh_helper(xmlNode *result,
void *user_data)
195 struct refresh_data *
data = user_data;
197 const char *state = NULL;
203 if (data->has_state) {
204 state = remote_state_from_cib(result);
228 mark_dirty(gpointer key, gpointer value, gpointer user_data)
234 is_dirty(gpointer key, gpointer value, gpointer user_data)
247 struct refresh_data data;
259 data.has_state = TRUE;
261 remote_cache_refresh_helper, &data);
269 data.field =
"value";
270 data.has_state = FALSE;
272 remote_cache_refresh_helper, &data);
274 data.has_state = FALSE;
276 remote_cache_refresh_helper, &data);
304 crm_reap_dead_member(gpointer key, gpointer value, gpointer user_data)
309 if (search == NULL) {
312 }
else if (search->
id && node->
id != search->
id) {
319 crm_info(
"Removing node with name %s and id %u from membership cache",
341 crm_trace(
"Membership cache not initialized, ignoring purge request");
346 search.
uname = name ? strdup(name) : NULL;
347 matches = g_hash_table_foreach_remove(
crm_peer_cache, crm_reap_dead_member, &search);
349 crm_notice(
"Purged %d peer%s with id=%u%s%s from the membership cache",
351 (search.
uname?
" and/or uname=" :
""),
355 crm_info(
"No peers with id=%u%s%s to purge from the membership cache",
356 search.
id, (search.
uname?
" and/or uname=" :
""),
365 count_peer(gpointer key, gpointer value, gpointer user_data)
367 guint *count = user_data;
387 destroy_crm_node(gpointer data)
411 if (known_node_cache == NULL) {
431 if (known_node_cache != NULL) {
432 crm_trace(
"Destroying known node cache with %d members",
433 g_hash_table_size(known_node_cache));
434 g_hash_table_destroy(known_node_cache);
435 known_node_cache = NULL;
441 const void *) = NULL;
456 peer_status_callback = dispatch;
473 crm_autoreap = autoreap;
477 dump_peer_hash(
int level,
const char *caller)
480 const char *
id = NULL;
481 crm_node_t *node = NULL;
484 while (g_hash_table_iter_next(&iter, (gpointer *) &
id, (gpointer *) &node)) {
485 do_crm_log(level,
"%s: Node %u/%s = %p - %s", caller, node->
id, node->
uname, node,
id);
490 hash_find_by_data(gpointer key, gpointer value, gpointer user_data)
492 return value == user_data;
508 crm_node_t *node = NULL;
536 crm_node_t *node = NULL;
565 crm_node_t *node = NULL;
566 crm_node_t *by_id = NULL;
567 crm_node_t *by_name = NULL;
575 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
576 if(node->
uname && strcasecmp(node->
uname, uname) == 0) {
586 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
596 if(by_id == by_name) {
598 crm_trace(
"Consistent: %p for %u/%s", by_id,
id, uname);
600 }
else if(by_id == NULL && by_name) {
601 crm_trace(
"Only one: %p for %u/%s", by_name,
id, uname);
603 if(
id && by_name->
id) {
604 dump_peer_hash(LOG_WARNING, __func__);
605 crm_crit(
"Node %u and %u share the same name '%s'",
606 id, by_name->
id, uname);
613 }
else if(by_name == NULL && by_id) {
614 crm_trace(
"Only one: %p for %u/%s", by_id,
id, uname);
616 if(uname && by_id->
uname) {
617 dump_peer_hash(LOG_WARNING, __func__);
618 crm_crit(
"Node '%s' and '%s' share the same cluster nodeid %u: assuming '%s' is correct",
619 uname, by_id->
uname,
id, uname);
622 }
else if(uname && by_id->
uname) {
624 crm_notice(
"Node '%s' has changed its ID from %u to %u", by_id->
uname, by_name->
id, by_id->
id);
625 g_hash_table_foreach_remove(
crm_peer_cache, hash_find_by_data, by_name);
628 crm_warn(
"Node '%s' and '%s' share the same cluster nodeid: %u %s", by_id->
uname, by_name->
uname,
id, uname);
629 dump_peer_hash(LOG_INFO, __func__);
630 crm_abort(__FILE__, __func__, __LINE__,
"member weirdness", TRUE,
634 }
else if(
id && by_name->
id) {
635 crm_warn(
"Node %u and %u share the same name: '%s'", by_id->
id, by_name->
id, uname);
644 dump_peer_hash(LOG_DEBUG, __func__);
646 crm_info(
"Merging %p into %p", by_name, by_id);
647 g_hash_table_foreach_remove(
crm_peer_cache, hash_find_by_data, by_name);
655 remove_conflicting_peer(crm_node_t *node)
659 crm_node_t *existing_node = NULL;
661 if (node->
id == 0 || node->
uname == NULL) {
670 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &existing_node)) {
671 if (existing_node->
id > 0
672 && existing_node->
id != node->
id
673 && existing_node->
uname != NULL
674 && strcasecmp(existing_node->
uname, node->
uname) == 0) {
680 crm_warn(
"Removing cached offline node %u/%s which has conflicting uname with %u",
681 existing_node->
id, existing_node->
uname, node->
id);
683 g_hash_table_iter_remove(&iter);
704 crm_node_t *node = NULL;
705 char *uname_lookup = NULL;
715 if ((node == NULL || node->
uname == NULL) && (uname == NULL)) {
720 uname = uname_lookup;
721 crm_trace(
"Inferred a name of '%s' for node %u", uname,
id);
733 node = calloc(1,
sizeof(crm_node_t));
736 crm_info(
"Created entry %s/%p for node %s/%u (%d total)",
737 uniqueid, node, uname,
id, 1 + g_hash_table_size(
crm_peer_cache));
741 if(
id > 0 && uname && (node->
id == 0 || node->
uname == NULL)) {
742 crm_info(
"Node %u is now known as %s",
id, uname);
745 if(
id > 0 && node->
id == 0) {
749 if (uname && (node->
uname == NULL)) {
750 update_peer_uname(node, uname);
753 if(node->
uuid == NULL) {
757 crm_info(
"Node %u has uuid %s",
id, uuid);
760 crm_info(
"Cannot obtain a UUID for node %u/%s",
id, node->
uname);
781 update_peer_uname(crm_node_t *node,
const char *
uname)
784 crm_err(
"Bug: can't update node name without name");
return);
786 crm_err(
"Bug: can't update node name to %s without node", uname);
790 crm_debug(
"Node uname '%s' did not change", uname);
794 for (
const char *c = uname; *c; ++c) {
795 if ((*c >=
'A') && (*c <=
'Z')) {
796 crm_warn(
"Node names with capitals are discouraged, consider changing '%s'",
803 node->
uname = strdup(uname);
806 if (peer_status_callback != NULL) {
812 remove_conflicting_peer(node);
825 static inline const char *
828 const char *text =
"unknown";
835 text =
"pacemaker-based";
838 text =
"pacemaker-controld";
841 text =
"pacemaker-schedulerd";
844 text =
"pacemaker-execd";
847 text =
"pacemaker-attrd";
850 text =
"pacemaker-fenced";
853 text =
"corosync-cpg";
879 gboolean changed = FALSE;
882 source, proc2text(flag), status);
891 if (status == NULL) {
899 node->
processes = pcmk__set_flags_as(__func__, __LINE__,
907 node->
processes = pcmk__clear_flags_as(__func__, __LINE__,
916 crm_info(
"%s: Node %s[%u] - all processes are now offline", source, node->
uname,
919 crm_info(
"%s: Node %s[%u] - %s is now %s", source, node->
uname, node->
id,
920 proc2text(flag), status);
926 if (peer_status_callback != NULL) {
938 const char *peer_state = NULL;
948 crm_trace(
"%s: Node %s[%u] - %s is unchanged (%s)", source, node->
uname, node->
id,
949 proc2text(flag), status);
964 const char *expected)
967 gboolean changed = FALSE;
969 CRM_CHECK(node != NULL,
crm_err(
"%s: Could not set 'expected' to %s", source, expected);
984 crm_info(
"%s: Node %s[%u] - expected state is now %s (was %s)", source, node->
uname, node->
id,
988 crm_trace(
"%s: Node %s[%u] - expected state is unchanged (%s)", source, node->
uname,
1010 update_peer_state_iter(
const char *source, crm_node_t *node,
const char *state,
1011 uint64_t membership, GHashTableIter *iter)
1016 crm_err(
"Could not set state for unknown host to %s"
1017 CRM_XS " source=%s", state, source);
1029 char *last = node->
state;
1031 node->
state = strdup(state);
1033 " nodeid=%u previous=%s source=%s", node->
uname, state,
1034 node->
id, (last? last :
"unknown"), source);
1035 if (peer_status_callback != NULL) {
1040 if (crm_autoreap && !is_member
1047 crm_notice(
"Purged 1 peer with id=%u and/or uname=%s from the membership cache", node->
id, node->
uname);
1048 g_hash_table_iter_remove(iter);
1058 " nodeid=%u source=%s", node->
uname, state, node->
id, source);
1080 const char *state, uint64_t membership)
1082 return update_peer_state_iter(source, node, state, membership, NULL);
1094 GHashTableIter iter;
1095 crm_node_t *node = NULL;
1099 while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&node)) {
1111 crm_info(
"State of node %s[%u] is still unknown",
1119 find_known_node(
const char *
id,
const char *uname)
1121 GHashTableIter iter;
1122 crm_node_t *node = NULL;
1123 crm_node_t *by_id = NULL;
1124 crm_node_t *by_name = NULL;
1127 g_hash_table_iter_init(&iter, known_node_cache);
1128 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
1129 if (node->
uname && strcasecmp(node->
uname, uname) == 0) {
1138 g_hash_table_iter_init(&iter, known_node_cache);
1139 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
1140 if(strcasecmp(node->
uuid,
id) == 0) {
1141 crm_trace(
"ID match: %s= %p",
id, node);
1149 if (by_id == by_name) {
1151 crm_trace(
"Consistent: %p for %s/%s", by_id,
id, uname);
1153 }
else if (by_id == NULL && by_name) {
1154 crm_trace(
"Only one: %p for %s/%s", by_name,
id, uname);
1163 }
else if (by_name == NULL && by_id) {
1164 crm_trace(
"Only one: %p for %s/%s", by_id,
id, uname);
1170 }
else if (uname && by_id->
uname
1175 }
else if (
id && by_name->
uuid
1189 uname?
" with name " :
"",
1197 known_node_cache_refresh_helper(xmlNode *xml_node,
void *user_data)
1201 crm_node_t * node = NULL;
1203 CRM_CHECK(
id != NULL && uname !=NULL,
return);
1204 node = find_known_node(
id, uname);
1209 node = calloc(1,
sizeof(crm_node_t));
1212 node->
uname = strdup(uname);
1215 node->
uuid = strdup(
id);
1218 g_hash_table_replace(known_node_cache, uniqueid, node);
1223 node->
uname = strdup(uname);
1234 refresh_known_node_cache(xmlNode *cib)
1238 g_hash_table_foreach(known_node_cache, mark_dirty, NULL);
1241 known_node_cache_refresh_helper, NULL);
1244 g_hash_table_foreach_remove(known_node_cache, is_dirty, NULL);
1251 refresh_known_node_cache(cib);
1268 crm_node_t *node = NULL;
1269 char *id_str = NULL;
1283 node = find_known_node(id_str, uname);
void crm_peer_destroy(void)
#define CRM_CHECK(expr, failure_action)
#define crm_notice(fmt, args...)
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.
#define crm_crit(fmt, args...)
char * crm_generate_uuid(void)
void pcmk__reap_unseen_nodes(uint64_t ring_id)
gboolean crm_is_peer_active(const crm_node_t *node)
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
void crm_set_autoreap(gboolean autoreap)
Tell the library whether to automatically reap lost nodes.
GHashTable * crm_remote_peer_cache
crm_node_t * pcmk__search_known_node_cache(unsigned int id, const char *uname, uint32_t flags)
int crm_terminate_member_no_mainloop(int nodeid, const char *uname, int *connection)
crm_node_t * crm_get_peer(unsigned int id, const char *uname)
Get a cluster node cache entry.
guint crm_active_peers(void)
char * get_node_name(uint32_t nodeid)
Get the node name corresponding to a cluster node ID.
crm_node_t * crm_get_peer_full(unsigned int id, const char *uname, int flags)
Get a node cache entry (cluster or Pacemaker Remote)
gboolean crm_is_corosync_peer_active(const crm_node_t *node)
Check whether a Corosync cluster peer is active.
#define crm_warn(fmt, args...)
crm_node_t * pcmk__update_peer_state(const char *source, crm_node_t *node, const char *state, uint64_t membership)
Update a node's state and membership information.
#define PCMK__XP_GUEST_NODE_CONFIG
#define clear_peer_flags(peer, flags_to_clear)
void crm_remote_peer_cache_remove(const char *node_name)
#define crm_debug(fmt, args...)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_terminate_member(int nodeid, const char *uname, void *unused)
#define crm_trace(fmt, args...)
crm_node_t * pcmk__search_cluster_node_cache(unsigned int id, const char *uname)
#define do_crm_log(level, fmt, args...)
Log a message.
crm_node_t * crm_update_peer_proc(const char *source, crm_node_t *peer, uint32_t flag, const char *status)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
#define PCMK__XP_REMOTE_NODE_CONFIG
Deprecated Pacemaker cluster API.
unsigned long long crm_peer_seq
guint reap_crm_member(uint32_t id, const char *name)
Remove all peer cache entries matching a node ID and/or uname.
const char * name_for_cluster_type(enum cluster_type_e type)
Get a log-friendly string equivalent of a cluster type.
void pcmk__update_peer_expected(const char *source, crm_node_t *node, const char *expected)
gboolean is_corosync_cluster(void)
Check whether the local cluster is a Corosync cluster.
#define PCMK__XP_REMOTE_NODE_STATUS
crm_node_t * pcmk__search_node_caches(unsigned int id, const char *uname, uint32_t flags)
crm_node_t * crm_remote_peer_get(const char *node_name)
Get a remote node peer cache entry, creating it if necessary.
#define crm_err(fmt, args...)
#define pcmk__plural_s(i)
void crm_foreach_xpath_result(xmlNode *xml, const char *xpath, void(*helper)(xmlNode *, void *), void *user_data)
Run a supplied function for each result of an xpath search.
bool pcmk__corosync_has_nodelist(void)
IPC interface to Pacemaker daemons.
#define set_peer_flags(peer, flags_to_set)
#define XML_NODE_IN_CLUSTER
gboolean crm_is_true(const char *s)
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
#define PCMK__XP_MEMBER_NODE_CONFIG
void crm_remote_peer_cache_refresh(xmlNode *cib)
Repopulate the remote peer cache based on CIB XML.
GHashTable * crm_peer_cache
#define crm_info(fmt, args...)
const char * crm_peer_uuid(crm_node_t *node)
Get (and set if needed) a node's UUID.
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
enum cluster_type_e get_cluster_type(void)
Get (and validate) the local cluster type.
int crm_remote_peer_cache_size(void)
void pcmk__refresh_node_caches_from_cib(xmlNode *cib)