diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c index df7cee1ebe..cf2caf5238 100644 --- a/daemons/attrd/attrd_alerts.c +++ b/daemons/attrd/attrd_alerts.c @@ -1,146 +1,146 @@ /* - * Copyright 2015-2019 the Pacemaker project contributors + * Copyright 2015-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include "pacemaker-attrd.h" 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 executor"); attrd_lrmd_disconnect(); break; default: break; } } static lrmd_t * attrd_lrmd_connect() { if (the_lrmd == NULL) { the_lrmd = lrmd_api_new(); the_lrmd->cmds->set_callback(the_lrmd, attrd_lrmd_callback); } if (!the_lrmd->cmds->is_connected(the_lrmd)) { const unsigned int max_attempts = 10; int ret = -ENOTCONN; for (int fails = 0; fails < max_attempts; ++fails) { ret = the_lrmd->cmds->connect(the_lrmd, T_ATTRD, NULL); if (ret == pcmk_ok) { break; } crm_debug("Could not connect to executor, %d tries remaining", (max_attempts - fails)); /* @TODO We don't want to block here with sleep, but we should wait * some time between connection attempts. We could possibly add a * timer with a callback, but then we'd likely need an alert queue. */ } if (ret != pcmk_ok) { attrd_lrmd_disconnect(); } } return the_lrmd; } void attrd_lrmd_disconnect() { if (the_lrmd) { lrmd_t *conn = the_lrmd; the_lrmd = NULL; /* in case we're called recursively */ lrmd_api_delete(conn); /* will disconnect if necessary */ } } static void config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { xmlNode *crmalerts = NULL; if (rc == -ENXIO) { crm_debug("Local CIB has no alerts section"); return; } else if (rc != pcmk_ok) { crm_notice("Could not query local CIB: %s", pcmk_strerror(rc)); return; } crmalerts = output; if (crmalerts && !crm_str_eq(crm_element_name(crmalerts), XML_CIB_TAG_ALERTS, TRUE)) { crmalerts = first_named_child(crmalerts, XML_CIB_TAG_ALERTS); } if (!crmalerts) { crm_notice("CIB query result has no " XML_CIB_TAG_ALERTS " section"); return; } pe_free_alert_list(attrd_alert_list); attrd_alert_list = pe_unpack_alerts(crmalerts); } #define XPATH_ALERTS \ "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_ALERTS gboolean attrd_read_options(gpointer user_data) { int call_id; CRM_CHECK(the_cib != NULL, return TRUE); call_id = the_cib->cmds->query(the_cib, XPATH_ALERTS, NULL, cib_xpath | cib_scope_local); the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, NULL, "config_query_callback", config_query_callback, free); crm_trace("Querying the CIB... call %d", call_id); return TRUE; } void attrd_cib_updated_cb(const char *event, xmlNode * msg) { - if (!attrd_shutting_down() && crm_patchset_contains_alert(msg, FALSE)) { + if (!attrd_shutting_down() && pcmk__alert_in_patchset(msg, FALSE)) { mainloop_set_trigger(attrd_config_read); } } int attrd_send_attribute_alert(const char *node, int nodeid, const char *attr, const char *value) { if (attrd_alert_list == NULL) { return pcmk_ok; } return lrmd_send_attribute_alert(attrd_lrmd_connect(), attrd_alert_list, node, nodeid, attr, value); } diff --git a/daemons/controld/controld_based.c b/daemons/controld/controld_based.c index 008a02d5f4..42e321fa06 100644 --- a/daemons/controld/controld_based.c +++ b/daemons/controld/controld_based.c @@ -1,245 +1,245 @@ /* - * Copyright 2004-2019 the Pacemaker project contributors + * Copyright 2004-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include /* sleep */ #include #include #include #include #include int cib_retries = 0; static void do_cib_updated(const char *event, xmlNode * msg) { - if (crm_patchset_contains_alert(msg, TRUE)) { + if (pcmk__alert_in_patchset(msg, TRUE)) { mainloop_set_trigger(config_read); } } 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 from the CIB manager"); 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 manager"); } if (action & A_CIB_START) { int rc = pcmk_ok; if (cur_state == S_STOPPING) { crm_err("Ignoring request to connect to the CIB manager 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 manager: %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); cib_retries = 0; } if (is_not_set(fsa_input_register, R_CIB_CONNECTED)) { cib_retries++; crm_warn("Couldn't complete CIB registration %d" " times... pause and retry", cib_retries); if (cib_retries < 30) { controld_start_timer(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); } } } } /*! * \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; } /*! * \internal * \brief Check whether an action type should be recorded in the CIB * * \param[in] action Action type * * \return TRUE if action should be recorded, FALSE otherwise */ bool controld_action_is_recordable(const char *action) { if (safe_str_eq(action, CRMD_ACTION_CANCEL) || safe_str_eq(action, CRMD_ACTION_DELETE) || safe_str_eq(action, CRMD_ACTION_NOTIFY) || safe_str_eq(action, CRMD_ACTION_METADATA)) { return FALSE; } return TRUE; } static void cib_delete_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { char *desc = user_data; if (rc == 0) { crm_debug("Deletion of %s (via CIB call %d) succeeded", desc, call_id); } else { crm_warn("Deletion of %s (via CIB call %d) failed: %s " CRM_XS " rc=%d", desc, call_id, pcmk_strerror(rc), rc); } } // Searches for various portions of node_state to delete // Match a particular node's node_state (takes node name 1x) #define XPATH_NODE_STATE "//" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" // Node's lrm section (name 1x) #define XPATH_NODE_LRM XPATH_NODE_STATE "/" XML_CIB_TAG_LRM // Node's transient_attributes section (name 1x) #define XPATH_NODE_ATTRS XPATH_NODE_STATE "/" XML_TAG_TRANSIENT_NODEATTRS // Everything under node_state (name 1x) #define XPATH_NODE_ALL XPATH_NODE_STATE "/*" /*! * \internal * \brief Delete subsection of a node's CIB node_state * * \param[in] uname Desired node * \param[in] section Subsection of node_state to delete * \param[in] options CIB call options to use */ void controld_delete_node_state(const char *uname, enum controld_section_e section, int options) { char *xpath = NULL; char *desc = NULL; CRM_CHECK(uname != NULL, return); switch (section) { case controld_section_lrm: xpath = crm_strdup_printf(XPATH_NODE_LRM, uname); desc = crm_strdup_printf("resource history for node %s", uname); break; case controld_section_attrs: xpath = crm_strdup_printf(XPATH_NODE_ATTRS, uname); desc = crm_strdup_printf("transient attributes for node %s", uname); break; case controld_section_all: xpath = crm_strdup_printf(XPATH_NODE_ALL, uname); desc = crm_strdup_printf("all state for node %s", uname); break; } if (fsa_cib_conn == NULL) { crm_warn("Unable to delete %s: no CIB connection", desc); free(desc); } else { int call_id; options |= cib_quorum_override|cib_xpath; call_id = fsa_cib_conn->cmds->remove(fsa_cib_conn, xpath, NULL, options); crm_info("Deleting %s (via CIB call %d) " CRM_XS " xpath=%s", desc, call_id, xpath); fsa_register_cib_callback(call_id, FALSE, desc, cib_delete_callback); // CIB library handles freeing desc } free(xpath); } diff --git a/daemons/execd/execd_alerts.c b/daemons/execd/execd_alerts.c index 994fb11c7d..d3d4c474c0 100644 --- a/daemons/execd/execd_alerts.c +++ b/daemons/execd/execd_alerts.c @@ -1,173 +1,175 @@ /* - * Copyright 2016-2018 Andrew Beekhof + * Copyright 2016-2020 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include "pacemaker-execd.h" /* Track in-flight alerts so we can wait for them at shutdown */ static GHashTable *inflight_alerts; /* key = call_id, value = timeout */ static gboolean draining_alerts = FALSE; static inline void add_inflight_alert(int call_id, int timeout) { if (inflight_alerts == NULL) { inflight_alerts = g_hash_table_new(g_direct_hash, g_direct_equal); } g_hash_table_insert(inflight_alerts, GINT_TO_POINTER(call_id), GINT_TO_POINTER(timeout)); } static inline void remove_inflight_alert(int call_id) { if (inflight_alerts != NULL) { g_hash_table_remove(inflight_alerts, GINT_TO_POINTER(call_id)); } } static int max_inflight_timeout() { GHashTableIter iter; gpointer timeout; int max_timeout = 0; if (inflight_alerts) { g_hash_table_iter_init(&iter, inflight_alerts); while (g_hash_table_iter_next(&iter, NULL, &timeout)) { if (GPOINTER_TO_INT(timeout) > max_timeout) { max_timeout = GPOINTER_TO_INT(timeout); } } } return max_timeout; } struct alert_cb_s { char *client_id; int call_id; }; static void alert_complete(svc_action_t *action) { struct alert_cb_s *cb_data = (struct alert_cb_s *) (action->cb_data); remove_inflight_alert(cb_data->call_id); crm_debug("Alert pid %d for %s completed with rc=%d", action->pid, cb_data->client_id, action->rc); free(cb_data->client_id); free(action->cb_data); action->cb_data = NULL; } int process_lrmd_alert_exec(crm_client_t *client, uint32_t id, xmlNode *request) { static int alert_sequence_no = 0; xmlNode *alert_xml = get_xpath_object("//" F_LRMD_ALERT, request, LOG_ERR); const char *alert_id = crm_element_value(alert_xml, F_LRMD_ALERT_ID); const char *alert_path = crm_element_value(alert_xml, F_LRMD_ALERT_PATH); svc_action_t *action = NULL; int alert_timeout = 0; int rc = pcmk_ok; GHashTable *params = NULL; struct alert_cb_s *cb_data = NULL; if ((alert_id == NULL) || (alert_path == NULL)) { return -EINVAL; } if (draining_alerts) { return pcmk_ok; } crm_element_value_int(alert_xml, F_LRMD_TIMEOUT, &alert_timeout); crm_info("Executing alert %s for %s", alert_id, client->id); params = xml2list(alert_xml); - crm_insert_alert_key_int(params, CRM_alert_node_sequence, - ++alert_sequence_no); + pcmk__add_alert_key_int(params, PCMK__alert_key_node_sequence, + ++alert_sequence_no); cb_data = calloc(1, sizeof(struct alert_cb_s)); CRM_CHECK(cb_data != NULL, rc = -ENOMEM; goto err); cb_data->client_id = strdup(client->id); CRM_CHECK(cb_data->client_id != NULL, rc = -ENOMEM; goto err); crm_element_value_int(request, F_LRMD_CALLID, &(cb_data->call_id)); action = services_alert_create(alert_id, alert_path, alert_timeout, params, alert_sequence_no, cb_data); rc = services_action_user(action, CRM_DAEMON_USER); if (rc < 0) { goto err; } add_inflight_alert(cb_data->call_id, alert_timeout); if (services_alert_async(action, alert_complete) == FALSE) { services_action_free(action); } return pcmk_ok; err: if (cb_data) { if (cb_data->client_id) { free(cb_data->client_id); } free(cb_data); } if (action) { services_action_free(action); } return rc; } static bool drain_check(guint remaining_timeout_ms) { if (inflight_alerts != NULL) { guint count = g_hash_table_size(inflight_alerts); if (count > 0) { crm_trace("%d alerts pending (%.3fs timeout remaining)", count, remaining_timeout_ms / 1000.0); return TRUE; } } return FALSE; } void lrmd_drain_alerts(GMainLoop *mloop) { if (inflight_alerts != NULL) { guint timer_ms = max_inflight_timeout() + 5000; crm_trace("Draining in-flight alerts (timeout %.3fs)", timer_ms / 1000.0); draining_alerts = TRUE; pcmk_drain_main_loop(mloop, timer_ms, drain_check); g_hash_table_destroy(inflight_alerts); inflight_alerts = NULL; } } diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index 2cd2e638e7..e0fa655cbc 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,99 +1,92 @@ /* - * Copyright 2015-2019 the Pacemaker project contributors + * Copyright 2015-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #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) +# define PCMK__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" +# define PCMK__ALERT_DEFAULT_TSTAMP_FORMAT "%H:%M:%S.%06N" -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 +enum pcmk__alert_flags { + pcmk__alert_none = 0, + pcmk__alert_node = (1 << 0), + pcmk__alert_fencing = (1 << 1), + pcmk__alert_resource = (1 << 2), + pcmk__alert_attribute = (1 << 3), + pcmk__alert_default = pcmk__alert_node|pcmk__alert_fencing| + pcmk__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; +} pcmk__alert_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_timestamp_epoch, - CRM_alert_timestamp_usec, - CRM_alert_exec_time, - CRM_alert_select_kind, - CRM_alert_select_attribute_name +enum pcmk__alert_keys_e { + PCMK__alert_key_recipient = 0, + PCMK__alert_key_node, + PCMK__alert_key_nodeid, + PCMK__alert_key_rsc, + PCMK__alert_key_task, + PCMK__alert_key_interval, + PCMK__alert_key_desc, + PCMK__alert_key_status, + PCMK__alert_key_target_rc, + PCMK__alert_key_rc, + PCMK__alert_key_kind, + PCMK__alert_key_version, + PCMK__alert_key_node_sequence, + PCMK__alert_key_timestamp, + PCMK__alert_key_attribute_name, + PCMK__alert_key_attribute_value, + PCMK__alert_key_timestamp_epoch, + PCMK__alert_key_timestamp_usec, + PCMK__alert_key_exec_time, + PCMK__alert_key_select_kind, + PCMK__alert_key_select_attribute_name }; -#define CRM_ALERT_INTERNAL_KEY_MAX 19 -#define CRM_ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" +#define PCMK__ALERT_INTERNAL_KEY_MAX 19 +#define PCMK__ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" -extern const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]; +extern const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3]; -crm_alert_entry_t *crm_dup_alert_entry(crm_alert_entry_t *entry); -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_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); +pcmk__alert_t *pcmk__dup_alert(pcmk__alert_t *entry); +pcmk__alert_t *pcmk__alert_new(const char *id, const char *path); +void pcmk__free_alert(pcmk__alert_t *entry); +void pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name, + const char *value); +void pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name, + int value); +bool pcmk__alert_in_patchset(xmlNode *msg, bool config); static inline const char * -crm_alert_flag2text(enum crm_alert_flags flag) +pcmk__alert_flag2text(enum pcmk__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"; + case pcmk__alert_node: return "node"; + case pcmk__alert_fencing: return "fencing"; + case pcmk__alert_resource: return "resource"; + case pcmk__alert_attribute: return "attribute"; + default: return "unknown"; } } #endif diff --git a/lib/common/agents.c b/lib/common/agents.c index 23c364f847..ccb6aa0761 100644 --- a/lib/common/agents.c +++ b/lib/common/agents.c @@ -1,146 +1,148 @@ /* - * Copyright 2004-2018 Andrew Beekhof + * Copyright 2004-2020 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include /*! * \brief Get capabilities of a resource agent standard * * \param[in] standard Standard name * * \return Bitmask of enum pcmk_ra_caps values */ uint32_t pcmk_get_ra_caps(const char *standard) { /* @COMPAT This should probably be case-sensitive, but isn't, * for backward compatibility. */ if (standard == NULL) { return pcmk_ra_cap_none; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF)) { return pcmk_ra_cap_provider | pcmk_ra_cap_params | pcmk_ra_cap_unique | pcmk_ra_cap_promotable; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_STONITH)) { /* @COMPAT Stonith resources can't really be unique clones, but we've * allowed it in the past and have it in some scheduler regression tests * (which were likely never used as real configurations). * * @TODO Remove pcmk_ra_cap_unique at the next major schema version * bump, with a transform to remove globally-unique from the config. */ return pcmk_ra_cap_params | pcmk_ra_cap_unique; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) || !strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) || !strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) || !strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART)) { /* Since service can map to LSB, systemd, or upstart, these should * have identical capabilities */ return pcmk_ra_cap_status; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS)) { return pcmk_ra_cap_params; } return pcmk_ra_cap_none; } char * crm_generate_ra_key(const char *standard, const char *provider, const char *type) { if (!standard && !provider && !type) { return NULL; } return crm_strdup_printf("%s%s%s:%s", (standard? standard : ""), (provider? ":" : ""), (provider? provider : ""), (type? type : "")); } /*! * \deprecated * \brief Check whether a resource standard requires a provider to be specified * * \param[in] standard Standard name * * \return TRUE if standard requires a provider, FALSE otherwise */ bool crm_provider_required(const char *standard) { return is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider); } /*! * \brief Parse a "standard[:provider]:type" agent specification * * \param[in] spec Agent specification * \param[out] standard Newly allocated memory containing agent standard (or NULL) * \param[out] provider Newly allocated memory containing agent provider (or NULL) * \param[put] type Newly allocated memory containing agent type (or NULL) * * \return pcmk_ok if the string could be parsed, -EINVAL otherwise * * \note It is acceptable for the type to contain a ':' if the standard supports * that. For example, systemd supports the form "systemd:UNIT@A:B". * \note It is the caller's responsibility to free the returned values. */ int crm_parse_agent_spec(const char *spec, char **standard, char **provider, char **type) { char *colon; CRM_CHECK(spec && standard && provider && type, return -EINVAL); *standard = NULL; *provider = NULL; *type = NULL; colon = strchr(spec, ':'); if ((colon == NULL) || (colon == spec)) { return -EINVAL; } *standard = strndup(spec, colon - spec); spec = colon + 1; if (is_set(pcmk_get_ra_caps(*standard), pcmk_ra_cap_provider)) { colon = strchr(spec, ':'); if ((colon == NULL) || (colon == spec)) { free(*standard); return -EINVAL; } *provider = strndup(spec, colon - spec); spec = colon + 1; } if (*spec == '\0') { free(*standard); free(*provider); return -EINVAL; } *type = strdup(spec); return pcmk_ok; } diff --git a/lib/common/alerts.c b/lib/common/alerts.c index a1e8df39cb..3c95cb1364 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -1,263 +1,255 @@ /* - * Copyright 2015-2019 Andrew Beekhof + * Copyright 2015-2020 the Pacemaker project contributors + * + * The version control history for this file may have further details. * * 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 /* for F_CIB_UPDATE_RESULT */ -/* - * to allow script compatibility we can have more than one - * set of environment variables +/* + * 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}, - [CRM_alert_timestamp_epoch] = {"CRM_notify_timestamp_epoch", "CRM_alert_timestamp_epoch", NULL}, - [CRM_alert_timestamp_usec] = {"CRM_notify_timestamp_usec", "CRM_alert_timestamp_usec", NULL}, - [CRM_alert_exec_time] = {"CRM_notify_exec_time", "CRM_alert_exec_time", NULL} +const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3] = +{ + [PCMK__alert_key_recipient] = { + "CRM_notify_recipient", "CRM_alert_recipient", NULL + }, + [PCMK__alert_key_node] = { + "CRM_notify_node", "CRM_alert_node", NULL + }, + [PCMK__alert_key_nodeid] = { + "CRM_notify_nodeid", "CRM_alert_nodeid", NULL + }, + [PCMK__alert_key_rsc] = { + "CRM_notify_rsc", "CRM_alert_rsc", NULL + }, + [PCMK__alert_key_task] = { + "CRM_notify_task", "CRM_alert_task", NULL + }, + [PCMK__alert_key_interval] = { + "CRM_notify_interval", "CRM_alert_interval", NULL + }, + [PCMK__alert_key_desc] = { + "CRM_notify_desc", "CRM_alert_desc", NULL + }, + [PCMK__alert_key_status] = { + "CRM_notify_status", "CRM_alert_status", NULL + }, + [PCMK__alert_key_target_rc] = { + "CRM_notify_target_rc", "CRM_alert_target_rc", NULL + }, + [PCMK__alert_key_rc] = { + "CRM_notify_rc", "CRM_alert_rc", NULL + }, + [PCMK__alert_key_kind] = { + "CRM_notify_kind", "CRM_alert_kind", NULL + }, + [PCMK__alert_key_version] = { + "CRM_notify_version", "CRM_alert_version", NULL + }, + [PCMK__alert_key_node_sequence] = { + "CRM_notify_node_sequence", PCMK__ALERT_NODE_SEQUENCE, NULL + }, + [PCMK__alert_key_timestamp] = { + "CRM_notify_timestamp", "CRM_alert_timestamp", NULL + }, + [PCMK__alert_key_attribute_name] = { + "CRM_notify_attribute_name", "CRM_alert_attribute_name", NULL + }, + [PCMK__alert_key_attribute_value] = { + "CRM_notify_attribute_value", "CRM_alert_attribute_value", NULL + }, + [PCMK__alert_key_timestamp_epoch] = { + "CRM_notify_timestamp_epoch", "CRM_alert_timestamp_epoch", NULL + }, + [PCMK__alert_key_timestamp_usec] = { + "CRM_notify_timestamp_usec", "CRM_alert_timestamp_usec", NULL + }, + [PCMK__alert_key_exec_time] = { + "CRM_notify_exec_time", "CRM_alert_exec_time", NULL + } }; /*! * \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(). + * using pcmk__free_alert(). */ -crm_alert_entry_t * -crm_alert_entry_new(const char *id, const char *path) +pcmk__alert_t * +pcmk__alert_new(const char *id, const char *path) { - crm_alert_entry_t *entry = calloc(1, sizeof(crm_alert_entry_t)); + pcmk__alert_t *entry = calloc(1, sizeof(pcmk__alert_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; + entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS; + entry->flags = pcmk__alert_default; return entry; } void -crm_free_alert_entry(crm_alert_entry_t *entry) -{ +pcmk__free_alert(pcmk__alert_t *entry) +{ if (entry) { free(entry->id); free(entry->path); free(entry->tstamp_format); free(entry->recipient); g_strfreev(entry->select_attribute_name); if (entry->envvars) { g_hash_table_destroy(entry->envvars); } free(entry); } -} +} /*! * \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) +pcmk__alert_t * +pcmk__dup_alert(pcmk__alert_t *entry) { - crm_alert_entry_t *new_entry = crm_alert_entry_new(entry->id, entry->path); + pcmk__alert_t *new_entry = pcmk__alert_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_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) +pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name, + const char *value) { - for (const char **key = crm_alert_keys[name]; *key; key++) { + for (const char **key = pcmk__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) +pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name, + int value) { - for (const char **key = crm_alert_keys[name]; *key; key++) { + for (const char **key = pcmk__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) +pcmk__alert_in_patchset(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; } diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index 8238e166c3..329ad755d8 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -1,388 +1,399 @@ /* - * Copyright 2015-2019 the Pacemaker project contributors + * Copyright 2015-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * 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 #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, +alert_key2param(lrmd_key_value_t *head, enum pcmk__alert_keys_e name, const char *value) { const char **key; if (value == NULL) { value = ""; } - for (key = crm_alert_keys[name]; *key; key++) { + for (key = pcmk__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, +alert_key2param_int(lrmd_key_value_t *head, enum pcmk__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 lrmd_key_value_t * -alert_key2param_ms(lrmd_key_value_t *head, enum crm_alert_keys_e name, +alert_key2param_ms(lrmd_key_value_t *head, enum pcmk__alert_keys_e name, guint value) { char *value_s = crm_strdup_printf("%u", 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) +alert_envvar2params(lrmd_key_value_t *head, pcmk__alert_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] lrmd Executor connection to use * \param[in] alert_list Alerts to execute * \param[in] kind Type of event that is being alerted for - * \param[in] attr_name If crm_alert_attribute, the attribute name + * \param[in] attr_name If pcmk__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(lrmd_t *lrmd, GList *alert_list, enum crm_alert_flags kind, +exec_alert_list(lrmd_t *lrmd, GList *alert_list, enum pcmk__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); + const char *kind_s = pcmk__alert_flag2text(kind); crm_time_hr_t *now = NULL; struct timeval tv_now; char timestamp_epoch[20]; char timestamp_usec[7]; - params = alert_key2param(params, CRM_alert_kind, kind_s); - params = alert_key2param(params, CRM_alert_version, VERSION); + params = alert_key2param(params, PCMK__alert_key_kind, kind_s); + params = alert_key2param(params, PCMK__alert_key_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); + pcmk__alert_t *entry = (pcmk__alert_t *)(iter->data); lrmd_key_value_t *copy_params = NULL; lrmd_key_value_t *head = 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) + if ((kind == pcmk__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) { if (gettimeofday(&tv_now, NULL) == 0) { now = crm_time_timeval_hr_convert(NULL, &tv_now); } } 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, + copy_params = alert_key2param(copy_params, PCMK__alert_key_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, + copy_params = alert_key2param(copy_params, + PCMK__alert_key_timestamp, timestamp); free(timestamp); } snprintf(timestamp_epoch, sizeof(timestamp_epoch), "%lld", (long long) tv_now.tv_sec); - copy_params = alert_key2param(copy_params, CRM_alert_timestamp_epoch, timestamp_epoch); + copy_params = alert_key2param(copy_params, + PCMK__alert_key_timestamp_epoch, + timestamp_epoch); snprintf(timestamp_usec, sizeof(timestamp_usec), "%06d", now->useconds); - copy_params = alert_key2param(copy_params, CRM_alert_timestamp_usec, timestamp_usec); + copy_params = alert_key2param(copy_params, + PCMK__alert_key_timestamp_usec, + timestamp_usec); } copy_params = alert_envvar2params(copy_params, entry); rc = lrmd->cmds->exec_alert(lrmd, 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; } } 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] lrmd Executor connection to use * \param[in] alert_list List of alert agents to execute * \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(lrmd_t *lrmd, GList *alert_list, 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 (lrmd == NULL) { return -2; } - 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); + params = alert_key2param(params, PCMK__alert_key_node, node); + params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid); + params = alert_key2param(params, PCMK__alert_key_attribute_name, attr_name); + params = alert_key2param(params, PCMK__alert_key_attribute_value, + attr_value); - rc = exec_alert_list(lrmd, alert_list, crm_alert_attribute, attr_name, + rc = exec_alert_list(lrmd, alert_list, pcmk__alert_attribute, attr_name, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a node membership event * * \param[in] lrmd Executor connection to use * \param[in] alert_list List of alert agents to execute * \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(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *state) { int rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (lrmd == NULL) { return -2; } - 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); + params = alert_key2param(params, PCMK__alert_key_node, node); + params = alert_key2param(params, PCMK__alert_key_desc, state); + params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid); - rc = exec_alert_list(lrmd, alert_list, crm_alert_node, NULL, params); + rc = exec_alert_list(lrmd, alert_list, pcmk__alert_node, NULL, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a fencing event * * \param[in] lrmd Executor connection to use * \param[in] alert_list List of alert agents to execute * \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(lrmd_t *lrmd, GList *alert_list, const char *target, const char *task, const char *desc, int op_rc) { int rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (lrmd == NULL) { return -2; } - 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); + params = alert_key2param(params, PCMK__alert_key_node, target); + params = alert_key2param(params, PCMK__alert_key_task, task); + params = alert_key2param(params, PCMK__alert_key_desc, desc); + params = alert_key2param_int(params, PCMK__alert_key_rc, op_rc); - rc = exec_alert_list(lrmd, alert_list, crm_alert_fencing, NULL, params); + rc = exec_alert_list(lrmd, alert_list, pcmk__alert_fencing, NULL, params); lrmd_key_value_freeall(params); return rc; } /*! * \internal * \brief Send an alert for a resource operation * * \param[in] lrmd Executor connection to use * \param[in] alert_list List of alert agents to execute * \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(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op) { int rc = pcmk_ok; int target_rc = pcmk_ok; lrmd_key_value_t *params = NULL; if (lrmd == NULL) { return -2; } target_rc = rsc_op_expected_rc(op); if ((op->interval_ms == 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_ms(params, CRM_alert_interval, op->interval_ms); - 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); + params = alert_key2param(params, PCMK__alert_key_node, node); + params = alert_key2param(params, PCMK__alert_key_rsc, op->rsc_id); + params = alert_key2param(params, PCMK__alert_key_task, op->op_type); + params = alert_key2param_ms(params, PCMK__alert_key_interval, + op->interval_ms); + params = alert_key2param_int(params, PCMK__alert_key_target_rc, target_rc); + params = alert_key2param_int(params, PCMK__alert_key_status, op->op_status); + params = alert_key2param_int(params, PCMK__alert_key_rc, op->rc); /* Reoccurring operations do not set exec_time, so on timeout, set it * to the operation timeout since that's closer to the actual value. */ if (op->op_status == PCMK_LRM_OP_TIMEOUT && op->exec_time == 0) { - params = alert_key2param_int(params, CRM_alert_exec_time, op->timeout); + params = alert_key2param_int(params, PCMK__alert_key_exec_time, + op->timeout); } else { - params = alert_key2param_int(params, CRM_alert_exec_time, op->exec_time); + params = alert_key2param_int(params, PCMK__alert_key_exec_time, + op->exec_time); } if (op->op_status == PCMK_LRM_OP_DONE) { - params = alert_key2param(params, CRM_alert_desc, services_ocf_exitcode_str(op->rc)); + params = alert_key2param(params, PCMK__alert_key_desc, + services_ocf_exitcode_str(op->rc)); } else { - params = alert_key2param(params, CRM_alert_desc, services_lrm_status_str(op->op_status)); + params = alert_key2param(params, PCMK__alert_key_desc, + services_lrm_status_str(op->op_status)); } - rc = exec_alert_list(lrmd, alert_list, crm_alert_resource, NULL, params); + rc = exec_alert_list(lrmd, alert_list, pcmk__alert_resource, NULL, params); lrmd_key_value_freeall(params); return rc; } diff --git a/lib/pengine/rules_alerts.c b/lib/pengine/rules_alerts.c index 938ed13b9f..e7670876db 100644 --- a/lib/pengine/rules_alerts.c +++ b/lib/pengine/rules_alerts.c @@ -1,251 +1,251 @@ /* - * Copyright 2015-2019 the Pacemaker project contributors + * Copyright 2015-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * 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 static void -get_meta_attrs_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, +get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry, guint *max_timeout) { GHashTable *config_hash = crm_str_table_new(); crm_time_t *now = crm_time_new(NULL); const char *value = NULL; pe_unpack_nvpairs(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash, NULL, FALSE, now, NULL); 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); + entry->id, PCMK__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->id, (char*)value, PCMK__ALERT_DEFAULT_TIMEOUT_MS); } - entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; + entry->timeout = PCMK__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) +get_envvars_from_cib(xmlNode *basenode, pcmk__alert_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) +unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry) { xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT); xmlNode *event_type = NULL; - uint32_t flags = crm_alert_none; + uint32_t flags = pcmk__alert_none; for (event_type = __xml_first_child_element(select); event_type != NULL; event_type = __xml_next_element(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; + flags |= pcmk__alert_fencing; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) { - flags |= crm_alert_node; + flags |= pcmk__alert_node; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) { - flags |= crm_alert_resource; + flags |= pcmk__alert_resource; } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) { xmlNode *attr; const char *attr_name; int nattrs = 0; - flags |= crm_alert_attribute; + flags |= pcmk__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) { + if (flags != pcmk__alert_none) { entry->flags = flags; - crm_debug("Alert %s receives events: attributes:%s, fencing:%s, nodes:%s, resources:%s", + crm_debug("Alert %s receives events: attributes:%s%s%s%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"); + (is_set(flags, pcmk__alert_attribute)? + (entry->select_attribute_name? "some" : "all") : "none"), + (is_set(flags, pcmk__alert_fencing)? " fencing" : ""), + (is_set(flags, pcmk__alert_node)? " nodes" : ""), + (is_set(flags, pcmk__alert_resource)? " resources" : "")); } } static void -unpack_alert(xmlNode *alert, crm_alert_entry_t *entry, guint *max_timeout) +unpack_alert(xmlNode *alert, pcmk__alert_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 scheduler 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; + pcmk__alert_t *entry; guint max_timeout = 0; GListPtr alert_list = NULL; if (alerts == NULL) { 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); + entry = pcmk__alert_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); + entry->tstamp_format = strdup(PCMK__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); + pcmk__alert_t *recipient_entry = pcmk__dup_alert(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); + pcmk__free_alert(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); + g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert); } }