|
|
3d71c6 |
From: Andrew Beekhof <andrew@beekhof.net>
|
|
|
3d71c6 |
Date: Tue, 1 Sep 2015 13:17:45 +1000
|
|
|
3d71c6 |
Subject: [PATCH] Feature: crmd: Implement reliable event notifications
|
|
|
3d71c6 |
|
|
|
3d71c6 |
(cherry picked from commit 0cd1b8f02b403976afe106e0ca3a8a8a16864c6c)
|
|
|
3d71c6 |
---
|
|
|
3d71c6 |
crmd/Makefile.am | 2 +-
|
|
|
3d71c6 |
crmd/callbacks.c | 4 +
|
|
|
3d71c6 |
crmd/control.c | 67 +++++++++++++---
|
|
|
3d71c6 |
crmd/crmd_utils.h | 1 +
|
|
|
3d71c6 |
crmd/lrm.c | 2 +
|
|
|
3d71c6 |
crmd/notify.c | 188 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
3d71c6 |
crmd/notify.h | 30 +++++++
|
|
|
3d71c6 |
crmd/te_utils.c | 2 +
|
|
|
3d71c6 |
cts/CIB.py | 2 +
|
|
|
3d71c6 |
extra/pcmk_notify_sample.sh | 68 ++++++++++++++++
|
|
|
3d71c6 |
include/crm_internal.h | 1 +
|
|
|
3d71c6 |
lib/common/utils.c | 27 +++++++
|
|
|
3d71c6 |
12 files changed, 380 insertions(+), 14 deletions(-)
|
|
|
3d71c6 |
create mode 100644 crmd/notify.c
|
|
|
3d71c6 |
create mode 100644 crmd/notify.h
|
|
|
3d71c6 |
create mode 100755 extra/pcmk_notify_sample.sh
|
|
|
3d71c6 |
|
|
|
3d71c6 |
diff --git a/crmd/Makefile.am b/crmd/Makefile.am
|
|
|
3d71c6 |
index 8e5e1df..984f5d0 100644
|
|
|
3d71c6 |
--- a/crmd/Makefile.am
|
|
|
3d71c6 |
+++ b/crmd/Makefile.am
|
|
|
3d71c6 |
@@ -28,7 +28,7 @@ noinst_HEADERS = crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h \
|
|
|
3d71c6 |
fsa_matrix.h fsa_proto.h crmd_utils.h crmd_callbacks.h \
|
|
|
3d71c6 |
crmd_lrm.h te_callbacks.h tengine.h
|
|
|
3d71c6 |
|
|
|
3d71c6 |
-crmd_SOURCES = main.c crmd.c corosync.c \
|
|
|
3d71c6 |
+crmd_SOURCES = main.c crmd.c corosync.c notify.c \
|
|
|
3d71c6 |
fsa.c control.c messages.c membership.c callbacks.c \
|
|
|
3d71c6 |
election.c join_client.c join_dc.c subsystems.c throttle.c \
|
|
|
3d71c6 |
cib.c pengine.c tengine.c lrm.c lrm_state.c remote_lrmd_ra.c \
|
|
|
3d71c6 |
diff --git a/crmd/callbacks.c b/crmd/callbacks.c
|
|
|
3d71c6 |
index f646927..38fb30b 100644
|
|
|
3d71c6 |
--- a/crmd/callbacks.c
|
|
|
3d71c6 |
+++ b/crmd/callbacks.c
|
|
|
3d71c6 |
@@ -126,6 +126,7 @@ peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *d
|
|
|
3d71c6 |
case crm_status_nstate:
|
|
|
3d71c6 |
crm_info("%s is now %s (was %s)",
|
|
|
3d71c6 |
node->uname, state_text(node->state), state_text(data));
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
if (safe_str_eq(data, node->state)) {
|
|
|
3d71c6 |
/* State did not change */
|
|
|
3d71c6 |
return;
|
|
|
3d71c6 |
@@ -147,7 +148,10 @@ peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *d
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ crmd_notify_node_event(node);
|
|
|
3d71c6 |
break;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
case crm_status_processes:
|
|
|
3d71c6 |
if (data) {
|
|
|
3d71c6 |
old = *(const uint32_t *)data;
|
|
|
3d71c6 |
diff --git a/crmd/control.c b/crmd/control.c
|
|
|
3d71c6 |
index f4add49..d92f46b 100644
|
|
|
3d71c6 |
--- a/crmd/control.c
|
|
|
3d71c6 |
+++ b/crmd/control.c
|
|
|
3d71c6 |
@@ -873,28 +873,64 @@ do_recover(long long action,
|
|
|
3d71c6 |
|
|
|
3d71c6 |
/* *INDENT-OFF* */
|
|
|
3d71c6 |
pe_cluster_option crmd_opts[] = {
|
|
|
3d71c6 |
- /* name, old-name, validate, default, description */
|
|
|
3d71c6 |
- { "dc-version", NULL, "string", NULL, "none", NULL, "Version of Pacemaker on the cluster's DC.", "Includes the hash which identifies the exact Mercurial changeset it was built from. Used for diagnostic purposes." },
|
|
|
3d71c6 |
- { "cluster-infrastructure", NULL, "string", NULL, "heartbeat", NULL, "The messaging stack on which Pacemaker is currently running.", "Used for informational and diagnostic purposes." },
|
|
|
3d71c6 |
- { XML_CONFIG_ATTR_DC_DEADTIME, "dc_deadtime", "time", NULL, "20s", &check_time, "How long to wait for a response from other nodes during startup.", "The \"correct\" value will depend on the speed/load of your network and the type of switches used." },
|
|
|
3d71c6 |
+ /* name, old-name, validate, values, default, short description, long description */
|
|
|
3d71c6 |
+ { "dc-version", NULL, "string", NULL, "none", NULL,
|
|
|
3d71c6 |
+ "Version of Pacemaker on the cluster's DC.",
|
|
|
3d71c6 |
+ "Includes the hash which identifies the exact changeset it was built from. Used for diagnostic purposes."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { "cluster-infrastructure", NULL, "string", NULL, "heartbeat", NULL,
|
|
|
3d71c6 |
+ "The messaging stack on which Pacemaker is currently running.",
|
|
|
3d71c6 |
+ "Used for informational and diagnostic purposes." },
|
|
|
3d71c6 |
+ { XML_CONFIG_ATTR_DC_DEADTIME, "dc_deadtime", "time", NULL, "20s", &check_time,
|
|
|
3d71c6 |
+ "How long to wait for a response from other nodes during startup.",
|
|
|
3d71c6 |
+ "The \"correct\" value will depend on the speed/load of your network and the type of switches used."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
{ XML_CONFIG_ATTR_RECHECK, "cluster_recheck_interval", "time",
|
|
|
3d71c6 |
- "Zero disables polling. Positive values are an interval in seconds (unless other SI units are specified. eg. 5min)", "15min", &check_timer,
|
|
|
3d71c6 |
+ "Zero disables polling. Positive values are an interval in seconds (unless other SI units are specified. eg. 5min)",
|
|
|
3d71c6 |
+ "15min", &check_timer,
|
|
|
3d71c6 |
"Polling interval for time based changes to options, resource parameters and constraints.",
|
|
|
3d71c6 |
"The Cluster is primarily event driven, however the configuration can have elements that change based on time."
|
|
|
3d71c6 |
- " To ensure these changes take effect, we can optionally poll the cluster's status for changes." },
|
|
|
3d71c6 |
+ " To ensure these changes take effect, we can optionally poll the cluster's status for changes."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ { "notification-script", NULL, "string", NULL, "/dev/null", &check_script,
|
|
|
3d71c6 |
+ "Notification script to be called after significant cluster events",
|
|
|
3d71c6 |
+ "Full path to a script that will be invoked when resources start/stop/fail, fencing occurs or nodes join/leave the cluster.\n"
|
|
|
3d71c6 |
+ "Must exist on all nodes in the cluster."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { "notification-target", NULL, "string", NULL, "", NULL,
|
|
|
3d71c6 |
+ "Destination for notifications (Optional)",
|
|
|
3d71c6 |
+ "Where should the supplied script send notifications to. Useful to avoid hard-coding this in the script."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
{ "load-threshold", NULL, "percentage", NULL, "80%", &check_utilization,
|
|
|
3d71c6 |
"The maximum amount of system resources that should be used by nodes in the cluster",
|
|
|
3d71c6 |
"The cluster will slow down its recovery process when the amount of system resources used"
|
|
|
3d71c6 |
- " (currently CPU) approaches this limit", },
|
|
|
3d71c6 |
+ " (currently CPU) approaches this limit",
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
{ "node-action-limit", NULL, "integer", NULL, "0", &check_number,
|
|
|
3d71c6 |
"The maximum number of jobs that can be scheduled per node. Defaults to 2x cores"},
|
|
|
3d71c6 |
- { XML_CONFIG_ATTR_ELECTION_FAIL, "election_timeout", "time", NULL, "2min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." },
|
|
|
3d71c6 |
- { XML_CONFIG_ATTR_FORCE_QUIT, "shutdown_escalation", "time", NULL, "20min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." },
|
|
|
3d71c6 |
- { "crmd-integration-timeout", NULL, "time", NULL, "3min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." },
|
|
|
3d71c6 |
- { "crmd-finalization-timeout", NULL, "time", NULL, "30min", &check_timer, "*** Advanced Use Only ***.", "If you need to adjust this value, it probably indicates the presence of a bug." },
|
|
|
3d71c6 |
- { "crmd-transition-delay", NULL, "time", NULL, "0s", &check_timer, "*** Advanced Use Only ***\nEnabling this option will slow down cluster recovery under all conditions", "Delay cluster recovery for the configured interval to allow for additional/related events to occur.\nUseful if your configuration is sensitive to the order in which ping updates arrive." },
|
|
|
3d71c6 |
+ { XML_CONFIG_ATTR_ELECTION_FAIL, "election_timeout", "time", NULL, "2min", &check_timer,
|
|
|
3d71c6 |
+ "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { XML_CONFIG_ATTR_FORCE_QUIT, "shutdown_escalation", "time", NULL, "20min", &check_timer,
|
|
|
3d71c6 |
+ "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { "crmd-integration-timeout", NULL, "time", NULL, "3min", &check_timer,
|
|
|
3d71c6 |
+ "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { "crmd-finalization-timeout", NULL, "time", NULL, "30min", &check_timer,
|
|
|
3d71c6 |
+ "*** Advanced Use Only ***.", "If you need to adjust this value, it probably indicates the presence of a bug."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
+ { "crmd-transition-delay", NULL, "time", NULL, "0s", &check_timer,
|
|
|
3d71c6 |
+ "*** Advanced Use Only ***\n"
|
|
|
3d71c6 |
+ "Enabling this option will slow down cluster recovery under all conditions",
|
|
|
3d71c6 |
+ "Delay cluster recovery for the configured interval to allow for additional/related events to occur.\n"
|
|
|
3d71c6 |
+ "Useful if your configuration is sensitive to the order in which ping updates arrive."
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
{ "stonith-watchdog-timeout", NULL, "time", NULL, NULL, &check_timer,
|
|
|
3d71c6 |
- "How long to wait before we can assume nodes are safely down", NULL },
|
|
|
3d71c6 |
+ "How long to wait before we can assume nodes are safely down", NULL
|
|
|
3d71c6 |
+ },
|
|
|
3d71c6 |
{ "no-quorum-policy", "no_quorum_policy", "enum", "stop, freeze, ignore, suicide", "stop", &check_quorum, NULL, NULL },
|
|
|
3d71c6 |
|
|
|
3d71c6 |
#if SUPPORT_PLUGIN
|
|
|
3d71c6 |
@@ -927,6 +963,7 @@ crmd_pref(GHashTable * options, const char *name)
|
|
|
3d71c6 |
static void
|
|
|
3d71c6 |
config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
|
|
|
3d71c6 |
{
|
|
|
3d71c6 |
+ const char *script = NULL;
|
|
|
3d71c6 |
const char *value = NULL;
|
|
|
3d71c6 |
GHashTable *config_hash = NULL;
|
|
|
3d71c6 |
crm_time_t *now = crm_time_new(NULL);
|
|
|
3d71c6 |
@@ -955,6 +992,10 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void
|
|
|
3d71c6 |
|
|
|
3d71c6 |
verify_crmd_options(config_hash);
|
|
|
3d71c6 |
|
|
|
3d71c6 |
+ script = crmd_pref(config_hash, "notification-script");
|
|
|
3d71c6 |
+ value = crmd_pref(config_hash, "notification-target");
|
|
|
3d71c6 |
+ crmd_enable_notifications(script, value);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
value = crmd_pref(config_hash, XML_CONFIG_ATTR_DC_DEADTIME);
|
|
|
3d71c6 |
election_trigger->period_ms = crm_get_msec(value);
|
|
|
3d71c6 |
|
|
|
3d71c6 |
diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
|
|
|
3d71c6 |
index 78214bf..7e8c3e6 100644
|
|
|
3d71c6 |
--- a/crmd/crmd_utils.h
|
|
|
3d71c6 |
+++ b/crmd/crmd_utils.h
|
|
|
3d71c6 |
@@ -21,6 +21,7 @@
|
|
|
3d71c6 |
# include <crm/crm.h>
|
|
|
3d71c6 |
# include <crm/common/xml.h>
|
|
|
3d71c6 |
# include <crm/cib/internal.h> /* For CIB_OP_MODIFY */
|
|
|
3d71c6 |
+# include "notify.h"
|
|
|
3d71c6 |
|
|
|
3d71c6 |
# define CLIENT_EXIT_WAIT 30
|
|
|
3d71c6 |
# define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
|
|
3d71c6 |
diff --git a/crmd/lrm.c b/crmd/lrm.c
|
|
|
3d71c6 |
index 418e7cf..48195e8 100644
|
|
|
3d71c6 |
--- a/crmd/lrm.c
|
|
|
3d71c6 |
+++ b/crmd/lrm.c
|
|
|
3d71c6 |
@@ -2415,6 +2415,8 @@ process_lrm_event(lrm_state_t * lrm_state, lrmd_event_data_t * op, struct recurr
|
|
|
3d71c6 |
free(prefix);
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
|
|
|
3d71c6 |
+ crmd_notify_resource_op(lrm_state->node_name, op);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
if (op->rsc_deleted) {
|
|
|
3d71c6 |
crm_info("Deletion of resource '%s' complete after %s", op->rsc_id, op_key);
|
|
|
3d71c6 |
delete_rsc_entry(lrm_state, NULL, op->rsc_id, NULL, pcmk_ok, NULL);
|
|
|
3d71c6 |
diff --git a/crmd/notify.c b/crmd/notify.c
|
|
|
3d71c6 |
new file mode 100644
|
|
|
3d71c6 |
index 0000000..980bfa6
|
|
|
3d71c6 |
--- /dev/null
|
|
|
3d71c6 |
+++ b/crmd/notify.c
|
|
|
3d71c6 |
@@ -0,0 +1,188 @@
|
|
|
3d71c6 |
+/*
|
|
|
3d71c6 |
+ * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * This program is free software; you can redistribute it and/or
|
|
|
3d71c6 |
+ * modify it under the terms of the GNU General Public
|
|
|
3d71c6 |
+ * License as published by the Free Software Foundation; either
|
|
|
3d71c6 |
+ * version 2 of the License, or (at your option) any later version.
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * This software is distributed in the hope that it will be useful,
|
|
|
3d71c6 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
3d71c6 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
3d71c6 |
+ * General Public License for more details.
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * You should have received a copy of the GNU General Public
|
|
|
3d71c6 |
+ * License along with this library; if not, write to the Free Software
|
|
|
3d71c6 |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
3d71c6 |
+ */
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+#include <crm_internal.h>
|
|
|
3d71c6 |
+#include <crm/crm.h>
|
|
|
3d71c6 |
+#include <crm/msg_xml.h>
|
|
|
3d71c6 |
+#include "notify.h"
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+char *notify_script = NULL;
|
|
|
3d71c6 |
+char *notify_target = NULL;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+static const char *notify_keys[] =
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ "CRM_notify_recipient",
|
|
|
3d71c6 |
+ "CRM_notify_node",
|
|
|
3d71c6 |
+ "CRM_notify_rsc",
|
|
|
3d71c6 |
+ "CRM_notify_task",
|
|
|
3d71c6 |
+ "CRM_notify_interval",
|
|
|
3d71c6 |
+ "CRM_notify_desc",
|
|
|
3d71c6 |
+ "CRM_notify_status",
|
|
|
3d71c6 |
+ "CRM_notify_target_rc",
|
|
|
3d71c6 |
+ "CRM_notify_rc",
|
|
|
3d71c6 |
+ "CRM_notify_kind",
|
|
|
3d71c6 |
+ "CRM_notify_version",
|
|
|
3d71c6 |
+};
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+void
|
|
|
3d71c6 |
+crmd_enable_notifications(const char *script, const char *target)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ free(notify_script);
|
|
|
3d71c6 |
+ notify_script = NULL;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ free(notify_target);
|
|
|
3d71c6 |
+ notify_target = NULL;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(safe_str_eq(script, "/dev/null")) {
|
|
|
3d71c6 |
+ crm_notice("Notifications disabled");
|
|
|
3d71c6 |
+ return;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ notify_script = strdup(script);
|
|
|
3d71c6 |
+ notify_target = strdup(target);
|
|
|
3d71c6 |
+ crm_notice("Notifications enabled");
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+static void
|
|
|
3d71c6 |
+set_notify_key(const char *name, const char *cvalue, char *value)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ int lpc;
|
|
|
3d71c6 |
+ bool found = 0;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(cvalue == NULL) {
|
|
|
3d71c6 |
+ cvalue = value;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ for(lpc = 0; lpc < DIMOF(notify_keys); lpc++) {
|
|
|
3d71c6 |
+ if(safe_str_eq(name, notify_keys[lpc])) {
|
|
|
3d71c6 |
+ found = 1;
|
|
|
3d71c6 |
+ crm_trace("Setting notify key %s = '%s'", name, cvalue);
|
|
|
3d71c6 |
+ setenv(name, cvalue, 1);
|
|
|
3d71c6 |
+ break;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ CRM_ASSERT(found != 0);
|
|
|
3d71c6 |
+ free(value);
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+static void
|
|
|
3d71c6 |
+send_notification(const char *kind)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ int lpc;
|
|
|
3d71c6 |
+ pid_t pid;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ crm_debug("Sending '%s' notification to '%s' via '%s'", kind, notify_target, notify_script);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_recipient", notify_target, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_kind", kind, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_version", VERSION, NULL);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ pid = fork();
|
|
|
3d71c6 |
+ if (pid == -1) {
|
|
|
3d71c6 |
+ crm_perror(LOG_ERR, "notification failed");
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if (pid == 0) {
|
|
|
3d71c6 |
+ /* crm_debug("notification: I am the child. Executing the nofitication program."); */
|
|
|
3d71c6 |
+ execl(notify_script, notify_script, NULL);
|
|
|
3d71c6 |
+ exit(EXIT_FAILURE);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ } else {
|
|
|
3d71c6 |
+ for(lpc = 0; lpc < DIMOF(notify_keys); lpc++) {
|
|
|
3d71c6 |
+ unsetenv(notify_keys[lpc]);
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+void crmd_notify_node_event(crm_node_t *node)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ if(notify_script == NULL) {
|
|
|
3d71c6 |
+ return;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_node", node->uname, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_desc", node->state, NULL);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ send_notification("node");
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+void
|
|
|
3d71c6 |
+crmd_notify_fencing_op(stonith_event_t * e)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ char *desc = NULL;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(notify_script) {
|
|
|
3d71c6 |
+ return;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ desc = crm_strdup_printf("Operation %s requested by %s for peer %s: %s (ref=%s)",
|
|
|
3d71c6 |
+ e->operation, e->origin, e->target, pcmk_strerror(e->result),
|
|
|
3d71c6 |
+ e->id);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_node", e->target, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_task", e->operation, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_desc", NULL, desc);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_rc", NULL, crm_itoa(e->result));
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ send_notification("fencing");
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+void
|
|
|
3d71c6 |
+crmd_notify_resource_op(const char *node, lrmd_event_data_t * op)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ int target_rc = 0;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(notify_script == NULL) {
|
|
|
3d71c6 |
+ return;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ target_rc = rsc_op_expected_rc(op);
|
|
|
3d71c6 |
+ if(op->interval == 0 && target_rc == op->rc && safe_str_eq(op->op_type, RSC_STATUS)) {
|
|
|
3d71c6 |
+ /* Leave it up to the script if they want to notify for
|
|
|
3d71c6 |
+ * 'failed' probes, only swallow ones for which the result was
|
|
|
3d71c6 |
+ * unexpected.
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * Even if we find a resource running, it was probably because
|
|
|
3d71c6 |
+ * someone erased the status section.
|
|
|
3d71c6 |
+ */
|
|
|
3d71c6 |
+ return;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_node", node, NULL);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_rsc", op->rsc_id, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_task", op->op_type, NULL);
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_interval", NULL, crm_itoa(op->interval));
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_target_rc", NULL, crm_itoa(target_rc));
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_status", NULL, crm_itoa(op->op_status));
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_rc", NULL, crm_itoa(op->rc));
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(op->op_status == PCMK_LRM_OP_DONE) {
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_desc", services_ocf_exitcode_str(op->rc), NULL);
|
|
|
3d71c6 |
+ } else {
|
|
|
3d71c6 |
+ set_notify_key("CRM_notify_desc", services_lrm_status_str(op->op_status), NULL);
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ send_notification("resource");
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
diff --git a/crmd/notify.h b/crmd/notify.h
|
|
|
3d71c6 |
new file mode 100644
|
|
|
3d71c6 |
index 0000000..4b138ea
|
|
|
3d71c6 |
--- /dev/null
|
|
|
3d71c6 |
+++ b/crmd/notify.h
|
|
|
3d71c6 |
@@ -0,0 +1,30 @@
|
|
|
3d71c6 |
+/*
|
|
|
3d71c6 |
+ * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * This program is free software; you can redistribute it and/or
|
|
|
3d71c6 |
+ * modify it under the terms of the GNU General Public
|
|
|
3d71c6 |
+ * License as published by the Free Software Foundation; either
|
|
|
3d71c6 |
+ * version 2 of the License, or (at your option) any later version.
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * This software is distributed in the hope that it will be useful,
|
|
|
3d71c6 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
3d71c6 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
3d71c6 |
+ * General Public License for more details.
|
|
|
3d71c6 |
+ *
|
|
|
3d71c6 |
+ * You should have received a copy of the GNU General Public
|
|
|
3d71c6 |
+ * License along with this library; if not, write to the Free Software
|
|
|
3d71c6 |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
3d71c6 |
+ */
|
|
|
3d71c6 |
+#ifndef CRMD_NOTIFY__H
|
|
|
3d71c6 |
+# define CRMD_NOTIFY__H
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+# include <crm/crm.h>
|
|
|
3d71c6 |
+# include <crm/cluster.h>
|
|
|
3d71c6 |
+# include <crm/stonith-ng.h>
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+void crmd_enable_notifications(const char *script, const char *target);
|
|
|
3d71c6 |
+void crmd_notify_node_event(crm_node_t *node);
|
|
|
3d71c6 |
+void crmd_notify_fencing_op(stonith_event_t * e);
|
|
|
3d71c6 |
+void crmd_notify_resource_op(const char *node, lrmd_event_data_t * op);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+#endif
|
|
|
3d71c6 |
diff --git a/crmd/te_utils.c b/crmd/te_utils.c
|
|
|
3d71c6 |
index a1d29f6..22551ba 100644
|
|
|
3d71c6 |
--- a/crmd/te_utils.c
|
|
|
3d71c6 |
+++ b/crmd/te_utils.c
|
|
|
3d71c6 |
@@ -124,6 +124,8 @@ tengine_stonith_notify(stonith_t * st, stonith_event_t * st_event)
|
|
|
3d71c6 |
return;
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
|
|
|
3d71c6 |
+ crmd_notify_fencing_op(st_event);
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
if (st_event->result == pcmk_ok && safe_str_eq("on", st_event->action)) {
|
|
|
3d71c6 |
crm_notice("%s was successfully unfenced by %s (at the request of %s)",
|
|
|
3d71c6 |
st_event->target, st_event->executioner ? st_event->executioner : "<anyone>", st_event->origin);
|
|
|
3d71c6 |
diff --git a/cts/CIB.py b/cts/CIB.py
|
|
|
3d71c6 |
index 8fbba6c..cd3a6a1 100644
|
|
|
3d71c6 |
--- a/cts/CIB.py
|
|
|
3d71c6 |
+++ b/cts/CIB.py
|
|
|
3d71c6 |
@@ -219,6 +219,8 @@ class CIB11(ConfigBase):
|
|
|
3d71c6 |
o["dc-deadtime"] = "5s"
|
|
|
3d71c6 |
o["no-quorum-policy"] = no_quorum
|
|
|
3d71c6 |
o["expected-quorum-votes"] = self.num_nodes
|
|
|
3d71c6 |
+ o["notification-script"] = "/var/lib/pacemaker/notify.sh"
|
|
|
3d71c6 |
+ o["notification-target"] = "/var/lib/pacemaker/notify.log"
|
|
|
3d71c6 |
|
|
|
3d71c6 |
if self.CM.Env["DoBSC"] == 1:
|
|
|
3d71c6 |
o["ident-string"] = "Linux-HA TEST configuration file - REMOVEME!!"
|
|
|
3d71c6 |
diff --git a/extra/pcmk_notify_sample.sh b/extra/pcmk_notify_sample.sh
|
|
|
3d71c6 |
new file mode 100755
|
|
|
3d71c6 |
index 0000000..83cf8e9
|
|
|
3d71c6 |
--- /dev/null
|
|
|
3d71c6 |
+++ b/extra/pcmk_notify_sample.sh
|
|
|
3d71c6 |
@@ -0,0 +1,68 @@
|
|
|
3d71c6 |
+#!/bin/bash
|
|
|
3d71c6 |
+#
|
|
|
3d71c6 |
+# Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
|
|
|
3d71c6 |
+#
|
|
|
3d71c6 |
+# This program is free software; you can redistribute it and/or
|
|
|
3d71c6 |
+# modify it under the terms of the GNU General Public
|
|
|
3d71c6 |
+# License as published by the Free Software Foundation; either
|
|
|
3d71c6 |
+# version 2 of the License, or (at your option) any later version.
|
|
|
3d71c6 |
+#
|
|
|
3d71c6 |
+# This software is distributed in the hope that it will be useful,
|
|
|
3d71c6 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
3d71c6 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
3d71c6 |
+# General Public License for more details.
|
|
|
3d71c6 |
+#
|
|
|
3d71c6 |
+# You should have received a copy of the GNU General Public
|
|
|
3d71c6 |
+# License along with this library; if not, write to the Free Software
|
|
|
3d71c6 |
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+if [ -z $CRM_notify_version ]; then
|
|
|
3d71c6 |
+ echo "Pacemaker version 1.1.14 is required" >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ exit 0
|
|
|
3d71c6 |
+fi
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+case $CRM_notify_kind in
|
|
|
3d71c6 |
+ node)
|
|
|
3d71c6 |
+ echo "Node '${CRM_notify_node}' is now '${CRM_notify_desc}'" >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ ;;
|
|
|
3d71c6 |
+ fencing)
|
|
|
3d71c6 |
+ # Other keys:
|
|
|
3d71c6 |
+ #
|
|
|
3d71c6 |
+ # CRM_notify_node
|
|
|
3d71c6 |
+ # CRM_notify_task
|
|
|
3d71c6 |
+ # CRM_notify_rc
|
|
|
3d71c6 |
+ #
|
|
|
3d71c6 |
+ echo "Fencing ${CRM_notify_desc}" >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ ;;
|
|
|
3d71c6 |
+ resource)
|
|
|
3d71c6 |
+ # Other keys:
|
|
|
3d71c6 |
+ #
|
|
|
3d71c6 |
+ # CRM_notify_target_rc
|
|
|
3d71c6 |
+ # CRM_notify_status
|
|
|
3d71c6 |
+ # CRM_notify_rc
|
|
|
3d71c6 |
+ #
|
|
|
3d71c6 |
+ if [ ${CRM_notify_interval} = "0" ]; then
|
|
|
3d71c6 |
+ CRM_notify_interval=""
|
|
|
3d71c6 |
+ else
|
|
|
3d71c6 |
+ CRM_notify_interval=" (${CRM_notify_interval})"
|
|
|
3d71c6 |
+ fi
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if [ ${CRM_notify_target_rc} = "0" ]; then
|
|
|
3d71c6 |
+ CRM_notify_target_rc=""
|
|
|
3d71c6 |
+ else
|
|
|
3d71c6 |
+ CRM_notify_target_rc=" (target: ${CRM_notify_target_rc})"
|
|
|
3d71c6 |
+ fi
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ case ${CRM_notify_desc} in
|
|
|
3d71c6 |
+ Cancelled) ;;
|
|
|
3d71c6 |
+ *)
|
|
|
3d71c6 |
+ echo "Resource operation '${CRM_notify_task}${CRM_notify_interval}' for '${CRM_notify_rsc}' on '${CRM_notify_node}': ${CRM_notify_desc}${CRM_notify_target_rc}" >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ ;;
|
|
|
3d71c6 |
+ esac
|
|
|
3d71c6 |
+ ;;
|
|
|
3d71c6 |
+ *)
|
|
|
3d71c6 |
+ echo "Unhandled $CRM_notify_kind notification" >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ env | grep CRM_notify >> ${CRM_notify_recipient}
|
|
|
3d71c6 |
+ ;;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+esac
|
|
|
3d71c6 |
diff --git a/include/crm_internal.h b/include/crm_internal.h
|
|
|
3d71c6 |
index c13bc7b..fb03537 100644
|
|
|
3d71c6 |
--- a/include/crm_internal.h
|
|
|
3d71c6 |
+++ b/include/crm_internal.h
|
|
|
3d71c6 |
@@ -127,6 +127,7 @@ gboolean check_timer(const char *value);
|
|
|
3d71c6 |
gboolean check_boolean(const char *value);
|
|
|
3d71c6 |
gboolean check_number(const char *value);
|
|
|
3d71c6 |
gboolean check_quorum(const char *value);
|
|
|
3d71c6 |
+gboolean check_script(const char *value);
|
|
|
3d71c6 |
gboolean check_utilization(const char *value);
|
|
|
3d71c6 |
|
|
|
3d71c6 |
/* Shared PE/crmd functionality */
|
|
|
3d71c6 |
diff --git a/lib/common/utils.c b/lib/common/utils.c
|
|
|
3d71c6 |
index 6a234dc..628cf2f 100644
|
|
|
3d71c6 |
--- a/lib/common/utils.c
|
|
|
3d71c6 |
+++ b/lib/common/utils.c
|
|
|
3d71c6 |
@@ -180,6 +180,33 @@ check_quorum(const char *value)
|
|
|
3d71c6 |
}
|
|
|
3d71c6 |
|
|
|
3d71c6 |
gboolean
|
|
|
3d71c6 |
+check_script(const char *value)
|
|
|
3d71c6 |
+{
|
|
|
3d71c6 |
+ struct stat st;
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(safe_str_eq(value, "/dev/null")) {
|
|
|
3d71c6 |
+ return TRUE;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(stat(value, &st) != 0) {
|
|
|
3d71c6 |
+ crm_err("Script %s does not exist", value);
|
|
|
3d71c6 |
+ return FALSE;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if(S_ISREG(st.st_mode) == 0) {
|
|
|
3d71c6 |
+ crm_err("Script %s is not a regular file", value);
|
|
|
3d71c6 |
+ return FALSE;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
|
|
|
3d71c6 |
+ crm_err("Script %s is not executable", value);
|
|
|
3d71c6 |
+ return FALSE;
|
|
|
3d71c6 |
+ }
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+ return TRUE;
|
|
|
3d71c6 |
+}
|
|
|
3d71c6 |
+
|
|
|
3d71c6 |
+gboolean
|
|
|
3d71c6 |
check_utilization(const char *value)
|
|
|
3d71c6 |
{
|
|
|
3d71c6 |
char *end = NULL;
|