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,2",options="header",align="center"]
-|=========================================================
-
-|Environment Variable
-|Description
-
|CRM_alert_node
-| The node name for which the status changed
+|Name of affected node
indexterm:[Environment Variable,CRM_alert_,node]
-|CRM_alert_nodeid
-| The node id for which the status changed
- indexterm:[Environment Variable,CRM_alert_,nodeid]
-
|CRM_alert_desc
-| The current node state; One of `member` or `lost`
+|Detail about event. For +node+ alerts, this is the node's current state
+ (+member+ or +lost+). For +fencing+ alerts, this is a summary of the
+ requested fencing operation, including origin, target, and fencing operation
+ error code, if any. For +resource+ alerts, this is a readable string
+ equivalent of +CRM_alert_status+.
indexterm:[Environment Variable,CRM_alert_,desc]
-|=========================================================
-
-.Environment Variables - Additional for `fencing` alerts
-
-[width="95%",cols="m,2>",options="header",align="center"]
-|=========================================================
-
-|Environment Variable
-|Description
-
-|CRM_alert_node
-| The node name the fencing operation is requested for
- indexterm:[Environment Variable,CRM_alert_,node]
+|CRM_alert_nodeid
+|ID of node whose status changed (provided with +node+ alerts only)
+ indexterm:[Environment Variable,CRM_alert_,nodeid]
|CRM_alert_task
-| The fencing operation that was requested
+|The requested fencing or resource operation
+ (provided with +fencing+ and +resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,task]
|CRM_alert_rc
-| The numerical return code of the operation
+|The numerical return code of the fencing or resource operation
+ (provided with +fencing+ and +resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,rc]
-|CRM_alert_desc
-| A summary of requested fencing operation, by origin, on target
-adding textual output relevant error code of the fencing operation (if any)
- indexterm:[Environment Variable,CRM_alert_,desc]
-
-
-|=========================================================
-
-.Environment Variables - Additional for `resource` alerts
-
-[width="95%",cols="m,2>",options="header",align="center"]
-|=========================================================
-
-|Environment Variable
-|Description
-
-|CRM_alert_node
-| The node name for which the status changed
- indexterm:[Environment Variable,CRM_alert_,node]
-
|CRM_alert_rsc
-| The name of the resource that changed the status
+|The name of the affected resource (+resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,rsc]
-|CRM_alert_task
-| The operation that caused the status change
- indexterm:[Environment Variable,CRM_alert_,task]
-
|CRM_alert_interval
-| The interval of a resource operation
+|The interval of the resource operation (+resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,interval]
-|CRM_alert_rc
-| The numerical return code of the operation
- indexterm:[Environment Variable,CRM_alert_,rc]
-
|CRM_alert_target_rc
-| The expected numerical return code of the operation
+|The expected numerical return code of the operation (+resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,target_rc]
|CRM_alert_status
-| The numerical representation of the status of the operation
+|A numerical code used by Pacemaker to represent the operation result
+ (+resource+ alerts only)
indexterm:[Environment Variable,CRM_alert_,status]
-|CRM_alert_desc
-| The textual output relevant error code of the operation (if any)
-that caused the status change
- indexterm:[Environment Variable,CRM_alert_,desc]
-
|=========================================================
+Special concerns when writing alert agents:
-.Meta-Attributes
+* Alert agents will be called once per recipient. If an agent is not
+ able to run concurrently, it should be configured with only a single
+ recipient. The agent is free, however, to interpret the recipient
+ as a list.
-[width="95%",cols="m,2>",options="header",align="center"]
-|=========================================================
-
-|Meta-Attribute
-|Description
-
-|timestamp-format
-| Format string as used with `date` command - including the nano-second part - defining the format in which the timestamp of a cluster event is passed to the alert-agent
- indexterm:[meta-attribute,timestamp-format]
-
-|timeout
-| Alert-Agents are forked as separate processes. So to prevent them from hogging system-resources they are observed and terminated if they don't complete within the timeout specified.
- indexterm:[meta-attribute,timeout]
-
-
-|=========================================================
+* Alert agents are run as the +hacluster+ user, which has a minimal set
+ of permissions. If an agent requires additional privileges, it is
+ recommended to configure +sudo+ to allow the agent to run the necessary
+ commands as another user with the appropriate privileges.
+[NOTE]
+=====
+The alerts interface is designed to be backward compatible with the external
+scripts interface used by the +ocf:pacemaker:ClusterMon+ resource, which is
+now deprecated. To preserve this compatibility, the environment variables
+passed to alert agents are available prepended with +CRM_notify_+
+as well as +CRM_alert_+. One break in compatibility is that ClusterMon ran
+external scripts as the +root+ user, while alert agents are run as the
++hacluster+ user.
+=====
diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c
index 06b0a7406e5..d0be0cfc73f 100644
--- a/lib/common/iso8601.c
+++ b/lib/common/iso8601.c
@@ -1001,6 +1001,8 @@ ha_set_tm_time(crm_time_t * target, struct tm *source)
int h_offset = 0;
int m_offset = 0;
+ target->duration = 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