diff options
Diffstat (limited to 'daemons/attrd/attrd_corosync.c')
-rw-r--r-- | daemons/attrd/attrd_corosync.c | 295 |
1 files changed, 143 insertions, 152 deletions
diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index 86dc67b..fb3b4e5 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the Pacemaker project contributors + * Copyright 2013-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -19,19 +19,19 @@ #include <crm/common/logging.h> #include <crm/common/results.h> #include <crm/common/strings_internal.h> -#include <crm/msg_xml.h> +#include <crm/common/xml.h> #include "pacemaker-attrd.h" static xmlNode * attrd_confirmation(int callid) { - xmlNode *node = create_xml_node(NULL, __func__); + xmlNode *node = pcmk__xe_create(NULL, __func__); - crm_xml_add(node, F_TYPE, T_ATTRD); - crm_xml_add(node, F_ORIG, get_local_node_name()); - crm_xml_add(node, PCMK__XA_TASK, PCMK__ATTRD_CMD_CONFIRM); - crm_xml_add_int(node, XML_LRM_ATTR_CALLID, callid); + crm_xml_add(node, PCMK__XA_T, PCMK__VALUE_ATTRD); + crm_xml_add(node, PCMK__XA_SRC, pcmk__cluster_local_node_name()); + crm_xml_add(node, PCMK_XA_TASK, PCMK__ATTRD_CMD_CONFIRM); + crm_xml_add_int(node, PCMK__XA_CALL_ID, callid); return node; } @@ -39,7 +39,7 @@ attrd_confirmation(int callid) static void attrd_peer_message(crm_node_t *peer, xmlNode *xml) { - const char *election_op = crm_element_value(xml, F_CRM_TASK); + const char *election_op = crm_element_value(xml, PCMK__XA_CRM_TASK); if (election_op) { attrd_handle_election_op(peer, xml); @@ -64,7 +64,7 @@ attrd_peer_message(crm_node_t *peer, xmlNode *xml) .result = PCMK__UNKNOWN_RESULT, }; - request.op = crm_element_value_copy(request.xml, PCMK__XA_TASK); + request.op = crm_element_value_copy(request.xml, PCMK_XA_TASK); CRM_CHECK(request.op != NULL, return); attrd_handle_request(&request); @@ -81,7 +81,7 @@ attrd_peer_message(crm_node_t *peer, xmlNode *xml) * response so the originating peer knows what they're a confirmation * for. */ - crm_element_value_int(xml, XML_LRM_ATTR_CALLID, &callid); + crm_element_value_int(xml, PCMK__XA_CALL_ID, &callid); reply = attrd_confirmation(callid); /* And then send the confirmation back to the originating peer. This @@ -106,22 +106,22 @@ attrd_cpg_dispatch(cpg_handle_t handle, uint32_t kind = 0; xmlNode *xml = NULL; const char *from = NULL; - char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from); + char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &kind, &from); if(data == NULL) { return; } if (kind == crm_class_cluster) { - xml = string2xml(data); + xml = pcmk__xml_parse(data); } if (xml == NULL) { crm_err("Bad message of class %d received from %s[%u]: '%.120s'", kind, from, nodeid, data); } else { - crm_node_t *peer = crm_get_peer(nodeid, from); - - attrd_peer_message(peer, xml); + attrd_peer_message(pcmk__get_node(nodeid, from, NULL, + pcmk__node_search_cluster_member), + xml); } free_xml(xml); @@ -143,86 +143,24 @@ attrd_cpg_destroy(gpointer unused) /*! * \internal - * \brief Override an attribute sync with a local value - * - * Broadcast the local node's value for an attribute that's different from the - * value provided in a peer's attribute synchronization response. This ensures a - * node's values for itself take precedence and all peers are kept in sync. + * \brief Broadcast an update for a single attribute value * - * \param[in] a Attribute entry to override - * - * \return Local instance of attribute value + * \param[in] a Attribute to broadcast + * \param[in] v Attribute value to broadcast */ -static attribute_value_t * -broadcast_local_value(const attribute_t *a) -{ - attribute_value_t *v = g_hash_table_lookup(a->values, attrd_cluster->uname); - xmlNode *sync = create_xml_node(NULL, __func__); - - crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE); - attrd_add_value_xml(sync, a, v, false); - attrd_send_message(NULL, sync, false); - free_xml(sync); - return v; -} - -/*! - * \internal - * \brief Ensure a Pacemaker Remote node is in the correct peer cache - * - * \param[in] node_name Name of Pacemaker Remote node to check - */ -static void -cache_remote_node(const char *node_name) +void +attrd_broadcast_value(const attribute_t *a, const attribute_value_t *v) { - /* If we previously assumed this node was an unseen cluster node, - * remove its entry from the cluster peer cache. - */ - crm_node_t *dup = pcmk__search_cluster_node_cache(0, node_name, NULL); + xmlNode *op = pcmk__xe_create(NULL, PCMK_XE_OP); - if (dup && (dup->uuid == NULL)) { - reap_crm_member(0, node_name); - } - - // Ensure node is in the remote peer cache - CRM_ASSERT(crm_remote_peer_get(node_name) != NULL); + crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE); + attrd_add_value_xml(op, a, v, false); + attrd_send_message(NULL, op, false); + free_xml(op); } #define state_text(state) pcmk__s((state), "in unknown state") -/*! - * \internal - * \brief Return host's hash table entry (creating one if needed) - * - * \param[in,out] values Hash table of values - * \param[in] host Name of peer to look up - * \param[in] xml XML describing the attribute - * - * \return Pointer to new or existing hash table entry - */ -static attribute_value_t * -attrd_lookup_or_create_value(GHashTable *values, const char *host, - const xmlNode *xml) -{ - attribute_value_t *v = g_hash_table_lookup(values, host); - int is_remote = 0; - - crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote); - if (is_remote) { - cache_remote_node(host); - } - - if (v == NULL) { - v = calloc(1, sizeof(attribute_value_t)); - CRM_ASSERT(v != NULL); - - pcmk__str_update(&v->nodename, host); - v->is_remote = is_remote; - g_hash_table_replace(values, v->nodename, v); - } - return(v); -} - static void attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *data) { @@ -254,7 +192,7 @@ attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *da */ if (attrd_election_won() && !pcmk_is_set(peer->flags, crm_remote_node)) { - attrd_peer_sync(peer, NULL); + attrd_peer_sync(peer); } } else { // Remove all attribute values associated with lost nodes @@ -269,17 +207,14 @@ attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *da attrd_remove_voter(peer); attrd_remove_peer_protocol_ver(peer->uname); attrd_do_not_expect_from_peer(peer->uname); - - // Ensure remote nodes that come up are in the remote node cache - } else if (!gone && is_remote) { - cache_remote_node(peer->uname); } } static void record_peer_nodeid(attribute_value_t *v, const char *host) { - crm_node_t *known_peer = crm_get_peer(v->nodeid, host); + crm_node_t *known_peer = pcmk__get_node(v->nodeid, host, NULL, + pcmk__node_search_cluster_member); crm_trace("Learned %s has node id %s", known_peer->uname, known_peer->uuid); if (attrd_election_won()) { @@ -287,34 +222,63 @@ record_peer_nodeid(attribute_value_t *v, const char *host) } } +#define readable_value(rv_v) pcmk__s((rv_v)->current, "(unset)") + +#define readable_peer(p) \ + (((p) == NULL)? "all peers" : pcmk__s((p)->uname, "unknown peer")) + static void update_attr_on_host(attribute_t *a, const crm_node_t *peer, const xmlNode *xml, const char *attr, const char *value, const char *host, - bool filter, int is_force_write) + bool filter) { + int is_remote = 0; + bool changed = false; attribute_value_t *v = NULL; - v = attrd_lookup_or_create_value(a->values, host, xml); + // Create entry for value if not already existing + v = g_hash_table_lookup(a->values, host); + if (v == NULL) { + v = pcmk__assert_alloc(1, sizeof(attribute_value_t)); + + v->nodename = pcmk__str_copy(host); + g_hash_table_replace(a->values, v->nodename, v); + } + + // If value is for a Pacemaker Remote node, remember that + crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote); + if (is_remote) { + attrd_set_value_flags(v, attrd_value_remote); + CRM_ASSERT(pcmk__cluster_lookup_remote_node(host) != NULL); + } - if (filter && !pcmk__str_eq(v->current, value, pcmk__str_casei) - && pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)) { + // Check whether the value changed + changed = !pcmk__str_eq(v->current, value, pcmk__str_casei); + if (changed && filter && pcmk__str_eq(host, attrd_cluster->uname, + pcmk__str_casei)) { + /* Broadcast the local value for an attribute that differs from the + * value provided in a peer's attribute synchronization response. This + * ensures a node's values for itself take precedence and all peers are + * kept in sync. + */ + v = g_hash_table_lookup(a->values, attrd_cluster->uname); crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s", - attr, host, v->current, value, peer->uname); - v = broadcast_local_value(a); + attr, host, readable_value(v), value, peer->uname); + attrd_broadcast_value(a, v); - } else if (!pcmk__str_eq(v->current, value, pcmk__str_casei)) { + } else if (changed) { crm_notice("Setting %s[%s]%s%s: %s -> %s " CRM_XS " from %s with %s write delay", attr, host, a->set_type ? " in " : "", - pcmk__s(a->set_type, ""), pcmk__s(v->current, "(unset)"), + pcmk__s(a->set_type, ""), readable_value(v), pcmk__s(value, "(unset)"), peer->uname, (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms)); pcmk__str_update(&v->current, value); - a->changed = true; + attrd_set_attr_flags(a, attrd_attr_changed); if (pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei) - && pcmk__str_eq(attr, XML_CIB_ATTR_SHUTDOWN, pcmk__str_none)) { + && pcmk__str_eq(attr, PCMK__NODE_ATTR_SHUTDOWN, pcmk__str_none)) { if (!pcmk__str_eq(value, "0", pcmk__str_null_matches)) { attrd_set_requesting_shutdown(); @@ -326,30 +290,37 @@ update_attr_on_host(attribute_t *a, const crm_node_t *peer, const xmlNode *xml, // Write out new value or start dampening timer if (a->timeout_ms && a->timer) { - crm_trace("Delayed write out (%dms) for %s", a->timeout_ms, attr); + crm_trace("Delaying write of %s %s for dampening", + attr, pcmk__readable_interval(a->timeout_ms)); mainloop_timer_start(a->timer); } else { attrd_write_or_elect_attribute(a); } } else { + int is_force_write = 0; + + crm_element_value_int(xml, PCMK__XA_ATTRD_IS_FORCE_WRITE, + &is_force_write); + if (is_force_write == 1 && a->timeout_ms && a->timer) { /* Save forced writing and set change flag. */ /* The actual attribute is written by Writer after election. */ - crm_trace("Unchanged %s[%s] from %s is %s(Set the forced write flag)", - attr, host, peer->uname, value); - a->force_write = TRUE; + crm_trace("%s[%s] from %s is unchanged (%s), forcing write", + attr, host, peer->uname, pcmk__s(value, "unset")); + attrd_set_attr_flags(a, attrd_attr_force_write); } else { - crm_trace("Unchanged %s[%s] from %s is %s", attr, host, peer->uname, value); + crm_trace("%s[%s] from %s is unchanged (%s)", + attr, host, peer->uname, pcmk__s(value, "unset")); } } - /* Set the seen flag for attribute processing held only in the own node. */ - v->seen = TRUE; + // This allows us to later detect local values that peer doesn't know about + attrd_set_value_flags(v, attrd_value_from_peer); /* If this is a cluster node whose node ID we are learning, remember it */ - if ((v->nodeid == 0) && (v->is_remote == FALSE) - && (crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID, + if ((v->nodeid == 0) && !pcmk_is_set(v->flags, attrd_value_remote) + && (crm_element_value_int(xml, PCMK__XA_ATTR_HOST_ID, (int*)&v->nodeid) == 0) && (v->nodeid > 0)) { record_peer_nodeid(v, host); } @@ -361,16 +332,13 @@ attrd_peer_update_one(const crm_node_t *peer, xmlNode *xml, bool filter) attribute_t *a = NULL; const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME); const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE); - const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME); - int is_force_write = 0; + const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST); if (attr == NULL) { crm_warn("Could not update attribute: peer did not specify name"); return; } - crm_element_value_int(xml, PCMK__XA_ATTR_FORCE, &is_force_write); - a = attrd_populate_attribute(xml, attr); if (a == NULL) { return; @@ -381,16 +349,16 @@ attrd_peer_update_one(const crm_node_t *peer, xmlNode *xml, bool filter) GHashTableIter vIter; crm_debug("Setting %s for all hosts to %s", attr, value); - xml_remove_prop(xml, PCMK__XA_ATTR_NODE_ID); + pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_HOST_ID); g_hash_table_iter_init(&vIter, a->values); while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) { - update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write); + update_attr_on_host(a, peer, xml, attr, value, host, filter); } } else { // Update attribute value for the given host - update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write); + update_attr_on_host(a, peer, xml, attr, value, host, filter); } /* If this is a message from some attrd instance broadcasting its protocol @@ -412,13 +380,18 @@ broadcast_unseen_local_values(void) g_hash_table_iter_init(&aIter, attributes); while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) { + g_hash_table_iter_init(&vIter, a->values); while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) { - if (!(v->seen) && pcmk__str_eq(v->nodename, attrd_cluster->uname, - pcmk__str_casei)) { + + if (!pcmk_is_set(v->flags, attrd_value_from_peer) + && pcmk__str_eq(v->nodename, attrd_cluster->uname, + pcmk__str_casei)) { + crm_trace("* %s[%s]='%s' is local-only", + a->id, v->nodename, readable_value(v)); if (sync == NULL) { - sync = create_xml_node(NULL, __func__); - crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE); + sync = pcmk__xe_create(NULL, __func__); + crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE); } attrd_add_value_xml(sync, a, v, a->timeout_ms && a->timer); } @@ -435,17 +408,21 @@ broadcast_unseen_local_values(void) int attrd_cluster_connect(void) { + int rc = pcmk_rc_ok; + attrd_cluster = pcmk_cluster_new(); - attrd_cluster->destroy = attrd_cpg_destroy; - attrd_cluster->cpg.cpg_deliver_fn = attrd_cpg_dispatch; - attrd_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership; + pcmk_cluster_set_destroy_fn(attrd_cluster, attrd_cpg_destroy); + pcmk_cpg_set_deliver_fn(attrd_cluster, attrd_cpg_dispatch); + pcmk_cpg_set_confchg_fn(attrd_cluster, pcmk__cpg_confchg_cb); - crm_set_status_callback(&attrd_peer_change_cb); + pcmk__cluster_set_status_callback(&attrd_peer_change_cb); - if (crm_cluster_connect(attrd_cluster) == FALSE) { + rc = pcmk_cluster_connect(attrd_cluster); + rc = pcmk_rc2legacy(rc); + if (rc != pcmk_ok) { crm_err("Cluster connection failed"); - return -ENOTCONN; + return rc; } return pcmk_ok; } @@ -455,15 +432,19 @@ attrd_peer_clear_failure(pcmk__request_t *request) { xmlNode *xml = request->xml; const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE); - const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME); - const char *op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION); - const char *interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL); - guint interval_ms = crm_parse_interval_spec(interval_spec); + const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST); + const char *op = crm_element_value(xml, PCMK__XA_ATTR_CLEAR_OPERATION); + const char *interval_spec = crm_element_value(xml, + PCMK__XA_ATTR_CLEAR_INTERVAL); + guint interval_ms = 0U; char *attr = NULL; GHashTableIter iter; regex_t regex; - crm_node_t *peer = crm_get_peer(0, request->peer); + crm_node_t *peer = pcmk__get_node(0, request->peer, NULL, + pcmk__node_search_cluster_member); + + pcmk_parse_interval_spec(interval_spec, &interval_ms); if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) { crm_info("Ignoring invalid request to clear failures for %s", @@ -471,10 +452,10 @@ attrd_peer_clear_failure(pcmk__request_t *request) return; } - crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE); + crm_xml_add(xml, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE); /* Make sure value is not set, so we delete */ - xml_remove_prop(xml, PCMK__XA_ATTR_VALUE); + pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_VALUE); g_hash_table_iter_init(&iter, attributes); while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) { @@ -492,7 +473,7 @@ attrd_peer_clear_failure(pcmk__request_t *request) * \internal * \brief Load attributes from a peer sync response * - * \param[in] peer Peer that sent clear request + * \param[in] peer Peer that sent sync response * \param[in] peer_won Whether peer is the attribute writer * \param[in,out] xml Request XML */ @@ -510,11 +491,11 @@ attrd_peer_sync_response(const crm_node_t *peer, bool peer_won, xmlNode *xml) } // Process each attribute update in the sync response - for (xmlNode *child = pcmk__xml_first_child(xml); child != NULL; - child = pcmk__xml_next(child)) { + for (xmlNode *child = pcmk__xe_first_child(xml, NULL, NULL, NULL); + child != NULL; child = pcmk__xe_next(child)) { + attrd_peer_update(peer, child, - crm_element_value(child, PCMK__XA_ATTR_NODE_NAME), - true); + crm_element_value(child, PCMK__XA_ATTR_HOST), true); } if (peer_won) { @@ -540,7 +521,9 @@ attrd_peer_remove(const char *host, bool uncache, const char *source) GHashTableIter aIter; CRM_CHECK(host != NULL, return); - crm_notice("Removing all %s attributes for peer %s", host, source); + crm_notice("Removing all %s attributes for node %s " + CRM_XS " %s reaping node from cache", + host, source, (uncache? "and" : "without")); g_hash_table_iter_init(&aIter, attributes); while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) { @@ -550,33 +533,40 @@ attrd_peer_remove(const char *host, bool uncache, const char *source) } if (uncache) { - crm_remote_peer_cache_remove(host); - reap_crm_member(0, host); + pcmk__purge_node_from_cache(host, 0); } } +/*! + * \internal + * \brief Send all known attributes and values to a peer + * + * \param[in] peer Peer to send sync to (if NULL, broadcast to all peers) + */ void -attrd_peer_sync(crm_node_t *peer, xmlNode *xml) +attrd_peer_sync(crm_node_t *peer) { GHashTableIter aIter; GHashTableIter vIter; attribute_t *a = NULL; attribute_value_t *v = NULL; - xmlNode *sync = create_xml_node(NULL, __func__); + xmlNode *sync = pcmk__xe_create(NULL, __func__); - crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE); + crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE); g_hash_table_iter_init(&aIter, attributes); while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) { g_hash_table_iter_init(&vIter, a->values); while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) { - crm_debug("Syncing %s[%s] = %s to %s", a->id, v->nodename, v->current, peer?peer->uname:"everyone"); + crm_debug("Syncing %s[%s]='%s' to %s", + a->id, v->nodename, readable_value(v), + readable_peer(peer)); attrd_add_value_xml(sync, a, v, false); } } - crm_debug("Syncing values to %s", peer?peer->uname:"everyone"); + crm_debug("Syncing values to %s", readable_peer(peer)); attrd_send_message(peer, sync, false); free_xml(sync); } @@ -589,9 +579,10 @@ attrd_peer_update(const crm_node_t *peer, xmlNode *xml, const char *host, CRM_CHECK((peer != NULL) && (xml != NULL), return); if (xml->children != NULL) { - for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL; - child = crm_next_same_xml(child)) { - attrd_copy_xml_attributes(xml, child); + for (xmlNode *child = pcmk__xe_first_child(xml, PCMK_XE_OP, NULL, NULL); + child != NULL; child = pcmk__xe_next_same(child)) { + + pcmk__xe_copy_attrs(child, xml, pcmk__xaf_no_overwrite); attrd_peer_update_one(peer, child, filter); if (attrd_request_has_sync_point(child)) { |