diff --git a/lib/pengine/rules_alerts.c b/lib/pengine/rules_alerts.c index 409d2dfb04..44674957c6 100644 --- a/lib/pengine/rules_alerts.c +++ b/lib/pengine/rules_alerts.c @@ -1,283 +1,290 @@ /* * Copyright (C) 2015-2017 Andrew Beekhof * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #ifdef RHEL7_COMPAT /* @COMPAT An early implementation of alerts was backported to RHEL 7, * even though it was never in an upstream release. */ static char *notify_script = NULL; static char *notify_target = NULL; void pe_enable_legacy_alerts(const char *script, const char *target) { free(notify_script); notify_script = (script && strcmp(script, "/dev/null"))? strdup(script) : NULL; free(notify_target); notify_target = target? strdup(target): NULL; + + if (notify_script || notify_target) { + pe_warn_once(pe_wo_legacy_notifs, + "Support for 'notification-agent' and 'notification-target' cluster options" + " is deprecated and will be removed in a future release" + " (use alerts feature instead)"); + } } #endif static void get_meta_attrs_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, guint *max_timeout) { GHashTable *config_hash = crm_str_table_new(); crm_time_t *now = crm_time_new(NULL); const char *value = NULL; unpack_instance_attributes(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash, NULL, FALSE, now); crm_time_free(now); value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT); if (value) { entry->timeout = crm_get_msec(value); if (entry->timeout <= 0) { if (entry->timeout == 0) { crm_trace("Alert %s uses default timeout of %dmsec", entry->id, CRM_ALERT_DEFAULT_TIMEOUT_MS); } else { crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec", entry->id, (char*)value, CRM_ALERT_DEFAULT_TIMEOUT_MS); } entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; } else { crm_trace("Alert %s uses timeout of %dmsec", entry->id, entry->timeout); } if (entry->timeout > *max_timeout) { *max_timeout = entry->timeout; } } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT); if (value) { /* hard to do any checks here as merely anything can * can be a valid time-format-string */ entry->tstamp_format = strdup(value); crm_trace("Alert %s uses timestamp format '%s'", entry->id, entry->tstamp_format); } g_hash_table_destroy(config_hash); } static void get_envvars_from_cib(xmlNode *basenode, crm_alert_entry_t *entry) { xmlNode *child; if ((basenode == NULL) || (entry == NULL)) { return; } child = first_named_child(basenode, XML_TAG_ATTR_SETS); if (child == NULL) { return; } if (entry->envvars == NULL) { entry->envvars = crm_str_table_new(); } for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL; child = crm_next_same_xml(child)) { const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE); if (value == NULL) { value = ""; } g_hash_table_insert(entry->envvars, strdup(name), strdup(value)); crm_trace("Alert %s: added environment variable %s='%s'", entry->id, name, value); } } static void unpack_alert_filter(xmlNode *basenode, crm_alert_entry_t *entry) { xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT); xmlNode *event_type = NULL; uint32_t flags = crm_alert_none; for (event_type = __xml_first_child(select); event_type != NULL; event_type = __xml_next(event_type)) { const char *tagname = crm_element_name(event_type); if (tagname == NULL) { continue; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_FENCING)) { flags |= crm_alert_fencing; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) { flags |= crm_alert_node; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) { flags |= crm_alert_resource; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) { xmlNode *attr; const char *attr_name; int nattrs = 0; flags |= crm_alert_attribute; for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR); attr != NULL; attr = crm_next_same_xml(attr)) { attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME); if (attr_name) { if (nattrs == 0) { g_strfreev(entry->select_attribute_name); entry->select_attribute_name = NULL; } ++nattrs; entry->select_attribute_name = realloc_safe(entry->select_attribute_name, (nattrs + 1) * sizeof(char*)); entry->select_attribute_name[nattrs - 1] = strdup(attr_name); entry->select_attribute_name[nattrs] = NULL; } } } } if (flags != crm_alert_none) { entry->flags = flags; crm_debug("Alert %s receives events: attributes:%s, fencing:%s, nodes:%s, resources:%s", entry->id, (flags & crm_alert_attribute)? (entry->select_attribute_name? "some" : "all") : "no", (flags & crm_alert_fencing)? "yes" : "no", (flags & crm_alert_node)? "yes" : "no", (flags & crm_alert_resource)? "yes" : "no"); } } static void unpack_alert(xmlNode *alert, crm_alert_entry_t *entry, guint *max_timeout) { get_envvars_from_cib(alert, entry); get_meta_attrs_from_cib(alert, entry, max_timeout); unpack_alert_filter(alert, entry); } /*! * \internal * \brief Unpack a CIB alerts section * * \param[in] alerts XML of alerts section * * \return List of unpacked alert entries * * \note Unlike most unpack functions, this is not used by the pengine itself, * but is supplied for use by daemons that need to send alerts. */ GListPtr pe_unpack_alerts(xmlNode *alerts) { xmlNode *alert; crm_alert_entry_t *entry; guint max_timeout = 0; GListPtr alert_list = NULL; if (alerts) { #ifdef RHEL7_COMPAT if (notify_script) { crm_warn("Ignoring deprecated notification configuration because alerts available"); } #endif } else { #ifdef RHEL7_COMPAT if (notify_script) { entry = crm_alert_entry_new("legacy_notification", notify_script); entry->recipient = strdup(notify_target); entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT); alert_list = g_list_prepend(alert_list, entry); crm_warn("Deprecated notification syntax in use (alerts syntax is preferable)"); } #endif return alert_list; } for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT); alert != NULL; alert = crm_next_same_xml(alert)) { xmlNode *recipient; int recipients = 0; const char *alert_id = ID(alert); const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH); /* The schema should enforce this, but to be safe ... */ if ((alert_id == NULL) || (alert_path == NULL)) { crm_warn("Ignoring invalid alert without id and path"); continue; } entry = crm_alert_entry_new(alert_id, alert_path); unpack_alert(alert, entry, &max_timeout); if (entry->tstamp_format == NULL) { entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT); } crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars", entry->id, entry->path, entry->timeout, entry->tstamp_format, (entry->envvars? g_hash_table_size(entry->envvars) : 0)); for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT); recipient != NULL; recipient = crm_next_same_xml(recipient)) { crm_alert_entry_t *recipient_entry = crm_dup_alert_entry(entry); recipients++; recipient_entry->recipient = strdup(crm_element_value(recipient, XML_ALERT_ATTR_REC_VALUE)); unpack_alert(recipient, recipient_entry, &max_timeout); alert_list = g_list_prepend(alert_list, recipient_entry); crm_debug("Alert %s has recipient %s with value %s and %d envvars", entry->id, ID(recipient), recipient_entry->recipient, (recipient_entry->envvars? g_hash_table_size(recipient_entry->envvars) : 0)); } if (recipients == 0) { alert_list = g_list_prepend(alert_list, entry); } else { crm_free_alert_entry(entry); } } return alert_list; } /*! * \internal * \brief Free an alert list generated by pe_unpack_alerts() * * \param[in] alert_list Alert list to free */ void pe_free_alert_list(GListPtr alert_list) { if (alert_list) { g_list_free_full(alert_list, (GDestroyNotify) crm_free_alert_entry); } } diff --git a/lib/pengine/unpack.h b/lib/pengine/unpack.h index 963ec3c191..02600ddf3b 100644 --- a/lib/pengine/unpack.h +++ b/lib/pengine/unpack.h @@ -1,125 +1,126 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This library 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.1 of the License, or (at your option) any later version. * * This library 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 * Lesser 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 PENGINE_UNPACK__H # define PENGINE_UNPACK__H extern gboolean unpack_remote_nodes(xmlNode * xml_resources, pe_working_set_t * data_set); extern gboolean unpack_resources(xmlNode * xml_resources, pe_working_set_t * data_set); extern gboolean unpack_config(xmlNode * config, pe_working_set_t * data_set); extern gboolean unpack_nodes(xmlNode * xml_nodes, pe_working_set_t * data_set); extern gboolean unpack_tags(xmlNode * xml_tags, pe_working_set_t * data_set); extern gboolean unpack_status(xmlNode * status, pe_working_set_t * data_set); extern gboolean unpack_remote_status(xmlNode * status, pe_working_set_t * data_set); extern gint sort_op_by_callid(gconstpointer a, gconstpointer b); extern gboolean unpack_lrm_resources(node_t * node, xmlNode * lrm_state, pe_working_set_t * data_set); extern gboolean add_node_attrs(xmlNode * attrs, node_t * node, gboolean overwrite, pe_working_set_t * data_set); extern gboolean determine_online_status(xmlNode * node_state, node_t * this_node, pe_working_set_t * data_set); /* * The man pages for both curses and ncurses suggest inclusion of "curses.h". * We believe the following to be acceptable and portable. */ # if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES) # if defined(HAVE_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_NCURSES_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_CURSES_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # else # define CURSES_ENABLED 0 # endif # else # define CURSES_ENABLED 0 # endif # if CURSES_ENABLED # define status_printw(fmt, args...) printw(fmt, ##args) # else # define status_printw(fmt, args...) \ crm_err("printw support requires ncurses to be available during configure"); \ do_crm_log(LOG_WARNING, fmt, ##args); # endif # define status_print(fmt, args...) \ if(options & pe_print_html) { \ FILE *stream = print_data; \ fprintf(stream, fmt, ##args); \ } else if(options & pe_print_ncurses) { \ status_printw(fmt, ##args); \ } else if(options & pe_print_printf) { \ FILE *stream = print_data; \ fprintf(stream, fmt, ##args); \ } else if(options & pe_print_xml) { \ FILE *stream = print_data; \ fprintf(stream, fmt, ##args); \ } else if(options & pe_print_log) { \ int log_level = *(int*)print_data; \ do_crm_log(log_level, fmt, ##args); \ } // Some warnings we don't want to print every transition enum pe_warn_once_e { pe_wo_blind = 0x0001, pe_wo_poweroff = 0x0002, pe_wo_arg_map = 0x0004, pe_wo_stonith_cmd = 0x0008, pe_wo_requires = 0x0010, pe_wo_isolation = 0x0020, pe_wo_default_stick = 0x0040, pe_wo_default_isman = 0x0080, pe_wo_default_timeo = 0x0100, pe_wo_rsc_failstick = 0x0200, pe_wo_default_rscfs = 0x0400, + pe_wo_legacy_notifs = 0x0800, }; extern uint32_t pe_wo; #define pe_warn_once(pe_wo_bit, fmt...) do { \ if (is_not_set(pe_wo, pe_wo_bit)) { \ if (pe_wo_bit == pe_wo_blind) { \ crm_warn(fmt); \ } else { \ pe_warn(fmt); \ } \ set_bit(pe_wo, pe_wo_bit); \ } \ } while (0); #endif