diff --git a/attrd/attrd_alerts.c b/attrd/attrd_alerts.c index e12f898ea4..7cc73894cd 100644 --- a/attrd/attrd_alerts.c +++ b/attrd/attrd_alerts.c @@ -1,566 +1,538 @@ /* * 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 #include "attrd_alerts.h" #include #include #include GHashTable *alert_info_cache = 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 attrd_parse_alerts(xmlNode *notifications) { xmlNode *alert; crm_alert_entry_t entry; guint max_timeout = 0; crm_free_alert_list(); 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 (notifications) { crm_info("We have an alerts section in the cib"); } else { crm_info("No optional alerts section in cib"); return; } for (alert = first_named_child(notifications, 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, .select_attribute_name = NULL }; crm_get_envvars_from_cib(alert, &entry, &envvars); config_hash = get_meta_attrs_from_cib(alert, &entry, &max_timeout); crm_debug("Found alert: id=%s, path=%s, timeout=%d, " "tstamp_format=%s, select_kind=%s, select_attribute_name=%s, %d additional environment variables", 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; recipient = __xml_next(recipient)) { int envvars_added = 0; entry.recipient = (char *) crm_element_value(recipient, XML_ALERT_ATTR_REC_VALUE); recipients++; crm_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); crm_add_dup_alert_list_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); } entry.envvars = crm_drop_envvars(&entry, envvars_added); } if (recipients == 0) { crm_add_dup_alert_list_entry(&entry); } crm_drop_envvars(&entry, -1); g_hash_table_destroy(config_hash); } if (max_timeout > 0) { crm_alert_max_alert_timeout = max_timeout; } } - static void config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { - GHashTable *config_hash = NULL; crm_time_t *now = crm_time_new(NULL); - xmlNode *crmconfig = NULL; - xmlNode *alerts = NULL; + xmlNode *crmalerts = NULL; if (rc != pcmk_ok) { crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc)); goto bail; } - crmconfig = output; - if ((crmconfig) && - (crm_element_name(crmconfig)) && - (strcmp(crm_element_name(crmconfig), XML_CIB_TAG_CRMCONFIG) != 0)) { - crmconfig = first_named_child(crmconfig, XML_CIB_TAG_CRMCONFIG); + 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 (!crmconfig) { - crm_err("Local CIB query for " XML_CIB_TAG_CRMCONFIG " section failed"); + if (!crmalerts) { + crm_err("Local CIB query for " XML_CIB_TAG_ALERTS " section failed"); goto bail; } - crm_debug("Call %d : Parsing CIB options", call_id); - config_hash = - g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); - - unpack_instance_attributes(crmconfig, crmconfig, XML_CIB_TAG_PROPSET, NULL, config_hash, - CIB_OPTIONS_FIRST, FALSE, now); + attrd_parse_alerts(crmalerts); - alerts = first_named_child(output, XML_CIB_TAG_ALERTS); - attrd_parse_alerts(alerts); - - g_hash_table_destroy(config_hash); 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_CRMCONFIG " | //" XML_CIB_TAG_ALERTS, + "//" 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_CRMCONFIG " | " \ "//" 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_CRMCONFIG "/") && !strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_ALERTS)) { xmlNode *section = NULL; const char *name = NULL; /* adding notifications section */ if ((strcmp(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION) != 0) || ((section = __xml_first_child(change)) == NULL) || ((name = crm_element_name(section)) == NULL) || (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { continue; } } mainloop_set_trigger(attrd_config_read); break; } } else { crm_warn("Unknown patch format: %d", format); } } 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); } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_SELECT_ATTRIBUTE_NAME); if (value) { entry->select_attribute_name_orig = (char*) 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 */ } void attrd_alert_fini() { if (alert_info_cache) { g_hash_table_destroy(alert_info_cache); alert_info_cache = NULL; } 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, lrmd_key_value_t * params, GListPtr alert_list, GHashTable *info_cache) { int call_id = 0; static int operations = 0; 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_version, VERSION); for (l = g_list_first(alert_list); l; l = g_list_next(l)) { lrmd_rsc_info_t *rsc = NULL; crm_alert_entry_t *entry = (crm_alert_entry_t *)(l->data); char *timestamp = crm_time_format_hr(entry->tstamp_format, now); 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); 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); continue; } crm_info("Sending '%s' alert to '%s' via '%s'", kind, entry->recipient, entry->path); rsc = g_hash_table_lookup(alert_info_cache, entry->id); if (rsc == NULL) { rsc = lrmd->cmds->get_rsc_info(lrmd, entry->id, 0); if (!rsc) { lrmd->cmds->register_rsc(lrmd, entry->id, PCMK_ALERT_CLASS, "pacemaker", entry->path, lrmd_opt_drop_recurring); rsc = lrmd->cmds->get_rsc_info(lrmd, entry->id, 0); if (!rsc) { crm_err("Could not add alert %s : %s", entry->id, entry->path); return -1; } /* cache the result */ g_hash_table_insert(alert_info_cache, entry->id, rsc); } } /* 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; } operations++; 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_node_sequence, crm_itoa(operations)); copy_params = lrmd_set_alert_key_to_lrmd_params(copy_params, CRM_alert_timestamp, timestamp); - lrmd_set_alert_envvar_to_lrmd_params(entry, copy_params); + lrmd_set_alert_envvar_to_lrmd_params(copy_params, entry); call_id = lrmd->cmds->exec_alert(lrmd, strdup(entry->id), entry->timeout, lrmd_opt_notify_orig_only, copy_params); if (call_id <= 0) { crm_err("Operation %s on %s failed: %d", "start", rsc->id, call_id); } else { crm_info("Operation %s on %s compete: %d", "start", rsc->id, call_id); } free(timestamp); } if (now) { free(now); } return call_id; } static void free_alert_info(gpointer value) { lrmd_rsc_info_t *rsc_info = value; lrmd_free_rsc_info(rsc_info); } static void attrd_alert_lrm_op_callback(lrmd_event_data_t * op) { - const char *nodename = NULL; - CRM_CHECK(op != NULL, return); -#if HAVE_ATOMIC_ATTRD - nodename = op->remote_nodename ? op->remote_nodename : attrd_cluster->uname; -#else - nodename = op->remote_nodename ? op->remote_nodename : attrd_uname; -#endif - -#if HAVE_ATOMIC_ATTRD - if (op->type == lrmd_event_disconnect && (safe_str_eq(nodename, attrd_cluster->uname))) { + if (op->type == lrmd_event_disconnect) { crm_info("Lost connection to LRMD service!"); -#else - if (op->type == lrmd_event_disconnect && (safe_str_eq(nodename, attrd_uname))) { - crm_notice("Lost connection to LRMD service!"); -#endif 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) { -#if HAVE_ATOMIC_ATTRD crm_info("Alert %s (%s) complete", value_tmp2, value_tmp1); -#else - crm_notice("Alert %s (%s) complete", value_tmp2, value_tmp1); -#endif } 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, GListPtr alert_list) { 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"); if (alert_info_cache == NULL) { alert_info_cache = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_alert_info); } 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, alert_list, alert_info_cache); 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_alert_list); 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/include/crm/lrmd_alerts_internal.h b/include/crm/lrmd_alerts_internal.h index 5db549a8ce..5df88ed048 100644 --- a/include/crm/lrmd_alerts_internal.h +++ b/include/crm/lrmd_alerts_internal.h @@ -1,23 +1,23 @@ /* * 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 LRMD_ALERT_INTERNAL_H #define LRMD_ALERT_INTERNAL_H lrmd_key_value_t * lrmd_set_alert_key_to_lrmd_params(lrmd_key_value_t *head, enum crm_alert_keys_e name, const char *value); -void lrmd_set_alert_envvar_to_lrmd_params(crm_alert_entry_t *entry, lrmd_key_value_t * params); +void lrmd_set_alert_envvar_to_lrmd_params(lrmd_key_value_t *head, crm_alert_entry_t *entry); #endif diff --git a/include/crm/services.h b/include/crm/services.h index 72f7413590..3ac3d8a879 100644 --- a/include/crm/services.h +++ b/include/crm/services.h @@ -1,419 +1,423 @@ /* * Copyright (C) 2010 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * \file * \brief Services API * \ingroup core */ #ifndef __PCMK_SERVICES__ # define __PCMK_SERVICES__ # ifdef __cplusplus extern "C" { # endif # include # include # include # include # ifndef OCF_ROOT_DIR # define OCF_ROOT_DIR "/usr/lib/ocf" # endif # ifndef LSB_ROOT_DIR # define LSB_ROOT_DIR "/etc/init.d" # endif /* TODO: Autodetect these two ?*/ # ifndef SYSTEMCTL # define SYSTEMCTL "/bin/systemctl" # endif /* Deprecated and unused by Pacemaker, kept for API backward compatibility */ # ifndef SERVICE_SCRIPT # define SERVICE_SCRIPT "/sbin/service" # endif /* Known resource classes */ #define PCMK_RESOURCE_CLASS_OCF "ocf" #define PCMK_RESOURCE_CLASS_SERVICE "service" #define PCMK_RESOURCE_CLASS_LSB "lsb" #define PCMK_RESOURCE_CLASS_SYSTEMD "systemd" #define PCMK_RESOURCE_CLASS_UPSTART "upstart" #define PCMK_RESOURCE_CLASS_HB "heartbeat" #define PCMK_RESOURCE_CLASS_NAGIOS "nagios" #define PCMK_RESOURCE_CLASS_STONITH "stonith" #define PCMK_ALERT_CLASS "alert" /* This is the string passed in the OCF_EXIT_REASON_PREFIX * environment variable. The stderr output that occurs * after this prefix is encountered is considered the exit * reason for a completed operationt */ #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:" /* *INDENT-OFF* */ enum lsb_exitcode { PCMK_LSB_OK = 0, PCMK_LSB_UNKNOWN_ERROR = 1, PCMK_LSB_INVALID_PARAM = 2, PCMK_LSB_UNIMPLEMENT_FEATURE = 3, PCMK_LSB_INSUFFICIENT_PRIV = 4, PCMK_LSB_NOT_INSTALLED = 5, PCMK_LSB_NOT_CONFIGURED = 6, PCMK_LSB_NOT_RUNNING = 7, }; /* The return codes for the status operation are not the same for other * operatios - go figure */ enum lsb_status_exitcode { PCMK_LSB_STATUS_OK = 0, PCMK_LSB_STATUS_VAR_PID = 1, PCMK_LSB_STATUS_VAR_LOCK = 2, PCMK_LSB_STATUS_NOT_RUNNING = 3, PCMK_LSB_STATUS_UNKNOWN = 4, /* custom codes should be in the 150-199 range reserved for application use */ PCMK_LSB_STATUS_NOT_INSTALLED = 150, PCMK_LSB_STATUS_INSUFFICIENT_PRIV = 151, }; /* Uniform exit codes * Everything is mapped to its OCF equivalent so that Pacemaker only deals with one set of codes */ enum ocf_exitcode { PCMK_OCF_OK = 0, PCMK_OCF_UNKNOWN_ERROR = 1, PCMK_OCF_INVALID_PARAM = 2, PCMK_OCF_UNIMPLEMENT_FEATURE = 3, PCMK_OCF_INSUFFICIENT_PRIV = 4, PCMK_OCF_NOT_INSTALLED = 5, PCMK_OCF_NOT_CONFIGURED = 6, PCMK_OCF_NOT_RUNNING = 7, /* End of overlap with LSB */ PCMK_OCF_RUNNING_MASTER = 8, PCMK_OCF_FAILED_MASTER = 9, /* 150-199 reserved for application use */ PCMK_OCF_CONNECTION_DIED = 189, /* Operation failure implied by disconnection of the LRM API to a local or remote node */ PCMK_OCF_DEGRADED = 190, /* Active resource that is no longer 100% functional */ PCMK_OCF_DEGRADED_MASTER = 191, /* Promoted resource that is no longer 100% functional */ PCMK_OCF_EXEC_ERROR = 192, /* Generic problem invoking the agent */ PCMK_OCF_UNKNOWN = 193, /* State of the service is unknown - used for recording in-flight operations */ PCMK_OCF_SIGNAL = 194, PCMK_OCF_NOT_SUPPORTED = 195, PCMK_OCF_PENDING = 196, PCMK_OCF_CANCELLED = 197, PCMK_OCF_TIMEOUT = 198, PCMK_OCF_OTHER_ERROR = 199, /* Keep the same codes as PCMK_LSB */ }; enum op_status { PCMK_LRM_OP_PENDING = -1, PCMK_LRM_OP_DONE, PCMK_LRM_OP_CANCELLED, PCMK_LRM_OP_TIMEOUT, PCMK_LRM_OP_NOTSUPPORTED, PCMK_LRM_OP_ERROR, PCMK_LRM_OP_ERROR_HARD, PCMK_LRM_OP_ERROR_FATAL, PCMK_LRM_OP_NOT_INSTALLED, }; enum nagios_exitcode { NAGIOS_STATE_OK = 0, NAGIOS_STATE_WARNING = 1, NAGIOS_STATE_CRITICAL = 2, NAGIOS_STATE_UNKNOWN = 3, NAGIOS_STATE_DEPENDENT = 4, NAGIOS_INSUFFICIENT_PRIV = 100, NAGIOS_NOT_INSTALLED = 101, }; enum svc_action_flags { /* On timeout, only kill pid, do not kill entire pid group */ SVC_ACTION_LEAVE_GROUP = 0x01, }; /* *INDENT-ON* */ typedef struct svc_action_private_s svc_action_private_t; typedef struct svc_action_s { char *id; char *rsc; char *action; int interval; char *standard; char *provider; char *agent; int timeout; GHashTable *params; - GHashTable *alert_params; int rc; int pid; int cancel; int status; int sequence; int expected_rc; int synchronous; enum svc_action_flags flags; char *stderr_data; char *stdout_data; /** * Data stored by the creator of the action. * * This may be used to hold data that is needed later on by a callback, * for example. */ void *cb_data; svc_action_private_t *opaque; + /* + * Store a parameter of Alert. + */ + GHashTable *alert_params; + } svc_action_t; /** * \brief Get a list of files or directories in a given path * * \param[in] root full path to a directory to read * \param[in] files return list of files if TRUE or directories if FALSE * \param[in] executable if TRUE and files is TRUE, only return executable files * * \return a list of what was found. The list items are char *. * \note It is the caller's responsibility to free the result with g_list_free_full(list, free). */ GList *get_directory_list(const char *root, gboolean files, gboolean executable); /** * Get a list of services * * \return a list of services. The list items are gchar *. This list _must_ * be destroyed using g_list_free_full(list, free). */ GList *services_list(void); /** * \brief Get a list of providers * * \param[in] standard list providers of this standard (e.g. ocf, lsb, etc.) * * \return a list of providers as char * list items (or NULL if standard does not support providers) * \note The caller is responsible for freeing the result using g_list_free_full(list, free). */ GList *resources_list_providers(const char *standard); /** * \brief Get a list of resource agents * * \param[in] standard list agents using this standard (e.g. ocf, lsb, etc.) (or NULL for all) * \param[in] provider list agents from this provider (or NULL for all) * * \return a list of resource agents. The list items are char *. * \note The caller is responsible for freeing the result using g_list_free_full(list, free). */ GList *resources_list_agents(const char *standard, const char *provider); /** * Get list of available standards * * \return a list of resource standards. The list items are char *. This list _must_ * be destroyed using g_list_free_full(list, free). */ GList *resources_list_standards(void); svc_action_t *services_action_create(const char *name, const char *action, int interval /* ms */ , int timeout /* ms */ ); /** * \brief Create a new resource action * * \param[in] name name of resource * \param[in] standard resource agent standard (ocf, lsb, etc.) * \param[in] provider resource agent provider * \param[in] agent resource agent name * \param[in] action action (start, stop, monitor, etc.) * \param[in] interval how often to repeat this action, in milliseconds (if 0, execute only once) * \param[in] timeout consider action failed if it does not complete in this many milliseconds * \param[in] params action parameters * * \return newly allocated action instance * * \post After the call, 'params' is owned, and later free'd by the svc_action_t result * \note The caller is responsible for freeing the return value using * services_action_free(). */ svc_action_t *resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval /* ms */ , int timeout /* ms */ , GHashTable * params, enum svc_action_flags flags); /** * Kick a recurring action so it is scheduled immediately for re-execution */ gboolean services_action_kick(const char *name, const char *action, int interval /* ms */); /** * Find the first class that can provide service::${agent} * * \param[in] agent which agent to search for * \return NULL, or the first class that provides the named agent */ const char *resources_find_service_class(const char *agent); /** * Utilize services API to execute an arbitrary command. * * This API has useful infrastructure in place to be able to run a command * in the background and get notified via a callback when the command finishes. * * \param[in] exec command to execute * \param[in] args arguments to the command, NULL terminated * * \return a svc_action_t object, used to pass to the execute function * (services_action_sync() or services_action_async()) and is * provided to the callback. */ svc_action_t *services_action_create_generic(const char *exec, const char *args[]); void services_action_cleanup(svc_action_t * op); void services_action_free(svc_action_t * op); gboolean services_action_sync(svc_action_t * op); /** * Run an action asynchronously. * * \param[in] op services action data * \param[in] action_callback callback for when the action completes * * \retval TRUE succesfully started execution * \retval FALSE failed to start execution, no callback will be received */ gboolean services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *)); gboolean services_action_cancel(const char *name, const char *action, int interval); static inline const char *services_lrm_status_str(enum op_status status) { switch (status) { case PCMK_LRM_OP_PENDING: return "pending"; case PCMK_LRM_OP_DONE:return "complete"; case PCMK_LRM_OP_CANCELLED:return "Cancelled"; case PCMK_LRM_OP_TIMEOUT:return "Timed Out"; case PCMK_LRM_OP_NOTSUPPORTED:return "NOT SUPPORTED"; case PCMK_LRM_OP_ERROR:return "Error"; case PCMK_LRM_OP_NOT_INSTALLED:return "Not installed"; default:return "UNKNOWN!"; } } static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) { switch (code) { case PCMK_OCF_OK: return "ok"; case PCMK_OCF_UNKNOWN_ERROR: return "unknown error"; case PCMK_OCF_INVALID_PARAM: return "invalid parameter"; case PCMK_OCF_UNIMPLEMENT_FEATURE: return "unimplemented feature"; case PCMK_OCF_INSUFFICIENT_PRIV: return "insufficient privileges"; case PCMK_OCF_NOT_INSTALLED: return "not installed"; case PCMK_OCF_NOT_CONFIGURED: return "not configured"; case PCMK_OCF_NOT_RUNNING: return "not running"; case PCMK_OCF_RUNNING_MASTER: return "master"; case PCMK_OCF_FAILED_MASTER: return "master (failed)"; case PCMK_OCF_SIGNAL: return "OCF_SIGNAL"; case PCMK_OCF_NOT_SUPPORTED: return "OCF_NOT_SUPPORTED"; case PCMK_OCF_PENDING: return "OCF_PENDING"; case PCMK_OCF_CANCELLED: return "OCF_CANCELLED"; case PCMK_OCF_TIMEOUT: return "OCF_TIMEOUT"; case PCMK_OCF_OTHER_ERROR: return "OCF_OTHER_ERROR"; case PCMK_OCF_DEGRADED: return "OCF_DEGRADED"; case PCMK_OCF_DEGRADED_MASTER: return "OCF_DEGRADED_MASTER"; default: return "unknown"; } } /** * \brief Get OCF equivalent of LSB exit code * * \param[in] action LSB action that produced exit code * \param[in] lsb_exitcode Exit code of LSB action * * \return PCMK_OCF_* constant that corresponds to LSB exit code */ static inline enum ocf_exitcode services_get_ocf_exitcode(const char *action, int lsb_exitcode) { /* For non-status actions, LSB and OCF share error code meaning <= 7 */ if (action && strcmp(action, "status") && strcmp(action, "monitor")) { if ((lsb_exitcode < 0) || (lsb_exitcode > PCMK_LSB_NOT_RUNNING)) { return PCMK_OCF_UNKNOWN_ERROR; } return (enum ocf_exitcode)lsb_exitcode; } /* status has different return codes */ switch (lsb_exitcode) { case PCMK_LSB_STATUS_OK: return PCMK_OCF_OK; case PCMK_LSB_STATUS_NOT_INSTALLED: return PCMK_OCF_NOT_INSTALLED; case PCMK_LSB_STATUS_INSUFFICIENT_PRIV: return PCMK_OCF_INSUFFICIENT_PRIV; case PCMK_LSB_STATUS_VAR_PID: case PCMK_LSB_STATUS_VAR_LOCK: case PCMK_LSB_STATUS_NOT_RUNNING: return PCMK_OCF_NOT_RUNNING; } return PCMK_OCF_UNKNOWN_ERROR; } # ifdef __cplusplus } # endif #endif /* __PCMK_SERVICES__ */ diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index c41e534028..398a7788d8 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -1,67 +1,62 @@ /* * 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 -#if 0 -lrmd_key_value_t * lrmd_set_alert_key_to_lrmd_params(lrmd_key_value_t *head, enum crm_alert_keys_e name, const char *value); -void lrmd_set_alert_envvar_to_lrmd_params(crm_alert_entry_t *entry, lrmd_key_value_t * params); -#endif - lrmd_key_value_t * lrmd_set_alert_key_to_lrmd_params(lrmd_key_value_t *head, 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); head = lrmd_key_value_add(head, *key, value); } return head; } void -lrmd_set_alert_envvar_to_lrmd_params(crm_alert_entry_t *entry, lrmd_key_value_t *head) +lrmd_set_alert_envvar_to_lrmd_params(lrmd_key_value_t *head, crm_alert_entry_t *entry) { GListPtr l; for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { crm_alert_envvar_t *ev = (crm_alert_envvar_t *)(l->data); crm_trace("Setting environment variable %s = '%s'", ev->name, ev->value?ev->value:""); lrmd_key_value_add(head, ev->name, ev->value); } }