Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4525695
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
110 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/Makefile.am b/Makefile.am
index 12ea936510..9b081aa00f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,131 +1,131 @@
#
# Pacemaker code
#
# Copyright (C) 2004 Andrew Beekhof
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
EXTRA_DIST = bootstrap ConfigureMe README.in libltdl.tar
RPM = @RPM@
RPMFLAGS = -ba
TARFILE = pacemaker.tar.gz
AM_TAR = tar
LAST_RELEASE = Pacemaker-0.6.2
STABLE_SERIES = stable-0.6
AUTOMAKE_OPTIONS = foreign
##ACLOCAL = aclocal -I $(auxdir)
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure DRF/config-h.in \
DRF/stamp-h.in libtool.m4 ltdl.m4 libltdl.tar
-SUBDIRS = debian build replace include lib cib crmd pengine transitioner crm tools doc cts xml
+SUBDIRS = debian build replace include lib cib pengine crmd crm tools doc cts xml
tgz:
rm -f $(TARFILE)
hg archive -t tgz $(TARFILE)
echo Rebuilt $(TARFILE) on `date`
changes:
printf "$(PACKAGE) ($(VERSION)-1) stable; urgency=medium\n"
printf " * Update source tarball to revision: `hg id`\n"
printf " * Statistics:\n"
printf " Changesets: `hg log -M --template "{desc|firstline|strip}\n" -r $(LAST_RELEASE):tip | wc -l`\n"
printf " Diff: "
hg diff -r $(LAST_RELEASE):tip | diffstat | tail -n 1
printf "\n * Testing Notes:\n"
printf "\n + Test hardware:\n"
printf "\n + All testing was performed with STONITH enabled\n"
printf "\n + Pending bugs encountered during testing:\n"
printf "\n * Changes since $(LAST_RELEASE)\n"
hg log -M --template " + {desc|firstline|strip}\n" -r $(LAST_RELEASE):tip | grep -v Low: | sort -uf
printf "\n -- Andrew Beekhof <abeekhof@suse.de> `date +"%a, %d %b %Y %T %z"`\n"
features:
printf "$(PACKAGE) ($(VERSION)-1) unstable; urgency=medium\n"
printf " * Update source tarball to revision: `hg id`\n"
printf " * Statistics:\n"
printf " Changesets: `hg out -M --template "{desc|firstline|strip}\n" ../$(STABLE_SERIES) | wc -l`\n"
printf " Diff: "
hg out -M -p ../$(STABLE_SERIES) | diffstat | tail -n 1
printf "\n * Changes added since $(STABLE_SERIES)\n"
hg out -M --template " + {desc|firstline|strip}\n" ../$(STABLE_SERIES) | grep -v Low: | sort -uf
printf "\n -- Andrew Beekhof <abeekhof@suse.de> `date +"%a, %d %b %Y %T %z"`\n"
obs: tgz
make changes > .changes
scp .changes $(TARFILE) vmhost.beekhof.net:Development/obs/server:ha-clustering/pacemaker/
dev: tgz
make features > .changes
scp .changes $(TARFILE) vmhost.beekhof.net:Development/obs/server:ha-clustering:UNSTABLE/pacemaker/
home: tgz
make changes > .changes
scp .changes $(TARFILE) vmhost.beekhof.net:Development/obs/home:beekhof/pacemaker-test/
global: clean-generic
gtags
htags -sanhIT
global-www: global
rsync -avzxlSD --progress HTML/ root@clusterlabs.org:/var/lib/global/pacemaker
rpmtgz: tgz
echo "Installing $(TARFILE) into /usr/src/packages/SOURCES for rpm"
-test -d /usr/src/packages/SOURCES && cp $(TARFILE) /usr/src/packages/SOURCES/
-test -d /usr/src/redhat/SOURCES && cp $(TARFILE) /usr/src/redhat/SOURCES/
rpm: rpmtgz
$(RPM) $(RPMFLAGS) $(top_srcdir)/pacemaker.spec </dev/null;
drpm: rpmtgz
$(RPM) --nodeps $(RPMFLAGS) $(top_srcdir)/pacemaker.spec </dev/null;
deb: tgz
rm -rf $(distdir)
tar -zxf $(TARFILE)
cd $(distdir) ; dpkg-buildpackage -rfakeroot -us -uc
rm -rf $(distdir)
install-exec-local:
if BUILD_AIS_SUPPORT
mkdir -p $(DESTDIR)$(LCRSODIR)
rm -f $(DESTDIR)$(LCRSODIR)/pacemaker.lcrso $(DESTDIR)$(LCRSODIR)/service_crm.so
cp $(DESTDIR)$(libdir)/service_crm.so $(DESTDIR)$(LCRSODIR)/pacemaker.lcrso
endif
clean-generic:
find . -name ".gres.*" -exec rm \{\} \;
find . -name "*~" -exec rm \{\} \;
dist-clean-local:
rm -f autoconf automake autoheader $(TARFILE)
maintainer-clean-local:
rm -f libltdl.tar
# "pkg" format for Solaris etc.
pkg:
(cd build/pkg && $(MAKE) PWD=`pwd` pkg)
# "port" format for BSD
portfile: dist
( cd build/port && $(MAKE) PWD=`pwd` portfile)
.PHONY: rpm pkg handy handy-copy
diff --git a/crmd/Makefile.am b/crmd/Makefile.am
index 95162f3d54..dffe29932f 100644
--- a/crmd/Makefile.am
+++ b/crmd/Makefile.am
@@ -1,69 +1,70 @@
#
# Copyright (C) 2004 Andrew Beekhof
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \
-I$(AISPREFIX)/include/openais
halibdir = $(libdir)/@HB_PKG@
COMMONLIBS = \
$(top_builddir)/lib/crm/common/libcrmcommon.la \
$(top_builddir)/lib/crm/pengine/libpe_rules.la \
$(top_builddir)/lib/crm/cib/libcib.la \
-lplumb \
$(GLIBLIB) $(LIBRT) $(GNUTLSLIBS)
## binary progs
halib_PROGRAMS = crmd atest
## SOURCES
noinst_HEADERS = crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h \
fsa_matrix.h fsa_proto.h crmd_utils.h crmd_callbacks.h \
crmd_lrm.h
atest_SOURCES = atest.c
atest_LDADD = $(COMMONLIBS)
crmd_SOURCES = main.c crmd.c \
fsa.c control.c messages.c ccm.c callbacks.c \
election.c join_client.c join_dc.c subsystems.c \
cib.c pengine.c tengine.c lrm.c \
- utils.c misc.c
+ utils.c misc.c te_events.c te_actions.c te_utils.c te_callbacks.c
-crmd_LDADD = $(COMMONLIBS) $(CLUSTERLIBS) -llrm \
+crmd_LDADD = $(COMMONLIBS) $(CLUSTERLIBS) -llrm \
+ $(top_builddir)/lib/crm/transition/libtransitioner.la \
$(top_builddir)/lib/crm/common/libcrmcluster.la
clean-generic:
rm -f *.log *.debug *.xml *~
install-exec-local:
uninstall-local:
graphs: fsa_inputs.png fsa_inputs_by_action.png fsa_actions_by_state.png
%.png: %.dot
dot -Tpng $< > $@
%.dot : fsa_matrix.h make_dot.pl
perl $(top_srcdir)/crm/crmd/make_dot.pl $(top_srcdir)/crm/crmd/fsa_matrix.h $(top_builddir)/crm/crmd
diff --git a/crmd/messages.c b/crmd/messages.c
index aca169002f..cfff8e784d 100644
--- a/crmd/messages.c
+++ b/crmd/messages.c
@@ -1,1196 +1,1166 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <string.h>
#include <time.h>
#include <crmd_fsa.h>
#include <lrm/lrm_api.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crm/common/cluster.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crmd_lrm.h>
GListPtr fsa_message_queue = NULL;
extern void crm_shutdown(int nsig);
enum crmd_fsa_input handle_request(xmlNode *stored_msg);
enum crmd_fsa_input handle_response(xmlNode *stored_msg);
enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg);
ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig);
gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data);
#ifdef MSG_LOG
# define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x); \
crm_log_xml(LOG_MSG, "router.log", msg);
#else
# define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x)
#endif
/* debug only, can wrap all it likes */
int last_data_id = 0;
void
register_fsa_error_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
fsa_data_t *cur_data, void *new_data, const char *raised_from)
{
/* save the current actions if any */
if(fsa_actions != A_NOTHING) {
register_fsa_input_adv(
cur_data?cur_data->fsa_cause:C_FSA_INTERNAL,
I_NULL, cur_data?cur_data->data:NULL,
fsa_actions, TRUE, __FUNCTION__);
}
/* reset the action list */
fsa_actions = A_NOTHING;
/* register the error */
register_fsa_input_adv(
cause, input, new_data, A_NOTHING, TRUE, raised_from);
}
static gboolean last_was_vote = FALSE;
int
register_fsa_input_adv(
enum crmd_fsa_cause cause, enum crmd_fsa_input input,
void *data, long long with_actions,
gboolean prepend, const char *raised_from)
{
unsigned old_len = g_list_length(fsa_message_queue);
fsa_data_t *fsa_data = NULL;
last_data_id++;
CRM_CHECK(raised_from != NULL, raised_from = "<unknown>");
crm_debug("%s %s FSA input %d (%s) (cause=%s) %s data",
raised_from, prepend?"prepended":"appended",last_data_id, fsa_input2string(input),
fsa_cause2string(cause), data?"with":"without");
if(input == I_WAIT_FOR_EVENT) {
do_fsa_stall = TRUE;
crm_debug("Stalling the FSA pending further input: cause=%s",
fsa_cause2string(cause));
if(old_len > 0) {
crm_warn("%s stalled the FSA with pending inputs",
raised_from);
fsa_dump_queue(LOG_DEBUG);
}
if(data == NULL) {
set_bit_inplace(fsa_actions, with_actions);
with_actions = A_NOTHING;
return 0;
}
crm_err("%s stalled the FSA with data - this may be broken",
raised_from);
}
if(old_len == 0) {
last_was_vote = FALSE;
}
if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){
/* no point doing anything */
crm_err("Cannot add entry to queue: no input and no action");
return 0;
} else if(data == NULL) {
last_was_vote = FALSE;
#if 0
} else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = crm_element_value(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
/* It is always safe to treat N successive votes as
* a single one
*
* If all the discarded votes are more "loosing" than
* the first then the result is accurate
* (win or loose).
*
* If any of the discarded votes are less "loosing"
* than the first then we will cast our vote and the
* eventual winner will vote us down again (which
* even in the case that N=2, is no worse than if we
* had not disarded the vote).
*/
crm_debug_2("Vote compression: %d", old_len);
return 0;
}
#endif
} else if (cause == C_HA_MESSAGE && input == I_ROUTER) {
const char *op = crm_element_value(
((ha_msg_input_t*)data)->msg, F_CRM_TASK);
if(safe_str_eq(op, CRM_OP_VOTE)) {
last_was_vote = TRUE;
crm_debug_3("Added vote: %d", old_len);
}
} else {
last_was_vote = FALSE;
}
crm_malloc0(fsa_data, sizeof(fsa_data_t));
fsa_data->id = last_data_id;
fsa_data->fsa_input = input;
fsa_data->fsa_cause = cause;
fsa_data->origin = raised_from;
fsa_data->data = NULL;
fsa_data->data_type = fsa_dt_none;
fsa_data->actions = with_actions;
if(with_actions != A_NOTHING) {
crm_debug_3("Adding actions %.16llx to input", with_actions);
}
if(data != NULL) {
switch(cause) {
case C_FSA_INTERNAL:
case C_CRMD_STATUS_CALLBACK:
case C_IPC_MESSAGE:
case C_HA_MESSAGE:
crm_debug_3("Copying %s data from %s as a HA msg",
fsa_cause2string(cause),
raised_from);
CRM_CHECK(((ha_msg_input_t*)data)->msg != NULL,
crm_err("Bogus data from %s", raised_from));
fsa_data->data = copy_ha_msg_input(data);
fsa_data->data_type = fsa_dt_ha_msg;
break;
case C_LRM_OP_CALLBACK:
crm_debug_3("Copying %s data from %s as lrm_op_t",
fsa_cause2string(cause),
raised_from);
fsa_data->data = copy_lrm_op((lrm_op_t*)data);
fsa_data->data_type = fsa_dt_lrm;
break;
case C_CCM_CALLBACK:
case C_SUBSYSTEM_CONNECT:
case C_LRM_MONITOR_CALLBACK:
case C_TIMER_POPPED:
case C_SHUTDOWN:
case C_HEARTBEAT_FAILED:
case C_HA_DISCONNECT:
case C_ILLEGAL:
case C_UNKNOWN:
case C_STARTUP:
crm_err("Copying %s data (from %s)"
" not yet implemented",
fsa_cause2string(cause), raised_from);
exit(1);
break;
}
crm_debug_4("%s data copied",
fsa_cause2string(fsa_data->fsa_cause));
}
/* make sure to free it properly later */
if(prepend) {
crm_debug_2("Prepending input");
fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
} else {
fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
}
crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue));
fsa_dump_queue(LOG_DEBUG_2);
if(old_len == g_list_length(fsa_message_queue)){
crm_err("Couldnt add message to the queue");
}
if(fsa_source) {
crm_debug_3("Triggering FSA: %s", __FUNCTION__);
G_main_set_trigger(fsa_source);
}
return last_data_id;
}
void
fsa_dump_queue(int log_level)
{
if(log_level < (int)crm_log_level) {
return;
}
slist_iter(
data, fsa_data_t, fsa_message_queue, lpc,
do_crm_log(log_level,
"queue[%d(%d)]: input %s raised by %s()\t(cause=%s)",
lpc, data->id, fsa_input2string(data->fsa_input),
data->origin, fsa_cause2string(data->fsa_cause));
);
}
ha_msg_input_t *
copy_ha_msg_input(ha_msg_input_t *orig)
{
ha_msg_input_t *copy = NULL;
xmlNodePtr data = NULL;
if(orig != NULL) {
crm_debug_4("Copy msg");
data = copy_xml(orig->msg);
} else {
crm_debug_3("No message to copy");
}
copy = new_ha_msg_input(data);
if(orig->msg != NULL) {
CRM_CHECK(copy->msg != NULL, crm_err("copy failed"));
}
return copy;
}
void
delete_fsa_input(fsa_data_t *fsa_data)
{
lrm_op_t *op = NULL;
xmlNode *foo = NULL;
if(fsa_data == NULL) {
return;
}
crm_debug_4("About to free %s data",
fsa_cause2string(fsa_data->fsa_cause));
if(fsa_data->data != NULL) {
switch(fsa_data->data_type) {
case fsa_dt_ha_msg:
delete_ha_msg_input(fsa_data->data);
break;
case fsa_dt_xml:
foo = fsa_data->data;
free_xml(foo);
break;
case fsa_dt_lrm:
op = (lrm_op_t*)fsa_data->data;
free_lrm_op(op);
break;
case fsa_dt_none:
if(fsa_data->data != NULL) {
crm_err("Dont know how to free %s data from %s",
fsa_cause2string(fsa_data->fsa_cause),
fsa_data->origin);
exit(1);
}
break;
}
crm_debug_4("%s data freed",
fsa_cause2string(fsa_data->fsa_cause));
}
crm_free(fsa_data);
}
/* returns the next message */
fsa_data_t *
get_message(void)
{
fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0);
fsa_message_queue = g_list_remove(fsa_message_queue, message);
crm_debug_2("Processing input %d", message->id);
return message;
}
/* returns the current head of the FIFO queue */
gboolean
is_message(void)
{
return (g_list_length(fsa_message_queue) > 0);
}
void *
fsa_typed_data_adv(
fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller)
{
void *ret_val = NULL;
if(fsa_data == NULL) {
do_crm_log(LOG_ERR, "%s: No FSA data available", caller);
} else if(fsa_data->data == NULL) {
do_crm_log(LOG_ERR, "%s: No message data available", caller);
} else if(fsa_data->data_type != a_type) {
do_crm_log(LOG_CRIT,
"%s: Message data was the wrong type! %d vs. requested=%d."
" Origin: %s", caller,
fsa_data->data_type, a_type, fsa_data->origin);
CRM_ASSERT(fsa_data->data_type == a_type);
} else {
ret_val = fsa_data->data;
}
return ret_val;
}
/* A_MSG_ROUTE */
void
do_msg_route(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
route_message(msg_data->fsa_cause, input->msg);
}
void
route_message(enum crmd_fsa_cause cause, xmlNode *input)
{
ha_msg_input_t fsa_input;
enum crmd_fsa_input result = I_NULL;
fsa_input.msg = input;
CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return);
/* try passing the buck first */
crm_debug_4("Attempting to route message");
if(relay_message(input, cause==C_IPC_MESSAGE)) {
crm_debug_4("Message routed...");
return;
}
crm_debug_4("Message wasn't routed... try handling locally");
/* calculate defer */
result = handle_message(input);
switch(result) {
case I_NULL:
crm_debug_4("Message processed");
break;
case I_CIB_OP:
break;
case I_ROUTER:
break;
case I_NODE_JOIN:
case I_JOIN_REQUEST:
case I_JOIN_RESULT:
break;
default:
crm_debug_4("Defering local processing of message");
register_fsa_input_later(cause, result, &fsa_input);
result = I_NULL;
break;
}
if(result != I_NULL) {
/* add to the front of the queue */
register_fsa_input(cause, result, &fsa_input);
}
}
gboolean
send_request(xmlNode *msg, char **msg_reference)
{
if(msg_reference != NULL) {
*msg_reference = crm_strdup(
crm_element_value(msg, XML_ATTR_REFERENCE));
}
if(relay_message(msg, TRUE) == FALSE) {
ha_msg_input_t fsa_input;
fsa_input.msg = msg;
register_fsa_input(C_IPC_MESSAGE, I_ROUTER, &fsa_input);
return FALSE;
}
return TRUE;
}
gboolean
relay_message(xmlNode *msg, gboolean originated_locally)
{
int is_for_dc = 0;
int is_for_dcib = 0;
int is_for_te = 0;
int is_for_crm = 0;
int is_for_cib = 0;
int is_local = 0;
gboolean processing_complete = FALSE;
const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
const char *sys_from= crm_element_value(msg, F_CRM_SYS_FROM);
const char *type = crm_element_value(msg, F_TYPE);
const char *msg_error = NULL;
crm_debug_3("Routing message %s",
crm_element_value(msg, XML_ATTR_REFERENCE));
if(msg == NULL) {
msg_error = "Cannot route empty message";
} else if(safe_str_eq(CRM_OP_HELLO,
crm_element_value(msg, F_CRM_TASK))){
/* quietly ignore */
processing_complete = TRUE;
} else if(safe_str_neq(type, T_CRM)) {
msg_error = "Bad message type";
} else if(sys_to == NULL) {
msg_error = "Bad message destination: no subsystem";
}
if(msg_error != NULL) {
processing_complete = TRUE;
crm_err("%s", msg_error);
crm_log_xml(LOG_WARNING, "bad msg", msg);
}
if(processing_complete) {
return TRUE;
}
processing_complete = TRUE;
is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
is_local = 0;
if(host_to == NULL || strlen(host_to) == 0) {
if(is_for_dc || is_for_te) {
is_local = 0;
} else if(is_for_crm && originated_locally) {
is_local = 0;
} else {
is_local = 1;
}
} else if(safe_str_eq(fsa_our_uname, host_to)) {
is_local=1;
}
if(is_for_dc || is_for_dcib || is_for_te) {
if(AM_I_DC && is_for_te) {
ROUTER_RESULT("Message result: Local relay");
send_msg_via_ipc(msg, sys_to);
} else if(AM_I_DC) {
ROUTER_RESULT("Message result: DC/CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(originated_locally
&& safe_str_neq(sys_from, CRM_SYSTEM_PENGINE)
&& safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) {
/* Neither the TE or PE should be sending messages
* to DC's on other nodes
*
* By definition, if we are no longer the DC, then
* the PE or TE's data should be discarded
*/
ROUTER_RESULT("Message result: External relay to DC");
send_msg_via_ha(msg);
} else {
/* discard */
ROUTER_RESULT("Message result: Discard, not DC");
}
} else if(is_local && (is_for_crm || is_for_cib)) {
ROUTER_RESULT("Message result: CRMd process");
processing_complete = FALSE; /* more to be done by caller */
} else if(is_local) {
ROUTER_RESULT("Message result: Local relay");
send_msg_via_ipc(msg, sys_to);
} else {
ROUTER_RESULT("Message result: External relay");
send_msg_via_ha(msg);
}
return processing_complete;
}
gboolean
crmd_authorize_message(xmlNode *client_msg, crmd_client_t *curr_client)
{
/* check the best case first */
const char *sys_from = crm_element_value(client_msg, F_CRM_SYS_FROM);
char *uuid = NULL;
char *client_name = NULL;
char *major_version = NULL;
char *minor_version = NULL;
const char *filtered_from;
gpointer table_key = NULL;
gboolean auth_result = FALSE;
struct crm_subsystem_s *the_subsystem = NULL;
gboolean can_reply = FALSE; /* no-one has registered with this id */
xmlNode *xml = NULL;
const char *op = crm_element_value(client_msg, F_CRM_TASK);
if (safe_str_neq(CRM_OP_HELLO, op)) {
if(sys_from == NULL) {
crm_warn("Message [%s] was had no value for %s... discarding",
crm_element_value(client_msg, XML_ATTR_REFERENCE),
F_CRM_SYS_FROM);
return FALSE;
}
filtered_from = sys_from;
/* The CIB can have two names on the DC */
if(strcasecmp(sys_from, CRM_SYSTEM_DCIB) == 0)
filtered_from = CRM_SYSTEM_CIB;
if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) {
can_reply = TRUE; /* reply can be routed */
}
crm_debug_2("Message reply can%s be routed from %s.",
can_reply?"":" not", sys_from);
if(can_reply == FALSE) {
crm_warn("Message [%s] not authorized",
crm_element_value(client_msg, XML_ATTR_REFERENCE));
}
return can_reply;
}
crm_debug_3("received client join msg");
crm_log_xml(LOG_MSG, "join", client_msg);
xml = get_message_xml(client_msg, F_CRM_DATA);
auth_result = process_hello_message(
xml, &uuid, &client_name,
&major_version, &minor_version);
if (auth_result == TRUE) {
if(client_name == NULL || uuid == NULL) {
crm_err("Bad client details (client_name=%s, uuid=%s)",
crm_str(client_name), crm_str(uuid));
auth_result = FALSE;
}
}
if (auth_result == TRUE) {
/* check version */
int mav = atoi(major_version);
int miv = atoi(minor_version);
crm_debug_3("Checking client version number");
if (mav < 0 || miv < 0) {
crm_err("Client version (%d:%d) is not acceptable",
mav, miv);
auth_result = FALSE;
}
crm_free(major_version);
crm_free(minor_version);
}
if (safe_str_eq(CRM_SYSTEM_PENGINE, client_name)) {
the_subsystem = pe_subsystem;
} else if (safe_str_eq(CRM_SYSTEM_TENGINE, client_name)) {
the_subsystem = te_subsystem;
}
if (auth_result == TRUE && the_subsystem != NULL) {
/* if we already have one of those clients
* only applies to te, pe etc. not admin clients
*/
crm_debug_3("Checking if %s is required/already connected",
client_name);
table_key = (gpointer)crm_strdup(client_name);
if(is_set(fsa_input_register, the_subsystem->flag_connected)) {
auth_result = FALSE;
crm_free(table_key);
table_key = NULL;
crm_warn("Bit\t%.16llx set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_err("Client %s is already connected",
client_name);
} else if(FALSE == is_set(fsa_input_register,
the_subsystem->flag_required)) {
crm_warn("Bit\t%.16llx not set in %.16llx",
the_subsystem->flag_connected,
fsa_input_register);
crm_warn("Client %s joined but we dont need it",
client_name);
stop_subsystem(the_subsystem, TRUE);
} else {
the_subsystem->ipc = curr_client->client_channel;
set_bit_inplace(fsa_input_register,
the_subsystem->flag_connected);
}
} else {
table_key = (gpointer)generate_hash_key(client_name, uuid);
}
if (auth_result == TRUE) {
crm_debug_2("Accepted client %s", crm_str(table_key));
curr_client->table_key = table_key;
curr_client->sub_sys = crm_strdup(client_name);
curr_client->uuid = crm_strdup(uuid);
g_hash_table_insert (ipc_clients,
table_key, curr_client->client_channel);
send_hello_message(curr_client->client_channel,
"n/a", CRM_SYSTEM_CRMD,
"0", "1");
crm_debug_3("Updated client list with %s", crm_str(table_key));
crm_debug_3("Triggering FSA: %s", __FUNCTION__);
G_main_set_trigger(fsa_source);
if(the_subsystem != NULL) {
CRM_CHECK(the_subsystem->client == NULL,
process_client_disconnect(the_subsystem->client));
the_subsystem->client = curr_client;
}
} else {
crm_free(table_key);
crm_warn("Rejected client logon request");
curr_client->client_channel->ch_status = IPC_DISC_PENDING;
}
if(uuid != NULL) crm_free(uuid);
if(minor_version != NULL) crm_free(minor_version);
if(major_version != NULL) crm_free(major_version);
if(client_name != NULL) crm_free(client_name);
/* hello messages should never be processed further */
return FALSE;
}
enum crmd_fsa_input
handle_message(xmlNode *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *type = NULL;
if(stored_msg == NULL) {
crm_err("No message to handle");
return I_NULL;
}
type = crm_element_value(stored_msg, F_CRM_MSG_TYPE);
if(safe_str_eq(type, XML_ATTR_REQUEST)) {
next_input = handle_request(stored_msg);
} else if(safe_str_eq(type, XML_ATTR_RESPONSE)) {
next_input = handle_response(stored_msg);
} else {
crm_err("Unknown message type: %s", type);
}
/* crm_debug_2("%s: Next input is %s", __FUNCTION__, */
/* fsa_input2string(next_input)); */
return next_input;
}
#define schedule_pe() do { \
next_input = I_PE_CALC; \
if(fsa_pe_ref) { \
crm_debug("Cancelling %s...", fsa_pe_ref); \
crm_free(fsa_pe_ref); \
fsa_pe_ref = NULL; \
} \
} while(0)
enum crmd_fsa_input
handle_request(xmlNode *stored_msg)
{
xmlNode *msg = NULL;
enum crmd_fsa_input next_input = I_NULL;
const char *op = crm_element_value(stored_msg, F_CRM_TASK);
const char *sys_to = crm_element_value(stored_msg, F_CRM_SYS_TO);
const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
crm_debug_2("Received %s "XML_ATTR_REQUEST" from %s in state %s",
op, host_from, fsa_state2string(fsa_state));
if(op == NULL) {
crm_log_xml(LOG_ERR, "Bad message", stored_msg);
/*========== common actions ==========*/
} else if(strcasecmp(op, CRM_OP_NOOP) == 0) {
crm_debug_2("no-op from %s", crm_str(host_from));
} else if(strcasecmp(op, CRM_OP_NOVOTE) == 0) {
ha_msg_input_t fsa_input;
fsa_input.msg = stored_msg;
register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__);
} else if(strcasecmp(op, CRM_OP_VOTE) == 0) {
/* count the vote and decide what to do after that */
ha_msg_input_t fsa_input;
fsa_input.msg = stored_msg;
register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__);
/* Sometimes we _must_ go into S_ELECTION */
if(fsa_state == S_HALT) {
crm_debug("Forcing an election from S_HALT");
next_input = I_ELECTION;
#if 0
} else if(AM_I_DC) {
/* This is the old way of doing things but what is gained? */
next_input = I_ELECTION;
#endif
}
} else if(strcasecmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
crm_shutdown(SIGTERM);
/*next_input = I_SHUTDOWN; */
next_input = I_NULL;
} else if(strcasecmp(op, CRM_OP_PING) == 0) {
/* eventually do some stuff to figure out
* if we /are/ ok
*/
xmlNode *ping = createPingAnswerFragment(sys_to, "ok");
crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state));
crm_info("Current ping state: %s", fsa_state2string(fsa_state));
msg = create_reply(stored_msg, ping);
relay_message(msg, TRUE);
free_xml(ping);
free_xml(msg);
/* probably better to do this via signals on the
* local node
*/
} else if(strcasecmp(op, CRM_OP_DEBUG_UP) == 0) {
alter_debug(DEBUG_INC);
crm_info("Debug set to %d", get_crm_log_level());
} else if(strcasecmp(op, CRM_OP_DEBUG_DOWN) == 0) {
alter_debug(DEBUG_DEC);
crm_info("Debug set to %d", get_crm_log_level());
} else if(strcasecmp(op, CRM_OP_JOIN_OFFER) == 0) {
next_input = I_JOIN_OFFER;
crm_debug("Raising I_JOIN_OFFER: join-%s",
crm_element_value(stored_msg, F_CRM_JOIN_ID));
} else if(strcasecmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
next_input = I_JOIN_RESULT;
crm_debug("Raising I_JOIN_RESULT: join-%s",
crm_element_value(stored_msg, F_CRM_JOIN_ID));
} else if(strcasecmp(op, CRM_OP_LRM_DELETE) == 0
|| strcasecmp(op, CRM_OP_LRM_FAIL) == 0
|| strcasecmp(op, CRM_OP_LRM_REFRESH) == 0
|| strcasecmp(op, CRM_OP_REPROBE) == 0) {
crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
next_input = I_ROUTER;
/* this functionality should only be enabled
* if this is a development build
*/
} else if(CRM_DEV_BUILD && strcasecmp(op, CRM_OP_DIE) == 0/*constant condition*/) {
crm_warn("Test-only code: Killing the CRM without mercy");
crm_warn("Inhibiting respawns");
exit(100);
/*========== (NOT_DC)-Only Actions ==========*/
} else if(AM_I_DC == FALSE){
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match || fsa_our_dc == NULL) {
if(strcasecmp(op, CRM_OP_HBEAT) == 0) {
crm_debug_3("Received DC heartbeat from %s",
host_from);
next_input = I_DC_HEARTBEAT;
} else if(fsa_our_dc == NULL) {
crm_warn("CRMd discarding request: %s"
" (DC: %s, from: %s)",
op, crm_str(fsa_our_dc), host_from);
crm_log_xml(LOG_WARNING, "Ignored Request", stored_msg);
} else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
next_input = I_STOP;
} else {
crm_err("CRMd didnt expect request: %s", op);
crm_log_xml(LOG_ERR, "bad request", stored_msg);
}
} else {
crm_warn("Discarding %s op from %s", op, host_from);
}
/*========== DC-Only Actions ==========*/
} else if(AM_I_DC) {
- const char *message = crm_element_value(
- stored_msg, "message");
-
- /* setting "fsa_pe_ref = NULL" makes sure we ignore any
- * PE reply that might be pending or in the queue while
- * we ask the CIB for a more up-to-date copy
- */
- if(safe_str_eq(op, CRM_OP_TEABORT)) {
- crm_debug("Transition cancelled: %s/%s", op, message);
- clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
- if(need_transition(fsa_state)) {
- schedule_pe();
-
- } else {
- crm_debug("Filtering %s op in state %s",
- op, fsa_state2string(fsa_state));
- }
-
- } else if(strcasecmp(op, CRM_OP_TECOMPLETE) == 0) {
- crm_debug("Transition complete: %s/%s", op, message);
- clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
- if(fsa_state == S_TRANSITION_ENGINE) {
- next_input = I_TE_SUCCESS;
- } else {
- crm_debug("Filtering %s op in state %s",
- op, fsa_state2string(fsa_state));
- }
-
- } else if(strcasecmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
+ if(strcasecmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
next_input = I_NODE_JOIN;
} else if(strcasecmp(op, CRM_OP_JOIN_REQUEST) == 0) {
next_input = I_JOIN_REQUEST;
} else if(strcasecmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
next_input = I_JOIN_RESULT;
} else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
if(dc_match) {
crm_err("We didnt ask to be shut down yet our"
" TE is telling us too."
" Better get out now!");
next_input = I_TERMINATE;
} else if(is_set(fsa_input_register, R_SHUTDOWN)) {
crm_info("Shutting ourselves down (DC)");
next_input = I_STOP;
} else if(fsa_state != S_STOPPING) {
crm_err("Another node is asking us to shutdown"
" but we think we're ok.");
next_input = I_ELECTION;
}
} else if(strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
/* a slave wants to shut down */
/* create cib fragment and add to message */
next_input = handle_shutdown_request(stored_msg);
} else {
crm_err("Unexpected request (%s) sent to the DC", op);
crm_log_xml(LOG_ERR, "Unexpected", stored_msg);
}
}
return next_input;
}
enum crmd_fsa_input
handle_response(xmlNode *stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *op = crm_element_value(stored_msg, F_CRM_TASK);
const char *sys_from = crm_element_value(stored_msg, F_CRM_SYS_FROM);
const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE);
crm_debug_2("Received %s "XML_ATTR_RESPONSE" from %s in state %s",
op, host_from, fsa_state2string(fsa_state));
if(op == NULL) {
crm_log_xml(LOG_ERR, "Bad message", stored_msg);
} else if(AM_I_DC && strcasecmp(op, CRM_OP_PECALC) == 0) {
crm_debug_2("Processing %s reply %s (fsa=%s)",
sys_from, msg_ref, crm_str(fsa_pe_ref));
if(msg_ref != NULL && safe_str_eq(msg_ref, fsa_pe_ref)) {
next_input = I_PE_SUCCESS;
crm_debug_2("Completed: %s...", fsa_pe_ref);
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
} else {
crm_debug_2("Skipping superceeded reply from %s",
sys_from);
}
} else if(strcasecmp(op, CRM_OP_VOTE) == 0
|| strcasecmp(op, CRM_OP_HBEAT) == 0
|| strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcasecmp(op, CRM_OP_SHUTDOWN) == 0) {
crm_debug_2("Ignoring %s from %s in %s",
op, host_from, fsa_state2string(fsa_state));
next_input = I_NULL;
} else {
crm_err("Unexpected response (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
next_input = I_NULL;
}
return next_input;
}
enum crmd_fsa_input
handle_shutdown_request(xmlNode *stored_msg)
{
/* handle here to avoid potential version issues
* where the shutdown message/proceedure may have
* been changed in later versions.
*
* This way the DC is always in control of the shutdown
*/
time_t now = time(NULL);
xmlNode *node_state = NULL;
const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
if(host_from == NULL) {
/* we're shutting down and the DC */
host_from = fsa_our_uname;
}
crm_info("Creating shutdown request for %s",host_from);
crm_log_xml(LOG_MSG, "message", stored_msg);
node_state = create_node_state(
host_from, NULL, NULL, NULL, NULL,
CRMD_STATE_INACTIVE, FALSE, __FUNCTION__);
crm_xml_add_int(node_state, XML_CIB_ATTR_SHUTDOWN, (int)now);
fsa_cib_anon_update(XML_CIB_TAG_STATUS,node_state, cib_quorum_override);
crm_log_xml_debug_2(node_state, "Shutdown update");
free_xml(node_state);
/* will be picked up by the TE as long as its running */
if(need_transition(fsa_state)
&& is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) {
register_fsa_action(A_TE_CANCEL);
}
return I_NULL;
}
/* frees msg upon completion */
gboolean
send_msg_via_ha(xmlNode *msg)
{
int log_level = LOG_DEBUG_3;
gboolean broadcast = FALSE;
gboolean all_is_good = TRUE;
const char *op = crm_element_value(msg, F_CRM_TASK);
const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
enum crm_ais_msg_types dest = 0;
if(is_openais_cluster()) {
dest = 1;
#if SUPPORT_AIS
dest = text2msg_type(sys_to);
#endif
}
if (msg == NULL) {
crm_err("Attempt to send NULL Message via HA failed.");
all_is_good = FALSE;
} else {
crm_debug_4("Relaying message to (%s) via HA", host_to);
}
if (all_is_good) {
if (sys_to == NULL || strlen(sys_to) == 0) {
crm_err("You did not specify a destination sub-system"
" for this message.");
all_is_good = FALSE;
}
}
/* There are a number of messages may not need to be ordered.
* At a later point perhaps we should detect them and send them
* as unordered messages.
*/
if (all_is_good) {
if (host_to == NULL
|| strlen(host_to) == 0
|| safe_str_eq(sys_to, CRM_SYSTEM_DC)) {
broadcast = TRUE;
all_is_good = send_cluster_message(NULL, dest, msg, FALSE);
} else {
all_is_good = send_cluster_message(host_to, dest, msg, FALSE);
}
}
if(all_is_good == FALSE) {
log_level = LOG_WARNING;
}
if(log_level == LOG_WARNING
|| (safe_str_neq(op, CRM_OP_HBEAT))) {
do_crm_log(log_level,
"Sending %sHA message (ref=%s) to %s@%s %s.",
broadcast?"broadcast ":"directed ",
crm_element_value(msg, XML_ATTR_REFERENCE),
crm_str(sys_to), host_to==NULL?"<all>":host_to,
all_is_good?"succeeded":"failed");
}
return all_is_good;
}
/* msg is deleted by the time this returns */
+extern gboolean process_te_message(xmlNode *msg, xmlNode *xml_data);
gboolean
send_msg_via_ipc(xmlNode *msg, const char *sys)
{
gboolean send_ok = TRUE;
IPC_Channel *client_channel;
crm_debug_4("relaying msg to sub_sys=%s via IPC", sys);
client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys);
if(crm_element_value(msg, F_CRM_HOST_FROM) == NULL) {
crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname);
}
if (client_channel != NULL) {
crm_debug_3("Sending message via channel %s.", sys);
send_ok = send_ipc_message(client_channel, msg);
-
- } else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_CIB) == 0) {
- crm_err("Sub-system (%s) has been incorporated into the CRMd.",
- sys);
- crm_err("Change the way we handle this CIB message");
- crm_log_xml(LOG_ERR, "cib op", msg);
- send_ok = FALSE;
-
+
+ } else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_TENGINE) == 0) {
+ xmlNode *data = get_message_xml(msg, F_CRM_DATA);
+ process_te_message(msg, data);
+
} else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_LRMD) == 0) {
fsa_data_t *fsa_data = NULL;
ha_msg_input_t *msg_copy = new_ha_msg_input(msg);
crm_malloc0(fsa_data, sizeof(fsa_data_t));
fsa_data->fsa_input = I_MESSAGE;
fsa_data->fsa_cause = C_IPC_MESSAGE;
fsa_data->data = msg_copy;
fsa_data->origin = __FUNCTION__;
fsa_data->data_type = fsa_dt_ha_msg;
#ifdef FSA_TRACE
crm_debug_2("Invoking action %s (%.16llx)",
fsa_action2string(A_LRM_INVOKE),
A_LRM_INVOKE);
#endif
do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, fsa_data);
crm_free(msg_copy);
crm_free(fsa_data);
} else {
crm_err("Unknown Sub-system (%s)... discarding message.",
crm_str(sys));
send_ok = FALSE;
}
return send_ok;
}
void
msg_queue_helper(void)
{
#if SUPPORT_HEARTBEAT
IPC_Channel *ipc = NULL;
if(fsa_cluster_conn != NULL) {
ipc = fsa_cluster_conn->llc_ops->ipcchan(
fsa_cluster_conn);
}
if(ipc != NULL) {
ipc->ops->resume_io(ipc);
}
/* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */
#endif
}
gboolean
ipc_queue_helper(gpointer key, gpointer value, gpointer user_data)
{
crmd_client_t *ipc_client = value;
if(ipc_client->client_channel != NULL) {
ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel);
}
return FALSE;
}
diff --git a/transitioner/actions.c b/crmd/te_actions.c
similarity index 90%
rename from transitioner/actions.c
rename to crmd/te_actions.c
index b9dc40b679..f9e688865f 100644
--- a/transitioner/actions.c
+++ b/crmd/te_actions.c
@@ -1,532 +1,521 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
#include <clplumbing/lsb_exitcodes.h>
+#include <crmd_fsa.h>
+#include <crmd_messages.h>
+#include <crm/common/cluster.h>
char *te_uuid = NULL;
-IPC_Channel *crm_ch = NULL;
void send_rsc_command(crm_action_t *action);
extern crm_action_timer_t *transition_timer;
static void
te_start_action_timer(crm_action_t *action)
{
crm_malloc0(action->timer, sizeof(crm_action_timer_t));
action->timer->timeout = action->timeout;
action->timer->reason = timeout_action_warn;
action->timer->action = action;
action->timer->source_id = Gmain_timeout_add(
action->timer->timeout,
action_timer_callback, (void*)action->timer);
CRM_ASSERT(action->timer->source_id != 0);
}
static gboolean
te_pseudo_action(crm_graph_t *graph, crm_action_t *pseudo)
{
crm_info("Pseudo action %d fired and confirmed", pseudo->id);
pseudo->confirmed = TRUE;
update_graph(graph, pseudo);
trigger_graph();
return TRUE;
}
#if SUPPORT_HEARTBEAT
void
send_stonith_update(stonith_ops_t * op)
{
enum cib_errors rc = cib_ok;
const char *target = op->node_name;
const char *uuid = op->node_uuid;
/* zero out the node-status & remove all LRM status info */
xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
CRM_CHECK(op->node_name != NULL, return);
CRM_CHECK(op->node_uuid != NULL, return);
crm_xml_add(node_state, XML_ATTR_UUID, uuid);
crm_xml_add(node_state, XML_ATTR_UNAME, target);
crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS);
crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO);
crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS);
crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN);
crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN);
crm_xml_add(node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM);
crm_xml_add(node_state, XML_ATTR_ORIGIN, __FUNCTION__);
- rc = te_cib_conn->cmds->update(
- te_cib_conn, XML_CIB_TAG_STATUS, node_state, NULL,
+ rc = fsa_cib_conn->cmds->update(
+ fsa_cib_conn, XML_CIB_TAG_STATUS, node_state, NULL,
cib_quorum_override|cib_scope_local);
if(rc < cib_ok) {
crm_err("CIB update failed: %s", cib_error2string(rc));
abort_transition(
INFINITY, tg_shutdown, "CIB update failed", node_state);
} else {
/* delay processing the trigger until the update completes */
add_cib_op_callback(rc, FALSE, NULL, cib_fencing_updated);
}
free_xml(node_state);
return;
}
#endif
static gboolean
te_fence_node(crm_graph_t *graph, crm_action_t *action)
{
#if SUPPORT_HEARTBEAT
if(is_heartbeat_cluster()) {
const char *id = NULL;
const char *uuid = NULL;
const char *target = NULL;
const char *type = NULL;
stonith_ops_t * st_op = NULL;
id = ID(action->xml);
target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
type = g_hash_table_lookup(action->params, crm_meta_name("stonith_action"));
CRM_CHECK(id != NULL,
crm_log_xml_warn(action->xml, "BadAction");
return FALSE);
CRM_CHECK(uuid != NULL,
crm_log_xml_warn(action->xml, "BadAction");
return FALSE);
CRM_CHECK(type != NULL,
crm_log_xml_warn(action->xml, "BadAction");
return FALSE);
CRM_CHECK(target != NULL,
crm_log_xml_warn(action->xml, "BadAction");
return FALSE);
te_log_action(LOG_INFO,
"Executing %s fencing operation (%s) on %s (timeout=%d)",
type, id, target,
transition_graph->transition_timeout / 2);
/* Passing NULL means block until we can connect... */
te_connect_stonith(NULL);
crm_malloc0(st_op, sizeof(stonith_ops_t));
if(safe_str_eq(type, "poweroff")) {
st_op->optype = POWEROFF;
} else {
st_op->optype = RESET;
}
st_op->timeout = transition_graph->transition_timeout / 2;
st_op->node_name = crm_strdup(target);
st_op->node_uuid = crm_strdup(uuid);
st_op->private_data = generate_transition_key(
transition_graph->id, action->id, 0, te_uuid);
CRM_ASSERT(stonithd_input_IPC_channel() != NULL);
if (ST_OK != stonithd_node_fence( st_op )) {
crm_err("Cannot fence %s: stonithd_node_fence() call failed ",
target);
}
return TRUE;
}
#endif
return FALSE;
}
static int get_target_rc(crm_action_t *action)
{
const char *target_rc_s = g_hash_table_lookup(
action->params, crm_meta_name(XML_ATTR_TE_TARGET_RC));
if(target_rc_s != NULL) {
return crm_parse_int(target_rc_s, "0");
}
return 0;
}
static gboolean
te_crm_command(crm_graph_t *graph, crm_action_t *action)
{
char *value = NULL;
char *counter = NULL;
xmlNode *cmd = NULL;
const char *id = NULL;
const char *task = NULL;
const char *on_node = NULL;
gboolean ret = TRUE;
id = ID(action->xml);
task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
CRM_CHECK(on_node != NULL && strlen(on_node) != 0,
te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node",
crm_str(id), crm_str(task));
return FALSE);
te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s",
crm_str(id), crm_str(task), on_node);
cmd = create_request(task, NULL, on_node, CRM_SYSTEM_CRMD,
CRM_SYSTEM_TENGINE, NULL);
counter = generate_transition_key(
transition_graph->id, action->id, get_target_rc(action), te_uuid);
crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter);
- ret = send_ipc_message(crm_ch, cmd);
+ ret = send_cluster_message(on_node, crm_proc_crmd, cmd, TRUE);
crm_free(counter);
free_xml(cmd);
value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT));
if(ret == FALSE) {
crm_err("Action %d failed: send", action->id);
return FALSE;
} else if(crm_is_true(value)) {
crm_info("Skipping wait for %d", action->id);
action->confirmed = TRUE;
update_graph(graph, action);
trigger_graph();
} else if(ret && action->timeout > 0) {
crm_debug("Setting timer for action %d",action->id);
action->timer->reason = timeout_action_warn;
te_start_action_timer(action);
}
return TRUE;
}
static gboolean
te_rsc_command(crm_graph_t *graph, crm_action_t *action)
{
/* never overwrite stop actions in the CIB with
* anything other than completed results
*
* Writing pending stops makes it look like the
* resource is running again
*/
const char *task = NULL;
const char *on_node = NULL;
action->executed = FALSE;
on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
CRM_CHECK(on_node != NULL && strlen(on_node) != 0,
te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node",
ID(action->xml), crm_str(task));
return FALSE);
send_rsc_command(action);
return TRUE;
}
gboolean
cib_action_update(crm_action_t *action, int status)
{
char *op_id = NULL;
char *code = NULL;
char *digest = NULL;
xmlNode *tmp = NULL;
xmlNode *params = NULL;
xmlNode *state = NULL;
xmlNode *rsc = NULL;
xmlNode *xml_op = NULL;
xmlNode *action_rsc = NULL;
enum cib_errors rc = cib_ok;
const char *name = NULL;
const char *value = NULL;
const char *rsc_id = NULL;
const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
const char *task_uuid = crm_element_value(
action->xml, XML_LRM_ATTR_TASK_KEY);
const char *target_uuid = crm_element_value(
action->xml, XML_LRM_ATTR_TARGET_UUID);
int call_options = cib_quorum_override|cib_scope_local;
crm_warn("%s %d: %s on %s timed out",
crm_element_name(action->xml), action->id, task_uuid, target);
action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE);
if(action_rsc == NULL) {
return FALSE;
}
rsc_id = ID(action_rsc);
CRM_CHECK(rsc_id != NULL,
crm_log_xml_err(action->xml, "Bad:action");
return FALSE);
code = crm_itoa(status);
/*
update the CIB
<node_state id="hadev">
<lrm>
<lrm_resources>
<lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
*/
state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_xml_add(state, XML_ATTR_UUID, target_uuid);
crm_xml_add(state, XML_ATTR_UNAME, target);
rsc = create_xml_node(state, XML_CIB_TAG_LRM);
crm_xml_add(rsc, XML_ATTR_ID, target_uuid);
rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES);
rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE);
crm_xml_add(rsc, XML_ATTR_ID, rsc_id);
name = XML_ATTR_TYPE;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
name = XML_AGENT_ATTR_CLASS;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
name = XML_AGENT_ATTR_PROVIDER;
value = crm_element_value(action_rsc, name);
crm_xml_add(rsc, name, value);
xml_op = create_xml_node(rsc, XML_LRM_TAG_RSC_OP);
crm_xml_add(xml_op, XML_ATTR_ID, task);
op_id = generate_op_key(rsc_id, task, action->interval);
crm_xml_add(xml_op, XML_ATTR_ID, op_id);
crm_free(op_id);
crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code);
crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1");
crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, action->interval);
crm_xml_add(xml_op, XML_LRM_ATTR_RC, code);
crm_xml_add(xml_op, XML_ATTR_ORIGIN, __FUNCTION__);
crm_free(code);
code = generate_transition_key(
transition_graph->id, action->id, get_target_rc(action), te_uuid);
crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code);
crm_free(code);
code = generate_transition_magic(
crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status);
crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code);
crm_free(code);
tmp = find_xml_node(action->xml, "attributes", TRUE);
params = create_xml_node(NULL, XML_TAG_PARAMS);
copy_in_properties(params, tmp);
filter_action_parameters(params, CRM_FEATURE_SET);
digest = calculate_xml_digest(params, TRUE, FALSE);
/* info for now as this area has been problematic to debug */
crm_debug("Calculated digest %s for %s (%s)\n",
digest, ID(xml_op),
crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
crm_log_xml(LOG_DEBUG, "digest:source", params);
crm_xml_add(xml_op, XML_LRM_ATTR_OP_DIGEST, digest);
crm_free(digest);
free_xml(params);
crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s",
status<0?"new action":XML_ATTR_TIMEOUT,
crm_element_name(action->xml), crm_str(task), rsc_id, target);
- rc = te_cib_conn->cmds->update(
- te_cib_conn, XML_CIB_TAG_STATUS, state, NULL, call_options);
+ rc = fsa_cib_conn->cmds->update(
+ fsa_cib_conn, XML_CIB_TAG_STATUS, state, NULL, call_options);
crm_debug("Updating CIB with %s action %d: %s on %s (call_id=%d)",
op_status2text(status), action->id, task_uuid, target, rc);
add_cib_op_callback(rc, FALSE, NULL, cib_action_updated);
free_xml(state);
action->sent_update = TRUE;
if(rc < cib_ok) {
return FALSE;
}
return TRUE;
}
void
send_rsc_command(crm_action_t *action)
{
xmlNode *cmd = NULL;
xmlNode *rsc_op = NULL;
char *counter = NULL;
const char *task = NULL;
const char *value = NULL;
const char *on_node = NULL;
const char *task_uuid = NULL;
CRM_ASSERT(action != NULL);
CRM_ASSERT(action->xml != NULL);
rsc_op = action->xml;
task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET);
counter = generate_transition_key(
transition_graph->id, action->id, get_target_rc(action), te_uuid);
crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter);
crm_info("Initiating action %d: %s %s on %s",
action->id, task, task_uuid, on_node);
crm_free(counter);
if(rsc_op != NULL) {
crm_log_xml_debug_2(rsc_op, "Performing");
}
cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node,
CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL);
-#if 1
- send_ipc_message(crm_ch, cmd);
-#else
- /* test the TE timer/recovery code */
- if((action->id % 11) == 0) {
- crm_err("Faking lost action %d: %s", action->id, task_uuid);
- } else {
- send_ipc_message(crm_ch, cmd);
- }
-#endif
+ send_cluster_message(on_node, crm_proc_lrmd, cmd, TRUE);
free_xml(cmd);
action->executed = TRUE;
value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT));
if(crm_is_true(value)) {
crm_debug("Skipping wait for %d", action->id);
action->confirmed = TRUE;
update_graph(transition_graph, action);
trigger_graph();
} else if(action->timeout > 0) {
int action_timeout = (2 * action->timeout) + transition_graph->network_delay;
crm_debug_3("Setting timer for action %s", task_uuid);
if(transition_graph->transition_timeout < action_timeout) {
crm_debug("Action %d:"
" Increasing transition %d timeout to %d (2*%d + %d)",
action->id, transition_graph->id, action_timeout,
action->timeout, transition_graph->network_delay);
transition_graph->transition_timeout = action_timeout;
}
te_start_action_timer(action);
}
}
crm_graph_functions_t te_graph_fns = {
te_pseudo_action,
te_rsc_command,
te_crm_command,
te_fence_node
};
-extern GMainLoop* mainloop;
-
void
notify_crmd(crm_graph_t *graph)
{
- xmlNode *cmd = NULL;
int log_level = LOG_DEBUG;
- const char *op = CRM_OP_TEABORT;
int pending_callbacks = num_cib_op_callbacks();
-
stop_te_timer(transition_timer);
if(pending_callbacks != 0) {
- crm_warn("Delaying completion until all CIB updates complete");
- return;
+ transition_graph->complete = FALSE;
+ crm_warn("Delaying completion until %d CIB updates complete", pending_callbacks);
+ return;
}
CRM_CHECK(graph->complete, graph->complete = TRUE);
switch(graph->completion_action) {
case tg_stop:
- op = CRM_OP_TECOMPLETE;
- log_level = LOG_INFO;
- break;
+ log_level = LOG_INFO;
+ clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
+ register_fsa_input(C_FSA_INTERNAL, I_TE_SUCCESS, NULL);
+ break;
case tg_abort:
case tg_restart:
- op = CRM_OP_TEABORT;
- break;
+ clear_bit_inplace(fsa_input_register, R_IN_TRANSITION);
+ if(need_transition(fsa_state)) {
+ /* setting "fsa_pe_ref = NULL" makes sure we ignore any
+ * PE reply that might be pending or in the queue while
+ * we ask the CIB for a more up-to-date copy
+ */
+ crm_free(fsa_pe_ref); fsa_pe_ref = NULL;
+ register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
+
+ } else {
+ crm_debug("Filtering %d op in state %s",
+ graph->completion_action, fsa_state2string(fsa_state));
+ }
+
+ break;
case tg_shutdown:
- crm_info("Exiting after transition");
- if (mainloop != NULL && g_main_is_running(mainloop)) {
- g_main_quit(mainloop);
- return;
- }
- exit(LSB_EXIT_OK);
+ crm_info("Exiting after transition");
+ return;
}
- te_log_action(log_level, "Transition %d status: %s - %s",
- graph->id, op, crm_str(graph->abort_reason));
+ te_log_action(log_level, "Transition %d status: %d - %s",
+ graph->id, graph->completion_action, crm_str(graph->abort_reason));
print_graph(LOG_DEBUG_3, graph);
- cmd = create_request(
- op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL);
-
- if(graph->abort_reason != NULL) {
- crm_xml_add(cmd, "message", graph->abort_reason);
- }
-
- send_ipc_message(crm_ch, cmd);
- free_xml(cmd);
-
graph->abort_reason = NULL;
graph->completion_action = tg_restart;
}
diff --git a/transitioner/callbacks.c b/crmd/te_callbacks.c
similarity index 77%
rename from transitioner/callbacks.c
rename to crmd/te_callbacks.c
index 6e8fcaef86..e1094c3463 100644
--- a/transitioner/callbacks.c
+++ b/crmd/te_callbacks.c
@@ -1,609 +1,483 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/stat.h>
#include <crm/crm.h>
#include <crm/common/xml.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#include <heartbeat.h>
#include <tengine.h>
#include <te_callbacks.h>
#include <clplumbing/Gmain_timeout.h>
void te_update_confirm(const char *event, xmlNode *msg);
-void te_update_diff(const char *event, xmlNode *msg);
xmlNode *need_abort(xmlNode *update);
void cib_fencing_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data);
extern char *te_uuid;
gboolean shuttingdown = FALSE;
crm_graph_t *transition_graph;
GTRIGSource *transition_trigger = NULL;
crm_action_timer_t *transition_timer = NULL;
-static gboolean
-start_global_timer(crm_action_timer_t *timer, int timeout)
-{
- CRM_ASSERT(timer != NULL);
- CRM_CHECK(timer > 0, return FALSE);
- CRM_CHECK(timer->source_id == 0, return FALSE);
-
- if(timeout <= 0) {
- crm_err("Tried to start timer with period: %d", timeout);
-
- } else if(timer->source_id == 0) {
- crm_debug_2("Starting abort timer: %dms", timeout);
- timer->timeout = timeout;
- timer->source_id = Gmain_timeout_add(
- timeout, global_timer_callback, (void*)timer);
- CRM_ASSERT(timer->source_id != 0);
- return TRUE;
-
- } else {
- crm_err("Timer is already active with period: %d", timer->timeout);
- }
-
- return FALSE;
-}
void
te_update_diff(const char *event, xmlNode *msg)
{
int rc = -1;
const char *op = NULL;
xmlNode *diff = NULL;
xmlNode *aborted = NULL;
const char *set_name = NULL;
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
if(msg == NULL) {
crm_err("NULL update");
return;
}
crm_element_value_int(msg, F_CIB_RC, &rc);
op = crm_element_value(msg, F_CIB_OPERATION);
if(rc < cib_ok) {
crm_debug_2("Ignoring failed %s operation: %s",
op, cib_error2string(rc));
return;
}
diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
cib_diff_version_details(
diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
crm_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op,
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
log_cib_diff(LOG_DEBUG_2, diff, op);
set_name = "diff-added";
if(diff != NULL) {
xmlNode *section = NULL;
xmlNode *change_set = find_xml_node(diff, set_name, FALSE);
change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);
if(change_set != NULL) {
crm_debug_2("Checking status changes");
section=get_object_root(XML_CIB_TAG_STATUS,change_set);
}
if(section != NULL) {
extract_event(section);
}
crm_debug_2("Checking change set: %s", set_name);
aborted = need_abort(change_set);
}
set_name = "diff-removed";
if(diff != NULL && aborted == NULL) {
xmlNode *attrs = NULL;
xmlNode *status = NULL;
xmlNode *change_set = find_xml_node(diff, set_name, FALSE);
change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);
crm_debug_2("Checking change set: %s", set_name);
aborted = need_abort(change_set);
if(aborted == NULL && change_set != NULL) {
status = get_object_root(XML_CIB_TAG_STATUS, change_set);
xml_child_iter_filter(
status, node_state, XML_CIB_TAG_STATE,
attrs = find_xml_node(
node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
if(attrs != NULL) {
crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions");
abort_transition(INFINITY, tg_restart,
XML_TAG_TRANSIENT_NODEATTRS, attrs);
}
);
}
}
if(aborted != NULL) {
abort_transition(
INFINITY, tg_restart, "Non-status change", NULL);
}
return;
}
-
-
gboolean
-process_te_message(xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender)
+process_te_message(xmlNode *msg, xmlNode *xml_data)
{
xmlNode *xml_obj = NULL;
const char *from = crm_element_value(msg, F_ORIG);
const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE);
const char *op = crm_element_value(msg, F_CRM_TASK);
const char *type = crm_element_value(msg, F_CRM_MSG_TYPE);
crm_debug_2("Processing %s (%s) message", op, ref);
crm_log_xml(LOG_DEBUG_3, "ipc", msg);
if(op == NULL){
/* error */
- } else if(strcasecmp(op, CRM_OP_HELLO) == 0) {
- /* ignore */
} else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_TENGINE) != 0) {
crm_debug_2("Bad sys-to %s", crm_str(sys_to));
return FALSE;
} else if(safe_str_eq(op, CRM_OP_INVOKE_LRM)
&& safe_str_eq(sys_from, CRM_SYSTEM_LRMD)
/* && safe_str_eq(type, XML_ATTR_RESPONSE) */
){
#if CRM_DEPRECATED_SINCE_2_0_4
if(safe_str_eq(crm_element_name(xml_data), XML_TAG_CIB)) {
xml_obj = xml_data;
} else {
xml_obj = find_xml_node(xml_data, XML_TAG_CIB, TRUE);
}
#else
xml_obj = xml_data;
CRM_CHECK(xml_obj != NULL,
crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
#endif
CRM_CHECK(xml_obj != NULL,
crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj);
CRM_CHECK(xml_obj != NULL,
crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg);
return FALSE);
crm_log_xml(LOG_DEBUG_2, "Processing (N)ACK", msg);
crm_info("Processing (N)ACK %s from %s",
crm_element_value(msg, XML_ATTR_REFERENCE), from);
extract_event(xml_obj);
- } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) {
- crm_err("Message was a response not a request. Discarding");
- return TRUE;
-
- } else if(strcasecmp(op, CRM_OP_TRANSITION) == 0) {
- const char *graph_file = crm_element_value(msg, F_CRM_TGRAPH);
- const char *graph_input = crm_element_value(msg, F_CRM_TGRAPH_INPUT);
- CRM_CHECK(graph_file != NULL || xml_data != NULL,
- crm_err("No graph provided");
- crm_log_xml(LOG_WARNING, "no graph", msg);
- return TRUE);
-
- if(transition_graph->complete == FALSE) {
- crm_info("Another transition is already active");
- abort_transition(
- INFINITY, tg_restart, "Transition Active", NULL);
-
- } else {
- const char *value = NULL;
- xmlNode *graph_data = xml_data;
- crm_debug("Processing graph derived from %s", graph_input);
-
- if(graph_file != NULL) {
- FILE *graph_fd = fopen(graph_file, "r");
-
- CRM_CHECK(graph_fd != NULL,
- cl_perror("Could not open graph file %s", graph_file);
- return TRUE);
-
- graph_data = file2xml(graph_fd, FALSE);
-
- unlink(graph_file);
- fclose(graph_fd);
- }
-
- destroy_graph(transition_graph);
- transition_graph = unpack_graph(graph_data);
- start_global_timer(transition_timer,
- transition_graph->transition_timeout);
-
- value = crm_element_value(graph_data, "failed-stop-offset");
- if(value) {
- failed_stop_offset = crm_strdup(value);
- }
-
- value = crm_element_value(graph_data, "failed-start-offset");
- if(value) {
- failed_start_offset = crm_strdup(value);
- }
-
- trigger_graph();
- print_graph(LOG_DEBUG_2, transition_graph);
-
- if(graph_data != xml_data) {
- free_xml(graph_data);
- }
- }
-
- } else if(strcasecmp(op, CRM_OP_TE_HALT) == 0) {
- abort_transition(INFINITY, tg_stop, "Peer Halt", NULL);
-
- } else if(strcasecmp(op, CRM_OP_TEABORT) == 0) {
- abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL);
-
} else {
crm_err("Unknown command: %s::%s from %s", type, op, sys_from);
}
crm_debug_3("finished processing message");
return TRUE;
}
#if SUPPORT_HEARTBEAT
void
tengine_stonith_callback(stonith_ops_t * op)
{
const char *allow_fail = NULL;
int target_rc = -1;
int stonith_id = -1;
int transition_id = -1;
char *uuid = NULL;
crm_action_t *stonith_action = NULL;
if(op == NULL) {
crm_err("Called with a NULL op!");
return;
}
crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s",
op->call_id, op->optype, op->node_name, op->op_result,
(char *)op->node_list, op->private_data);
/* this will mark the event complete if a match is found */
CRM_CHECK(op->private_data != NULL, return);
/* filter out old STONITH actions */
CRM_CHECK(decode_transition_key(
op->private_data, &uuid, &transition_id, &stonith_id, &target_rc),
crm_err("Invalid event detected");
goto bail;
);
if(transition_graph->complete
|| stonith_id < 0
|| safe_str_neq(uuid, te_uuid)
|| transition_graph->id != transition_id) {
crm_info("Ignoring STONITH action initiated outside"
" of the current transition");
}
stonith_action = get_action(stonith_id, TRUE);
if(stonith_action == NULL) {
crm_err("Stonith action not matched");
goto bail;
}
switch(op->op_result) {
case STONITH_SUCCEEDED:
send_stonith_update(op);
break;
case STONITH_CANNOT:
case STONITH_TIMEOUT:
case STONITH_GENERIC:
stonith_action->failed = TRUE;
allow_fail = g_hash_table_lookup(
stonith_action->params,
crm_meta_name(XML_ATTR_TE_ALLOWFAIL));
if(FALSE == crm_is_true(allow_fail)) {
crm_err("Stonith of %s failed (%d)..."
" aborting transition.",
op->node_name, op->op_result);
abort_transition(INFINITY, tg_restart,
"Stonith failed", NULL);
}
break;
default:
crm_err("Unsupported action result: %d", op->op_result);
abort_transition(INFINITY, tg_restart,
"Unsupport Stonith result", NULL);
}
update_graph(transition_graph, stonith_action);
trigger_graph();
bail:
crm_free(uuid);
return;
}
void
tengine_stonith_connection_destroy(gpointer user_data)
{
crm_err("Fencing daemon has left us");
stonith_src = NULL;
if(stonith_src == NULL) {
G_main_set_trigger(stonith_reconnect);
}
/* cbchan will be garbage at this point, arrange for it to be reset */
set_stonithd_input_IPC_channel_NULL();
return;
}
gboolean
tengine_stonith_dispatch(IPC_Channel *sender, void *user_data)
{
int lpc = 0;
while(stonithd_op_result_ready()) {
if (sender->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
if(ST_FAIL == stonithd_receive_ops_result(FALSE)) {
crm_err("stonithd_receive_ops_result() failed");
} else {
lpc++;
}
}
crm_debug_2("Processed %d messages", lpc);
if (sender->ch_status == IPC_DISCONNECT) {
return FALSE;
}
return TRUE;
}
#endif
void
cib_fencing_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data)
{
trigger_graph();
if(rc < cib_ok) {
crm_err("CIB update failed: %s", cib_error2string(rc));
crm_log_xml_warn(msg, "Failed update");
}
}
void
cib_action_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data)
{
trigger_graph();
if(rc < cib_ok) {
crm_err("Update %d FAILED: %s", call_id, cib_error2string(rc));
}
}
void
cib_failcount_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data)
{
trigger_graph();
if(rc < cib_ok) {
crm_err("Update %d FAILED: %s", call_id, cib_error2string(rc));
}
}
gboolean
action_timer_callback(gpointer data)
{
crm_action_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (crm_action_timer_t*)data;
stop_te_timer(timer);
crm_warn("Timer popped (abort_level=%d, complete=%s)",
transition_graph->abort_priority,
transition_graph->complete?"true":"false");
CRM_CHECK(timer->action != NULL, return FALSE);
if(transition_graph->complete) {
crm_warn("Ignoring timeout while not in transition");
} else if(timer->reason == timeout_action_warn) {
print_action(
LOG_WARNING,"Action missed its timeout", timer->action);
} else {
/* fail the action */
cib_action_update(timer->action, LRM_OP_TIMEOUT);
}
return FALSE;
}
static int
unconfirmed_actions(gboolean send_updates)
{
int unconfirmed = 0;
const char *key = NULL;
const char *task = NULL;
const char *node = NULL;
crm_debug_2("Unconfirmed actions...");
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
/* lookup event */
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(action->executed == FALSE) {
continue;
} else if(action->confirmed) {
continue;
}
unconfirmed++;
task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
crm_info("Action %s %d unconfirmed from %s",
key, action->id, node);
if(action->type != action_type_rsc) {
continue;
} else if(send_updates == FALSE) {
continue;
} else if(safe_str_eq(task, "cancel")) {
/* we dont need to update the CIB with these */
continue;
} else if(safe_str_eq(task, "stop")) {
/* *never* update the CIB with these */
continue;
}
cib_action_update(action, LRM_OP_PENDING);
);
);
if(unconfirmed > 0) {
crm_warn("Waiting on %d unconfirmed actions", unconfirmed);
}
return unconfirmed;
}
gboolean
global_timer_callback(gpointer data)
{
crm_action_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (crm_action_timer_t*)data;
stop_te_timer(timer);
crm_warn("Timer popped (abort_level=%d, complete=%s)",
transition_graph->abort_priority,
transition_graph->complete?"true":"false");
CRM_CHECK(timer->action == NULL, return FALSE);
if(transition_graph->complete) {
crm_err("Ignoring timeout while not in transition");
} else if(timer->reason == timeout_abort) {
int unconfirmed = unconfirmed_actions(FALSE);
crm_warn("Transition abort timeout reached..."
" marking transition complete.");
transition_graph->complete = TRUE;
abort_transition(INFINITY, tg_restart, "Global Timeout", NULL);
if(unconfirmed != 0) {
crm_warn("Writing %d unconfirmed actions to the CIB",
unconfirmed);
unconfirmed_actions(TRUE);
}
}
return FALSE;
}
-gboolean
-te_graph_trigger(gpointer user_data)
-{
- int timeout = 0;
- enum transition_status graph_rc = -1;
-
- if(transition_graph->complete == FALSE) {
- graph_rc = run_graph(transition_graph);
- timeout = transition_graph->transition_timeout;
- print_graph(LOG_DEBUG_3, transition_graph);
-
- if(graph_rc == transition_active) {
- crm_debug_3("Transition not yet complete");
- stop_te_timer(transition_timer);
- start_global_timer(transition_timer, timeout);
- return TRUE;
-
- } else if(graph_rc == transition_pending) {
- crm_debug_3("Transition not yet complete - no actions fired");
- return TRUE;
- }
-
- if(graph_rc != transition_complete) {
- crm_err("Transition failed: %s", transition_status(graph_rc));
- print_graph(LOG_WARNING, transition_graph);
- }
- }
-
- transition_graph->complete = TRUE;
- notify_crmd(transition_graph);
-
- return TRUE;
-}
diff --git a/transitioner/te_callbacks.h b/crmd/te_callbacks.h
similarity index 96%
rename from transitioner/te_callbacks.h
rename to crmd/te_callbacks.h
index 462cc0553c..ed9336f6fd 100644
--- a/transitioner/te_callbacks.h
+++ b/crmd/te_callbacks.h
@@ -1,42 +1,43 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#ifndef TE_CALLBACKS__H
#define TE_CALLBACKS__H
extern void cib_fencing_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data);
extern void cib_action_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data);
extern void cib_failcount_updated(xmlNode *msg, int call_id, int rc,
xmlNode *output, void *user_data);
extern gboolean global_timer_callback(gpointer data);
extern gboolean action_timer_callback(gpointer data);
extern gboolean te_graph_trigger(gpointer user_data);
extern void tengine_stonith_connection_destroy(gpointer user_data);
+extern void te_update_diff(const char *event, xmlNode *msg);
#if SUPPORT_HEARTBEAT
extern void tengine_stonith_callback(stonith_ops_t * op);
extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data);
#endif
#endif
diff --git a/transitioner/events.c b/crmd/te_events.c
similarity index 98%
rename from transitioner/events.c
rename to crmd/te_events.c
index 8b94a7f899..3744e020a1 100644
--- a/transitioner/events.c
+++ b/crmd/te_events.c
@@ -1,577 +1,578 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
+#include <crmd_fsa.h>
char *failed_stop_offset = NULL;
char *failed_start_offset = NULL;
xmlNode *need_abort(xmlNode *update);
void process_graph_event(xmlNode *event, const char *event_node);
int match_graph_event(int action_id, xmlNode *event, const char *event_node,
int op_status, int op_rc, int target_rc);
xmlNode *
need_abort(xmlNode *update)
{
xmlNode *section_xml = NULL;
const char *section = NULL;
if(update == NULL) {
return NULL;
}
xml_prop_iter(update, name, value,
if(safe_str_eq(name, XML_ATTR_HAVE_QUORUM)) {
goto do_abort; /* possibly not required */
} else if(safe_str_eq(name, XML_ATTR_NUMPEERS)) {
goto do_abort;
} else if(safe_str_eq(name, XML_ATTR_GENERATION)) {
goto do_abort;
} else if(safe_str_eq(name, XML_ATTR_GENERATION_ADMIN)) {
goto do_abort;
}
continue;
do_abort:
crm_debug("Aborting on change to %s", name);
crm_log_xml_debug(update, "Abort: CIB Attrs");
return update;
);
section = XML_CIB_TAG_NODES;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_RESOURCES;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_CONSTRAINTS;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
section = XML_CIB_TAG_CRMCONFIG;
section_xml = get_object_root(section, update);
xml_child_iter(section_xml, child,
return section_xml;
);
return NULL;
}
static gboolean
fail_incompletable_actions(crm_graph_t *graph, const char *down_node)
{
const char *target = NULL;
xmlNode *last_action = NULL;
slist_iter(
synapse, synapse_t, graph->synapses, lpc,
if (synapse->confirmed) {
continue;
}
slist_iter(
action, crm_action_t, synapse->actions, lpc,
if(action->type == action_type_pseudo || action->confirmed) {
continue;
}
target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
if(safe_str_eq(target, down_node)) {
action->failed = TRUE;
last_action = action->xml;
update_graph(graph, action);
crm_notice("Action %d (%s) is scheduled for %s (offline)",
action->id, ID(action->xml), down_node);
}
);
);
if(last_action != NULL) {
crm_warn("Node %s shutdown resulted in un-runnable actions", down_node);
abort_transition(INFINITY, tg_restart, "Node failure", last_action);
return TRUE;
}
return FALSE;
}
gboolean
extract_event(xmlNode *msg)
{
int shutdown = 0;
const char *shutdown_s = NULL;
const char *event_node = NULL;
/*
[cib fragment]
...
<status>
<node_state id="node1" state=CRMD_STATE_ACTIVE exp_state="active">
<lrm>
<lrm_resources>
<rsc_state id="" rsc_id="rsc4" node_id="node1" rsc_state="stopped"/>
*/
crm_debug_4("Extracting event from %s", crm_element_name(msg));
xml_child_iter_filter(
msg, node_state, XML_CIB_TAG_STATE,
xmlNode *attrs = NULL;
xmlNode *resources = NULL;
const char *ccm_state = crm_element_value(
node_state, XML_CIB_ATTR_INCCM);
const char *crmd_state = crm_element_value(
node_state, XML_CIB_ATTR_CRMDSTATE);
/* Transient node attribute changes... */
event_node = crm_element_value(node_state, XML_ATTR_ID);
crm_debug_2("Processing state update from %s", event_node);
crm_log_xml_debug_3(node_state, "Processing");
attrs = find_xml_node(
node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
if(attrs != NULL) {
crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" changes for %s", event_node);
abort_transition(INFINITY, tg_restart,
XML_TAG_TRANSIENT_NODEATTRS, attrs);
}
resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
resources = find_xml_node(
resources, XML_LRM_TAG_RESOURCES, FALSE);
/* LRM resource update... */
xml_child_iter(
resources, rsc,
xml_child_iter(
rsc, rsc_op,
crm_log_xml_debug_3(rsc_op, "Processing resource update");
process_graph_event(rsc_op, event_node);
);
);
/*
* node state update... possibly from a shutdown we requested
*/
if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE)
|| safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) {
crm_action_t *shutdown = NULL;
shutdown = match_down_event(0, event_node, NULL);
if(shutdown != NULL) {
update_graph(transition_graph, shutdown);
trigger_graph();
} else {
crm_info("Stonith/shutdown of %s not matched", event_node);
abort_transition(INFINITY, tg_restart, "Node failure", node_state);
}
fail_incompletable_actions(transition_graph, event_node);
}
shutdown_s = crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN);
if(shutdown_s) {
shutdown = crm_parse_int(shutdown_s, NULL);
}
if(shutdown_s && shutdown > 0) {
crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node);
abort_transition(INFINITY, tg_restart, "Shutdown request", node_state);
}
);
return TRUE;
}
static void
update_failcount(xmlNode *event, const char *event_node, int rc, int target_rc)
{
int interval = 0;
char *task = NULL;
char *rsc_id = NULL;
char *attr_name = NULL;
const char *id = ID(event);
const char *on_uuid = event_node;
const char *value = NULL;
if(rc == 99) {
/* this is an internal code for "we're busy, try again" */
return;
} else if(rc == target_rc) {
return;
}
if(failed_stop_offset == NULL) {
failed_stop_offset = crm_strdup(INFINITY_S);
}
if(failed_start_offset == NULL) {
failed_start_offset = crm_strdup(INFINITY_S);
}
CRM_CHECK(on_uuid != NULL, return);
CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval),
crm_err("Couldn't parse: %s", ID(event));
goto bail);
CRM_CHECK(task != NULL, goto bail);
CRM_CHECK(rsc_id != NULL, goto bail);
if(safe_str_eq(task, CRMD_ACTION_START)) {
interval = 1;
value = failed_start_offset;
} else if(safe_str_eq(task, CRMD_ACTION_STOP)) {
interval = 1;
value = failed_stop_offset;
}
if(value == NULL || safe_str_neq(value, INFINITY_S)) {
value = XML_NVPAIR_ATTR_VALUE"++";
}
if(interval > 0) {
int call_id = 0;
char *now = crm_itoa(time(NULL));
attr_name = crm_concat("fail-count", rsc_id, '-');
crm_warn("Updating failcount for %s on %s after failed %s:"
" rc=%d (update=%s, time=%s)", rsc_id, on_uuid, task, rc, value, now);
/* don't let notificatios of these updates cause new transitions */
- call_id = update_attr(te_cib_conn, cib_inhibit_notify, XML_CIB_TAG_STATUS,
+ call_id = update_attr(fsa_cib_conn, cib_inhibit_notify, XML_CIB_TAG_STATUS,
on_uuid, NULL,NULL, attr_name, value, FALSE);
add_cib_op_callback(call_id, FALSE, NULL, cib_failcount_updated);
crm_free(attr_name);
attr_name = crm_concat("last-failure", rsc_id, '-');
/* don't let notificatios of these updates cause new transitions */
- call_id = update_attr(te_cib_conn, cib_inhibit_notify, XML_CIB_TAG_STATUS,
+ call_id = update_attr(fsa_cib_conn, cib_inhibit_notify, XML_CIB_TAG_STATUS,
on_uuid, NULL,NULL, attr_name, now, FALSE);
add_cib_op_callback(call_id, FALSE, NULL, cib_failcount_updated);
crm_free(attr_name);
crm_free(now);
}
bail:
crm_free(rsc_id);
crm_free(task);
}
static int
status_from_rc(crm_action_t *action, int orig_status, int rc, int target_rc)
{
int status = orig_status;
if(target_rc == rc) {
crm_debug_2("Target rc: == %d", rc);
if(status != LRM_OP_DONE) {
crm_debug_2("Re-mapping op status to"
" LRM_OP_DONE for rc=%d", rc);
status = LRM_OP_DONE;
}
} else {
crm_debug_2("Target rc: != %d", rc);
if(status != LRM_OP_ERROR) {
crm_info("Re-mapping op status to"
" LRM_OP_ERROR for rc=%d", rc);
status = LRM_OP_ERROR;
}
}
/* 99 is the code we use for direct nack's */
if(rc != 99 && status != LRM_OP_DONE) {
const char *task, *uname;
task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
crm_warn("Action %d (%s) on %s failed (target: %d vs. rc: %d): %s",
action->id, task, uname, target_rc, rc, op_status2text(status));
}
return status;
}
/*
* returns the ID of the action if a match is found
* returns -1 if a match was not found
* returns -2 if a match was found but the action failed (and was
* not allowed to)
*/
int
match_graph_event(int action_id, xmlNode *event, const char *event_node,
int op_status, int op_rc, int target_rc)
{
const char *target = NULL;
const char *allow_fail = NULL;
const char *this_event = ID(event);
crm_action_t *action = NULL;
action = get_action(action_id, FALSE);
if(action == NULL) {
return -1;
}
op_status = status_from_rc(action, op_status, op_rc, target_rc);
if(op_status != LRM_OP_DONE) {
update_failcount(event, event_node, op_rc, target_rc);
}
/* Process OP status */
switch(op_status) {
case LRM_OP_PENDING:
crm_debug("Ignoring pending operation");
return action->id;
break;
case LRM_OP_DONE:
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
action->failed = TRUE;
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
crm_err("Dont know what to do for cancelled ops yet");
break;
default:
action->failed = TRUE;
crm_err("Unsupported action result: %d", op_status);
}
/* stop this event's timer if it had one */
stop_te_timer(action->timer);
action->confirmed = TRUE;
update_graph(transition_graph, action);
trigger_graph();
if(action->failed) {
allow_fail = g_hash_table_lookup(
action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL));
if(crm_is_true(allow_fail)) {
action->failed = FALSE;
}
}
if(action->failed) {
abort_transition(action->synapse->priority+1,
tg_restart, "Event failed", event);
}
target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
te_log_action(LOG_INFO, "Action %s (%d) confirmed on %s (rc=%d)",
crm_str(this_event), action->id, crm_str(target),
op_status);
return action->id;
}
crm_action_t *
get_action(int id, gboolean confirmed)
{
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(action->id == id) {
if(confirmed) {
stop_te_timer(action->timer);
action->confirmed = TRUE;
}
return action;
}
)
);
return NULL;
}
crm_action_t *
match_down_event(int id, const char *target, const char *filter)
{
const char *this_action = NULL;
const char *this_node = NULL;
crm_action_t *match = NULL;
slist_iter(
synapse, synapse_t, transition_graph->synapses, lpc,
/* lookup event */
slist_iter(
action, crm_action_t, synapse->actions, lpc2,
if(id > 0 && action->id == id) {
match = action;
break;
}
this_action = crm_element_value(
action->xml, XML_LRM_ATTR_TASK);
if(action->type != action_type_crm) {
continue;
} else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){
continue;
} else if(filter != NULL
&& safe_str_neq(this_action, filter)) {
continue;
}
this_node = crm_element_value(
action->xml, XML_LRM_ATTR_TARGET_UUID);
if(this_node == NULL) {
crm_log_xml_err(action->xml, "No node uuid");
}
if(safe_str_neq(this_node, target)) {
crm_debug("Action %d : Node mismatch: %s",
action->id, this_node);
continue;
}
match = action;
break;
);
if(match != NULL) {
/* stop this event's timer if it had one */
break;
}
);
if(match != NULL) {
/* stop this event's timer if it had one */
crm_debug("Match found for action %d: %s on %s", id,
crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY),
target);
stop_te_timer(match->timer);
match->confirmed = TRUE;
} else if(id > 0) {
crm_err("No match for action %d", id);
} else {
crm_warn("No match for shutdown action on %s", target);
}
return match;
}
void
process_graph_event(xmlNode *event, const char *event_node)
{
int rc = -1;
int status = -1;
int action = -1;
int target_rc = -1;
int transition_num = -1;
char *update_te_uuid = NULL;
gboolean passed = FALSE;
const char *id = NULL;
const char *magic = NULL;
CRM_ASSERT(event != NULL);
id = ID(event);
magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC);
if(magic == NULL) {
/* non-change */
return;
}
CRM_CHECK(decode_transition_magic(
magic, &update_te_uuid, &transition_num, &action,
&status, &rc, &target_rc),
crm_err("Invalid event %s detected", id);
abort_transition(INFINITY, tg_restart,"Bad event", event);
);
if(status == LRM_OP_PENDING) {
goto bail;
}
if(transition_num == -1) {
crm_err("Action %s (%s) initiated outside of a transition",
id, magic);
abort_transition(INFINITY, tg_restart,"Unexpected event",event);
} else if(action < 0 || safe_str_neq(update_te_uuid, te_uuid)) {
crm_info("Action %s (%s) initiated by a different transitioner",
id, magic);
abort_transition(INFINITY, tg_restart,"Foreign event", event);
} else if(transition_graph->id != transition_num) {
crm_info("Detected action %s from a different transition:"
" %d vs. %d", id, transition_num, transition_graph->id);
abort_transition(INFINITY, tg_restart,"Old event", event);
} else if(transition_graph->complete) {
crm_info("Action %s arrived after a completed transition", id);
abort_transition(INFINITY, tg_restart, "Inactive graph", event);
} else if(match_graph_event(
action, event, event_node, status, rc, target_rc) < 0) {
crm_err("Unknown graph action %s", id);
abort_transition(INFINITY, tg_restart, "Unknown event", event);
} else {
passed = TRUE;
crm_debug_2("Processed update to %s: %s", id, magic);
}
if(passed == FALSE && rc != EXECRA_OK) {
update_failcount(event, event_node, rc, target_rc);
}
bail:
crm_free(update_te_uuid);
return;
}
diff --git a/transitioner/utils.c b/crmd/te_utils.c
similarity index 71%
rename from transitioner/utils.c
rename to crmd/te_utils.c
index ac2772048c..b55d1a81cc 100644
--- a/transitioner/utils.c
+++ b/crmd/te_utils.c
@@ -1,150 +1,210 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
extern cib_t *te_cib_conn;
GCHSource *stonith_src = NULL;
GTRIGSource *stonith_reconnect = NULL;
gboolean
te_connect_stonith(gpointer user_data)
{
#if SUPPORT_HEARTBEAT
if(is_heartbeat_cluster()) {
int lpc = 0;
int rc = ST_OK;
IPC_Channel *fence_ch = NULL;
if(stonith_src != NULL) {
crm_debug("Still connected");
return TRUE;
}
for(lpc = 0; lpc < 30; lpc++) {
crm_info("Attempting connection to fencing daemon...");
sleep(1);
rc = stonithd_signon("tengine");
if(rc == ST_OK) {
break;
}
if(user_data != NULL) {
crm_err("Sign-in failed: triggered a retry");
G_main_set_trigger(stonith_reconnect);
return TRUE;
}
crm_err("Sign-in failed: pausing and trying again in 2s...");
sleep(1);
}
CRM_ASSERT(rc == ST_OK); /* If not, we failed 30 times... just get out */
CRM_ASSERT(stonithd_set_stonith_ops_callback(
tengine_stonith_callback) == ST_OK);
crm_debug_2("Grabbing IPC channel");
fence_ch = stonithd_input_IPC_channel();
CRM_ASSERT(fence_ch != NULL);
crm_debug_2("Attaching to mainloop");
stonith_src = G_main_add_IPC_Channel(
G_PRIORITY_LOW, fence_ch, FALSE, tengine_stonith_dispatch, NULL,
tengine_stonith_connection_destroy);
CRM_ASSERT(stonith_src != NULL);
crm_info("Connected");
return TRUE;
}
#endif
return FALSE;
}
+gboolean
+start_global_timer(crm_action_timer_t *timer, int timeout)
+{
+ CRM_ASSERT(timer != NULL);
+ CRM_CHECK(timer > 0, return FALSE);
+ CRM_CHECK(timer->source_id == 0, return FALSE);
+
+ if(timeout <= 0) {
+ crm_err("Tried to start timer with period: %d", timeout);
+
+ } else if(timer->source_id == 0) {
+ crm_debug_2("Starting abort timer: %dms", timeout);
+ timer->timeout = timeout;
+ timer->source_id = Gmain_timeout_add(
+ timeout, global_timer_callback, (void*)timer);
+ CRM_ASSERT(timer->source_id != 0);
+ return TRUE;
+
+ } else {
+ crm_err("Timer is already active with period: %d", timer->timeout);
+ }
+
+ return FALSE;
+}
+
gboolean
stop_te_timer(crm_action_timer_t *timer)
{
const char *timer_desc = "action timer";
if(timer == NULL) {
return FALSE;
}
if(timer->reason == timeout_abort) {
timer_desc = "global timer";
}
if(timer->source_id != 0) {
crm_debug_2("Stopping %s", timer_desc);
Gmain_timeout_remove(timer->source_id);
timer->source_id = 0;
} else {
return FALSE;
}
return TRUE;
}
+gboolean
+te_graph_trigger(gpointer user_data)
+{
+ int timeout = 0;
+ enum transition_status graph_rc = -1;
+
+ if(transition_graph->complete == FALSE) {
+ graph_rc = run_graph(transition_graph);
+ timeout = transition_graph->transition_timeout;
+ print_graph(LOG_DEBUG_3, transition_graph);
+
+ if(graph_rc == transition_active) {
+ crm_debug_3("Transition not yet complete");
+ stop_te_timer(transition_timer);
+ start_global_timer(transition_timer, timeout);
+ return TRUE;
+
+ } else if(graph_rc == transition_pending) {
+ crm_debug_3("Transition not yet complete - no actions fired");
+ return TRUE;
+ }
+
+ if(graph_rc != transition_complete) {
+ crm_err("Transition failed: %s", transition_status(graph_rc));
+ print_graph(LOG_WARNING, transition_graph);
+ }
+ }
+
+ transition_graph->complete = TRUE;
+ notify_crmd(transition_graph);
+
+ return TRUE;
+}
+
void
trigger_graph_processing(const char *fn, int line)
{
G_main_set_trigger(transition_trigger);
crm_debug_2("%s:%d - Triggered graph processing", fn, line);
}
void
abort_transition_graph(
int abort_priority, enum transition_action abort_action,
const char *abort_text, xmlNode *reason, const char *fn, int line)
{
int log_level = LOG_DEBUG;
/*
if(abort_priority >= INFINITY) {
log_level = LOG_INFO;
}
*/
update_abort_priority(
transition_graph, abort_priority, abort_action, abort_text);
do_crm_log(log_level, "%s:%d - Triggered graph processing : %s",
fn, line, abort_text);
if(reason != NULL) {
const char *magic = crm_element_value(
reason, XML_ATTR_TRANSITION_MAGIC);
if(magic) {
do_crm_log(log_level, "Caused by update to %s: %s",
ID(reason), magic);
} else {
crm_log_xml(log_level, "Cause", reason);
}
}
G_main_set_trigger(transition_trigger);
}
+
diff --git a/crmd/tengine.c b/crmd/tengine.c
index 704308fa68..001d368d45 100644
--- a/crmd/tengine.c
+++ b/crmd/tengine.c
@@ -1,173 +1,309 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <clplumbing/realtime.h>
#include <sys/types.h> /* for calls to open */
#include <sys/stat.h> /* for calls to open */
#include <fcntl.h> /* for calls to open */
#include <pwd.h> /* for getpwuid */
#include <grp.h> /* for initgroups */
#include <sys/time.h> /* for getrlimit */
#include <sys/resource.h>/* for getrlimit */
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crm/cib.h>
#include <crmd.h>
+#include <tengine.h>
+#include <te_callbacks.h>
+extern crm_graph_functions_t te_graph_fns;
struct crm_subsystem_s *te_subsystem = NULL;
+gboolean te_init(void);
+
+
+static void global_cib_callback(const xmlNode *msg, int callid ,int rc, xmlNode *output)
+{
+#if 1
+ if(transition_graph->complete == FALSE) {
+ int pending_callbacks = num_cib_op_callbacks();
+ if(pending_callbacks == 0) {
+ crm_debug("Triggering the TE");
+ trigger_graph();
+ }
+ }
+#endif
+}
+
/* A_TE_START, A_TE_STOP, A_TE_RESTART */
void
do_te_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
- struct crm_subsystem_s *this_subsys = te_subsystem;
-
- long long stop_actions = A_TE_STOP;
- long long start_actions = A_TE_START;
+ int dummy;
+ gboolean init_ok = TRUE;
-/* if(action & stop_actions && cur_state != S_STOPPING */
-/* && is_set(fsa_input_register, R_TE_PEND)) { */
-/* result = I_WAIT_FOR_EVENT; */
-/* return result; */
-/* } */
+ cl_uuid_t new_uuid;
+ char uuid_str[UU_UNPARSE_SIZEOF];
- if(action & stop_actions) {
- stop_subsystem(this_subsys, FALSE);
+ if(action & A_TE_STOP) {
+ if(transition_graph) {
+ destroy_graph(transition_graph);
}
+ }
- if(action & start_actions) {
- if(cur_state != S_STOPPING) {
- if(start_subsystem(this_subsys) == FALSE) {
- register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
- }
- } else {
- crm_info("Ignoring request to start %s while shutting down",
- this_subsys->name);
- }
+ if((action & A_TE_START) && cur_state == S_STOPPING) {
+ crm_info("Ignoring request to start %s while shutting down",
+ te_subsystem->name);
+ return;
+ }
+
+ if((action & A_TE_START) == 0) {
+ return;
+ }
+
+ cl_uuid_generate(&new_uuid);
+ cl_uuid_unparse(&new_uuid, uuid_str);
+ te_uuid = crm_strdup(uuid_str);
+ crm_info("Registering TE UUID: %s", te_uuid);
+
+ if(transition_trigger == NULL) {
+ transition_trigger = G_main_add_TriggerHandler(
+ G_PRIORITY_LOW, te_graph_trigger, NULL, NULL);
+ }
+
+ if(stonith_reconnect == NULL) {
+ stonith_reconnect = G_main_add_TriggerHandler(
+ G_PRIORITY_LOW, te_connect_stonith, &dummy, NULL);
+ }
+
+ if(cib_ok != fsa_cib_conn->cmds->add_notify_callback(
+ fsa_cib_conn, T_CIB_DIFF_NOTIFY, te_update_diff)) {
+ crm_err("Could not set CIB notification callback");
+ init_ok = FALSE;
+ }
+
+ if(cib_ok != fsa_cib_conn->cmds->set_op_callback(fsa_cib_conn, global_cib_callback)) {
+ crm_err("Could not set CIB global callback");
+ init_ok = FALSE;
+ }
+
+ if(is_heartbeat_cluster() && init_ok) {
+ G_main_set_trigger(stonith_reconnect);
+ }
+
+ if(init_ok) {
+ set_graph_functions(&te_graph_fns);
+
+ if(transition_graph) {
+ destroy_graph(transition_graph);
}
+
+ /* create a blank one */
+ transition_graph = unpack_graph(NULL);
+ transition_graph->complete = TRUE;
+ transition_graph->abort_reason = "DC Takeover";
+ transition_graph->completion_action = tg_restart;
+
+ crm_malloc0(transition_timer, sizeof(crm_action_timer_t));
+ transition_timer->source_id = 0;
+ transition_timer->reason = timeout_abort;
+ transition_timer->action = NULL;
+ }
}
/* A_TE_INVOKE, A_TE_CANCEL */
void
do_te_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
xmlNode *cmd = NULL;
if(AM_I_DC == FALSE) {
- crm_debug("Not DC: No need to invoke the TE (anymore): %s",
- fsa_action2string(action));
+ crm_err("Not DC: No need to invoke the TE (anymore): %s",
+ fsa_action2string(action));
return;
} else if(fsa_state != S_TRANSITION_ENGINE && (action & A_TE_INVOKE)) {
- crm_debug("No need to invoke the TE (%s) in state %s",
- fsa_action2string(action),
- fsa_state2string(fsa_state));
+ crm_err("No need to invoke the TE (%s) in state %s",
+ fsa_action2string(action),
+ fsa_state2string(fsa_state));
return;
+ }
- } else if(!is_set(fsa_input_register, te_subsystem->flag_required)) {
- crm_err("Ignoring action %s in state: %s"
- " - We dont want the TE anymore",
- fsa_action2string(action), fsa_state2string(cur_state));
- return;
-
- } else if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) {
- crm_info("Waiting for the TE to connect before action %s",
- fsa_action2string(action));
-
- if(action & A_TE_INVOKE) {
- register_fsa_input(
- msg_data->fsa_cause, msg_data->fsa_input,
- msg_data->data);
- }
+ if(action & A_TE_CANCEL) {
+ crm_debug("Cancelling the active Transition");
+ abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL);
- crmd_fsa_stall(NULL);
- return;
- }
+ } else if(action & A_TE_HALT) {
+ abort_transition(INFINITY, tg_stop, "Peer Halt", NULL);
- if(action & A_TE_INVOKE) {
+ } else if(action & A_TE_INVOKE) {
+ const char *value = NULL;
+ xmlNode *graph_data = NULL;
ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
const char *graph_file = crm_element_value(input->msg, F_CRM_TGRAPH);
const char *graph_input = crm_element_value(input->msg, F_CRM_TGRAPH_INPUT);
- if(graph_file != NULL || input->xml != NULL) {
- crm_debug("Starting a transition");
- set_bit_inplace(fsa_input_register, R_IN_TRANSITION);
-
- cmd = create_request(
- CRM_OP_TRANSITION, input->xml, NULL,
- CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL);
-
- crm_xml_add(cmd, F_CRM_TGRAPH_INPUT, graph_input);
- if(graph_file) {
- crm_xml_add(cmd, F_CRM_TGRAPH, graph_file);
- }
-
- send_request(cmd, NULL);
-
- } else {
+ if(graph_file != NULL && input->xml == NULL) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
+ return;
}
-
- } else if(action & A_TE_CANCEL) {
- crm_debug("Cancelling the active Transition");
- cmd = create_request(
- CRM_OP_TEABORT, NULL, NULL,
- CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL);
- send_request(cmd, NULL);
+ if(transition_graph->complete == FALSE) {
+ crm_info("Another transition is already active");
+ abort_transition(INFINITY, tg_restart, "Transition Active", NULL);
+ return;
- } else if(action & A_TE_HALT) {
- cmd = create_request(
- CRM_OP_TE_HALT, NULL, NULL,
- CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL);
+ }
+ crm_debug("Processing graph derived from %s", graph_input);
+
+ graph_data = input->xml;
+ if(graph_file != NULL) {
+ FILE *graph_fd = fopen(graph_file, "r");
+
+ CRM_CHECK(graph_fd != NULL,
+ cl_perror("Could not open graph file %s", graph_file); return);
+
+ graph_data = file2xml(graph_fd, FALSE);
+
+ unlink(graph_file);
+ fclose(graph_fd);
+ }
+
+ destroy_graph(transition_graph);
+ transition_graph = unpack_graph(graph_data);
+ start_global_timer(transition_timer, transition_graph->transition_timeout);
+
+ value = crm_element_value(graph_data, "failed-stop-offset");
+ if(value) {
+ failed_stop_offset = crm_strdup(value);
+ }
+
+ value = crm_element_value(graph_data, "failed-start-offset");
+ if(value) {
+ failed_start_offset = crm_strdup(value);
+ }
+
+ trigger_graph();
+ print_graph(LOG_DEBUG_2, transition_graph);
- send_request(cmd, NULL);
+ if(graph_data != input->xml) {
+ free_xml(graph_data);
+ }
}
free_xml(cmd);
}
+gboolean te_init(void)
+{
+ int dummy = 0;
+ gboolean init_ok = TRUE;
+
+ transition_trigger = G_main_add_TriggerHandler(
+ G_PRIORITY_LOW, te_graph_trigger, NULL, NULL);
+
+ stonith_reconnect = G_main_add_TriggerHandler(
+ G_PRIORITY_LOW, te_connect_stonith, &dummy, NULL);
+
+ if(init_ok) {
+ crm_debug_4("Setting CIB notification callback");
+ if(cib_ok != fsa_cib_conn->cmds->add_notify_callback(
+ fsa_cib_conn, T_CIB_DIFF_NOTIFY, te_update_diff)) {
+ crm_err("Could not set CIB notification callback");
+ init_ok = FALSE;
+ }
+ }
+
+ if(is_heartbeat_cluster() && init_ok) {
+ G_main_set_trigger(stonith_reconnect);
+ }
+
+ if(init_ok) {
+ cl_uuid_t new_uuid;
+ char uuid_str[UU_UNPARSE_SIZEOF];
+
+ cl_uuid_generate(&new_uuid);
+ cl_uuid_unparse(&new_uuid, uuid_str);
+ te_uuid = crm_strdup(uuid_str);
+ crm_info("Registering TE UUID: %s", te_uuid);
+ set_graph_functions(&te_graph_fns);
+
+ /* create a blank one */
+ transition_graph = unpack_graph(NULL);
+ transition_graph->complete = TRUE;
+ transition_graph->abort_reason = "DC Takeover";
+ transition_graph->completion_action = tg_restart;
+ crm_malloc0(transition_timer, sizeof(crm_action_timer_t));
+ transition_timer->source_id = 0;
+ transition_timer->reason = timeout_abort;
+ transition_timer->action = NULL;
+ }
+ return init_ok;
+}
+
+#if 0
+gboolean shuttingdown;
+gboolean tengine_shutdown(int nsig, gpointer unused)
+{
+ shuttingdown = TRUE;
+ abort_transition(INFINITY, tg_shutdown, "Shutdown", NULL);
+ return TRUE;
+}
+
+gboolean te_stop(void)
+{
+ destroy_graph(transition_graph);
+ crm_free(transition_timer);
+
+#if SUPPORT_HEARTBEAT
+ if(is_heartbeat_cluster()) {
+ stonithd_signoff();
+ }
+#endif
+ crm_free(te_uuid);
+}
+#endif
diff --git a/transitioner/tengine.h b/crmd/tengine.h
similarity index 92%
rename from transitioner/tengine.h
rename to crmd/tengine.h
index 88ae354331..16aa2a0adc 100644
--- a/transitioner/tengine.h
+++ b/crmd/tengine.h
@@ -1,77 +1,73 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 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
*/
#ifndef TENGINE__H
#define TENGINE__H
#include <crm/transition.h>
#include <clplumbing/ipc.h>
#if SUPPORT_HEARTBEAT
# include <fencing/stonithd_api.h>
extern void send_stonith_update(stonith_ops_t * op);
#endif
-extern IPC_Channel *crm_ch;
-extern GMainLoop* mainloop;
-
/* tengine */
extern crm_action_t *match_down_event(
int rc, const char *target, const char *filter);
extern gboolean cib_action_update(crm_action_t *action, int status);
/* utils */
extern crm_action_t *get_action(int id, gboolean confirmed);
+extern gboolean start_global_timer(crm_action_timer_t *timer, int timeout);
extern gboolean stop_te_timer(crm_action_timer_t *timer);
extern const char *get_rsc_state(const char *task, op_status_t status);
/* unpack */
extern gboolean extract_event(xmlNode *msg);
-extern gboolean process_te_message(
- xmlNode * msg, xmlNode *xml_data, IPC_Channel *sender);
+extern gboolean process_te_message(xmlNode * msg, xmlNode *xml_data);
extern crm_graph_t *transition_graph;
extern GTRIGSource *transition_trigger;
extern char *te_uuid;
-extern cib_t *te_cib_conn;
extern void notify_crmd(crm_graph_t *graph);
#include <te_callbacks.h>
extern void trigger_graph_processing(const char *fn, int line);
extern void abort_transition_graph(
int abort_priority, enum transition_action abort_action,
const char *abort_text, xmlNode *reason, const char *fn, int line);
#define trigger_graph() trigger_graph_processing(__FUNCTION__, __LINE__)
#define abort_transition(pri, action, text, reason) \
abort_transition_graph(pri, action, text, reason,__FUNCTION__,__LINE__);
extern gboolean te_connect_stonith(gpointer user_data);
extern GCHSource *stonith_src;
extern GTRIGSource *transition_trigger;
extern GTRIGSource *stonith_reconnect;
extern crm_action_timer_t *transition_timer;
extern char *failed_stop_offset;
extern char *failed_start_offset;
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 26, 7:46 PM (1 d, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1959593
Default Alt Text
(110 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment