summaryrefslogtreecommitdiffstats
path: root/daemons/attrd/attrd_alerts.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/attrd/attrd_alerts.c')
-rw-r--r--daemons/attrd/attrd_alerts.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c
new file mode 100644
index 0000000..b694891
--- /dev/null
+++ b/daemons/attrd/attrd_alerts.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015-2021 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ */
+
+#include <crm_internal.h>
+#include <crm/crm.h>
+#include <crm/cib/internal.h>
+#include <crm/msg_xml.h>
+#include <crm/cluster/internal.h>
+#include <crm/cluster/election_internal.h>
+#include <crm/common/alerts_internal.h>
+#include <crm/pengine/rules_internal.h>
+#include <crm/lrmd_internal.h>
+#include "pacemaker-attrd.h"
+
+static GList *attrd_alert_list = NULL;
+
+static void
+attrd_lrmd_callback(lrmd_event_data_t * op)
+{
+ CRM_CHECK(op != NULL, return);
+ switch (op->type) {
+ case lrmd_event_disconnect:
+ crm_info("Lost connection to executor");
+ attrd_lrmd_disconnect();
+ break;
+ default:
+ break;
+ }
+}
+
+static lrmd_t *
+attrd_lrmd_connect(void)
+{
+ if (the_lrmd == NULL) {
+ the_lrmd = lrmd_api_new();
+ the_lrmd->cmds->set_callback(the_lrmd, attrd_lrmd_callback);
+ }
+
+ if (!the_lrmd->cmds->is_connected(the_lrmd)) {
+ const unsigned int max_attempts = 10;
+ int ret = -ENOTCONN;
+
+ for (int fails = 0; fails < max_attempts; ++fails) {
+ ret = the_lrmd->cmds->connect(the_lrmd, T_ATTRD, NULL);
+ if (ret == pcmk_ok) {
+ break;
+ }
+
+ crm_debug("Could not connect to executor, %d tries remaining",
+ (max_attempts - fails));
+ /* @TODO We don't want to block here with sleep, but we should wait
+ * some time between connection attempts. We could possibly add a
+ * timer with a callback, but then we'd likely need an alert queue.
+ */
+ }
+
+ if (ret != pcmk_ok) {
+ attrd_lrmd_disconnect();
+ }
+ }
+
+ return the_lrmd;
+}
+
+void
+attrd_lrmd_disconnect(void) {
+ if (the_lrmd) {
+ lrmd_t *conn = the_lrmd;
+
+ the_lrmd = NULL; /* in case we're called recursively */
+ lrmd_api_delete(conn); /* will disconnect if necessary */
+ }
+}
+
+static void
+config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
+{
+ xmlNode *crmalerts = NULL;
+
+ if (rc == -ENXIO) {
+ crm_debug("Local CIB has no alerts section");
+ return;
+ } else if (rc != pcmk_ok) {
+ crm_notice("Could not query local CIB: %s", pcmk_strerror(rc));
+ return;
+ }
+
+ crmalerts = output;
+ if (crmalerts && !pcmk__str_eq(crm_element_name(crmalerts), XML_CIB_TAG_ALERTS, pcmk__str_none)) {
+ crmalerts = first_named_child(crmalerts, XML_CIB_TAG_ALERTS);
+ }
+ if (!crmalerts) {
+ crm_notice("CIB query result has no " XML_CIB_TAG_ALERTS " section");
+ return;
+ }
+
+ pe_free_alert_list(attrd_alert_list);
+ 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)
+{
+ int call_id;
+
+ CRM_CHECK(the_cib != NULL, return TRUE);
+
+ call_id = the_cib->cmds->query(the_cib, XPATH_ALERTS, NULL,
+ cib_xpath | cib_scope_local);
+
+ the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, NULL,
+ "config_query_callback",
+ config_query_callback, free);
+
+ crm_trace("Querying the CIB... call %d", call_id);
+ 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)
+{
+ if (attrd_alert_list == NULL) {
+ return pcmk_ok;
+ }
+ return lrmd_send_attribute_alert(attrd_lrmd_connect(), attrd_alert_list,
+ node, nodeid, attr, value);
+}