diff --git a/attrd/attrd_alerts.c b/attrd/attrd_alerts.c index c8af726dfc..a527d25cdf 100644 --- a/attrd/attrd_alerts.c +++ b/attrd/attrd_alerts.c @@ -1,348 +1,342 @@ /* * 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; lrmd_t * attrd_lrmd_connect(int max_retry, void callback(lrmd_event_data_t * op)) { int ret = -ENOTCONN; int fails = 0; if (!the_lrmd) { the_lrmd = lrmd_api_new(); } while(fails < max_retry) { the_lrmd->cmds->set_callback(the_lrmd, callback); ret = the_lrmd->cmds->connect(the_lrmd, T_ATTRD, NULL); if (ret != pcmk_ok) { fails++; crm_trace("lrmd_connect RETRY!(%d)", fails); } else { crm_trace("lrmd_connect OK!"); break; } } if (ret != pcmk_ok) { if (the_lrmd->cmds->is_connected(the_lrmd)) { lrmd_api_delete(the_lrmd); } the_lrmd = NULL; } return the_lrmd; } static void config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { crm_time_t *now = crm_time_new(NULL); xmlNode *crmalerts = NULL; if (rc != pcmk_ok) { crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc)); goto bail; } crmalerts = output; if ((crmalerts) && (crm_element_name(crmalerts)) && (strcmp(crm_element_name(crmalerts), XML_CIB_TAG_ALERTS) != 0)) { crmalerts = first_named_child(crmalerts, XML_CIB_TAG_ALERTS); } if (!crmalerts) { crm_err("Local CIB query for " XML_CIB_TAG_ALERTS " section failed"); goto bail; } pe_free_alert_list(attrd_alert_list); attrd_alert_list = pe_unpack_alerts(crmalerts); bail: crm_time_free(now); } 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; } 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; } /* modifying properties */ if (!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(attrd_config_read); break; } } else { crm_warn("Unknown patch format: %d", format); } } -void -attrd_alert_fini() -{ - if (crm_alert_kind_default) { - g_strfreev(crm_alert_kind_default); - crm_alert_kind_default = NULL; - } -} - static int -exec_alerts(lrmd_t *lrmd, const char *kind, const char *attribute_name, +exec_alerts(lrmd_t *lrmd, enum crm_alert_flags kind, const char *attribute_name, lrmd_key_value_t *params) { int rc = pcmk_ok; GListPtr l; crm_time_hr_t *now = crm_time_hr_new(NULL); - params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_kind, kind); + params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_kind, + crm_alert_flag2text(kind)); params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_version, VERSION); for (l = g_list_first(attrd_alert_list); l; l = g_list_next(l)) { crm_alert_entry_t *entry = (crm_alert_entry_t *)(l->data); - char *timestamp = crm_time_format_hr(entry->tstamp_format, now); + char *timestamp; lrmd_key_value_t * copy_params = NULL; lrmd_key_value_t *head, *p; - if (crm_is_target_alert(entry->select_kind == NULL ? crm_alert_kind_default : entry->select_kind, kind) == FALSE) { - crm_trace("Cannot sending '%s' alert to '%s' via '%s'(select_kind=%s)", kind, entry->recipient, entry->path, - entry->select_kind == NULL ? CRM_ALERT_KIND_DEFAULT : entry->select_kind_orig); - free(timestamp); + if (is_not_set(entry->flags, kind)) { + crm_trace("Filtering unwanted %s alert to %s via %s", + crm_alert_flag2text(kind), entry->recipient, entry->id); continue; } - if (crm_is_target_alert(entry->select_attribute_name, attribute_name) == FALSE) { - crm_trace("Cannot sending '%s' alert to '%s' via '%s'(select_attribute_name=%s attribute_name=%s)", kind, entry->recipient, entry->path, - entry->select_attribute_name_orig, attribute_name); - free(timestamp); + if ((kind == crm_alert_attribute) + && !crm_is_target_alert(entry->select_attribute_name, attribute_name)) { + + crm_trace("Filtering unwanted attribute '%s' alert to %s via %s", + attribute_name, entry->recipient, entry->id); continue; } crm_info("Sending %s alert to %s via %s", - kind, entry->recipient, entry->id); + crm_alert_flag2text(kind), entry->recipient, entry->id); /* Because there is a parameter to turn into every transmission, Copy a parameter. */ head = params; while (head) { p = head->next; copy_params = lrmd_key_value_add(copy_params, head->key, head->value); head = p; } + timestamp = crm_time_format_hr(entry->tstamp_format, now); + copy_params = lrmd_key_value_add(copy_params, CRM_ALERT_KEY_PATH, entry->path); copy_params = lrmd_set_alert_key_to_lrmd_params(copy_params, CRM_alert_recipient, entry->recipient); copy_params = lrmd_set_alert_key_to_lrmd_params(copy_params, CRM_alert_timestamp, timestamp); lrmd_set_alert_envvar_to_lrmd_params(copy_params, entry); rc = lrmd->cmds->exec_alert(lrmd, entry->id, entry->path, entry->timeout, lrmd_opt_notify_orig_only, copy_params); if (rc < 0) { crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d", entry->id, pcmk_strerror(rc), rc); } free(timestamp); } if (now) { free(now); } return rc; } static void attrd_alert_lrm_op_callback(lrmd_event_data_t * op) { CRM_CHECK(op != NULL, return); if (op->type == lrmd_event_disconnect) { crm_info("Lost connection to LRMD service!"); if (the_lrmd->cmds->is_connected(the_lrmd)) { the_lrmd->cmds->disconnect(the_lrmd); lrmd_api_delete(the_lrmd); } the_lrmd = NULL; return; } else if (op->type != lrmd_event_exec_complete) { return; } if (op->params != NULL) { void *value_tmp1, *value_tmp2; value_tmp1 = g_hash_table_lookup(op->params, CRM_ALERT_KEY_PATH); if (value_tmp1 != NULL) { value_tmp2 = g_hash_table_lookup(op->params, CRM_ALERT_NODE_SEQUENCE); if(op->rc == 0) { crm_info("Alert %s (%s) complete", value_tmp2, value_tmp1); } else { crm_warn("Alert %s (%s) failed: %d", value_tmp2, value_tmp1, op->rc); } } } } int attrd_send_alerts(lrmd_t *lrmd, const char *node, uint32_t nodeid, const char *attribute_name, const char *attribute_value) { int ret = pcmk_ok; lrmd_key_value_t *params = NULL; if (lrmd == NULL) { lrmd = attrd_lrmd_connect(10, attrd_alert_lrm_op_callback); if (lrmd == NULL) { crm_warn("LRMD connection not active"); return ret; } } crm_trace("LRMD connection active"); params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_node, node); params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_nodeid, crm_itoa(nodeid)); params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_attribute_name, attribute_name); params = lrmd_set_alert_key_to_lrmd_params(params, CRM_alert_attribute_value, attribute_value == NULL ? "null" : attribute_value); - ret = exec_alerts(lrmd, "attribute", attribute_name, params); + ret = exec_alerts(lrmd, crm_alert_attribute, attribute_name, params); crm_trace("ret : %d, node : %s, nodeid: %s, name: %s, value : %s", ret, node, crm_itoa(nodeid), attribute_name, attribute_value); if (params) { lrmd_key_value_freeall(params); } return ret; } #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 call_id = 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)) { call_id = attrd_send_alerts(the_lrmd, at->nodename, at->nodeid, a->id, at->current); crm_trace("call_id : %d, nodename : %s, nodeid: %d, name: %s, value : %s", call_id, at->nodename, at->nodeid, a->id, at->current); } } #endif diff --git a/attrd/attrd_alerts.h b/attrd/attrd_alerts.h index 2879b0e8f1..99c2952d24 100644 --- a/attrd/attrd_alerts.h +++ b/attrd/attrd_alerts.h @@ -1,42 +1,41 @@ /* * 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 ATTRD_ALERT__H # define ATTRD_ALERT__H # include # include # include extern cib_t *the_cib; extern lrmd_t *the_lrmd; extern crm_trigger_t *attrd_config_read; lrmd_t *attrd_lrmd_connect(int max_retry, void callback(lrmd_event_data_t * op)); gboolean attrd_read_options(gpointer user_data); void attrd_cib_updated_cb(const char *event, xmlNode * msg); void attrd_enable_alerts(const char *script, const char *target); -void attrd_alert_fini(void); int attrd_send_alerts(lrmd_t *lrmd, const char *node, uint32_t nodeid, const char *attribute_name, const char *attribute_value); #if HAVE_ATOMIC_ATTRD void set_alert_attribute_value(GHashTable *t, attribute_value_t *v); void send_alert_attributes_value(attribute_t *a, GHashTable *t); #endif #endif diff --git a/attrd/main.c b/attrd/main.c index d61826d67a..ff132f0238 100644 --- a/attrd/main.c +++ b/attrd/main.c @@ -1,364 +1,362 @@ /* * Copyright (C) 2013 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "attrd_alerts.h" cib_t *the_cib = NULL; lrmd_t *the_lrmd = NULL; crm_cluster_t *attrd_cluster = NULL; election_t *writer = NULL; int attrd_error = pcmk_ok; crm_trigger_t *attrd_config_read = NULL; static void attrd_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *groupName, uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { uint32_t kind = 0; xmlNode *xml = NULL; const char *from = NULL; char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from); if(data == NULL) { return; } if (kind == crm_class_cluster) { xml = string2xml(data); } if (xml == NULL) { crm_err("Bad message of class %d received from %s[%u]: '%.120s'", kind, from, nodeid, data); } else { crm_node_t *peer = crm_get_peer(nodeid, from); attrd_peer_message(peer, xml); } free_xml(xml); free(data); } static void attrd_cpg_destroy(gpointer unused) { if (attrd_shutting_down()) { crm_info("Corosync disconnection complete"); } else { crm_crit("Lost connection to Corosync service!"); attrd_error = ECONNRESET; attrd_shutdown(0); } } static void attrd_cib_replaced_cb(const char *event, xmlNode * msg) { crm_notice("Updating all attributes after %s event", event); if(election_state(writer) == election_won) { write_attributes(TRUE, FALSE); } } 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_err("Lost connection to CIB service!"); attrd_error = ECONNRESET; attrd_shutdown(0); } return; } static cib_t * attrd_cib_connect(int max_retry) { int rc = -ENOTCONN; static int attempts = 0; cib_t *connection = cib_new(); if(connection == NULL) { return NULL; } do { if(attempts > 0) { sleep(attempts); } attempts++; crm_debug("CIB signon attempt %d", attempts); rc = connection->cmds->signon(connection, T_ATTRD, cib_command); } while(rc != pcmk_ok && attempts < max_retry); if (rc != pcmk_ok) { crm_err("Signon to CIB failed: %s (%d)", pcmk_strerror(rc), rc); goto cleanup; } crm_info("Connected to the CIB after %d attempts", attempts); rc = connection->cmds->set_connection_dnotify(connection, attrd_cib_destroy_cb); if (rc != pcmk_ok) { crm_err("Could not set disconnection callback"); goto cleanup; } rc = connection->cmds->add_notify_callback(connection, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb); if(rc != pcmk_ok) { crm_err("Could not set CIB notification callback"); goto cleanup; } rc = connection->cmds->add_notify_callback(connection, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb); if (rc != pcmk_ok) { crm_err("Could not set CIB notification callback (update)"); goto cleanup; } return connection; cleanup: connection->cmds->signoff(connection); cib_delete(connection); return NULL; } static int32_t attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size) { uint32_t id = 0; uint32_t flags = 0; crm_client_t *client = crm_client_get(c); xmlNode *xml = crm_ipcs_recv(client, data, size, &id, &flags); const char *op; if (xml == NULL) { crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c); return 0; } #if ENABLE_ACL CRM_ASSERT(client->user != NULL); crm_acl_get_set_user(xml, F_ATTRD_USER, client->user); #endif crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c); crm_log_xml_trace(xml, __FUNCTION__); op = crm_element_value(xml, F_ATTRD_TASK); if (client->name == NULL) { const char *value = crm_element_value(xml, F_ORIG); client->name = crm_strdup_printf("%s.%d", value?value:"unknown", client->pid); } if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) { attrd_send_ack(client, id, flags); attrd_client_peer_remove(client->name, xml); } else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) { attrd_send_ack(client, id, flags); attrd_client_clear_failure(xml); } else if (safe_str_eq(op, ATTRD_OP_UPDATE)) { attrd_send_ack(client, id, flags); attrd_client_update(xml); } else if (safe_str_eq(op, ATTRD_OP_UPDATE_BOTH)) { attrd_send_ack(client, id, flags); attrd_client_update(xml); } else if (safe_str_eq(op, ATTRD_OP_UPDATE_DELAY)) { attrd_send_ack(client, id, flags); attrd_client_update(xml); } else if (safe_str_eq(op, ATTRD_OP_REFRESH)) { attrd_send_ack(client, id, flags); attrd_client_refresh(); } else if (safe_str_eq(op, ATTRD_OP_QUERY)) { /* queries will get reply, so no ack is necessary */ attrd_client_query(client, id, flags, xml); } else { crm_info("Ignoring request from client %s with unknown operation %s", client->name, op); } free_xml(xml); return 0; } /* *INDENT-OFF* */ static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\tThis text"}, {"verbose", 0, 0, 'V', "\tIncrease debug output"}, {0, 0, 0, 0} }; /* *INDENT-ON* */ int main(int argc, char **argv) { int rc = pcmk_ok; int flag = 0; int index = 0; int argerr = 0; qb_ipcs_service_t *ipcs = NULL; attrd_init_mainloop(); crm_log_preinit(NULL, argc, argv); crm_set_options(NULL, "[options]", long_options, "Daemon for aggregating and atomically storing node attribute updates into the CIB"); mainloop_add_signal(SIGTERM, attrd_shutdown); while (1) { flag = crm_get_option(argc, argv, &index); if (flag == -1) break; switch (flag) { case 'V': crm_bump_log_level(argc, argv); break; case 'h': /* Help message */ crm_help(flag, EX_OK); break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', EX_USAGE); } crm_log_init(T_ATTRD, LOG_INFO, TRUE, FALSE, argc, argv, FALSE); crm_info("Starting up"); attributes = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_attribute); attrd_cluster = malloc(sizeof(crm_cluster_t)); attrd_cluster->destroy = attrd_cpg_destroy; attrd_cluster->cpg.cpg_deliver_fn = attrd_cpg_dispatch; attrd_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership; crm_set_status_callback(&attrd_peer_change_cb); if (crm_cluster_connect(attrd_cluster) == FALSE) { crm_err("Cluster connection failed"); rc = DAEMON_RESPAWN_STOP; goto done; } crm_info("Cluster connection active"); writer = election_init(T_ATTRD, attrd_cluster->uname, 120000, attrd_election_cb); attrd_init_ipc(&ipcs, attrd_ipc_dispatch); crm_info("Accepting attribute updates"); the_cib = attrd_cib_connect(10); if (the_cib == NULL) { rc = DAEMON_RESPAWN_STOP; goto done; } crm_info("CIB connection active"); attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL); /* Reading of cib(Alert section) after the start */ mainloop_set_trigger(attrd_config_read); attrd_run_mainloop(); done: crm_info("Shutting down attribute manager"); election_fini(writer); if (ipcs) { crm_client_disconnect_all(ipcs); qb_ipcs_destroy(ipcs); g_hash_table_destroy(attributes); } - attrd_alert_fini(); - if (the_lrmd) { the_lrmd->cmds->disconnect(the_lrmd); lrmd_api_delete(the_lrmd); the_lrmd = NULL; } if (the_cib) { the_cib->cmds->signoff(the_cib); cib_delete(the_cib); } if(attrd_error) { return crm_exit(attrd_error); } return crm_exit(rc); } diff --git a/crmd/crmd_alerts.c b/crmd/crmd_alerts.c index b185179398..7be982663f 100644 --- a/crmd/crmd_alerts.c +++ b/crmd/crmd_alerts.c @@ -1,226 +1,220 @@ /* * 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 "crmd_alerts.h" #include "crmd_messages.h" #include #include #include static GListPtr crmd_alert_list = NULL; static int alerts_inflight = 0; static gboolean draining_alerts = FALSE; void crmd_unpack_alerts(xmlNode *alerts) { pe_free_alert_list(crmd_alert_list); crmd_alert_list = pe_unpack_alerts(alerts); } static void crmd_alert_complete(svc_action_t *op) { alerts_inflight--; if(op->rc == 0) { crm_info("Alert %d (%s) complete", op->sequence, op->agent); } else { crm_warn("Alert %d (%s) failed: %d", op->sequence, op->agent, op->rc); } } static void -send_alerts(const char *kind) +send_alerts(enum crm_alert_flags kind) { svc_action_t *alert = NULL; static int operations = 0; GListPtr l; crm_time_hr_t *now = crm_time_hr_new(NULL); - crm_set_alert_key(CRM_alert_kind, kind); + crm_set_alert_key(CRM_alert_kind, crm_alert_flag2text(kind)); crm_set_alert_key(CRM_alert_version, VERSION); for (l = g_list_first(crmd_alert_list); l; l = g_list_next(l)) { crm_alert_entry_t *entry = (crm_alert_entry_t *)(l->data); - char *timestamp = crm_time_format_hr(entry->tstamp_format, now); + char *timestamp; - if (crm_is_target_alert(entry->select_kind == NULL ? crm_alert_kind_default : entry->select_kind, kind) == FALSE) { - crm_trace("Cannot sending '%s' alert to '%s' via '%s'(select_kind=%s)", kind, entry->recipient, entry->path, - entry->select_kind == NULL ? CRM_ALERT_KIND_DEFAULT : entry->select_kind_orig); - free(timestamp); + if (is_not_set(entry->flags, kind)) { + crm_trace("Filtering unwanted %s alert to %s via %s", + crm_alert_flag2text(kind), entry->recipient, entry->id); continue; } operations++; + timestamp = crm_time_format_hr(entry->tstamp_format, now); if (!draining_alerts) { - crm_debug("Sending '%s' alert to '%s' via '%s'", kind, - entry->recipient, entry->path); + crm_debug("Sending %s alert to %s via %s", + crm_alert_flag2text(kind), entry->recipient, entry->id); crm_set_alert_key(CRM_alert_recipient, entry->recipient); crm_set_alert_key_int(CRM_alert_node_sequence, operations); crm_set_alert_key(CRM_alert_timestamp, timestamp); alert = services_action_create_generic(entry->path, NULL); alert->timeout = entry->timeout; alert->standard = strdup("event"); alert->id = strdup(entry->id); alert->agent = strdup(entry->path); alert->sequence = operations; crm_set_envvar_list(entry); alerts_inflight++; if(services_action_async(alert, &crmd_alert_complete) == FALSE) { services_action_free(alert); alerts_inflight--; } crm_unset_envvar_list(entry); } else { - crm_warn("Ignoring '%s' alert to '%s' via '%s' received " - "while shutting down", - kind, entry->recipient, entry->path); + crm_warn("Ignoring %s alert to %s via %s received while shutting down", + crm_alert_flag2text(kind), entry->recipient, entry->id); } free(timestamp); } crm_unset_alert_keys(); if (now) { free(now); } } void crmd_alert_node_event(crm_node_t *node) { if (crmd_alert_list == NULL) { return; } crm_set_alert_key(CRM_alert_node, node->uname); crm_set_alert_key_int(CRM_alert_nodeid, node->id); crm_set_alert_key(CRM_alert_desc, node->state); - send_alerts("node"); + send_alerts(crm_alert_node); } void crmd_alert_fencing_op(stonith_event_t * e) { char *desc = NULL; if (crmd_alert_list == NULL) { return; } desc = crm_strdup_printf( "Operation %s of %s by %s for %s@%s: %s (ref=%s)", e->action, e->target, e->executioner ? e->executioner : "", e->client_origin, e->origin, pcmk_strerror(e->result), e->id); crm_set_alert_key(CRM_alert_node, e->target); crm_set_alert_key(CRM_alert_task, e->operation); crm_set_alert_key(CRM_alert_desc, desc); crm_set_alert_key_int(CRM_alert_rc, e->result); - send_alerts("fencing"); + send_alerts(crm_alert_fencing); free(desc); } void crmd_alert_resource_op(const char *node, lrmd_event_data_t * op) { int target_rc = 0; if (crmd_alert_list == NULL) { return; } target_rc = rsc_op_expected_rc(op); if(op->interval == 0 && target_rc == op->rc && safe_str_eq(op->op_type, RSC_STATUS)) { /* Leave it up to the script if they want to alert for * 'failed' probes, only swallow ones for which the result was * unexpected. * * Even if we find a resource running, it was probably because * someone erased the status section. */ return; } crm_set_alert_key(CRM_alert_node, node); crm_set_alert_key(CRM_alert_rsc, op->rsc_id); crm_set_alert_key(CRM_alert_task, op->op_type); crm_set_alert_key_int(CRM_alert_interval, op->interval); crm_set_alert_key_int(CRM_alert_target_rc, target_rc); crm_set_alert_key_int(CRM_alert_status, op->op_status); crm_set_alert_key_int(CRM_alert_rc, op->rc); if(op->op_status == PCMK_LRM_OP_DONE) { crm_set_alert_key(CRM_alert_desc, services_ocf_exitcode_str(op->rc)); } else { crm_set_alert_key(CRM_alert_desc, services_lrm_status_str(op->op_status)); } - send_alerts("resource"); + send_alerts(crm_alert_resource); } static gboolean alert_drain_timeout_callback(gpointer user_data) { gboolean *timeout_popped = (gboolean *) user_data; *timeout_popped = TRUE; return FALSE; } void crmd_drain_alerts(GMainContext *ctx) { guint timer; gboolean timeout_popped = FALSE; draining_alerts = TRUE; timer = g_timeout_add(crm_alert_max_alert_timeout + 5000, alert_drain_timeout_callback, (gpointer) &timeout_popped); while(alerts_inflight && !timeout_popped) { crm_trace("Draining mainloop while still %d alerts are in flight (timeout=%dms)", alerts_inflight, crm_alert_max_alert_timeout + 5000); g_main_context_iteration(ctx, TRUE); } if (!timeout_popped && (timer > 0)) { g_source_remove(timer); } - - if (crm_alert_kind_default) { - g_strfreev(crm_alert_kind_default); - crm_alert_kind_default = NULL; - } } diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index f675fe1225..c3c39c2375 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,90 +1,112 @@ /* * 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 /* 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; - int timeout; char *tstamp_format; char *recipient; - char *select_kind_orig; - char **select_kind; - char *select_attribute_name_orig; char **select_attribute_name; GListPtr 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_KEY_PATH "CRM_alert_path" #define CRM_ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" -#define CRM_ALERT_KIND_DEFAULT "node,fencing,resource" extern guint crm_alert_max_alert_timeout; extern const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]; -extern char **crm_alert_kind_default; 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); 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); gboolean crm_is_target_alert(char **list, const char *value); +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 af9d17858c..44130c2071 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -1,268 +1,259 @@ /* * 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 guint crm_alert_max_alert_timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; -char **crm_alert_kind_default = NULL; /* * 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); } void crm_free_alert_entry(crm_alert_entry_t *entry) { free(entry->id); free(entry->path); free(entry->tstamp_format); free(entry->recipient); - free(entry->select_kind_orig); - if (entry->select_kind) { - g_strfreev(entry->select_kind); - } - - free(entry->select_attribute_name_orig); if(entry->select_attribute_name) { g_strfreev(entry->select_attribute_name); } if (entry->envvars) { g_list_free_full(entry->envvars, (GDestroyNotify) crm_free_alert_envvar); } 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; } static GListPtr copy_envvar_list_remove_dupes(crm_alert_entry_t *entry) { GListPtr dst = NULL, ls, ld; /* we are adding to the front so variable dupes coming via * recipient-section have got precedence over those in the * global section - we don't expect that many variables here * that it pays off to go for a hash-table to make dupe elimination * more efficient - maybe later when we might decide to do more * with the variables than cycling through them */ for (ls = g_list_first(entry->envvars); ls; ls = g_list_next(ls)) { for (ld = g_list_first(dst); ld; ld = g_list_next(ld)) { if (!strcmp(((crm_alert_envvar_t *)(ls->data))->name, ((crm_alert_envvar_t *)(ld->data))->name)) { break; } } if (!ld) { dst = g_list_prepend(dst, crm_dup_alert_envvar((crm_alert_envvar_t *)(ls->data))); } } 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_t *) calloc(1, sizeof(crm_alert_entry_t)); CRM_ASSERT(new_entry); *new_entry = (crm_alert_entry_t) { .id = strdup(entry->id), .path = strdup(entry->path), .timeout = entry->timeout, .tstamp_format = entry->tstamp_format?strdup(entry->tstamp_format):NULL, .recipient = entry->recipient?strdup(entry->recipient):NULL, - .select_kind_orig = entry->select_kind_orig?g_strdup(entry->select_kind_orig):NULL, - .select_kind = entry->select_kind?g_strdupv(entry->select_kind):NULL, - .select_attribute_name_orig = entry->select_attribute_name_orig?g_strdup(entry->select_attribute_name_orig):NULL, + .flags = entry->flags, .select_attribute_name = entry->select_attribute_name?g_strdupv(entry->select_attribute_name):NULL, .envvars = entry->envvars? copy_envvar_list_remove_dupes(entry) :NULL }; 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)); } } void crm_set_envvar_list(crm_alert_entry_t *entry) { GListPtr l; for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { crm_alert_envvar_t *env = (crm_alert_envvar_t *)(l->data); crm_trace("Setting environment variable %s = '%s'", env->name, env->value?env->value:""); if (env->value) { setenv(env->name, env->value, 1); } else { unsetenv(env->name); } } } void crm_unset_envvar_list(crm_alert_entry_t *entry) { GListPtr l; for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { crm_alert_envvar_t *env = (crm_alert_envvar_t *)(l->data); crm_trace("Unsetting environment variable %s", env->name); unsetenv(env->name); } } gboolean crm_is_target_alert(char **list, const char *value) { int target_list_num = 0; gboolean rc = FALSE; if (list == NULL) return TRUE; target_list_num = g_strv_length(list); for( int cnt = 0; cnt < target_list_num; cnt++ ) { if (strcmp(list[cnt], value) == 0) { rc = TRUE; break; } } return rc; } diff --git a/lib/pengine/rules_alerts.c b/lib/pengine/rules_alerts.c index edbf01e15f..be29a3d937 100644 --- a/lib/pengine/rules_alerts.c +++ b/lib/pengine/rules_alerts.c @@ -1,272 +1,287 @@ /* * 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; } #endif static GHashTable * get_meta_attrs_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, guint *max_timeout) { GHashTable *config_hash = g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); 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); 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("Setting timeout to default %dmsec", CRM_ALERT_DEFAULT_TIMEOUT_MS); } else { crm_warn("Invalid timeout value setting to default %dmsec", CRM_ALERT_DEFAULT_TIMEOUT_MS); } entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; } else { crm_trace("Found timeout %dmsec", 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 = (char *) value; crm_trace("Found timestamp format string '%s'", value); } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_SELECT_KIND); if (value) { - entry->select_kind_orig = (char *) value; - entry->select_kind = g_strsplit((char *) value, ",", 0); - crm_trace("Found select_kind string '%s'", (char *) value); + int n = 0; + uint32_t flags = crm_alert_none; + + crm_debug("Alert %s has event filter: %s", entry->id, value); + while (*value != 0) { + while (*value == ',') { + ++value; + } + n = 0; + while ((value[n] != ',') && (value[n] != 0)) { + ++n; + } + if (!strncmp(value, "node", n)) { + flags |= crm_alert_node; + } else if (!strncmp(value, "fencing", n)) { + flags |= crm_alert_fencing; + } else if (!strncmp(value, "resource", n)) { + flags |= crm_alert_resource; + } else if (!strncmp(value, "attribute", n)) { + flags |= crm_alert_attribute; + } else { + crm_warn("Unrecognized alert type '%s' for %s", value, entry->id); + } + value += n; + } + if (flags) { + entry->flags = flags; + } } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_SELECT_ATTRIBUTE_NAME); if (value) { - entry->select_attribute_name_orig = (char*) value; + crm_debug("Alert %s has attribute filter: %s", entry->id, value); entry->select_attribute_name = g_strsplit((char*) value, ",", 0); crm_trace("Found attribute_name string '%s'", (char *) value); } crm_time_free(now); return config_hash; /* keep hash as long as strings are needed */ } static void drop_envvars(crm_alert_entry_t *entry, int count) { int i; for (i = 0; entry->envvars && ((count < 0) || (i < count)); i++) { GListPtr first = g_list_first(entry->envvars); crm_free_alert_envvar((crm_alert_envvar_t *) first->data); entry->envvars = g_list_delete_link(entry->envvars, first); } } static GListPtr get_envvars_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, int *count) { xmlNode *child; if (basenode == NULL) { return entry->envvars; } child = first_named_child(basenode, XML_TAG_ATTR_SETS); if (child == NULL) { return entry->envvars; } for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL; child = __xml_next(child)) { crm_alert_envvar_t envvar_entry = (crm_alert_envvar_t) { .name = (char *) crm_element_value(child, XML_NVPAIR_ATTR_NAME), .value = (char *) crm_element_value(child, XML_NVPAIR_ATTR_VALUE) }; crm_trace("Found environment variable %s = '%s'", envvar_entry.name, (envvar_entry.value? envvar_entry.value : "")); (*count)++; entry->envvars = g_list_prepend(entry->envvars, crm_dup_alert_envvar(&envvar_entry)); } return entry->envvars; } /*! * \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; crm_alert_max_alert_timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; - if (crm_alert_kind_default == NULL) { - crm_alert_kind_default = g_strsplit(CRM_ALERT_KIND_DEFAULT, ",", 0); - } 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_t) { .id = (char *) "legacy_notification", .path = notify_script, .timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS, .recipient = notify_target, - .select_kind_orig = NULL, - .select_kind = NULL, - .select_attribute_name_orig = NULL, + .flags = crm_alert_default, .select_attribute_name = NULL }; alert_list = g_list_prepend(alert_list, crm_dup_alert_entry(&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; alert = __xml_next(alert)) { xmlNode *recipient; int recipients = 0, envvars = 0; GHashTable *config_hash = NULL; entry = (crm_alert_entry_t) { .id = (char *) crm_element_value(alert, XML_ATTR_ID), .path = (char *) crm_element_value(alert, XML_ALERT_ATTR_PATH), .timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS, .tstamp_format = (char *) CRM_ALERT_DEFAULT_TSTAMP_FORMAT, - .select_kind_orig = NULL, - .select_kind = NULL, - .select_attribute_name_orig = NULL, + .flags = crm_alert_default, .select_attribute_name = NULL }; get_envvars_from_cib(alert, &entry, &envvars); config_hash = get_meta_attrs_from_cib(alert, &entry, &max_timeout); - crm_debug("Found alert %s with path=%s timeout=%d tstamp_format=%s " - "select_kind=%s select_attribute_name=%s " - "%d additional environment variables", + crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %d vars", entry.id, entry.path, entry.timeout, entry.tstamp_format, - entry.select_kind_orig, entry.select_attribute_name_orig, envvars); for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT); recipient != NULL; recipient = __xml_next(recipient)) { int envvars_added = 0; entry.recipient = (char *) crm_element_value(recipient, XML_ALERT_ATTR_REC_VALUE); recipients++; get_envvars_from_cib(recipient, &entry, &envvars_added); { crm_alert_entry_t recipient_entry = entry; GHashTable *config_hash = get_meta_attrs_from_cib(recipient, &recipient_entry, &max_timeout); alert_list = g_list_prepend(alert_list, crm_dup_alert_entry(&recipient_entry)); crm_debug("Alert has recipient: id=%s, value=%s, " "%d additional environment variables", crm_element_value(recipient, XML_ATTR_ID), recipient_entry.recipient, envvars_added); g_hash_table_destroy(config_hash); } drop_envvars(&entry, envvars_added); } if (recipients == 0) { alert_list = g_list_prepend(alert_list, crm_dup_alert_entry(&entry)); } drop_envvars(&entry, -1); g_hash_table_destroy(config_hash); } if (max_timeout > 0) { crm_alert_max_alert_timeout = max_timeout; } 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); } }