diff --git a/attrd/commands.c b/attrd/commands.c index 3583179b961..94becc94a79 100644 --- a/attrd/commands.c +++ b/attrd/commands.c @@ -252,6 +252,9 @@ attrd_client_update(xmlNode *xml) } else if (attr == NULL) { crm_err("Update request did not specify attribute or regular expression"); + free(key); + free(set); + free(host); return; } diff --git a/crmd/control.c b/crmd/control.c index 1fb92bbff02..7cc888beadd 100644 --- a/crmd/control.c +++ b/crmd/control.c @@ -1076,7 +1076,7 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void fsa_cluster_name = strdup(value); } - alerts = output?first_named_child(output, XML_CIB_TAG_ALERTS):NULL; + alerts = first_named_child(output, XML_CIB_TAG_ALERTS); parse_notifications(alerts); set_bit(fsa_input_register, R_READ_CONFIG); diff --git a/crmd/notify.c b/crmd/notify.c index e3a27517561..67654433ab6 100644 --- a/crmd/notify.c +++ b/crmd/notify.c @@ -596,35 +596,38 @@ crmd_enable_notifications(const char *script, const char *target) } static void -set_notify_key(enum notify_keys_e name, const char *cvalue, char *value) +set_alert_key(enum notify_keys_e name, const char *value) { const char **key; - if(!cvalue) { - cvalue = value; - } - - for(key = notify_keys[name]; *key; key++) { - crm_trace("Setting notify key %s = '%s'", *key, cvalue); - if (cvalue) { - setenv(*key, cvalue, 1); + for (key = notify_keys[name]; *key; key++) { + crm_trace("Setting alert key %s = '%s'", *key, value); + if (value) { + setenv(*key, value, 1); } else { unsetenv(*key); } } +} - free(value); +static void +set_alert_key_int(enum notify_keys_e name, int value) +{ + char *s = crm_itoa(value); + + set_alert_key(name, s); + free(s); } static void -unset_notify_keys() +unset_alert_keys() { const char **key; enum notify_keys_e name; for(name = 0; name < DIMOF(notify_keys); name++) { for(key = notify_keys[name]; *key; key++) { - crm_trace("Unsetting notify key %s", *key); + crm_trace("Unsetting alert key %s", *key); unsetenv(*key); } } @@ -680,8 +683,8 @@ send_notifications(const char *kind) GListPtr l; crm_time_hr_t *now = crm_time_hr_new(NULL); - set_notify_key(CRM_notify_kind, kind, NULL); - set_notify_key(CRM_notify_version, VERSION, NULL); + set_alert_key(CRM_notify_kind, kind); + set_alert_key(CRM_notify_version, VERSION); for (l = g_list_first(notify_list); l; l = g_list_next(l)) { notify_entry_t *entry = (notify_entry_t *)(l->data); @@ -690,9 +693,9 @@ send_notifications(const char *kind) operations++; crm_debug("Sending '%s' notification to '%s' via '%s'", kind, entry->recipient, entry->path); - set_notify_key(CRM_notify_recipient, entry->recipient, NULL); - set_notify_key(CRM_notify_node_sequence, crm_itoa(operations), NULL); - set_notify_key(CRM_notify_timestamp, timestamp, NULL); + set_alert_key(CRM_notify_recipient, entry->recipient); + set_alert_key_int(CRM_notify_node_sequence, operations); + set_alert_key(CRM_notify_timestamp, timestamp); notify = services_action_create_generic(entry->path, NULL); @@ -713,7 +716,7 @@ send_notifications(const char *kind) free(timestamp); } - unset_notify_keys(); + unset_alert_keys(); if (now) { free(now); } @@ -726,9 +729,9 @@ crmd_notify_node_event(crm_node_t *node) return; } - set_notify_key(CRM_notify_node, node->uname, NULL); - set_notify_key(CRM_notify_nodeid, NULL, crm_itoa(node->id)); - set_notify_key(CRM_notify_desc, node->state, NULL); + set_alert_key(CRM_notify_node, node->uname); + set_alert_key_int(CRM_notify_nodeid, node->id); + set_alert_key(CRM_notify_desc, node->state); send_notifications("node"); } @@ -747,10 +750,10 @@ crmd_notify_fencing_op(stonith_event_t * e) e->operation, e->origin, e->target, pcmk_strerror(e->result), e->id); - set_notify_key(CRM_notify_node, e->target, NULL); - set_notify_key(CRM_notify_task, e->operation, NULL); - set_notify_key(CRM_notify_desc, NULL, desc); - set_notify_key(CRM_notify_rc, NULL, crm_itoa(e->result)); + set_alert_key(CRM_notify_node, e->target); + set_alert_key(CRM_notify_task, e->operation); + set_alert_key(CRM_notify_desc, desc); + set_alert_key_int(CRM_notify_rc, e->result); send_notifications("fencing"); } @@ -777,23 +780,21 @@ crmd_notify_resource_op(const char *node, lrmd_event_data_t * op) return; } - set_notify_key(CRM_notify_node, node, NULL); + set_alert_key(CRM_notify_node, node); - set_notify_key(CRM_notify_rsc, op->rsc_id, NULL); - set_notify_key(CRM_notify_task, op->op_type, NULL); - set_notify_key(CRM_notify_interval, NULL, crm_itoa(op->interval)); + set_alert_key(CRM_notify_rsc, op->rsc_id); + set_alert_key(CRM_notify_task, op->op_type); + set_alert_key_int(CRM_notify_interval, op->interval); - set_notify_key(CRM_notify_target_rc, NULL, crm_itoa(target_rc)); - set_notify_key(CRM_notify_status, NULL, crm_itoa(op->op_status)); - set_notify_key(CRM_notify_rc, NULL, crm_itoa(op->rc)); + set_alert_key_int(CRM_notify_target_rc, target_rc); + set_alert_key_int(CRM_notify_status, op->op_status); + set_alert_key_int(CRM_notify_rc, op->rc); if(op->op_status == PCMK_LRM_OP_DONE) { - set_notify_key(CRM_notify_desc, - services_ocf_exitcode_str(op->rc), NULL); + set_alert_key(CRM_notify_desc, services_ocf_exitcode_str(op->rc)); } else { - set_notify_key(CRM_notify_desc, - services_lrm_status_str(op->op_status), NULL); + set_alert_key(CRM_notify_desc, services_lrm_status_str(op->op_status)); } send_notifications("resource"); -} \ No newline at end of file +} diff --git a/doc/Pacemaker_Explained/en-US/Ch-Alerts.txt b/doc/Pacemaker_Explained/en-US/Ch-Alerts.txt index 79e7aef35fe..499b6498d7f 100644 --- a/doc/Pacemaker_Explained/en-US/Ch-Alerts.txt +++ b/doc/Pacemaker_Explained/en-US/Ch-Alerts.txt @@ -1,131 +1,178 @@ -= Receiving Alerts for Cluster Events = += Alerts = //// We prefer [[ch-alerts]], but older versions of asciidoc don't deal well with that construct for chapter headings //// -anchor:ch-alerts[Chapter 7, Receiving Alerts for Cluster Events] +anchor:ch-alerts[Chapter 7, Alerts] indexterm:[Resource,Alerts] -A Pacemaker cluster is an event-driven system. In this context, an 'event' -might be a resource failure or a configuration change, among others. +'Alerts' may be configured to take some external action when a cluster event +occurs (node failure, resource starting or stopping, etc.). +== Alert Agents == +As with resource agents, the cluster calls an external program (an +'alert agent') to handle alerts. The cluster passes information about the event +to the agent via environment variables. Agents can do anything +desired with this information (send an e-mail, log to a file, +update a monitoring system, etc.). +.Simple alert configuration +===== +[source,XML] +----- + + + + + +----- +===== -[[s-alerts-configuration]] -== Configuring Alerts via Alert-Agents == +In the example above, the cluster will call +my-script.sh+ for each event. -As with resource-agents an external program (alert-agent) is required to pass alerts generated from cluster events to a recipient (IP address, email address, URI). +Multiple alert agents may be configured; the cluster will call all of them for +each event. -When triggered, the alert-agent is fed with dynamically filled environment -variables describing precisely the cluster event that occurred. By making -smart usage of these variables in your alert-agent code, you can trigger -any action. -It is possible to use multiple alert-agents at the same time. +== Alert Recipients == -Similarly as with resource-agents, +meta-attributes+ can be used to configure how pacemaker is treating the alert-agent (formatting of environment-variables, timeout-handling, ...). +Each alert may be configured with one or more recipients. +The cluster will call the agent separately for each recipient. -If an alert-agent needs additional configuration - again similar as with resource-agents - +instance-attributes+ can be added to be passed to the alert-agents as additional environment variables. +.Alert configuration with recipient +===== +[source,XML] +----- + + + + + + + +----- +===== -For each of the configured alert-agents it is possible to configure multiple recipients. The alert-agents are called separately for each of the recipients configured. +In the above example, the cluster will call +my-script.sh+ for each event, +passing the recipient +some-address+ as an environment variable. -Instance- and meta-attributes can either be configured globally per alert-agent and/or per recipient. +The recipient may be anything the alert agent can recognize -- +an IP address, an e-mail address, a file name, whatever the particular +agent supports. -[NOTE] -===== -When there are multiple alert-agents and/or recipients configured on each cluster event there are multiple processes forked at the same time - for each alert-agent and each recipient one. -Assuming that not all of these processes get scheduled right away this would lead to timestamps, being taken from withing these processes, would differ for a single cluster event. And they would be delayed. +== Alert Meta-Attributes == -Thus pacemaker creates a u-second-resolution timestamp whenever a cluster event occurs and passes that to the alert-agents. +As with resource agents, meta-attributes can be configured for alert agents +to affect how Pacemaker calls them. -Furthermore pacemaker as well passes an every time increased sequence-number whenever an alert-agent is called. The sequence-numbers are valid just withing one cluster-node. An alert created for a cluster event that happened later in time does reliably have a higher sequence number than those for cluster events that had happened prior to this event. -===== +.Meta-Attributes of an Alert -[NOTE] -===== -The interface is realized as backward-compatible evolution of the interfaces previously provided with +ocf:pacemaker:Clustermon+ and *integrated-notifications*. -To preserve script-compatibility the environment-variables passed to the alert-agents are available prepended +CRM_notify+ (compatibility version) as well as +CRM_alert+. And they implement a superset of those previous features. -===== +[width="95%",cols="m,1,2 - - - - - - + + + - + + + + + + + + + + ----- ===== -.Sending Cluster Events as SNMP Traps +In the above example, the +my-script.sh+ will get called twice for each event, +with each call using a 15-second timeout. One call will be passed the recipient ++someuser@example.com+ and a timestamp in the format +%D %H:%M+, while the +other call will be passed the recipient +otheruser@example.com+ and a timestamp +in the format +%c+. + + +== Alert Instance Attributes == + +As with resource agents, agent-specific configuration values may be configured +as instance attributes. These will be passed to the agent as additional +environment variables. The number, names and allowed values of these +instance attributes are completely up to the particular agent. + +.Alert configuration with instance attributes ===== [source,XML] ----- - - - - - - + + + - - - - ------ -Alternatively attributes can be added to the recipient-section as well. -[source,XML] ------ - - - - - - - - - - - + + + + ----- ===== -.Sending Cluster Events as E-Mails + +== Using the Sample Alert Agents == + +Several sample alert agents are provided in the +https://github.com/ClusterLabs/pacemaker/tree/master/extra/alerts[+extra/alerts+] +directory of the pacemaker source tree. If you installed Pacemaker via a +package, these might be available somewhere on your system, such as ++/usr/share/pacemaker+. + +While these sample scripts may be used directly as alert agents, +they are provided mainly as templates to be edited to suit your purposes. +See their source code for the full set of instance attributes they support. + +.Sending cluster events as SNMP traps ===== [source,XML] ----- @@ -146,153 +193,127 @@ Alternatively attributes can be added to the recipient-section as well. ----- ===== -[[s-alerts-reference]] -== Alerts - Reference == +.Sending cluster events as e-mails +===== +[source,XML] +----- + + + + + + + + + + +----- +===== -.Environment Variables Passed to the External Agent - Common +== Writing an Alert Agent == -[width="95%",cols="m,2>",options="header",align="center"] + +.Environment variables passed to alert agents + +[width="95%",cols="m,2duration = FALSE; + if (source->tm_year > 0) { /* years since 1900 */ target->years = 1900 + source->tm_year; diff --git a/lib/common/xpath.c b/lib/common/xpath.c index 9a058192b2a..a6adaa04f1d 100644 --- a/lib/common/xpath.c +++ b/lib/common/xpath.c @@ -207,12 +207,11 @@ get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level) } xpath_prefix = (char *)xmlGetNodePath(xml_obj); - len += strlen(xpath_prefix); - len += strlen(xpath); - xpath_full = strdup(xpath_prefix); - xpath_full = realloc_safe(xpath_full, len + 1); - strncat(xpath_full, xpath, len); + len = strlen(xpath_prefix) + strlen(xpath) + 1; + xpath_full = malloc(len); + strcpy(xpath_full, xpath_prefix); + strcat(xpath_full, xpath); result = get_xpath_object(xpath_full, xml_obj, error_level); diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c index 4997cf82a20..118fe406e41 100644 --- a/lib/fencing/st_client.c +++ b/lib/fencing/st_client.c @@ -839,7 +839,7 @@ stonith_action_async_done(mainloop_child_t * p, pid_t pid, int core, int signo, static int internal_stonith_action_execute(stonith_action_t * action) { - int pid, status, len, rc = -EPROTO; + int pid, status = 0, len, rc = -EPROTO; int ret; int total = 0; int p_read_fd, p_write_fd; /* parent read/write file descriptors */ diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index d7421d152a5..7941440458c 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -698,7 +698,7 @@ unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container, } } - /* Begin compatability code */ + /* Begin compatibility code ("requires" set on start action not resource) */ value = g_hash_table_lookup(action->meta, "requires"); if (safe_str_neq(action->task, RSC_START) @@ -715,8 +715,8 @@ unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container, } else if (safe_str_eq(value, "unfencing")) { action->needs = rsc_req_stonith; set_bit(action->rsc->flags, pe_rsc_needs_unfencing); - if (is_set(data_set->flags, pe_flag_stonith_enabled)) { - crm_notice("%s requires (un)fencing but fencing is disabled", action->rsc->id); + if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) { + crm_notice("%s requires unfencing but fencing is disabled", action->rsc->id); } } else if (is_set(data_set->flags, pe_flag_stonith_enabled) @@ -725,7 +725,7 @@ unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container, if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) { crm_notice("%s requires fencing but fencing is disabled", action->rsc->id); } - /* End compatability code */ + /* End compatibility code */ } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) { action->needs = rsc_req_stonith; diff --git a/pengine/native.c b/pengine/native.c index 2c04ea95f8b..9662a2c11a4 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -1350,7 +1350,7 @@ native_internal_constraints(resource_t * rsc, pe_working_set_t * data_set) if(rsc != top) { /* Only create these constraints once, rsc is almost certainly cloned */ - clear_bit_recursive(top, pe_rsc_have_unfencing); + set_bit_recursive(top, pe_rsc_have_unfencing); } g_hash_table_iter_init(&iter, rsc->allowed_nodes); diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c index 7b7ebd4b0f7..3a32a40d231 100644 --- a/tools/crm_resource_runtime.c +++ b/tools/crm_resource_runtime.c @@ -589,21 +589,20 @@ cli_delete_attr(cib_t * cib_conn, const char * host_uname, const char * attr_nam pe_working_set_t * data_set) { node_t *node = pe_find_node(data_set->nodes, host_uname); + gboolean is_remote = FALSE; - if (node == NULL) { - CMD_ERR("Error deleting attribute '%s': node '%s' is unknown", attr_name, host_uname); - return -ENXIO; - } - -#if !HAVE_ATOMIC_ATTRD - if (is_remote_node(node)) { + if (node && is_remote_node(node)) { +#if HAVE_ATOMIC_ATTRD + is_remote = TRUE; +#else /* Talk directly to cib for remote nodes if it's legacy attrd */ return delete_attr_delegate(cib_conn, cib_sync_call, XML_CIB_TAG_STATUS, node->details->id, NULL, NULL, NULL, attr_name, NULL, FALSE, NULL); - } #endif - return attrd_update_delegate(NULL, 'D', node->details->uname, attr_name, NULL, XML_CIB_TAG_STATUS, NULL, - NULL, NULL, node ? is_remote_node(node) : FALSE); + } + return attrd_update_delegate(NULL, 'D', host_uname, attr_name, NULL, + XML_CIB_TAG_STATUS, NULL, NULL, NULL, + is_remote); } int