diff options
Diffstat (limited to 'daemons/attrd')
-rw-r--r-- | daemons/attrd/Makefile.am | 43 | ||||
-rw-r--r-- | daemons/attrd/attrd_alerts.c | 21 | ||||
-rw-r--r-- | daemons/attrd/attrd_attributes.c | 46 | ||||
-rw-r--r-- | daemons/attrd/attrd_cib.c | 464 | ||||
-rw-r--r-- | daemons/attrd/attrd_corosync.c | 21 | ||||
-rw-r--r-- | daemons/attrd/attrd_elections.c | 14 | ||||
-rw-r--r-- | daemons/attrd/attrd_ipc.c | 25 | ||||
-rw-r--r-- | daemons/attrd/attrd_messages.c | 34 | ||||
-rw-r--r-- | daemons/attrd/attrd_sync.c | 4 | ||||
-rw-r--r-- | daemons/attrd/attrd_utils.c | 59 | ||||
-rw-r--r-- | daemons/attrd/pacemaker-attrd.c | 140 | ||||
-rw-r--r-- | daemons/attrd/pacemaker-attrd.h | 17 |
12 files changed, 541 insertions, 347 deletions
diff --git a/daemons/attrd/Makefile.am b/daemons/attrd/Makefile.am index 6bb81c4..f8d8bc9 100644 --- a/daemons/attrd/Makefile.am +++ b/daemons/attrd/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004-2022 the Pacemaker project contributors +# Copyright 2004-2023 the Pacemaker project contributors # # The version control history for this file may have further details. # @@ -18,31 +18,32 @@ noinst_HEADERS = pacemaker-attrd.h pacemaker_attrd_CFLAGS = $(CFLAGS_HARDENED_EXE) pacemaker_attrd_LDFLAGS = $(LDFLAGS_HARDENED_EXE) -pacemaker_attrd_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ - $(top_builddir)/lib/pengine/libpe_rules.la \ - $(top_builddir)/lib/common/libcrmcommon.la \ - $(top_builddir)/lib/cib/libcib.la \ - $(top_builddir)/lib/lrmd/liblrmd.la \ - $(CLUSTERLIBS) +pacemaker_attrd_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la +pacemaker_attrd_LDADD += $(top_builddir)/lib/cib/libcib.la +pacemaker_attrd_LDADD += $(top_builddir)/lib/pengine/libpe_rules.la +pacemaker_attrd_LDADD += $(top_builddir)/lib/lrmd/liblrmd.la +pacemaker_attrd_LDADD += $(top_builddir)/lib/common/libcrmcommon.la +pacemaker_attrd_LDADD += $(CLUSTERLIBS) pacemaker_attrd_SOURCES = attrd_alerts.c \ - attrd_attributes.c \ - attrd_cib.c \ - attrd_corosync.c \ - attrd_elections.c \ - attrd_ipc.c \ - attrd_messages.c \ - attrd_sync.c \ - attrd_utils.c \ - pacemaker-attrd.c - -clean-generic: - rm -f *.log *.debug *.xml *~ - -if BUILD_LEGACY_LINKS + attrd_attributes.c \ + attrd_cib.c \ + attrd_corosync.c \ + attrd_elections.c \ + attrd_ipc.c \ + attrd_messages.c \ + attrd_sync.c \ + attrd_utils.c \ + pacemaker-attrd.c + +.PHONY: install-exec-hook install-exec-hook: +if BUILD_LEGACY_LINKS cd $(DESTDIR)$(CRM_DAEMON_DIR) && rm -f attrd && $(LN_S) pacemaker-attrd attrd +endif +.PHONY: uninstall-hook uninstall-hook: +if BUILD_LEGACY_LINKS cd $(DESTDIR)$(CRM_DAEMON_DIR) && rm -f attrd endif diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c index b694891..495e18f 100644 --- a/daemons/attrd/attrd_alerts.c +++ b/daemons/attrd/attrd_alerts.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the Pacemaker project contributors + * Copyright 2015-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -14,6 +14,7 @@ #include <crm/cluster/internal.h> #include <crm/cluster/election_internal.h> #include <crm/common/alerts_internal.h> +#include <crm/common/cib_internal.h> #include <crm/pengine/rules_internal.h> #include <crm/lrmd_internal.h> #include "pacemaker-attrd.h" @@ -92,7 +93,7 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void } crmalerts = output; - if (crmalerts && !pcmk__str_eq(crm_element_name(crmalerts), XML_CIB_TAG_ALERTS, pcmk__str_none)) { + if ((crmalerts != NULL) && !pcmk__xe_is(crmalerts, XML_CIB_TAG_ALERTS)) { crmalerts = first_named_child(crmalerts, XML_CIB_TAG_ALERTS); } if (!crmalerts) { @@ -104,9 +105,6 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void attrd_alert_list = pe_unpack_alerts(crmalerts); } -#define XPATH_ALERTS \ - "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_ALERTS - gboolean attrd_read_options(gpointer user_data) { @@ -114,8 +112,9 @@ attrd_read_options(gpointer user_data) CRM_CHECK(the_cib != NULL, return TRUE); - call_id = the_cib->cmds->query(the_cib, XPATH_ALERTS, NULL, - cib_xpath | cib_scope_local); + call_id = the_cib->cmds->query(the_cib, + pcmk__cib_abs_xpath_for(XML_CIB_TAG_ALERTS), + NULL, cib_xpath|cib_scope_local); the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, NULL, "config_query_callback", @@ -125,14 +124,6 @@ attrd_read_options(gpointer user_data) return TRUE; } -void -attrd_cib_updated_cb(const char *event, xmlNode * msg) -{ - if (!attrd_shutting_down() && pcmk__alert_in_patchset(msg, false)) { - mainloop_set_trigger(attrd_config_read); - } -} - int attrd_send_attribute_alert(const char *node, int nodeid, const char *attr, const char *value) diff --git a/daemons/attrd/attrd_attributes.c b/daemons/attrd/attrd_attributes.c index 516ced7..388c181 100644 --- a/daemons/attrd/attrd_attributes.c +++ b/daemons/attrd/attrd_attributes.c @@ -25,25 +25,45 @@ static attribute_t * attrd_create_attribute(xmlNode *xml) { + int is_private = 0; int dampen = 0; - const char *value = crm_element_value(xml, PCMK__XA_ATTR_DAMPENING); - attribute_t *a = calloc(1, sizeof(attribute_t)); + const char *name = crm_element_value(xml, PCMK__XA_ATTR_NAME); + const char *set_type = crm_element_value(xml, PCMK__XA_ATTR_SET_TYPE); + const char *dampen_s = crm_element_value(xml, PCMK__XA_ATTR_DAMPENING); + attribute_t *a = NULL; + + if (set_type == NULL) { + set_type = XML_TAG_ATTR_SETS; + } + + /* Set type is meaningful only when writing to the CIB. Private + * attributes are not written. + */ + crm_element_value_int(xml, PCMK__XA_ATTR_IS_PRIVATE, &is_private); + if ((is_private != 0) + && !pcmk__str_any_of(set_type, XML_TAG_ATTR_SETS, XML_TAG_UTILIZATION, + NULL)) { + crm_warn("Ignoring attribute %s with invalid set type %s", + pcmk__s(name, "(unidentified)"), set_type); + return NULL; + } + a = calloc(1, sizeof(attribute_t)); CRM_ASSERT(a != NULL); - a->id = crm_element_value_copy(xml, PCMK__XA_ATTR_NAME); - a->set_id = crm_element_value_copy(xml, PCMK__XA_ATTR_SET); - a->set_type = crm_element_value_copy(xml, PCMK__XA_ATTR_SET_TYPE); - a->uuid = crm_element_value_copy(xml, PCMK__XA_ATTR_UUID); - a->values = pcmk__strikey_table(NULL, attrd_free_attribute_value); + a->is_private = is_private; + pcmk__str_update(&a->id, name); + pcmk__str_update(&a->set_type, set_type); - crm_element_value_int(xml, PCMK__XA_ATTR_IS_PRIVATE, &a->is_private); + a->set_id = crm_element_value_copy(xml, PCMK__XA_ATTR_SET); + a->uuid = crm_element_value_copy(xml, PCMK__XA_ATTR_UUID); + a->values = pcmk__strikey_table(NULL, attrd_free_attribute_value); a->user = crm_element_value_copy(xml, PCMK__XA_ATTR_USER); crm_trace("Performing all %s operations as user '%s'", a->id, a->user); - if (value != NULL) { - dampen = crm_get_msec(value); + if (dampen_s != NULL) { + dampen = crm_get_msec(dampen_s); } crm_trace("Created attribute %s with %s write delay", a->id, (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms)); @@ -52,7 +72,7 @@ attrd_create_attribute(xmlNode *xml) a->timeout_ms = dampen; a->timer = attrd_add_timer(a->id, a->timeout_ms, a); } else if (dampen < 0) { - crm_warn("Ignoring invalid delay %s for attribute %s", value, a->id); + crm_warn("Ignoring invalid delay %s for attribute %s", dampen_s, a->id); } g_hash_table_replace(attributes, a->id, a); @@ -169,6 +189,10 @@ attrd_populate_attribute(xmlNode *xml, const char *attr) if (a == NULL) { if (update_both || pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE, pcmk__str_none)) { a = attrd_create_attribute(xml); + if (a == NULL) { + return NULL; + } + } else { crm_warn("Could not update %s: attribute not found", attr); return NULL; diff --git a/daemons/attrd/attrd_cib.c b/daemons/attrd/attrd_cib.c index 928c013..80e5580 100644 --- a/daemons/attrd/attrd_cib.c +++ b/daemons/attrd/attrd_cib.c @@ -10,6 +10,7 @@ #include <crm_internal.h> #include <errno.h> +#include <inttypes.h> // PRIu32 #include <stdbool.h> #include <stdlib.h> #include <glib.h> @@ -24,6 +25,188 @@ static int last_cib_op_done = 0; +static void write_attribute(attribute_t *a, bool ignore_delay); + +static void +attrd_cib_destroy_cb(gpointer user_data) +{ + cib_t *cib = user_data; + + cib->cmds->signoff(cib); + + if (attrd_shutting_down(false)) { + crm_info("Disconnected from the CIB manager"); + + } else { + // @TODO This should trigger a reconnect, not a shutdown + crm_crit("Lost connection to the CIB manager, shutting down"); + attrd_exit_status = CRM_EX_DISCONNECT; + attrd_shutdown(0); + } +} + +static void +attrd_cib_updated_cb(const char *event, xmlNode *msg) +{ + const xmlNode *patchset = NULL; + const char *client_name = NULL; + + if (attrd_shutting_down(true)) { + return; + } + + if (cib__get_notify_patchset(msg, &patchset) != pcmk_rc_ok) { + return; + } + + if (cib__element_in_patchset(patchset, XML_CIB_TAG_ALERTS)) { + mainloop_set_trigger(attrd_config_read); + } + + if (!attrd_election_won()) { + // Don't write attributes if we're not the writer + return; + } + + client_name = crm_element_value(msg, F_CIB_CLIENTNAME); + if (!cib__client_triggers_refresh(client_name)) { + // The CIB is still accurate + return; + } + + if (cib__element_in_patchset(patchset, XML_CIB_TAG_NODES) + || cib__element_in_patchset(patchset, XML_CIB_TAG_STATUS)) { + + /* An unsafe client modified the nodes or 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); + } + crm_notice("Updating all attributes after %s event triggered by %s", + event, pcmk__s(client_name, "(unidentified client)")); + + attrd_write_attributes(attrd_write_all); + } +} + +int +attrd_cib_connect(int max_retry) +{ + static int attempts = 0; + + int rc = -ENOTCONN; + + the_cib = cib_new(); + if (the_cib == NULL) { + return -ENOTCONN; + } + + do { + if (attempts > 0) { + sleep(attempts); + } + attempts++; + crm_debug("Connection attempt %d to the CIB manager", attempts); + rc = the_cib->cmds->signon(the_cib, T_ATTRD, cib_command); + + } while ((rc != pcmk_ok) && (attempts < max_retry)); + + if (rc != pcmk_ok) { + crm_err("Connection to the CIB manager failed: %s " CRM_XS " rc=%d", + pcmk_strerror(rc), rc); + goto cleanup; + } + + crm_debug("Connected to the CIB manager after %d attempts", attempts); + + rc = the_cib->cmds->set_connection_dnotify(the_cib, attrd_cib_destroy_cb); + if (rc != pcmk_ok) { + crm_err("Could not set disconnection callback"); + goto cleanup; + } + + rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, + attrd_cib_updated_cb); + if (rc != pcmk_ok) { + crm_err("Could not set CIB notification callback"); + goto cleanup; + } + + return pcmk_ok; + +cleanup: + cib__clean_up_connection(&the_cib); + return -ENOTCONN; +} + +void +attrd_cib_disconnect(void) +{ + CRM_CHECK(the_cib != NULL, return); + the_cib->cmds->del_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, + attrd_cib_updated_cb); + cib__clean_up_connection(&the_cib); +} + +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); +} + +#define XPATH_TRANSIENT "//node_state[@uname='%s']/" XML_TAG_TRANSIENT_NODEATTRS + +/*! + * \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. + * + * \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(). + */ +static void +attrd_erase_attrs(void) +{ + int call_id = 0; + char *xpath = crm_strdup_printf(XPATH_TRANSIENT, attrd_cluster->uname); + + crm_info("Clearing transient attributes from CIB " CRM_XS " xpath=%s", + 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, + "attrd_erase_cb", attrd_erase_cb, + free); +} + +/*! + * \internal + * \brief Prepare the CIB after cluster is connected + */ +void +attrd_cib_init(void) +{ + // We have no attribute values in memory, wipe the CIB to match + attrd_erase_attrs(); + + // Set a trigger for reading the CIB (for the alerts section) + attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL); + + // Always read the CIB at start-up + mainloop_set_trigger(attrd_config_read); +} + static gboolean attribute_timer_cb(gpointer data) { @@ -92,7 +275,7 @@ attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *use /* We deferred a write of a new update because this update was in * progress. Write out the new value without additional delay. */ - attrd_write_attribute(a, false); + write_attribute(a, false); /* We're re-attempting a write because the original failed; delay * the next attempt so we don't potentially flood the CIB manager @@ -121,48 +304,134 @@ attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *use } } -static void -build_update_element(xmlNode *parent, attribute_t *a, const char *nodeid, const char *value) +/*! + * \internal + * \brief Add a set-attribute update request to the current CIB transaction + * + * \param[in] attr Attribute to update + * \param[in] attr_id ID of attribute to update + * \param[in] node_id ID of node for which to update attribute value + * \param[in] set_id ID of attribute set + * \param[in] value New value for attribute + * + * \return Standard Pacemaker return code + */ +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) { - const char *set = NULL; - xmlNode *xml_obj = NULL; + xmlNode *update = create_xml_node(NULL, XML_CIB_TAG_STATE); + xmlNode *child = update; + int rc = ENOMEM; - xml_obj = create_xml_node(parent, XML_CIB_TAG_STATE); - crm_xml_add(xml_obj, XML_ATTR_ID, nodeid); + if (child == NULL) { + goto done; + } + crm_xml_add(child, XML_ATTR_ID, node_id); - xml_obj = create_xml_node(xml_obj, XML_TAG_TRANSIENT_NODEATTRS); - crm_xml_add(xml_obj, XML_ATTR_ID, nodeid); + child = create_xml_node(child, XML_TAG_TRANSIENT_NODEATTRS); + if (child == NULL) { + goto done; + } + crm_xml_add(child, XML_ATTR_ID, node_id); - if (pcmk__str_eq(a->set_type, XML_TAG_ATTR_SETS, pcmk__str_null_matches)) { - xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS); - } else if (pcmk__str_eq(a->set_type, XML_TAG_UTILIZATION, pcmk__str_none)) { - xml_obj = create_xml_node(xml_obj, XML_TAG_UTILIZATION); - } else { - crm_err("Unknown set type attribute: %s", a->set_type); + child = create_xml_node(child, attr->set_type); + if (child == NULL) { + goto done; } + crm_xml_add(child, XML_ATTR_ID, set_id); - if (a->set_id) { - crm_xml_set_id(xml_obj, "%s", a->set_id); - } else { - crm_xml_set_id(xml_obj, "%s-%s", XML_CIB_TAG_STATUS, nodeid); + child = create_xml_node(child, XML_CIB_TAG_NVPAIR); + if (child == NULL) { + goto done; } - set = ID(xml_obj); + 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); + + rc = the_cib->cmds->modify(the_cib, XML_CIB_TAG_STATUS, update, + cib_can_create|cib_transaction); + rc = pcmk_legacy2rc(rc); + +done: + free_xml(update); + return rc; +} + +/*! + * \internal + * \brief Add an unset-attribute update request to the current CIB transaction + * + * \param[in] attr Attribute to update + * \param[in] attr_id ID of attribute to update + * \param[in] node_id ID of node for which to update attribute value + * \param[in] set_id ID of attribute set + * + * \return Standard Pacemaker return code + */ +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']", + node_id, node_id, attr->set_type, set_id, + attr_id, attr->id); + + int rc = the_cib->cmds->remove(the_cib, xpath, NULL, + cib_xpath|cib_transaction); + + free(xpath); + return pcmk_legacy2rc(rc); +} + +/*! + * \internal + * \brief Add an attribute update request to the current CIB transaction + * + * \param[in] attr Attribute to update + * \param[in] value New value for attribute + * \param[in] node_id ID of node for which to update attribute value + * + * \return Standard Pacemaker return code + */ +static int +add_attr_update(const attribute_t *attr, const char *value, const char *node_id) +{ + char *set_id = NULL; + char *attr_id = NULL; + int rc = pcmk_rc_ok; - xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); - if (a->uuid) { - crm_xml_set_id(xml_obj, "%s", a->uuid); + if (attr->set_id != NULL) { + pcmk__str_update(&set_id, attr->set_id); } else { - crm_xml_set_id(xml_obj, "%s-%s", set, a->id); + set_id = crm_strdup_printf("%s-%s", XML_CIB_TAG_STATUS, node_id); } - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, a->id); + crm_xml_sanitize_id(set_id); - if(value) { - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, value); + 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); } else { - crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, ""); - crm_xml_add(xml_obj, "__delete__", XML_NVPAIR_ATTR_VALUE); + rc = add_unset_attr_update(attr, attr_id, node_id, set_id); } + free(set_id); + free(attr_id); + return rc; } static void @@ -202,15 +471,22 @@ attrd_add_timer(const char *id, int timeout_ms, attribute_t *attr) return mainloop_timer_add(id, timeout_ms, FALSE, attribute_timer_cb, attr); } -void -attrd_write_attribute(attribute_t *a, bool ignore_delay) +/*! + * \internal + * \brief Write an attribute's values to the CIB if appropriate + * + * \param[in,out] a Attribute to write + * \param[in] ignore_delay If true, write attribute now regardless of any + * configured delay + */ +static void +write_attribute(attribute_t *a, bool ignore_delay) { int private_updates = 0, cib_updates = 0; - xmlNode *xml_top = NULL; attribute_value_t *v = NULL; GHashTableIter iter; - enum cib_call_options flags = cib_none; GHashTable *alert_attribute_value = NULL; + int rc = pcmk_ok; if (a == NULL) { return; @@ -218,32 +494,37 @@ attrd_write_attribute(attribute_t *a, bool ignore_delay) /* If this attribute will be written to the CIB ... */ if (!stand_alone && !a->is_private) { - /* Defer the write if now's not a good time */ - CRM_CHECK(the_cib != NULL, return); if (a->update && (a->update < last_cib_op_done)) { - crm_info("Write out of '%s' continuing: update %d considered lost", a->id, a->update); + crm_info("Write out of '%s' continuing: update %d considered lost", + a->id, a->update); a->update = 0; // Don't log this message again } else if (a->update) { - crm_info("Write out of '%s' delayed: update %d in progress", a->id, a->update); - return; + crm_info("Write out of '%s' delayed: update %d in progress", + a->id, a->update); + goto done; } else if (mainloop_timer_running(a->timer)) { if (ignore_delay) { - /* 'refresh' forces a write of the current value of all attributes - * Cancel any existing timers, we're writing it NOW - */ mainloop_timer_stop(a->timer); - crm_debug("Write out of '%s': timer is running but ignore delay", a->id); + crm_debug("Overriding '%s' write delay", a->id); } else { - crm_info("Write out of '%s' delayed: timer is running", a->id); - return; + crm_info("Delaying write of '%s'", a->id); + goto done; } } - /* Initialize the status update XML */ - xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS); + // Initiate a transaction for all the peer value updates + CRM_CHECK(the_cib != NULL, goto done); + 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 " + "CIB transaction", + a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a")); + goto done; + } } /* Attribute will be written shortly, so clear changed flag */ @@ -256,12 +537,14 @@ attrd_write_attribute(attribute_t *a, bool ignore_delay) a->force_write = FALSE; /* Make the table for the attribute trap */ - alert_attribute_value = pcmk__strikey_table(NULL, attrd_free_attribute_value); + alert_attribute_value = pcmk__strikey_table(NULL, + attrd_free_attribute_value); /* 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); + 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); /* If the value's peer info does not correspond to a peer, ignore it */ if (peer == NULL) { @@ -291,11 +574,20 @@ attrd_write_attribute(attribute_t *a, bool ignore_delay) continue; } - /* Add this value to status update XML */ - crm_debug("Updating %s[%s]=%s (peer known as %s, UUID %s, ID %u/%u)", + // Update this value as part of the CIB transaction we're building + rc = add_attr_update(a, v->current, peer->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)); + 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); - build_update_element(xml_top, a, peer->uuid, v->current); cib_updates++; /* Preservation of the attribute to transmit alert */ @@ -305,12 +597,6 @@ attrd_write_attribute(attribute_t *a, bool ignore_delay) v->requested = NULL; if (v->current) { v->requested = strdup(v->current); - } else { - /* Older attrd versions don't know about the cib_mixed_update - * flag so make sure it goes to the local cib which does - */ - cib__set_call_options(flags, crm_system_name, - cib_mixed_update|cib_scope_local); } } @@ -319,40 +605,55 @@ attrd_write_attribute(attribute_t *a, bool ignore_delay) private_updates, pcmk__plural_s(private_updates), a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a")); } - if (cib_updates) { - crm_log_xml_trace(xml_top, __func__); + if (cib_updates > 0) { + char *id = NULL; - a->update = cib_internal_op(the_cib, PCMK__CIB_REQUEST_MODIFY, NULL, - XML_CIB_TAG_STATUS, xml_top, NULL, flags, - a->user); + // 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)", a->update, cib_updates, pcmk__plural_s(cib_updates), a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a")); - the_cib->cmds->register_callback_full(the_cib, a->update, - CIB_OP_TIMEOUT_S, FALSE, - strdup(a->id), - "attrd_cib_callback", - attrd_cib_callback, free); - /* Transmit alert of the attribute */ - send_alert_attributes_value(a, alert_attribute_value); + 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", + attrd_cib_callback, free)) { + // Transmit alert of the attribute + send_alert_attributes_value(a, alert_attribute_value); + } } - g_hash_table_destroy(alert_attribute_value); - free_xml(xml_top); +done: + // Discard transaction (if any) + if (the_cib != NULL) { + the_cib->cmds->end_transaction(the_cib, false, cib_none); + the_cib->cmds->set_user(the_cib, NULL); + } + + if (alert_attribute_value != NULL) { + g_hash_table_destroy(alert_attribute_value); + } } +/*! + * \internal + * \brief Write out attributes + * + * \param[in] options Group of enum attrd_write_options + */ void -attrd_write_attributes(bool all, bool ignore_delay) +attrd_write_attributes(uint32_t options) { GHashTableIter iter; attribute_t *a = NULL; - crm_debug("Writing out %s attributes", all? "all" : "changed"); + crm_debug("Writing out %s attributes", + 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 (!all && a->unknown_peer_uuids) { + if (!pcmk_is_set(options, attrd_write_all) && a->unknown_peer_uuids) { // Try writing this attribute again, in case peer ID was learned a->changed = true; } else if (a->force_write) { @@ -360,9 +661,14 @@ attrd_write_attributes(bool all, bool ignore_delay) a->changed = true; } - if(all || a->changed) { - /* When forced write flag is set, ignore delay. */ - attrd_write_attribute(a, (a->force_write ? true : ignore_delay)); + if (pcmk_is_set(options, attrd_write_all) || a->changed) { + bool ignore_delay = pcmk_is_set(options, attrd_write_no_delay); + + if (a->force_write) { + // Always ignore delay when forced write flag is set + ignore_delay = true; + } + write_attribute(a, ignore_delay); } else { crm_trace("Skipping unchanged attribute %s", a->id); } @@ -373,7 +679,7 @@ void attrd_write_or_elect_attribute(attribute_t *a) { if (attrd_election_won()) { - attrd_write_attribute(a, false); + write_attribute(a, false); } else { attrd_start_election_if_needed(); } diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index ef205e6..86dc67b 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -23,8 +23,6 @@ #include "pacemaker-attrd.h" -extern crm_exit_t attrd_exit_status; - static xmlNode * attrd_confirmation(int callid) { @@ -48,7 +46,7 @@ attrd_peer_message(crm_node_t *peer, xmlNode *xml) return; } - if (attrd_shutting_down()) { + if (attrd_shutting_down(false)) { /* If we're shutting down, we want to continue responding to election * ops as long as we're a cluster member (because our vote may be * needed). Ignore all other messages. @@ -133,11 +131,11 @@ attrd_cpg_dispatch(cpg_handle_t handle, static void attrd_cpg_destroy(gpointer unused) { - if (attrd_shutting_down()) { - crm_info("Corosync disconnection complete"); + if (attrd_shutting_down(false)) { + crm_info("Disconnected from Corosync process group"); } else { - crm_crit("Lost connection to cluster layer, shutting down"); + crm_crit("Lost connection to Corosync process group, shutting down"); attrd_exit_status = CRM_EX_DISCONNECT; attrd_shutdown(0); } @@ -180,7 +178,7 @@ cache_remote_node(const char *node_name) /* 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); + crm_node_t *dup = pcmk__search_cluster_node_cache(0, node_name, NULL); if (dup && (dup->uuid == NULL)) { reap_crm_member(0, node_name); @@ -285,7 +283,7 @@ record_peer_nodeid(attribute_value_t *v, const char *host) crm_trace("Learned %s has node id %s", known_peer->uname, known_peer->uuid); if (attrd_election_won()) { - attrd_write_attributes(false, false); + attrd_write_attributes(attrd_write_changed); } } @@ -476,9 +474,7 @@ attrd_peer_clear_failure(pcmk__request_t *request) crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE); /* Make sure value is not set, so we delete */ - if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) { - crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL); - } + xml_remove_prop(xml, PCMK__XA_ATTR_VALUE); g_hash_table_iter_init(&iter, attributes); while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) { @@ -591,7 +587,8 @@ attrd_peer_update(const crm_node_t *peer, xmlNode *xml, const char *host, { bool handle_sync_point = false; - if (xml_has_children(xml)) { + 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); diff --git a/daemons/attrd/attrd_elections.c b/daemons/attrd/attrd_elections.c index 3b6b55a..82fbe8a 100644 --- a/daemons/attrd/attrd_elections.c +++ b/daemons/attrd/attrd_elections.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the Pacemaker project contributors + * Copyright 2013-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -25,9 +25,11 @@ attrd_election_cb(gpointer user_data) /* Update the peers after an election */ attrd_peer_sync(NULL, NULL); - /* Update the CIB after an election */ - attrd_write_attributes(true, false); - return FALSE; + /* After winning an election, update the CIB with the values of all + * attributes as the winner knows them. + */ + attrd_write_attributes(attrd_write_all); + return G_SOURCE_REMOVE; } void @@ -48,7 +50,7 @@ attrd_start_election_if_needed(void) { if ((peer_writer == NULL) && (election_state(writer) != election_in_progress) - && !attrd_shutting_down()) { + && !attrd_shutting_down(false)) { crm_info("Starting an election to determine the writer"); election_vote(writer); @@ -70,7 +72,7 @@ attrd_handle_election_op(const crm_node_t *peer, xmlNode *xml) crm_xml_add(xml, F_CRM_HOST_FROM, peer->uname); // Don't become writer if we're shutting down - rc = election_count_vote(writer, xml, !attrd_shutting_down()); + rc = election_count_vote(writer, xml, !attrd_shutting_down(false)); switch(rc) { case election_start: diff --git a/daemons/attrd/attrd_ipc.c b/daemons/attrd/attrd_ipc.c index 9d3dfff..05c4a69 100644 --- a/daemons/attrd/attrd_ipc.c +++ b/daemons/attrd/attrd_ipc.c @@ -140,12 +140,8 @@ attrd_client_clear_failure(pcmk__request_t *request) } /* Make sure attribute and value are not set, so we delete via regex */ - if (crm_element_value(xml, PCMK__XA_ATTR_NAME)) { - crm_xml_replace(xml, PCMK__XA_ATTR_NAME, NULL); - } - if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) { - crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL); - } + xml_remove_prop(xml, PCMK__XA_ATTR_NAME); + xml_remove_prop(xml, PCMK__XA_ATTR_VALUE); return attrd_client_update(request); } @@ -166,7 +162,8 @@ attrd_client_peer_remove(pcmk__request_t *request) crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID, &nodeid); if (nodeid > 0) { - crm_node_t *node = pcmk__search_cluster_node_cache(nodeid, NULL); + crm_node_t *node = pcmk__search_cluster_node_cache(nodeid, NULL, + NULL); char *host_alloc = NULL; if (node && node->uname) { @@ -235,7 +232,7 @@ attrd_client_refresh(pcmk__request_t *request) crm_info("Updating all attributes"); attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags); - attrd_write_attributes(true, true); + attrd_write_attributes(attrd_write_all|attrd_write_no_delay); pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); return NULL; @@ -282,7 +279,7 @@ expand_regexes(xmlNode *xml, const char *attr, const char *value, const char *re * regex and replace it with the name. */ attrd_copy_xml_attributes(xml, child); - crm_xml_replace(child, PCMK__XA_ATTR_PATTERN, NULL); + xml_remove_prop(child, PCMK__XA_ATTR_PATTERN); crm_xml_add(child, PCMK__XA_ATTR_NAME, attr); } } @@ -401,14 +398,18 @@ send_child_update(xmlNode *child, void *data) xmlNode * attrd_client_update(pcmk__request_t *request) { - xmlNode *xml = request->xml; + xmlNode *xml = NULL; const char *attr, *value, *regex; + CRM_CHECK((request != NULL) && (request->xml != NULL), return NULL); + + xml = request->xml; + /* If the message has children, that means it is a message from a newer * client that supports sending multiple operations at a time. There are * two ways we can handle that. */ - if (xml_has_children(xml)) { + if (xml->children != NULL) { if (ATTRD_SUPPORTS_MULTI_MESSAGE(minimum_protocol_version)) { /* First, if all peers support a certain protocol version, we can * just broadcast the big message and they'll handle it. However, @@ -494,7 +495,7 @@ static int32_t attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { crm_trace("New client connection %p", c); - if (attrd_shutting_down()) { + if (attrd_shutting_down(false)) { crm_info("Ignoring new connection from pid %d during shutdown", pcmk__client_pid(c)); return -EPERM; diff --git a/daemons/attrd/attrd_messages.c b/daemons/attrd/attrd_messages.c index 184176a..89da6d8 100644 --- a/daemons/attrd/attrd_messages.c +++ b/daemons/attrd/attrd_messages.c @@ -20,6 +20,36 @@ int minimum_protocol_version = -1; static GHashTable *attrd_handlers = NULL; +static bool +is_sync_point_attr(xmlAttrPtr attr, void *data) +{ + return pcmk__str_eq((const char *) attr->name, PCMK__XA_ATTR_SYNC_POINT, pcmk__str_none); +} + +static int +remove_sync_point_attribute(xmlNode *xml, void *data) +{ + pcmk__xe_remove_matching_attrs(xml, is_sync_point_attr, NULL); + pcmk__xe_foreach_child(xml, XML_ATTR_OP, remove_sync_point_attribute, NULL); + return pcmk_rc_ok; +} + +/* Sync points on a multi-update IPC message to an attrd too old to support + * multi-update messages won't work. Strip the sync point attribute off here + * so we don't pretend to support this situation and instead ACK the client + * immediately. + */ +static void +remove_unsupported_sync_points(pcmk__request_t *request) +{ + if (request->xml->children != NULL && !ATTRD_SUPPORTS_MULTI_MESSAGE(minimum_protocol_version) && + attrd_request_has_sync_point(request->xml)) { + crm_warn("Ignoring sync point in request from %s because not all nodes support it", + pcmk__request_origin(request)); + remove_sync_point_attribute(request->xml, NULL); + } +} + static xmlNode * handle_unknown_request(pcmk__request_t *request) { @@ -42,6 +72,8 @@ handle_clear_failure_request(pcmk__request_t *request) pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); return NULL; } else { + remove_unsupported_sync_points(request); + if (attrd_request_has_sync_point(request->xml)) { /* If this client supplied a sync point it wants to wait for, add it to * the wait list. Clients on this list will not receive an ACK until @@ -180,6 +212,8 @@ handle_update_request(pcmk__request_t *request) return NULL; } else { + remove_unsupported_sync_points(request); + if (attrd_request_has_sync_point(request->xml)) { /* If this client supplied a sync point it wants to wait for, add it to * the wait list. Clients on this list will not receive an ACK until diff --git a/daemons/attrd/attrd_sync.c b/daemons/attrd/attrd_sync.c index d59ddd5..1a6c24c 100644 --- a/daemons/attrd/attrd_sync.c +++ b/daemons/attrd/attrd_sync.c @@ -313,7 +313,9 @@ attrd_cluster_sync_point_update(xmlNode *xml) const char * attrd_request_sync_point(xmlNode *xml) { - if (xml_has_children(xml)) { + CRM_CHECK(xml != NULL, return NULL); + + if (xml->children != NULL) { xmlNode *child = pcmk__xe_match(xml, XML_ATTR_OP, PCMK__XA_ATTR_SYNC_POINT, NULL); if (child) { diff --git a/daemons/attrd/attrd_utils.c b/daemons/attrd/attrd_utils.c index 7de8dd9..341ee1a 100644 --- a/daemons/attrd/attrd_utils.c +++ b/daemons/attrd/attrd_utils.c @@ -56,26 +56,22 @@ attrd_clear_requesting_shutdown(void) /*! * \internal - * \brief Check whether we're currently requesting shutdown + * \brief Check whether local attribute manager is shutting down * - * \return true if requesting shutdown, false otherwise - */ -bool -attrd_requesting_shutdown(void) -{ - return requesting_shutdown; -} - -/*! - * \internal - * \brief Check whether we're currently shutting down + * \param[in] if_requested Also consider presence of "shutdown" attribute * - * \return true if shutting down, false otherwise + * \return \c true if local attribute manager has begun shutdown sequence + * or (if \p if_requested is \c true) whether local node has a nonzero + * "shutdown" attribute set, otherwise \c false + * \note Most callers should pass \c false for \p if_requested, because the + * attribute manager needs to continue performing while the controller is + * shutting down, and even needs to be eligible for election in case all + * nodes are shutting down. */ bool -attrd_shutting_down(void) +attrd_shutting_down(bool if_requested) { - return shutting_down; + return shutting_down || (if_requested && requesting_shutdown); } /*! @@ -137,39 +133,6 @@ attrd_run_mainloop(void) g_main_loop_run(mloop); } -void -attrd_cib_disconnect(void) -{ - CRM_CHECK(the_cib != NULL, return); - the_cib->cmds->del_notify_callback(the_cib, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb); - the_cib->cmds->del_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb); - cib__clean_up_connection(&the_cib); -} - -void -attrd_cib_replaced_cb(const char *event, xmlNode * msg) -{ - int change_section = cib_change_section_nodes | cib_change_section_status | cib_change_section_alerts; - - if (attrd_requesting_shutdown() || attrd_shutting_down()) { - return; - } - - crm_element_value_int(msg, F_CIB_CHANGE_SECTION, &change_section); - - if (attrd_election_won()) { - if (change_section & (cib_change_section_nodes | cib_change_section_status)) { - crm_notice("Updating all attributes after %s event", event); - attrd_write_attributes(true, false); - } - } - - if (change_section & cib_change_section_alerts) { - // Check for changes in alerts - mainloop_set_trigger(attrd_config_read); - } -} - /* strlen("value") */ #define plus_plus_len (5) diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 037825b..8091c5b 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -63,140 +63,6 @@ crm_cluster_t *attrd_cluster = NULL; crm_trigger_t *attrd_config_read = NULL; crm_exit_t attrd_exit_status = CRM_EX_OK; -static void -attrd_cib_destroy_cb(gpointer user_data) -{ - cib_t *conn = user_data; - - conn->cmds->signoff(conn); /* Ensure IPC is cleaned up */ - - if (attrd_shutting_down()) { - crm_info("Connection disconnection complete"); - - } else { - /* eventually this should trigger a reconnect, not a shutdown */ - crm_crit("Lost connection to the CIB manager, shutting down"); - attrd_exit_status = CRM_EX_DISCONNECT; - attrd_shutdown(0); - } - - return; -} - -static void -attrd_erase_cb(xmlNode *msg, int call_id, int rc, xmlNode *output, - void *user_data) -{ - do_crm_log_unlikely((rc? LOG_NOTICE : LOG_DEBUG), - "Cleared transient attributes: %s " - CRM_XS " xpath=%s rc=%d", - pcmk_strerror(rc), (char *) user_data, rc); -} - -#define XPATH_TRANSIENT "//node_state[@uname='%s']/" XML_TAG_TRANSIENT_NODEATTRS - -/*! - * \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. - * - * \todo If pacemaker-attrd respawns after crashing (see PCMK_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(). - */ -static void -attrd_erase_attrs(void) -{ - int call_id; - char *xpath = crm_strdup_printf(XPATH_TRANSIENT, attrd_cluster->uname); - - crm_info("Clearing transient attributes from CIB " CRM_XS " xpath=%s", - 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, - "attrd_erase_cb", attrd_erase_cb, - free); -} - -static int -attrd_cib_connect(int max_retry) -{ - static int attempts = 0; - - int rc = -ENOTCONN; - - the_cib = cib_new(); - if (the_cib == NULL) { - return -ENOTCONN; - } - - do { - if(attempts > 0) { - sleep(attempts); - } - - attempts++; - crm_debug("Connection attempt %d to the CIB manager", attempts); - rc = the_cib->cmds->signon(the_cib, T_ATTRD, cib_command); - - } while(rc != pcmk_ok && attempts < max_retry); - - if (rc != pcmk_ok) { - crm_err("Connection to the CIB manager failed: %s " CRM_XS " rc=%d", - pcmk_strerror(rc), rc); - goto cleanup; - } - - crm_debug("Connected to the CIB manager after %d attempts", attempts); - - rc = the_cib->cmds->set_connection_dnotify(the_cib, attrd_cib_destroy_cb); - if (rc != pcmk_ok) { - crm_err("Could not set disconnection callback"); - goto cleanup; - } - - rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb); - if(rc != pcmk_ok) { - crm_err("Could not set CIB notification callback"); - goto cleanup; - } - - rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb); - if (rc != pcmk_ok) { - crm_err("Could not set CIB notification callback (update)"); - goto cleanup; - } - - return pcmk_ok; - - cleanup: - cib__clean_up_connection(&the_cib); - return -ENOTCONN; -} - -/*! - * \internal - * \brief Prepare the CIB after cluster is connected - */ -static void -attrd_cib_init(void) -{ - // We have no attribute values in memory, wipe the CIB to match - attrd_erase_attrs(); - - // Set a trigger for reading the CIB (for the alerts section) - attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL); - - // Always read the CIB at start-up - mainloop_set_trigger(attrd_config_read); -} - static bool ipc_already_running(void) { @@ -208,8 +74,10 @@ ipc_already_running(void) return false; } - rc = pcmk_connect_ipc(old_instance, pcmk_ipc_dispatch_sync); + rc = pcmk__connect_ipc(old_instance, pcmk_ipc_dispatch_sync, 2); if (rc != pcmk_rc_ok) { + crm_debug("No existing %s manager instance found: %s", + pcmk_ipc_name(old_instance, true), pcmk_rc_str(rc)); pcmk_free_ipc_api(old_instance); return false; } @@ -277,7 +145,7 @@ main(int argc, char **argv) attrd_exit_status = CRM_EX_OK; g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status, "%s", msg); - crm_err(msg); + crm_err("%s", msg); goto done; } diff --git a/daemons/attrd/pacemaker-attrd.h b/daemons/attrd/pacemaker-attrd.h index 329fb5a..b8929a7 100644 --- a/daemons/attrd/pacemaker-attrd.h +++ b/daemons/attrd/pacemaker-attrd.h @@ -57,13 +57,14 @@ void attrd_run_mainloop(void); void attrd_set_requesting_shutdown(void); void attrd_clear_requesting_shutdown(void); void attrd_free_waitlist(void); -bool attrd_requesting_shutdown(void); -bool attrd_shutting_down(void); +bool attrd_shutting_down(bool if_requested); void attrd_shutdown(int nsig); void attrd_init_ipc(void); void attrd_ipc_fini(void); +int attrd_cib_connect(int max_retry); void attrd_cib_disconnect(void); +void attrd_cib_init(void); bool attrd_value_needs_expansion(const char *value); int attrd_expand_value(const char *value, const char *old_value); @@ -92,6 +93,7 @@ int attrd_failure_regex(regex_t *regex, const char *rsc, const char *op, guint interval_ms); extern cib_t *the_cib; +extern crm_exit_t attrd_exit_status; /* Alerts */ @@ -100,8 +102,6 @@ extern crm_trigger_t *attrd_config_read; void attrd_lrmd_disconnect(void); gboolean attrd_read_options(gpointer user_data); -void attrd_cib_replaced_cb(const char *event, xmlNode * msg); -void attrd_cib_updated_cb(const char *event, xmlNode *msg); int attrd_send_attribute_alert(const char *node, int nodeid, const char *attr, const char *value); @@ -177,8 +177,13 @@ void attrd_free_attribute(gpointer data); void attrd_free_attribute_value(gpointer data); attribute_t *attrd_populate_attribute(xmlNode *xml, const char *attr); -void attrd_write_attribute(attribute_t *a, bool ignore_delay); -void attrd_write_attributes(bool all, bool ignore_delay); +enum attrd_write_options { + attrd_write_changed = 0, + attrd_write_all = (1 << 0), + attrd_write_no_delay = (1 << 1), +}; + +void attrd_write_attributes(uint32_t options); void attrd_write_or_elect_attribute(attribute_t *a); extern int minimum_protocol_version; |