diff --git a/attrd/attrd_alerts.c b/attrd/attrd_alerts.c index c677df0e06..e12a27e11b 100644 --- a/attrd/attrd_alerts.c +++ b/attrd/attrd_alerts.c @@ -1,230 +1,179 @@ /* * Copyright (C) 2015 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "attrd_alerts.h" #include #include #include #include static GListPtr 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 LRMD"); attrd_lrmd_disconnect(); break; default: break; } } lrmd_t * attrd_lrmd_connect() { int ret = -ENOTCONN; int fails = 0; const unsigned int max_attempts = 10; if (!the_lrmd) { the_lrmd = lrmd_api_new(); } the_lrmd->cmds->set_callback(the_lrmd, attrd_lrmd_callback); while (fails < max_attempts) { ret = the_lrmd->cmds->connect(the_lrmd, T_ATTRD, NULL); if (ret != pcmk_ok) { fails++; crm_debug("Could not connect to LRMD, %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. */ } else { break; } } if (ret != pcmk_ok) { attrd_lrmd_disconnect(); } return the_lrmd; } void attrd_lrmd_disconnect() { 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 != pcmk_ok) { crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc)); return; } crmalerts = output; if (crmalerts && !crm_str_eq(crm_element_name(crmalerts), XML_CIB_TAG_ALERTS, TRUE)) { crmalerts = first_named_child(crmalerts, XML_CIB_TAG_ALERTS); } if (!crmalerts) { crm_err("Local CIB query for " XML_CIB_TAG_ALERTS " section failed"); return; } pe_free_alert_list(attrd_alert_list); attrd_alert_list = pe_unpack_alerts(crmalerts); } gboolean attrd_read_options(gpointer user_data) { int call_id; if (the_cib) { call_id = the_cib->cmds->query(the_cib, "//" 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", config_query_callback, free); crm_trace("Querying the CIB... call %d", call_id); } else { crm_err("Querying the CIB...CIB connection not active"); } return TRUE; } void attrd_cib_updated_cb(const char *event, xmlNode * msg) { - int rc = -1; - int format= 1; - xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT); - xmlNode *change = NULL; - xmlXPathObject *xpathObj = NULL; - - CRM_CHECK(msg != NULL, return); - - crm_element_value_int(msg, F_CIB_RC, &rc); - if (rc < pcmk_ok) { - crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc)); - return; + if (crm_patchset_contains_alert(msg, FALSE)) { + mainloop_set_trigger(attrd_config_read); } - - crm_element_value_int(patchset, "format", &format); - if (format == 1) { - if ((xpathObj = xpath_search( - msg, - "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_ALERTS - )) != NULL) { - freeXpathObject(xpathObj); - mainloop_set_trigger(attrd_config_read); - } - } else if (format == 2) { - for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) { - const char *xpath = crm_element_value(change, XML_DIFF_PATH); - - if (xpath == NULL) { - continue; - } - - if (!strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_ALERTS)) { - /* this is not a change to an existing alerts section */ - - xmlNode *section = NULL; - const char *name = NULL; - - if ((strcmp(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION) != 0) || - ((section = __xml_first_child(change)) == NULL) || - ((name = crm_element_name(section)) == NULL) || - (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { - /* this is not a newly added alerts section */ - continue; - } - } - - mainloop_set_trigger(attrd_config_read); - break; - } - - } else { - crm_warn("Unknown patch format: %d", format); - } - } #if HAVE_ATOMIC_ATTRD 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); a_v->nodeid = v->nodeid; a_v->nodename = strdup(v->nodename); if (v->current != NULL) { a_v->current = strdup(v->current); } g_hash_table_replace(t, a_v->nodename, a_v); } void send_alert_attributes_value(attribute_t *a, GHashTable *t) { int rc = 0; attribute_value_t *at = NULL; GHashTableIter vIter; g_hash_table_iter_init(&vIter, t); while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & at)) { rc = lrmd_send_attribute_alert(attrd_alert_list, attrd_lrmd_connect, at->nodename, at->nodeid, a->id, at->current); crm_trace("Sent alerts for %s[%s]=%s: nodeid=%d rc=%d", a->id, at->nodename, at->current, at->nodeid, rc); } } #endif diff --git a/crmd/cib.c b/crmd/cib.c index b10256a7d1..7044f1b60c 100644 --- a/crmd/cib.c +++ b/crmd/cib.c @@ -1,272 +1,223 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include /* for access */ #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include +#include #include #include #include #include struct crm_subsystem_s *cib_subsystem = NULL; int cib_retries = 0; static void do_cib_updated(const char *event, xmlNode * msg) { - int rc = -1; - int format= 1; - xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT); - xmlNode *change = NULL; - xmlXPathObject *xpathObj = NULL; - - CRM_CHECK(msg != NULL, return); - crm_element_value_int(msg, F_CIB_RC, &rc); - if (rc < pcmk_ok) { - crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc)); - return; - } - - crm_element_value_int(patchset, "format", &format); - if (format == 1) { - if ((xpathObj = xpath_search( - msg, - "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_CRMCONFIG " | " \ - "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_ALERTS - )) != NULL) { - freeXpathObject(xpathObj); - mainloop_set_trigger(config_read); - } - } else if (format == 2) { - for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) { - const char *xpath = crm_element_value(change, XML_DIFF_PATH); - - if (xpath == NULL) { - continue; - } - - /* modifying properties */ - if (!strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_CRMCONFIG "/") && - !strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_ALERTS)) { - xmlNode *section = NULL; - const char *name = NULL; - - /* adding notifications section */ - if ((strcmp(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION) != 0) || - ((section = __xml_first_child(change)) == NULL) || - ((name = crm_element_name(section)) == NULL) || - (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { - continue; - } - } - - mainloop_set_trigger(config_read); - break; - } - - } else { - crm_warn("Unknown patch format: %d", format); + if (crm_patchset_contains_alert(msg, TRUE)) { + mainloop_set_trigger(config_read); } } static void revision_check_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { int cmp = -1; xmlNode *generation = NULL; const char *revision = NULL; if (rc != pcmk_ok) { fsa_data_t *msg_data = NULL; register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } generation = output; CRM_CHECK(safe_str_eq(crm_element_name(generation), XML_TAG_CIB), crm_log_xml_err(output, __FUNCTION__); return); crm_trace("Checking our feature revision %s is allowed", CRM_FEATURE_SET); revision = crm_element_value(generation, XML_ATTR_CRM_VERSION); cmp = compare_version(revision, CRM_FEATURE_SET); if (cmp > 0) { crm_err("Shutting down because the current configuration is not supported by this version " CRM_XS " build=%s supported=%s current=%s", PACEMAKER_VERSION, CRM_FEATURE_SET, revision); /* go into a stall state */ register_fsa_error_adv(C_FSA_INTERNAL, I_SHUTDOWN, NULL, NULL, __FUNCTION__); return; } } static void do_cib_replaced(const char *event, xmlNode * msg) { crm_debug("Updating the CIB after a replace: DC=%s", AM_I_DC ? "true" : "false"); if (AM_I_DC == FALSE) { return; } else if (fsa_state == S_FINALIZE_JOIN && is_set(fsa_input_register, R_CIB_ASKED)) { /* no need to restart the join - we asked for this replace op */ return; } /* start the join process again so we get everyone's LRM status */ populate_cib_nodes(node_update_quick|node_update_all, __FUNCTION__); register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); } /* A_CIB_STOP, A_CIB_START, O_CIB_RESTART */ void do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { CRM_ASSERT(fsa_cib_conn != NULL); if (action & A_CIB_STOP) { if (fsa_cib_conn->state != cib_disconnected && last_resource_update != 0) { crm_info("Waiting for resource update %d to complete", last_resource_update); crmd_fsa_stall(FALSE); return; } crm_info("Disconnecting CIB"); clear_bit(fsa_input_register, R_CIB_CONNECTED); fsa_cib_conn->cmds->del_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY, do_cib_updated); if (fsa_cib_conn->state != cib_disconnected) { fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local); fsa_cib_conn->cmds->signoff(fsa_cib_conn); } crm_notice("Disconnected from the CIB"); } if (action & A_CIB_START) { int rc = pcmk_ok; if (cur_state == S_STOPPING) { crm_err("Ignoring request to start the CIB after shutdown"); return; } rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking); if (rc != pcmk_ok) { /* a short wait that usually avoids stalling the FSA */ sleep(1); rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking); } if (rc != pcmk_ok) { crm_info("Could not connect to the CIB service: %s", pcmk_strerror(rc)); } else if (pcmk_ok != fsa_cib_conn->cmds->set_connection_dnotify(fsa_cib_conn, crmd_cib_connection_destroy)) { crm_err("Could not set dnotify callback"); } else if (pcmk_ok != fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_REPLACE_NOTIFY, do_cib_replaced)) { crm_err("Could not set CIB notification callback (replace)"); } else if (pcmk_ok != fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY, do_cib_updated)) { crm_err("Could not set CIB notification callback (update)"); } else { set_bit(fsa_input_register, R_CIB_CONNECTED); } if (is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { cib_retries++; crm_warn("Couldn't complete CIB registration %d" " times... pause and retry", cib_retries); if (cib_retries < 30) { crm_timer_start(wait_timer); crmd_fsa_stall(FALSE); } else { crm_err("Could not complete CIB" " registration %d times..." " hard error", cib_retries); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } else { int call_id = 0; crm_info("CIB connection established"); call_id = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local); fsa_register_cib_callback(call_id, FALSE, NULL, revision_check_callback); cib_retries = 0; } } } /*! * \internal * \brief Get CIB call options to use local scope if master unavailable * * \return CIB call options */ int crmd_cib_smart_opt() { int call_opt = cib_quorum_override; if (fsa_state == S_ELECTION || fsa_state == S_PENDING) { crm_info("Sending update to local CIB in state: %s", fsa_state2string(fsa_state)); call_opt |= cib_scope_local; } return call_opt; } diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index d2fdf04f3a..92849d560a 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,112 +1,114 @@ /* * Copyright (C) 2015 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ALERT_INTERNAL_H #define ALERT_INTERNAL_H #include +#include /* Default-Timeout to use before killing a alerts script (in milliseconds) */ # define CRM_ALERT_DEFAULT_TIMEOUT_MS (30000) /* Default-Format-String used to pass timestamps to the alerts scripts */ # define CRM_ALERT_DEFAULT_TSTAMP_FORMAT "%H:%M:%S.%06N" typedef struct { char *name; char *value; } crm_alert_envvar_t; enum crm_alert_flags { crm_alert_none = 0x0000, crm_alert_node = 0x0001, crm_alert_fencing = 0x0002, crm_alert_resource = 0x0004, crm_alert_attribute = 0x0008, crm_alert_default = crm_alert_node|crm_alert_fencing|crm_alert_resource }; typedef struct { char *id; char *path; char *tstamp_format; char *recipient; char **select_attribute_name; GHashTable *envvars; int timeout; uint32_t flags; } crm_alert_entry_t; enum crm_alert_keys_e { CRM_alert_recipient = 0, CRM_alert_node, CRM_alert_nodeid, CRM_alert_rsc, CRM_alert_task, CRM_alert_interval, CRM_alert_desc, CRM_alert_status, CRM_alert_target_rc, CRM_alert_rc, CRM_alert_kind, CRM_alert_version, CRM_alert_node_sequence, CRM_alert_timestamp, CRM_alert_attribute_name, CRM_alert_attribute_value, CRM_alert_select_kind, CRM_alert_select_attribute_name }; #define CRM_ALERT_INTERNAL_KEY_MAX 16 #define CRM_ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" extern const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]; crm_alert_entry_t *crm_dup_alert_entry(crm_alert_entry_t *entry); crm_alert_envvar_t *crm_dup_alert_envvar(crm_alert_envvar_t *src); crm_alert_entry_t *crm_alert_entry_new(const char *id, const char *path); void crm_free_alert_entry(crm_alert_entry_t *entry); void crm_free_alert_envvar(crm_alert_envvar_t *entry); void crm_set_alert_key(enum crm_alert_keys_e name, const char *value); void crm_set_alert_key_int(enum crm_alert_keys_e name, int value); void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value); void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value); void crm_unset_alert_keys(void); void crm_set_envvar_list(crm_alert_entry_t *entry); void crm_unset_envvar_list(crm_alert_entry_t *entry); +bool crm_patchset_contains_alert(xmlNode *msg, bool config); static inline const char * crm_alert_flag2text(enum crm_alert_flags flag) { switch (flag) { case crm_alert_node: return "node"; case crm_alert_fencing: return "fencing"; case crm_alert_resource: return "resource"; case crm_alert_attribute: return "attribute"; default: return "unknown"; } } #endif diff --git a/lib/common/alerts.c b/lib/common/alerts.c index bf32c3be87..de3b241b80 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -1,232 +1,315 @@ /* * Copyright (C) 2015 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include +#include /* for F_CIB_UPDATE_RESULT */ /* * to allow script compatibility we can have more than one * set of environment variables */ const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3] = { [CRM_alert_recipient] = {"CRM_notify_recipient", "CRM_alert_recipient", NULL}, [CRM_alert_node] = {"CRM_notify_node", "CRM_alert_node", NULL}, [CRM_alert_nodeid] = {"CRM_notify_nodeid", "CRM_alert_nodeid", NULL}, [CRM_alert_rsc] = {"CRM_notify_rsc", "CRM_alert_rsc", NULL}, [CRM_alert_task] = {"CRM_notify_task", "CRM_alert_task", NULL}, [CRM_alert_interval] = {"CRM_notify_interval", "CRM_alert_interval", NULL}, [CRM_alert_desc] = {"CRM_notify_desc", "CRM_alert_desc", NULL}, [CRM_alert_status] = {"CRM_notify_status", "CRM_alert_status", NULL}, [CRM_alert_target_rc] = {"CRM_notify_target_rc", "CRM_alert_target_rc", NULL}, [CRM_alert_rc] = {"CRM_notify_rc", "CRM_alert_rc", NULL}, [CRM_alert_kind] = {"CRM_notify_kind", "CRM_alert_kind", NULL}, [CRM_alert_version] = {"CRM_notify_version", "CRM_alert_version", NULL}, [CRM_alert_node_sequence] = {"CRM_notify_node_sequence", CRM_ALERT_NODE_SEQUENCE, NULL}, [CRM_alert_timestamp] = {"CRM_notify_timestamp", "CRM_alert_timestamp", NULL}, [CRM_alert_attribute_name] = {"CRM_notify_attribute_name", "CRM_alert_attribute_name", NULL}, [CRM_alert_attribute_value] = {"CRM_notify_attribute_value", "CRM_alert_attribute_value", NULL} }; void crm_free_alert_envvar(crm_alert_envvar_t *entry) { free(entry->name); free(entry->value); free(entry); } /*! * \brief Create a new alert entry structure * * \param[in] id ID to use * \param[in] path Path to alert agent executable * * \return Pointer to newly allocated alert entry * \note Non-string fields will be filled in with defaults. * It is the caller's responsibility to free the result, * using crm_free_alert_entry(). */ crm_alert_entry_t * crm_alert_entry_new(const char *id, const char *path) { crm_alert_entry_t *entry = calloc(1, sizeof(crm_alert_entry_t)); CRM_ASSERT(entry && id && path); entry->id = strdup(id); entry->path = strdup(path); entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; entry->flags = crm_alert_default; return entry; } void crm_free_alert_entry(crm_alert_entry_t *entry) { free(entry->id); free(entry->path); free(entry->tstamp_format); free(entry->recipient); if(entry->select_attribute_name) { g_strfreev(entry->select_attribute_name); } if (entry->envvars) { g_hash_table_destroy(entry->envvars); } free(entry); } crm_alert_envvar_t * crm_dup_alert_envvar(crm_alert_envvar_t *src) { crm_alert_envvar_t *dst = calloc(1, sizeof(crm_alert_envvar_t)); CRM_ASSERT(dst); dst->name = strdup(src->name); dst->value = src->value?strdup(src->value):NULL; return dst; } /*! * \internal * \brief Duplicate an alert entry * * \param[in] entry Alert entry to duplicate * * \return Duplicate of alert entry */ crm_alert_entry_t * crm_dup_alert_entry(crm_alert_entry_t *entry) { crm_alert_entry_t *new_entry = crm_alert_entry_new(entry->id, entry->path); new_entry->timeout = entry->timeout; new_entry->flags = entry->flags; new_entry->envvars = crm_str_table_dup(entry->envvars); if (entry->tstamp_format) { new_entry->tstamp_format = strdup(entry->tstamp_format); } if (entry->recipient) { new_entry->recipient = strdup(entry->recipient); } if (entry->select_attribute_name) { new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name); } return new_entry; } void crm_set_alert_key(enum crm_alert_keys_e name, const char *value) { const char **key; for (key = crm_alert_keys[name]; *key; key++) { crm_trace("Setting alert key %s = '%s'", *key, value); if (value) { setenv(*key, value, 1); } else { unsetenv(*key); } } } void crm_set_alert_key_int(enum crm_alert_keys_e name, int value) { char *s = crm_itoa(value); crm_set_alert_key(name, s); free(s); } void crm_unset_alert_keys() { const char **key; enum crm_alert_keys_e name; for(name = 0; name < DIMOF(crm_alert_keys); name++) { for(key = crm_alert_keys[name]; *key; key++) { crm_trace("Unsetting alert key %s", *key); unsetenv(*key); } } } void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = '%s'", *key, value); if (value) { g_hash_table_insert(table, strdup(*key), strdup(value)); } else { g_hash_table_remove(table, *key); } } } void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = %d", *key, value); g_hash_table_insert(table, strdup(*key), crm_itoa(value)); } } static void set_envvar(gpointer key, gpointer value, gpointer user_data) { gboolean always_unset = GPOINTER_TO_INT(user_data); crm_trace("%s environment variable %s='%s'", (value? "Setting" : "Unsetting"), (char*)key, (value? (char*)value : "")); if (value && !always_unset) { setenv(key, value, 1); } else { unsetenv(key); } } void crm_set_envvar_list(crm_alert_entry_t *entry) { if (entry->envvars) { g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(FALSE)); } } /* * \note We have no way of restoring a previous value if one was set. */ void crm_unset_envvar_list(crm_alert_entry_t *entry) { if (entry->envvars) { g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(TRUE)); } } + +#define XPATH_PATCHSET1_DIFF "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED + +#define XPATH_PATCHSET1_CRMCONFIG XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_CRMCONFIG +#define XPATH_PATCHSET1_ALERTS XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_ALERTS + +#define XPATH_PATCHSET1_EITHER \ + XPATH_PATCHSET1_CRMCONFIG " | " XPATH_PATCHSET1_ALERTS + +#define XPATH_CONFIG "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION + +#define XPATH_CRMCONFIG XPATH_CONFIG "/" XML_CIB_TAG_CRMCONFIG "/" +#define XPATH_ALERTS XPATH_CONFIG "/" XML_CIB_TAG_ALERTS + +/*! + * \internal + * \brief Check whether a CIB update affects alerts + * + * \param[in] msg XML containing CIB update + * \param[in] config Whether to check for crmconfig change as well + * + * \return TRUE if update affects alerts, FALSE otherwise + */ +bool +crm_patchset_contains_alert(xmlNode *msg, bool config) +{ + int rc = -1; + int format= 1; + xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT); + xmlNode *change = NULL; + xmlXPathObject *xpathObj = NULL; + + CRM_CHECK(msg != NULL, return FALSE); + + crm_element_value_int(msg, F_CIB_RC, &rc); + if (rc < pcmk_ok) { + crm_trace("Ignore failed CIB update: %s (%d)", pcmk_strerror(rc), rc); + return FALSE; + } + + crm_element_value_int(patchset, "format", &format); + if (format == 1) { + const char *diff = (config? XPATH_PATCHSET1_EITHER : XPATH_PATCHSET1_ALERTS); + + if ((xpathObj = xpath_search(msg, diff)) != NULL) { + freeXpathObject(xpathObj); + return TRUE; + } + } else if (format == 2) { + for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) { + const char *xpath = crm_element_value(change, XML_DIFF_PATH); + + if (xpath == NULL) { + continue; + } + + if ((!config || !strstr(xpath, XPATH_CRMCONFIG)) + && !strstr(xpath, XPATH_ALERTS)) { + + /* this is not a change to an existing section ... */ + + xmlNode *section = NULL; + const char *name = NULL; + + if ((strcmp(xpath, XPATH_CONFIG) != 0) || + ((section = __xml_first_child(change)) == NULL) || + ((name = crm_element_name(section)) == NULL) || + (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { + + /* ... nor is it a newly added alerts section */ + continue; + } + } + + return TRUE; + } + + } else { + crm_warn("Unknown patch format: %d", format); + } + return FALSE; +}