summaryrefslogtreecommitdiffstats
path: root/daemons/attrd/attrd_cib.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/attrd/attrd_cib.c')
-rw-r--r--daemons/attrd/attrd_cib.c316
1 files changed, 156 insertions, 160 deletions
diff --git a/daemons/attrd/attrd_cib.c b/daemons/attrd/attrd_cib.c
index 80e5580..2537ade 100644
--- a/daemons/attrd/attrd_cib.c
+++ b/daemons/attrd/attrd_cib.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.
*
@@ -15,11 +15,12 @@
#include <stdlib.h>
#include <glib.h>
-#include <crm/msg_xml.h>
+#include <crm/cib/internal.h> // cib__*
#include <crm/common/logging.h>
#include <crm/common/results.h>
#include <crm/common/strings_internal.h>
#include <crm/common/xml.h>
+#include <crm/cluster/internal.h> // pcmk__get_node()
#include "pacemaker-attrd.h"
@@ -50,8 +51,10 @@ attrd_cib_updated_cb(const char *event, xmlNode *msg)
{
const xmlNode *patchset = NULL;
const char *client_name = NULL;
+ bool status_changed = false;
if (attrd_shutting_down(true)) {
+ crm_debug("Ignoring CIB change during shutdown");
return;
}
@@ -59,29 +62,32 @@ attrd_cib_updated_cb(const char *event, xmlNode *msg)
return;
}
- if (cib__element_in_patchset(patchset, XML_CIB_TAG_ALERTS)) {
+ if (cib__element_in_patchset(patchset, PCMK_XE_ALERTS)) {
mainloop_set_trigger(attrd_config_read);
}
- if (!attrd_election_won()) {
- // Don't write attributes if we're not the writer
- return;
- }
+ status_changed = cib__element_in_patchset(patchset, PCMK_XE_STATUS);
- client_name = crm_element_value(msg, F_CIB_CLIENTNAME);
+ client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTNAME);
if (!cib__client_triggers_refresh(client_name)) {
- // The CIB is still accurate
+ /* This change came from a source that ensured the CIB is consistent
+ * with our attributes table, so we don't need to write anything out.
+ */
return;
}
- if (cib__element_in_patchset(patchset, XML_CIB_TAG_NODES)
- || cib__element_in_patchset(patchset, XML_CIB_TAG_STATUS)) {
+ if (!attrd_election_won()) {
+ // Don't write attributes if we're not the writer
+ return;
+ }
- /* An unsafe client modified the nodes or status section. Write
- * transient attributes to ensure they're up-to-date in the CIB.
+ if (status_changed || cib__element_in_patchset(patchset, PCMK_XE_NODES)) {
+ /* An unsafe client modified the PCMK_XE_NODES or PCMK_XE_STATUS
+ * section. Write transient attributes to ensure they're up-to-date in
+ * the CIB.
*/
if (client_name == NULL) {
- client_name = crm_element_value(msg, F_CIB_CLIENTID);
+ client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTID);
}
crm_notice("Updating all attributes after %s event triggered by %s",
event, pcmk__s(client_name, "(unidentified client)"));
@@ -108,7 +114,7 @@ attrd_cib_connect(int max_retry)
}
attempts++;
crm_debug("Connection attempt %d to the CIB manager", attempts);
- rc = the_cib->cmds->signon(the_cib, T_ATTRD, cib_command);
+ rc = the_cib->cmds->signon(the_cib, PCMK__VALUE_ATTRD, cib_command);
} while ((rc != pcmk_ok) && (attempts < max_retry));
@@ -126,7 +132,8 @@ attrd_cib_connect(int max_retry)
goto cleanup;
}
- rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_DIFF_NOTIFY,
+ rc = the_cib->cmds->add_notify_callback(the_cib,
+ PCMK__VALUE_CIB_DIFF_NOTIFY,
attrd_cib_updated_cb);
if (rc != pcmk_ok) {
crm_err("Could not set CIB notification callback");
@@ -144,7 +151,7 @@ void
attrd_cib_disconnect(void)
{
CRM_CHECK(the_cib != NULL, return);
- the_cib->cmds->del_notify_callback(the_cib, T_CIB_DIFF_NOTIFY,
+ the_cib->cmds->del_notify_callback(the_cib, PCMK__VALUE_CIB_DIFF_NOTIFY,
attrd_cib_updated_cb);
cib__clean_up_connection(&the_cib);
}
@@ -153,39 +160,44 @@ static void
attrd_erase_cb(xmlNode *msg, int call_id, int rc, xmlNode *output,
void *user_data)
{
- do_crm_log_unlikely(((rc != pcmk_ok)? LOG_NOTICE : LOG_DEBUG),
- "Cleared transient attributes: %s "
- CRM_XS " xpath=%s rc=%d",
- pcmk_strerror(rc), (char *) user_data, rc);
+ const char *node = pcmk__s((const char *) user_data, "a node");
+
+ if (rc == pcmk_ok) {
+ crm_info("Cleared transient node attributes for %s from CIB", node);
+ } else {
+ crm_err("Unable to clear transient node attributes for %s from CIB: %s",
+ node, pcmk_strerror(rc));
+ }
}
-#define XPATH_TRANSIENT "//node_state[@uname='%s']/" XML_TAG_TRANSIENT_NODEATTRS
+#define XPATH_TRANSIENT "//" PCMK__XE_NODE_STATE \
+ "[@" PCMK_XA_UNAME "='%s']" \
+ "/" PCMK__XE_TRANSIENT_ATTRIBUTES
/*!
* \internal
- * \brief Wipe all transient attributes for this node from the CIB
- *
- * Clear any previous transient node attributes from the CIB. This is
- * normally done by the DC's controller when this node leaves the cluster, but
- * this handles the case where the node restarted so quickly that the
- * cluster layer didn't notice.
+ * \brief Wipe all transient node attributes for a node from the CIB
*
- * \todo If pacemaker-attrd respawns after crashing (see PCMK_ENV_RESPAWNED),
- * ideally we'd skip this and sync our attributes from the writer.
- * However, currently we reject any values for us that the writer has, in
- * attrd_peer_update().
+ * \param[in] node Node to clear attributes for
*/
-static void
-attrd_erase_attrs(void)
+void
+attrd_cib_erase_transient_attrs(const char *node)
{
int call_id = 0;
- char *xpath = crm_strdup_printf(XPATH_TRANSIENT, attrd_cluster->uname);
+ char *xpath = NULL;
+
+ CRM_CHECK(node != NULL, return);
+
+ xpath = crm_strdup_printf(XPATH_TRANSIENT, node);
- crm_info("Clearing transient attributes from CIB " CRM_XS " xpath=%s",
- xpath);
+ crm_debug("Clearing transient node attributes for %s from CIB using %s",
+ node, xpath);
call_id = the_cib->cmds->remove(the_cib, xpath, NULL, cib_xpath);
- the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, xpath,
+ free(xpath);
+
+ the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE,
+ pcmk__str_copy(node),
"attrd_erase_cb", attrd_erase_cb,
free);
}
@@ -197,8 +209,17 @@ attrd_erase_attrs(void)
void
attrd_cib_init(void)
{
- // We have no attribute values in memory, wipe the CIB to match
- attrd_erase_attrs();
+ /* We have no attribute values in memory, so wipe the CIB to match. This is
+ * normally done by the DC's controller when this node leaves the cluster, but
+ * this handles the case where the node restarted so quickly that the
+ * cluster layer didn't notice.
+ *
+ * \todo If pacemaker-attrd respawns after crashing (see PCMK_ENV_RESPAWNED),
+ * ideally we'd skip this and sync our attributes from the writer.
+ * However, currently we reject any values for us that the writer has, in
+ * attrd_peer_update().
+ */
+ attrd_cib_erase_transient_attrs(attrd_cluster->uname);
// Set a trigger for reading the CIB (for the alerts section)
attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL);
@@ -262,19 +283,24 @@ attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *use
g_hash_table_iter_init(&iter, a->values);
while (g_hash_table_iter_next(&iter, (gpointer *) & peer, (gpointer *) & v)) {
- do_crm_log(level, "* %s[%s]=%s", a->id, peer, v->requested);
- free(v->requested);
- v->requested = NULL;
- if (rc != pcmk_ok) {
- a->changed = true; /* Attempt write out again */
+ if (rc == pcmk_ok) {
+ crm_info("* Wrote %s[%s]=%s",
+ a->id, peer, pcmk__s(v->requested, "(unset)"));
+ pcmk__str_update(&(v->requested), NULL);
+ } else {
+ do_crm_log(level, "* Could not write %s[%s]=%s",
+ a->id, peer, pcmk__s(v->requested, "(unset)"));
+ /* Reattempt write below if we are still the writer */
+ attrd_set_attr_flags(a, attrd_attr_changed);
}
}
- if (a->changed && attrd_election_won()) {
+ if (pcmk_is_set(a->flags, attrd_attr_changed) && attrd_election_won()) {
if (rc == pcmk_ok) {
/* We deferred a write of a new update because this update was in
* progress. Write out the new value without additional delay.
*/
+ crm_debug("Pending update for %s can be written now", a->id);
write_attribute(a, false);
/* We're re-attempting a write because the original failed; delay
@@ -320,40 +346,27 @@ static int
add_set_attr_update(const attribute_t *attr, const char *attr_id,
const char *node_id, const char *set_id, const char *value)
{
- xmlNode *update = create_xml_node(NULL, XML_CIB_TAG_STATE);
+ xmlNode *update = pcmk__xe_create(NULL, PCMK__XE_NODE_STATE);
xmlNode *child = update;
int rc = ENOMEM;
- if (child == NULL) {
- goto done;
- }
- crm_xml_add(child, XML_ATTR_ID, node_id);
+ crm_xml_add(child, PCMK_XA_ID, node_id);
- child = create_xml_node(child, XML_TAG_TRANSIENT_NODEATTRS);
- if (child == NULL) {
- goto done;
- }
- crm_xml_add(child, XML_ATTR_ID, node_id);
+ child = pcmk__xe_create(child, PCMK__XE_TRANSIENT_ATTRIBUTES);
+ crm_xml_add(child, PCMK_XA_ID, node_id);
- child = create_xml_node(child, attr->set_type);
- if (child == NULL) {
- goto done;
- }
- crm_xml_add(child, XML_ATTR_ID, set_id);
+ child = pcmk__xe_create(child, attr->set_type);
+ crm_xml_add(child, PCMK_XA_ID, set_id);
- child = create_xml_node(child, XML_CIB_TAG_NVPAIR);
- if (child == NULL) {
- goto done;
- }
- crm_xml_add(child, XML_ATTR_ID, attr_id);
- crm_xml_add(child, XML_NVPAIR_ATTR_NAME, attr->id);
- crm_xml_add(child, XML_NVPAIR_ATTR_VALUE, value);
+ child = pcmk__xe_create(child, PCMK_XE_NVPAIR);
+ crm_xml_add(child, PCMK_XA_ID, attr_id);
+ crm_xml_add(child, PCMK_XA_NAME, attr->id);
+ crm_xml_add(child, PCMK_XA_VALUE, value);
- rc = the_cib->cmds->modify(the_cib, XML_CIB_TAG_STATUS, update,
+ rc = the_cib->cmds->modify(the_cib, PCMK_XE_STATUS, update,
cib_can_create|cib_transaction);
rc = pcmk_legacy2rc(rc);
-done:
free_xml(update);
return rc;
}
@@ -373,16 +386,16 @@ static int
add_unset_attr_update(const attribute_t *attr, const char *attr_id,
const char *node_id, const char *set_id)
{
- char *xpath = crm_strdup_printf("/" XML_TAG_CIB
- "/" XML_CIB_TAG_STATUS
- "/" XML_CIB_TAG_STATE
- "[@" XML_ATTR_ID "='%s']"
- "/" XML_TAG_TRANSIENT_NODEATTRS
- "[@" XML_ATTR_ID "='%s']"
- "/%s[@" XML_ATTR_ID "='%s']"
- "/" XML_CIB_TAG_NVPAIR
- "[@" XML_ATTR_ID "='%s' "
- "and @" XML_NVPAIR_ATTR_NAME "='%s']",
+ char *xpath = crm_strdup_printf("/" PCMK_XE_CIB
+ "/" PCMK_XE_STATUS
+ "/" PCMK__XE_NODE_STATE
+ "[@" PCMK_XA_ID "='%s']"
+ "/" PCMK__XE_TRANSIENT_ATTRIBUTES
+ "[@" PCMK_XA_ID "='%s']"
+ "/%s[@" PCMK_XA_ID "='%s']"
+ "/" PCMK_XE_NVPAIR
+ "[@" PCMK_XA_ID "='%s' "
+ "and @" PCMK_XA_NAME "='%s']",
node_id, node_id, attr->set_type, set_id,
attr_id, attr->id);
@@ -406,31 +419,17 @@ add_unset_attr_update(const attribute_t *attr, const char *attr_id,
static int
add_attr_update(const attribute_t *attr, const char *value, const char *node_id)
{
- char *set_id = NULL;
- char *attr_id = NULL;
+ char *set_id = attrd_set_id(attr, node_id);
+ char *nvpair_id = attrd_nvpair_id(attr, node_id);
int rc = pcmk_rc_ok;
- if (attr->set_id != NULL) {
- pcmk__str_update(&set_id, attr->set_id);
- } else {
- set_id = crm_strdup_printf("%s-%s", XML_CIB_TAG_STATUS, node_id);
- }
- crm_xml_sanitize_id(set_id);
-
- if (attr->uuid != NULL) {
- pcmk__str_update(&attr_id, attr->uuid);
- } else {
- attr_id = crm_strdup_printf("%s-%s", set_id, attr->id);
- }
- crm_xml_sanitize_id(attr_id);
-
- if (value != NULL) {
- rc = add_set_attr_update(attr, attr_id, node_id, set_id, value);
+ if (value == NULL) {
+ rc = add_unset_attr_update(attr, nvpair_id, node_id, set_id);
} else {
- rc = add_unset_attr_update(attr, attr_id, node_id, set_id);
+ rc = add_set_attr_update(attr, nvpair_id, node_id, set_id, value);
}
free(set_id);
- free(attr_id);
+ free(nvpair_id);
return rc;
}
@@ -454,13 +453,11 @@ send_alert_attributes_value(attribute_t *a, GHashTable *t)
static void
set_alert_attribute_value(GHashTable *t, attribute_value_t *v)
{
- attribute_value_t *a_v = NULL;
- a_v = calloc(1, sizeof(attribute_value_t));
- CRM_ASSERT(a_v != NULL);
+ attribute_value_t *a_v = pcmk__assert_alloc(1, sizeof(attribute_value_t));
a_v->nodeid = v->nodeid;
- a_v->nodename = strdup(v->nodename);
- pcmk__str_update(&a_v->current, v->current);
+ a_v->nodename = pcmk__str_copy(v->nodename);
+ a_v->current = pcmk__str_copy(v->current);
g_hash_table_replace(t, a_v->nodename, a_v);
}
@@ -493,7 +490,7 @@ write_attribute(attribute_t *a, bool ignore_delay)
}
/* If this attribute will be written to the CIB ... */
- if (!stand_alone && !a->is_private) {
+ if (!stand_alone && !pcmk_is_set(a->flags, attrd_attr_is_private)) {
/* Defer the write if now's not a good time */
if (a->update && (a->update < last_cib_op_done)) {
crm_info("Write out of '%s' continuing: update %d considered lost",
@@ -520,21 +517,17 @@ write_attribute(attribute_t *a, bool ignore_delay)
the_cib->cmds->set_user(the_cib, a->user);
rc = the_cib->cmds->init_transaction(the_cib);
if (rc != pcmk_ok) {
- crm_err("Failed to write %s (id %s, set %s): Could not initiate "
+ crm_err("Failed to write %s (set %s): Could not initiate "
"CIB transaction",
- a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a"));
+ a->id, pcmk__s(a->set_id, "unspecified"));
goto done;
}
}
- /* Attribute will be written shortly, so clear changed flag */
- a->changed = false;
-
- /* We will check all peers' uuids shortly, so initialize this to false */
- a->unknown_peer_uuids = false;
-
- /* Attribute will be written shortly, so clear forced write flag */
- a->force_write = FALSE;
+ /* Attribute will be written shortly, so clear changed flag and force
+ * write flag, and initialize UUID missing flag to false.
+ */
+ attrd_clear_attr_flags(a, attrd_attr_changed|attrd_attr_uuid_missing|attrd_attr_force_write);
/* Make the table for the attribute trap */
alert_attribute_value = pcmk__strikey_table(NULL,
@@ -543,79 +536,80 @@ write_attribute(attribute_t *a, bool ignore_delay)
/* Iterate over each peer value of this attribute */
g_hash_table_iter_init(&iter, a->values);
while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &v)) {
- crm_node_t *peer = crm_get_peer_full(v->nodeid, v->nodename,
- CRM_GET_PEER_ANY);
+ const char *uuid = NULL;
- /* If the value's peer info does not correspond to a peer, ignore it */
- if (peer == NULL) {
- crm_notice("Cannot update %s[%s]=%s because peer not known",
- a->id, v->nodename, v->current);
- continue;
- }
+ if (pcmk_is_set(v->flags, attrd_value_remote)) {
+ /* If this is a Pacemaker Remote node, the node's UUID is the same
+ * as its name, which we already have.
+ */
+ uuid = v->nodename;
- /* If we're just learning the peer's node id, remember it */
- if (peer->id && (v->nodeid == 0)) {
- crm_trace("Learned ID %u for node %s", peer->id, v->nodename);
- v->nodeid = peer->id;
+ } else {
+ // This will create a cluster node cache entry if none exists
+ crm_node_t *peer = pcmk__get_node(v->nodeid, v->nodename, NULL,
+ pcmk__node_search_any);
+
+ uuid = peer->uuid;
+
+ // Remember peer's node ID if we're just now learning it
+ if ((peer->id != 0) && (v->nodeid == 0)) {
+ crm_trace("Learned ID %u for node %s", peer->id, v->nodename);
+ v->nodeid = peer->id;
+ }
}
/* If this is a private attribute, no update needs to be sent */
- if (stand_alone || a->is_private) {
+ if (stand_alone || pcmk_is_set(a->flags, attrd_attr_is_private)) {
private_updates++;
continue;
}
- /* If the peer is found, but its uuid is unknown, defer write */
- if (peer->uuid == NULL) {
- a->unknown_peer_uuids = true;
- crm_notice("Cannot update %s[%s]=%s because peer UUID not known "
- "(will retry if learned)",
+ // Defer write if this is a cluster node that's never been seen
+ if (uuid == NULL) {
+ attrd_set_attr_flags(a, attrd_attr_uuid_missing);
+ crm_notice("Cannot update %s[%s]='%s' now because node's UUID is "
+ "unknown (will retry if learned)",
a->id, v->nodename, v->current);
continue;
}
// Update this value as part of the CIB transaction we're building
- rc = add_attr_update(a, v->current, peer->uuid);
+ rc = add_attr_update(a, v->current, uuid);
if (rc != pcmk_rc_ok) {
- crm_err("Failed to update %s[%s]=%s (peer known as %s, UUID %s, "
- "ID %" PRIu32 "/%" PRIu32 "): %s",
- a->id, v->nodename, v->current, peer->uname, peer->uuid,
- peer->id, v->nodeid, pcmk_rc_str(rc));
+ crm_err("Failed to update %s[%s]='%s': %s "
+ CRM_XS " node uuid=%s id=%" PRIu32,
+ a->id, v->nodename, v->current, pcmk_rc_str(rc),
+ uuid, v->nodeid);
continue;
}
- crm_debug("Updating %s[%s]=%s (peer known as %s, UUID %s, ID "
- "%" PRIu32 "/%" PRIu32 ")",
- a->id, v->nodename, v->current,
- peer->uname, peer->uuid, peer->id, v->nodeid);
+ crm_debug("Writing %s[%s]=%s (node-state-id=%s node-id=%" PRIu32 ")",
+ a->id, v->nodename, pcmk__s(v->current, "(unset)"),
+ uuid, v->nodeid);
cib_updates++;
/* Preservation of the attribute to transmit alert */
set_alert_attribute_value(alert_attribute_value, v);
- free(v->requested);
- v->requested = NULL;
- if (v->current) {
- v->requested = strdup(v->current);
- }
+ // Save this value so we can log it when write completes
+ pcmk__str_update(&(v->requested), v->current);
}
if (private_updates) {
- crm_info("Processed %d private change%s for %s, id=%s, set=%s",
+ crm_info("Processed %d private change%s for %s (set %s)",
private_updates, pcmk__plural_s(private_updates),
- a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a"));
+ a->id, pcmk__s(a->set_id, "unspecified"));
}
if (cib_updates > 0) {
- char *id = NULL;
+ char *id = pcmk__str_copy(a->id);
// Commit transaction
a->update = the_cib->cmds->end_transaction(the_cib, true, cib_none);
- crm_info("Sent CIB request %d with %d change%s for %s (id %s, set %s)",
+ crm_info("Sent CIB request %d with %d change%s for %s (set %s)",
a->update, cib_updates, pcmk__plural_s(cib_updates),
- a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a"));
+ a->id, pcmk__s(a->set_id, "unspecified"));
- pcmk__str_update(&id, a->id);
if (the_cib->cmds->register_callback_full(the_cib, a->update,
CIB_OP_TIMEOUT_S, FALSE, id,
"attrd_cib_callback",
@@ -653,18 +647,20 @@ attrd_write_attributes(uint32_t options)
pcmk_is_set(options, attrd_write_all)? "all" : "changed");
g_hash_table_iter_init(&iter, attributes);
while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & a)) {
- if (!pcmk_is_set(options, attrd_write_all) && a->unknown_peer_uuids) {
+ if (!pcmk_is_set(options, attrd_write_all) &&
+ pcmk_is_set(a->flags, attrd_attr_uuid_missing)) {
// Try writing this attribute again, in case peer ID was learned
- a->changed = true;
- } else if (a->force_write) {
+ attrd_set_attr_flags(a, attrd_attr_changed);
+ } else if (pcmk_is_set(a->flags, attrd_attr_force_write)) {
/* If the force_write flag is set, write the attribute. */
- a->changed = true;
+ attrd_set_attr_flags(a, attrd_attr_changed);
}
- if (pcmk_is_set(options, attrd_write_all) || a->changed) {
+ if (pcmk_is_set(options, attrd_write_all) ||
+ pcmk_is_set(a->flags, attrd_attr_changed)) {
bool ignore_delay = pcmk_is_set(options, attrd_write_no_delay);
- if (a->force_write) {
+ if (pcmk_is_set(a->flags, attrd_attr_force_write)) {
// Always ignore delay when forced write flag is set
ignore_delay = true;
}