diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index ad7eaee05e..487e48c470 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -1,379 +1,379 @@ /* * Copyright (c) 2015 David Vossel * * 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 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include static lrmd_key_value_t * alert_key2param(lrmd_key_value_t *head, enum crm_alert_keys_e name, const char *value) { const char **key; if (value == NULL) { value = ""; } for (key = crm_alert_keys[name]; *key; key++) { crm_trace("Setting alert key %s = '%s'", *key, value); head = lrmd_key_value_add(head, *key, value); } return head; } static lrmd_key_value_t * alert_key2param_int(lrmd_key_value_t *head, enum crm_alert_keys_e name, int value) { char *value_s = crm_itoa(value); head = alert_key2param(head, name, value_s); free(value_s); return head; } static void set_ev_kv(gpointer key, gpointer value, gpointer user_data) { lrmd_key_value_t **head = (lrmd_key_value_t **) user_data; if (value) { crm_trace("Setting environment variable %s='%s'", (char*)key, (char*)value); *head = lrmd_key_value_add(*head, key, value); } } static lrmd_key_value_t * alert_envvar2params(lrmd_key_value_t *head, crm_alert_entry_t *entry) { if (entry->envvars) { g_hash_table_foreach(entry->envvars, set_ev_kv, &head); } return head; } /* * We could use g_strv_contains() instead of this function, * but that has only been available since glib 2.43.2. */ static gboolean is_target_alert(char **list, const char *value) { int target_list_num = 0; gboolean rc = FALSE; CRM_CHECK(value != NULL, return 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; } /*! * \internal * \brief Execute alert agents for an event * * \param[in] alert_list Alerts to execute * \param[in] lrmd_connect_func Function that returns an LRMD connection * \param[in] kind Type of event that is being alerted for * \param[in] attr_name If crm_alert_attribute, the attribute name * \param[in,out] params Environment variables to pass to agents * * \retval pcmk_ok on success * \retval -1 if some alerts failed * \retval -2 if all alerts failed */ static int exec_alert_list(GList *alert_list, lrmd_t *(*lrmd_connect_func)(void), enum crm_alert_flags kind, const char *attr_name, lrmd_key_value_t *params) { bool any_success = FALSE, any_failure = FALSE; const char *kind_s = crm_alert_flag2text(kind); crm_time_hr_t *now = NULL; params = alert_key2param(params, CRM_alert_kind, kind_s); params = alert_key2param(params, CRM_alert_version, VERSION); for (GList *iter = g_list_first(alert_list); iter; iter = g_list_next(iter)) { crm_alert_entry_t *entry = (crm_alert_entry_t *)(iter->data); lrmd_key_value_t *copy_params = NULL; lrmd_key_value_t *head = NULL; lrmd_t *lrmd_conn = NULL; int rc; if (is_not_set(entry->flags, kind)) { crm_trace("Filtering unwanted %s alert to %s via %s", kind_s, entry->recipient, entry->id); continue; } if ((kind == crm_alert_attribute) && !is_target_alert(entry->select_attribute_name, attr_name)) { crm_trace("Filtering unwanted attribute '%s' alert to %s via %s", attr_name, entry->recipient, entry->id); continue; } if (now == NULL) { now = crm_time_hr_new(NULL); } crm_info("Sending %s alert via %s to %s", kind_s, entry->id, entry->recipient); /* Make a copy of the parameters, because each alert will be unique */ for (head = params; head != NULL; head = head->next) { copy_params = lrmd_key_value_add(copy_params, head->key, head->value); } copy_params = alert_key2param(copy_params, CRM_alert_recipient, entry->recipient); if (now) { char *timestamp = crm_time_format_hr(entry->tstamp_format, now); if (timestamp) { copy_params = alert_key2param(copy_params, CRM_alert_timestamp, timestamp); free(timestamp); } } copy_params = alert_envvar2params(copy_params, entry); lrmd_conn = (*lrmd_connect_func)(); if (lrmd_conn == NULL) { crm_warn("Cannot send alerts: No LRMD connection"); any_failure = TRUE; goto done; } rc = lrmd_conn->cmds->exec_alert(lrmd_conn, entry->id, entry->path, entry->timeout, copy_params); if (rc < 0) { crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d", entry->id, pcmk_strerror(rc), rc); any_failure = TRUE; } else { any_success = TRUE; } } done: if (now) { free(now); } if (any_failure) { return (any_success? -1 : -2); } return pcmk_ok; } /*! * \internal * \brief Send an alert for a node attribute change * * \param[in] alert_list List of alert agents to execute * \param[in] lrmd_connect_func Function that returns an LRMD connection * \param[in] node Name of node with attribute change * \param[in] nodeid Node ID of node with attribute change * \param[in] attr_name Name of attribute that changed * \param[in] attr_value New value of attribute that changed * * \retval pcmk_ok on success * \retval -1 if some alert agents failed * \retval -2 if all alert agents failed */ int lrmd_send_attribute_alert(GList *alert_list, lrmd_t *(*lrmd_connect_func)(void), const char *node, uint32_t nodeid, const char *attr_name, const char *attr_value) { int rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (alert_list == NULL) { return pcmk_ok; } params = alert_key2param(params, CRM_alert_node, node); params = alert_key2param_int(params, CRM_alert_nodeid, nodeid); params = alert_key2param(params, CRM_alert_attribute_name, attr_name); params = alert_key2param(params, CRM_alert_attribute_value, attr_value); rc = exec_alert_list(alert_list, lrmd_connect_func, crm_alert_attribute, attr_name, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a node membership event * * \param[in] alert_list List of alert agents to execute * \param[in] lrmd_connect_func Function that returns an LRMD connection * \param[in] node Name of node with change * \param[in] nodeid Node ID of node with change * \param[in] state New state of node with change * * \retval pcmk_ok on success * \retval -1 if some alert agents failed * \retval -2 if all alert agents failed */ int lrmd_send_node_alert(GList *alert_list, lrmd_t *(*lrmd_connect_func)(void), const char *node, uint32_t nodeid, const char *state) { int rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (alert_list == NULL) { return pcmk_ok; } params = alert_key2param(params, CRM_alert_node, node); params = alert_key2param(params, CRM_alert_desc, state); params = alert_key2param_int(params, CRM_alert_nodeid, nodeid); rc = exec_alert_list(alert_list, lrmd_connect_func, crm_alert_node, NULL, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a fencing event * * \param[in] alert_list List of alert agents to execute * \param[in] lrmd_connect_func Function that returns an LRMD connection * \param[in] target Name of fence target node * \param[in] task Type of fencing event that occurred * \param[in] desc Readable description of event * \param[in] op_rc Result of fence action * * \retval pcmk_ok on success * \retval -1 if some alert agents failed * \retval -2 if all alert agents failed */ int lrmd_send_fencing_alert(GList *alert_list, lrmd_t *(*lrmd_connect_func)(void), const char *target, const char *task, const char *desc, int op_rc) { int rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (alert_list == NULL) { return pcmk_ok; } params = alert_key2param(params, CRM_alert_node, target); params = alert_key2param(params, CRM_alert_task, task); params = alert_key2param(params, CRM_alert_desc, desc); params = alert_key2param_int(params, CRM_alert_rc, op_rc); rc = exec_alert_list(alert_list, lrmd_connect_func, crm_alert_fencing, NULL, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a resource operation * * \param[in] alert_list List of alert agents to execute * \param[in] lrmd_connect_func Function that returns an LRMD connection * \param[in] node Name of node that executed operation * \param[in] op Resource operation * * \retval pcmk_ok on success * \retval -1 if some alert agents failed * \retval -2 if all alert agents failed */ int lrmd_send_resource_alert(GList *alert_list, lrmd_t *(*lrmd_connect_func)(void), const char *node, lrmd_event_data_t *op) { int rc = pcmk_ok; int target_rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (alert_list == NULL) { return pcmk_ok; } target_rc = rsc_op_expected_rc(op); if ((op->interval == 0) && (target_rc == op->rc) && safe_str_eq(op->op_type, RSC_STATUS)) { /* Don't send alerts for probes with the expected result. Leave it up to * the agent whether to alert for 'failed' probes. (Even if we find a * resource running, it was probably because someone did a clean-up of * the status section.) */ return pcmk_ok; } params = alert_key2param(params, CRM_alert_node, node); params = alert_key2param(params, CRM_alert_rsc, op->rsc_id); params = alert_key2param(params, CRM_alert_task, op->op_type); params = alert_key2param_int(params, CRM_alert_interval, op->interval); params = alert_key2param_int(params, CRM_alert_target_rc, target_rc); params = alert_key2param_int(params, CRM_alert_status, op->op_status); params = alert_key2param_int(params, 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)); + params = alert_key2param(params, CRM_alert_desc, services_ocf_exitcode_str(op->rc)); } else { - crm_set_alert_key(CRM_alert_desc, services_lrm_status_str(op->op_status)); + params = alert_key2param(params, CRM_alert_desc, services_lrm_status_str(op->op_status)); } rc = exec_alert_list(alert_list, lrmd_connect_func, crm_alert_resource, NULL, params); lrmd_key_value_freeall(params); return rc; }