Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/crmd/Makefile.am b/crm/crmd/Makefile.am
index 3a6f775bab..5b431fd2a2 100644
--- a/crm/crmd/Makefile.am
+++ b/crm/crmd/Makefile.am
@@ -1,94 +1,94 @@
#
# 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$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \
-I$(top_builddir) -I$(top_srcdir)
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
havarlibdir = $(localstatedir)/lib/@HB_PKG@
PIDFILE = $(localstatedir)/run/crmd.pid
XML_FLAGS = `xml2-config --cflags`
XML_LIBS = `xml2-config --libs`
# sockets with path
crmdir = $(havarlibdir)/crm
apigid = @HA_APIGID@
crmuid = @HA_CCMUID@
COMMONLIBS = $(CRM_DEBUG_LIBS) \
$(top_builddir)/lib/clplumbing/libplumb.la \
$(top_builddir)/$(CRM_DIR)/common/libcrmcommon.la \
$(top_builddir)/$(CRM_DIR)/cib/libcib.la \
$(top_builddir)/lib/apphb/libapphb.la \
$(top_builddir)/lib/hbclient/libhbclient.la \
$(GLIBLIB) \
$(LIBRT)
LIBRT = @LIBRT@
AM_CFLAGS = @CFLAGS@ \
-DPIDFILE='"$(PIDFILE)"' \
$(CRM_DEBUG_FLAGS)
## libraries
lib_LTLIBRARIES =
## binary progs
halib_PROGRAMS = crmd
## SOURCES
-noinst_HEADERS = crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h \
- fsa_matrix.h fsa_proto.h crmd_utils.h
+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_SOURCES = crmdmain.c crmd.c \
- fsa.c control.c messages.c ccm.c \
+ fsa.c control.c messages.c ccm.c callbacks.c \
election.c subsystems.c lrm.c join.c utils.c misc.c
crmd_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"'
crmd_LDFLAGS = $(XML_LIBS)
crmd_LDADD = $(COMMONLIBS) \
$(top_builddir)/$(CRM_DIR)/cib/libcib.la \
$(top_builddir)/lib/lrm/liblrm.la \
$(top_builddir)/membership/ccm/libccmclient.la
# Simple HA client app
#clnt_SOURCES = clnt.c
#clnt_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"'
#clnt_LDFLAGS = $(XML_LIBS)
#clnt_LDADD = $(COMMONLIBS)
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
perl make_dot.pl
diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c
new file mode 100644
index 0000000000..5b653e4514
--- /dev/null
+++ b/crm/crmd/callbacks.c
@@ -0,0 +1,322 @@
+/*
+ * 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 <portability.h>
+#include <crm/crm.h>
+#include <string.h>
+#include <crmd_fsa.h>
+#include <libxml/tree.h>
+
+#include <heartbeat.h>
+
+#include <hb_api.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/common/msg.h>
+#include <crm/cib.h>
+
+#include <crmd.h>
+#include <crmd_messages.h>
+
+#include <crm/dmalloc_wrapper.h>
+
+FILE *msg_in_strm = NULL;
+
+xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg);
+
+void
+crmd_ha_input_callback(const struct ha_msg* msg, void* private_data)
+{
+ const char *from = ha_msg_value(msg, F_ORIG);
+ const char *to = NULL;
+ xmlNodePtr root_xml_node;
+
+ FNIN();
+
+#ifdef MSG_LOG
+ if(msg_in_strm == NULL) {
+ msg_in_strm = fopen("/tmp/inbound.log", "w");
+ }
+#endif
+
+ if(from == NULL || strcmp(from, fsa_our_uname) == 0) {
+#ifdef MSG_LOG
+ fprintf(msg_in_strm,
+ "Discarded message [F_SEQ=%s] from ourselves.\n",
+ ha_msg_value(msg, F_SEQ));
+#endif
+ FNOUT();
+ }
+
+#ifdef MSG_LOG
+ fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n",
+ from,
+ ha_msg_value(msg, F_SEQ),
+ ha_msg_value(msg, F_TYPE),
+ ha_msg_value(msg, "xml")
+ );
+ fflush(msg_in_strm);
+#endif
+
+ root_xml_node = find_xml_in_hamessage(msg);
+ to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO);
+
+ if(to != NULL && strlen(to) > 0 && strcmp(to, fsa_our_uname) != 0) {
+#ifdef MSG_LOG
+ fprintf(msg_in_strm,
+ "Discarding message [F_SEQ=%s] for someone else.",
+ ha_msg_value(msg, F_SEQ));
+#endif
+ FNOUT();
+ }
+
+ set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from);
+ s_crmd_fsa(C_HA_MESSAGE, I_ROUTER, root_xml_node);
+
+ free_xml(root_xml_node);
+
+ FNOUT();
+}
+
+/*
+ * Apparently returning TRUE means "stay connected, keep doing stuff".
+ * Returning FALSE means "we're all done, close the connection"
+ */
+gboolean
+crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data)
+{
+ int lpc = 0;
+ char *buffer = NULL;
+ IPC_Message *msg = NULL;
+ gboolean hack_return_good = TRUE;
+ xmlNodePtr root_xml_node;
+ crmd_client_t *curr_client = (crmd_client_t*)user_data;
+
+ FNIN();
+ CRM_DEBUG("Processing IPC message from %s",
+ curr_client->table_key);
+
+ while(client->ops->is_message_pending(client)) {
+ if (client->ch_status == IPC_DISCONNECT) {
+ /* The message which was pending for us is that
+ * the IPC status is now IPC_DISCONNECT */
+ break;
+ }
+ if (client->ops->recv(client, &msg) != IPC_OK) {
+ perror("Receive failure:");
+ FNRET(!hack_return_good);
+ }
+ if (msg == NULL) {
+ cl_log(LOG_WARNING, "No message this time");
+ continue;
+ }
+
+ lpc++;
+ buffer = (char*)msg->msg_body;
+ CRM_DEBUG("Processing xml from %s [text=%s]",
+ curr_client->table_key, buffer);
+
+ root_xml_node =
+ find_xml_in_ipcmessage(msg, FALSE);
+ if (root_xml_node != NULL) {
+
+ if (crmd_authorize_message(root_xml_node,
+ msg,
+ curr_client)) {
+ s_crmd_fsa(C_IPC_MESSAGE,
+ I_ROUTER,
+ root_xml_node);
+ }
+ } else {
+ cl_log(LOG_INFO,
+ "IPC Message was not valid... discarding.");
+ }
+ free_xml(root_xml_node);
+ msg->msg_done(msg);
+
+ msg = NULL;
+ buffer = NULL;
+ root_xml_node = NULL;
+ }
+
+ CRM_DEBUG("Processed %d messages", lpc);
+
+ if (client->ch_status == IPC_DISCONNECT)
+ {
+ cl_log(LOG_INFO,
+ "received HUP from %s",
+ curr_client->table_key);
+ if (curr_client != NULL) {
+ struct crm_subsystem_s *the_subsystem = NULL;
+
+ if (curr_client->sub_sys == NULL) {
+ cl_log(LOG_WARNING,
+ "Client hadn't registered with us yet");
+
+ } else if (strcmp(CRM_SYSTEM_PENGINE,
+ curr_client->sub_sys) == 0) {
+ the_subsystem = pe_subsystem;
+
+ } else if (strcmp(CRM_SYSTEM_TENGINE,
+ curr_client->sub_sys) == 0) {
+ the_subsystem = te_subsystem;
+
+ } else if (strcmp(CRM_SYSTEM_CIB,
+ curr_client->sub_sys) == 0){
+ the_subsystem = cib_subsystem;
+ }
+
+
+ if(the_subsystem != NULL) {
+ cleanup_subsystem(the_subsystem);
+ } // else that was a transient client
+
+ if (curr_client->table_key != NULL) {
+ /*
+ * Key is destroyed below:
+ * curr_client->table_key
+ * Value is cleaned up by:
+ * G_main_del_IPC_Channel
+ */
+ g_hash_table_remove(
+ ipc_clients, curr_client->table_key);
+ }
+
+
+ if(curr_client->client_source != NULL) {
+ gboolean det = G_main_del_IPC_Channel(
+ curr_client->client_source);
+
+ CRM_DEBUG("crm_client was %s detached",
+ det?"successfully":"not");
+ }
+
+ crm_free(curr_client->table_key);
+ crm_free(curr_client->sub_sys);
+ crm_free(curr_client->uuid);
+ crm_free(curr_client);
+ }
+ FNRET(!hack_return_good);
+ }
+
+ FNRET(hack_return_good);
+}
+
+
+void
+lrm_op_callback (lrm_op_t* op)
+{
+ s_crmd_fsa(C_LRM_OP_CALLBACK, I_LRM_EVENT, op);
+}
+
+void
+lrm_monitor_callback (lrm_mon_t* monitor)
+{
+ s_crmd_fsa(C_LRM_MONITOR_CALLBACK, I_LRM_EVENT, monitor);
+}
+
+void
+CrmdClientStatus(const char * node, const char * client,
+ const char * status, void * private)
+{
+ const char *join = NULL;
+ const char *extra = NULL;
+ xmlNodePtr update = NULL;
+ xmlNodePtr fragment = NULL;
+
+ if(safe_str_eq(status, JOINSTATUS)){
+ status = ONLINESTATUS;
+ extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
+
+ } else if(safe_str_eq(status, LEAVESTATUS)){
+ status = OFFLINESTATUS;
+ join = CRMD_JOINSTATE_DOWN;
+ extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
+ }
+
+ cl_log(LOG_NOTICE,
+ "Status update: Client %s/%s now has status [%s]\n",
+ node, client, status);
+
+ if(AM_I_DC) {
+ update = create_node_state(node, NULL, status, join);
+
+ if(extra != NULL) {
+ set_xml_property_copy(update, extra, XML_BOOLEAN_TRUE);
+ }
+
+ fragment = create_cib_fragment(update, NULL);
+ store_request(NULL, fragment,
+ CRM_OP_UPDATE, CRM_SYSTEM_DCIB);
+
+ free_xml(fragment);
+ free_xml(update);
+
+ s_crmd_fsa(C_CRMD_STATUS_CALLBACK, I_NULL, NULL);
+
+ } else {
+ cl_log(LOG_ERR, "Got client status callback in non-DC mode");
+ }
+}
+
+
+xmlNodePtr
+find_xml_in_hamessage(const struct ha_msg* msg)
+{
+ const char *xml;
+ xmlDocPtr doc;
+ xmlNodePtr root;
+
+ FNIN();
+ if (msg == NULL) {
+ cl_log(LOG_INFO,
+ "**** ha_crm_msg_callback called on a NULL message");
+ FNRET(NULL);
+ }
+
+#if 0
+ cl_log(LOG_DEBUG, "[F_TYPE=%s]", ha_msg_value(msg, F_TYPE));
+ cl_log(LOG_DEBUG, "[F_ORIG=%s]", ha_msg_value(msg, F_ORIG));
+ cl_log(LOG_DEBUG, "[F_TO=%s]", ha_msg_value(msg, F_TO));
+ cl_log(LOG_DEBUG, "[F_COMMENT=%s]", ha_msg_value(msg, F_COMMENT));
+ cl_log(LOG_DEBUG, "[F_XML=%s]", ha_msg_value(msg, "xml"));
+// cl_log(LOG_DEBUG, "[F_=%s]", ha_msg_value(ha_msg, F_));
+#endif
+
+ if (strcmp("CRM", ha_msg_value(msg, F_TYPE)) != 0) {
+ cl_log(LOG_INFO, "Received a (%s) message by mistake.",
+ ha_msg_value(msg, F_TYPE));
+ FNRET(NULL);
+ }
+ xml = ha_msg_value(msg, "xml");
+ if (xml == NULL) {
+ cl_log(LOG_INFO, "No XML attached to this message.");
+ FNRET(NULL);
+ }
+ doc = xmlParseMemory(xml, strlen(xml));
+ if (doc == NULL) {
+ cl_log(LOG_INFO, "XML Buffer was not valid.");
+ FNRET(NULL);
+ }
+
+ root = xmlDocGetRootElement(doc);
+ if (root == NULL) {
+ cl_log(LOG_INFO, "Root node was NULL.");
+ FNRET(NULL);
+ }
+ FNRET(root);
+}
diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c
index fa84d4f149..279a4c0d21 100644
--- a/crm/crmd/ccm.c
+++ b/crm/crmd/ccm.c
@@ -1,577 +1,577 @@
/*
* 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
*/
/* put these first so that uuid_t is defined without conflicts */
#include <portability.h>
#include <ocf/oc_event.h>
#include <ocf/oc_membership.h>
+#include <clplumbing/GSource.h>
+#include <string.h>
+
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/cib.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crmd_messages.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
-void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
-
-#include <clplumbing/GSource.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/xmlutils.h>
-#include <crmd_messages.h>
-#include <string.h>
#include <crm/dmalloc_wrapper.h>
+void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
+
int register_with_ccm(ll_cluster_t *hb_cluster);
void msg_ccm_join(const struct ha_msg *msg, void *foo);
void crmd_ccm_input_callback(oc_ed_t event,
void *cookie,
size_t size,
const void *data);
void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event);
gboolean ccm_dispatch(int fd, gpointer user_data);
gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data);
void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data);
#define CCM_EVENT_DETAIL 1
oc_ev_t *fsa_ev_token;
/* A_CCM_CONNECT */
enum crmd_fsa_input
do_ccm_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
int ret;
int fsa_ev_fd;
FNIN();
if(action & A_CCM_DISCONNECT){
oc_ev_unregister(fsa_ev_token);
}
if(action & A_CCM_CONNECT) {
cl_log(LOG_INFO, "Registering with CCM");
oc_ev_register(&fsa_ev_token);
cl_log(LOG_INFO, "Setting up CCM callbacks");
oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS,
crmd_ccm_input_callback,
NULL);
oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
cl_log(LOG_INFO, "Activating CCM token");
ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd);
if (ret){
cl_log(LOG_INFO, "CCM Activation failed... unregistering");
oc_ev_unregister(fsa_ev_token);
return(I_FAIL);
}
cl_log(LOG_INFO, "CCM Activation passed... all set to go!");
//GFDSource*
G_main_add_fd(G_PRIORITY_LOW, fsa_ev_fd, FALSE, ccm_dispatch,
fsa_ev_token,
default_ipc_input_destroy);
}
if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) {
cl_log(LOG_ERR, "Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
FNRET(I_NULL);
}
/* A_CCM_EVENT */
enum crmd_fsa_input
do_ccm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input return_input = I_NULL;
const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc;
oc_ed_t event = *((struct ccm_data *)data)->event;
FNIN();
cl_log(LOG_INFO,"event=%s",
event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP":
event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY":
event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED":
event==OC_EV_MS_EVICTED?"EVICTED":
"NO QUORUM MEMBERSHIP");
if(CCM_EVENT_DETAIL) {
ccm_event_detail(oc, event);
}
if (OC_EV_MS_EVICTED == event) {
/* get out... NOW! */
return_input = I_SHUTDOWN;
}
if(return_input == I_SHUTDOWN) {
; /* ignore everything, the new DC will handle it */
} else {
/* My understanding is that we will never get both
* node leaving *and* node joining callbacks at the
* same time.
*
* This logic would need to change if this is not
* the case
*/
if(oc->m_n_out !=0) {
return_input = I_NODE_LEFT;
} else if(oc->m_n_in !=0) {
/* delay the I_NODE_JOIN until they acknowledge our
* DC status and send us their CIB
*/
return_input = I_NULL;
} else {
cl_log(LOG_INFO,
"So why are we here? What CCM event happened?");
}
}
FNRET(return_input);
}
/* A_CCM_UPDATE_CACHE */
/*
* Take the opportunity to update the node status in the CIB as well
* (but only if we are the DC)
*/
enum crmd_fsa_input
do_ccm_update_cache(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input next_input = I_NULL;
int lpc, offset;
GHashTable *members = NULL;
oc_ed_t event = *((struct ccm_data *)data)->event;
const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc;
oc_node_list_t *tmp = NULL, *membership_copy = (oc_node_list_t *)
crm_malloc(sizeof(oc_node_list_t));
FNIN();
cl_log(LOG_INFO,"Updating CCM cache after a \"%s\" event.",
event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP":
event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY":
event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED":
event==OC_EV_MS_EVICTED?"EVICTED":
"NO QUORUM MEMBERSHIP");
/*--*-- All Member Nodes --*--*/
offset = oc->m_memb_idx;
membership_copy->members_size = oc->m_n_member;
if(membership_copy->members_size > 0) {
membership_copy->members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->members;
for(lpc=0; lpc < membership_copy->members_size; lpc++) {
oc_node_t *member = (oc_node_t *)
crm_malloc(sizeof(oc_node_t));
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->members = NULL;
}
/*--*-- New Member Nodes --*--*/
offset = oc->m_in_idx;
membership_copy->new_members_size = oc->m_n_in;
if(membership_copy->new_members_size > 0) {
membership_copy->new_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->new_members;
for(lpc=0; lpc < membership_copy->new_members_size; lpc++) {
oc_node_t *member = (oc_node_t *)
crm_malloc(sizeof(oc_node_t));
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->new_members = NULL;
}
/*--*-- Recently Dead Member Nodes --*--*/
offset = oc->m_out_idx;
membership_copy->dead_members_size = oc->m_n_out;
if(membership_copy->dead_members_size > 0) {
membership_copy->dead_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->dead_members;
for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) {
oc_node_t *member = (oc_node_t *)
crm_malloc(sizeof(oc_node_t));
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->dead_members = NULL;
}
tmp = fsa_membership_copy;
fsa_membership_copy = membership_copy;
if(AM_I_DC) {
// should be sufficient for only the DC to do this
free_xml(do_update_cib_nodes(NULL, FALSE));
}
/* Free the old copy */
if(tmp != NULL) {
if(tmp->members != NULL)
g_hash_table_foreach_remove(
tmp->members, ghash_node_clfree, NULL);
if(tmp->new_members != NULL)
g_hash_table_foreach_remove(
tmp->new_members, ghash_node_clfree, NULL);
if(tmp->dead_members != NULL)
g_hash_table_foreach_remove(
tmp->dead_members, ghash_node_clfree, NULL);
crm_free(tmp);
}
FNRET(next_input);
}
void
ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event)
{
int member_id = -1;
gboolean member = FALSE;
int lpc;
int node_list_size;
cl_log(LOG_INFO,"trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
cl_log(LOG_INFO, "NODES IN THE PRIMARY MEMBERSHIP");
node_list_size = oc->m_n_member;
for(lpc=0; lpc<node_list_size; lpc++) {
cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]",
oc->m_array[oc->m_memb_idx+lpc].node_uname,
oc->m_array[oc->m_memb_idx+lpc].node_id,
oc->m_array[oc->m_memb_idx+lpc].node_born_on);
CRM_DEBUG("%s ? %s", fsa_our_uname,
oc->m_array[oc->m_memb_idx+lpc].node_uname);
if(safe_str_eq(fsa_our_uname,
oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
member = TRUE;
member_id = oc->m_array[oc->m_memb_idx+lpc].node_id;
}
}
if (member == FALSE) {
cl_log(LOG_WARNING,
"MY NODE IS NOT IN CCM THE MEMBERSHIP LIST");
} else {
cl_log(LOG_INFO, "MY NODE ID IS %d", member_id);
}
cl_log(LOG_INFO, "NEW MEMBERS");
if (oc->m_n_in==0)
cl_log(LOG_INFO, "\tNONE");
for(lpc=0; lpc<oc->m_n_in; lpc++) {
cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]",
oc->m_array[oc->m_in_idx+lpc].node_uname,
oc->m_array[oc->m_in_idx+lpc].node_id,
oc->m_array[oc->m_in_idx+lpc].node_born_on);
}
cl_log(LOG_INFO, "MEMBERS LOST");
if (oc->m_n_out==0)
cl_log(LOG_INFO, "\tNONE");
for(lpc=0; lpc<oc->m_n_out; lpc++) {
cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]",
oc->m_array[oc->m_out_idx+lpc].node_uname,
oc->m_array[oc->m_out_idx+lpc].node_id,
oc->m_array[oc->m_out_idx+lpc].node_born_on);
if(fsa_our_uname != NULL
&& strcmp(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
cl_log(LOG_ERR,
"We're not part of the cluster anymore");
}
}
cl_log(LOG_INFO, "-----------------------");
}
int
register_with_ccm(ll_cluster_t *hb_cluster)
{
FNRET(0);
}
gboolean ccm_dispatch(int fd, gpointer user_data)
{
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
oc_ev_handle_event(ccm_token);
return TRUE;
}
void
crmd_ccm_input_callback(oc_ed_t event,
void *cookie,
size_t size,
const void *data)
{
struct ccm_data *event_data = NULL;
FNIN();
if(data != NULL) {
event_data = (struct ccm_data *)
crm_malloc(sizeof(struct ccm_data));
event_data->event = &event;
event_data->oc = (const oc_ev_membership_t *)data;
s_crmd_fsa(C_CCM_CALLBACK, I_CCM_EVENT, (void*)event_data);
event_data->event = NULL;
event_data->oc = NULL;
crm_free(event_data);
} else {
cl_log(LOG_INFO, "CCM Callback with NULL data... "
"I dont /think/ this is bad");
}
oc_ev_callback_done(cookie);
FNOUT();
}
void
msg_ccm_join(const struct ha_msg *msg, void *foo)
{
FNIN();
cl_log(LOG_INFO, "\n###### Recieved ccm_join message...");
if (msg != NULL)
{
cl_log(LOG_INFO,
"[type=%s]",
ha_msg_value(msg, F_TYPE));
cl_log(LOG_INFO,
"[orig=%s]",
ha_msg_value(msg, F_ORIG));
cl_log(LOG_INFO,
"[to=%s]",
ha_msg_value(msg, F_TO));
cl_log(LOG_INFO,
"[status=%s]",
ha_msg_value(msg, F_STATUS));
cl_log(LOG_INFO,
"[info=%s]",
ha_msg_value(msg, F_COMMENT));
cl_log(LOG_INFO,
"[rsc_hold=%s]",
ha_msg_value(msg, F_RESOURCES));
cl_log(LOG_INFO,
"[stable=%s]",
ha_msg_value(msg, F_ISSTABLE));
cl_log(LOG_INFO,
"[rtype=%s]",
ha_msg_value(msg, F_RTYPE));
cl_log(LOG_INFO,
"[ts=%s]",
ha_msg_value(msg, F_TIME));
cl_log(LOG_INFO,
"[seq=%s]",
ha_msg_value(msg, F_SEQ));
cl_log(LOG_INFO,
"[generation=%s]",
ha_msg_value(msg, F_HBGENERATION));
// cl_log(LOG_INFO, "[=%s]", ha_msg_value(msg, F_));
}
FNOUT();
}
struct update_data_s
{
xmlNodePtr updates;
const char *state;
const char *join;
};
xmlNodePtr
do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite)
{
struct update_data_s update_data;
update_data.updates = updates;
update_data.state = XML_BOOLEAN_NO;
update_data.join = CRMD_JOINSTATE_DOWN;
if(fsa_membership_copy->dead_members != NULL) {
g_hash_table_foreach(fsa_membership_copy->dead_members,
ghash_update_cib_node, &update_data);
}
update_data.state = XML_BOOLEAN_YES;
update_data.join = NULL;
if(overwrite) {
update_data.join = CRMD_JOINSTATE_PENDING;
}
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->members,
ghash_update_cib_node, &update_data);
}
/* this is most likely overkill...
*
* make *sure* that the join status of nodes entering the ccm list
* is reset
*
update_data.join = CRMD_JOINSTATE_PENDING;
if(fsa_membership_copy->new_members != NULL) {
g_hash_table_foreach(fsa_membership_copy->new_members,
ghash_update_cib_node, &update_data);
}
*/
if(update_data.updates != NULL) {
xmlNodePtr fragment =
create_cib_fragment(update_data.updates, NULL);
store_request(NULL, fragment,
CRM_OP_UPDATE, CRM_SYSTEM_DCIB);
free_xml(fragment);
}
return update_data.updates;
}
void
ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
{
xmlNodePtr tmp1 = NULL;
const char *node_uname = (const char*)key;
struct update_data_s* data = (struct update_data_s*)user_data;
const char *state = data->join;
crm_debug("%s processing %s (%s)",
__FUNCTION__, node_uname, data->state);
if(state != NULL
&& safe_str_eq(fsa_our_uname, node_uname)) {
/* the DC is always a member */
state = CRMD_JOINSTATE_MEMBER;
}
tmp1 = create_node_state(node_uname, data->state, NULL, state);
if(data->updates == NULL) {
crm_debug("Creating first update");
data->updates = tmp1;
} else {
xmlAddNextSibling(data->updates, tmp1);
}
}
gboolean
ghash_node_clfree(gpointer key, gpointer value, gpointer user_data)
{
// value->node_uname is free'd as "key"
if(key != NULL) {
crm_free(key);
}
if(value != NULL) {
crm_free(value);
}
return TRUE;
}
diff --git a/crm/crmd/control.c b/crm/crmd/control.c
index bec444e709..03c1adfe11 100644
--- a/crm/crmd/control.c
+++ b/crm/crmd/control.c
@@ -1,415 +1,553 @@
/*
* 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 <portability.h>
+
#include <crm/crm.h>
+#include <crm/common/ctrl.h>
+
+#include <crmd.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
-#include <crmd.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/crmutils.h>
#include <crmd_messages.h>
+#include <crmd_callbacks.h>
-#include <clplumbing/Gmain_timeout.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <crm/dmalloc_wrapper.h>
#define PID_FILE WORKING_DIR"/crm.pid"
#define DAEMON_LOG LOG_DIR"/crm.log"
#define DAEMON_DEBUG LOG_DIR"/crm.debug"
gboolean crmd_ha_input_dispatch(int fd, gpointer user_data);
+
void crmd_ha_input_destroy(gpointer user_data);
+
void crm_shutdown(int nsig);
+IPC_WaitConnection *wait_channel_init(char daemonsocket[]);
+
+int init_server_ipc_comms(
+ const char *child,
+ gboolean (*channel_client_connect)(IPC_Channel *newclient,
+ gpointer user_data),
+ void (*channel_input_destroy)(gpointer user_data));
+
+
+gboolean
+register_with_ha(ll_cluster_t *hb_cluster, const char *client_name,
+ gboolean (*dispatch_method)(int fd, gpointer user_data),
+ void (*message_callback)(const struct ha_msg* msg,
+ void* private_data),
+ GDestroyNotify cleanup_method);
+
GHashTable *ipc_clients = NULL;
/* A_HA_CONNECT */
enum crmd_fsa_input
do_ha_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
gboolean registered = FALSE;
FNIN();
if(action & A_HA_DISCONNECT) {
if(fsa_cluster_conn != NULL) {
fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn);
}
}
if(action & A_HA_CONNECT) {
if(fsa_cluster_conn == NULL)
fsa_cluster_conn = ll_cluster_new("heartbeat");
// make sure we are disconnected first
fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn);
registered = register_with_ha(fsa_cluster_conn,
crm_system_name,
crmd_ha_input_dispatch,
crmd_ha_input_callback,
crmd_ha_input_destroy);
if(registered == FALSE) {
FNRET(I_FAIL);
}
}
if(action & ~(A_HA_CONNECT|A_HA_DISCONNECT)) {
cl_log(LOG_ERR, "Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
FNRET(I_NULL);
}
/* A_SHUTDOWN */
enum crmd_fsa_input
do_shutdown(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input next_input = I_NULL;
enum crmd_fsa_input tmp = I_NULL;
FNIN();
/* last attempt to shut these down */
if(is_set(fsa_input_register, R_PE_CONNECTED)) {
cl_log(LOG_WARNING,
"Last attempt to shutdown the PolicyEngine");
tmp = do_pe_control(A_PE_STOP, cause, cur_state,
current_input, data);
if(tmp != I_NULL) {
next_input = I_ERROR;
cl_log(LOG_ERR, "Failed to shutdown the PolicyEngine");
}
}
if(is_set(fsa_input_register, R_TE_CONNECTED)) {
cl_log(LOG_WARNING,
"Last attempt to shutdown the Transitioner");
tmp = do_pe_control(A_TE_STOP, cause, cur_state,
current_input, data);
if(tmp != I_NULL) {
next_input = I_ERROR;
cl_log(LOG_ERR, "Failed to shutdown the Transitioner");
}
}
/* TODO: shutdown all remaining resources? */
FNRET(next_input);
}
/* A_SHUTDOWN_REQ */
enum crmd_fsa_input
do_shutdown_req(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input next_input = I_NULL;
FNIN();
if(send_request(NULL, NULL, CRM_OP_SHUTDOWN_REQ,
NULL, CRM_SYSTEM_DC, NULL) == FALSE){
next_input = I_ERROR;
}
FNRET(next_input);
}
gboolean
crmd_ha_input_dispatch(int fd, gpointer user_data)
{
int lpc = 0;
ll_cluster_t* hb_cluster = (ll_cluster_t*)user_data;
FNIN();
while(hb_cluster->llc_ops->msgready(hb_cluster))
{
lpc++;
// invoke the callbacks but dont block
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
if(lpc == 0){
// hey what happened??
cl_log(LOG_ERR, "We were called but no message was ready.\n"
"\tLikely the connection to Heartbeat failed, check the logs");
// TODO: feed this back into the FSA
FNRET(FALSE);
}
FNRET(TRUE);
}
void
crmd_ha_input_destroy(gpointer user_data)
{
cl_log(LOG_INFO, "in my hb_input_destroy");
}
/* A_EXIT_0, A_EXIT_1 */
enum crmd_fsa_input
do_exit(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action);
if(action & A_EXIT_0) {
g_main_quit(crmd_mainloop);
} else {
exit(1);
}
FNRET(I_NULL);
}
/* A_STARTUP */
enum crmd_fsa_input
do_startup(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
int facility;
int was_error = 0;
int interval = 1; // seconds between DC heartbeats
FNIN();
fsa_input_register = 0; // zero out the regester
cl_log(LOG_INFO, "Register PID");
register_pid(PID_FILE, FALSE, crm_shutdown);
cl_log_set_logfile(DAEMON_LOG);
/* if (crm_debug()) { */
cl_log_set_debugfile(DAEMON_DEBUG);
/* cl_log_enable_stderr(FALSE);
} */
ipc_clients = g_hash_table_new(&g_str_hash, &g_str_equal);
/* change the logging facility to the one used by heartbeat daemon */
fsa_cluster_conn = ll_cluster_new("heartbeat");
cl_log(LOG_INFO, "Switching to Heartbeat logger");
if ((facility =
fsa_cluster_conn->llc_ops->get_logfacility(
fsa_cluster_conn)) > 0) {
cl_log_set_facility(facility);
}
CRM_DEBUG("Facility: %d", facility);
if(was_error == 0) {
cl_log(LOG_INFO, "Init server comms");
was_error = init_server_ipc_comms(CRM_SYSTEM_CRMD,
crmd_client_connect,
default_ipc_input_destroy);
}
if (was_error == 0) {
fsa_our_uname = fsa_cluster_conn->llc_ops->get_mynodeid(
fsa_cluster_conn);
if (fsa_our_uname == NULL) {
cl_log(LOG_ERR, "get_mynodeid() failed");
was_error = 1;
}
cl_log(LOG_INFO, "FSA Hostname: %s", fsa_our_uname);
}
/* set up the timers */
dc_heartbeat = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t));
integration_timer= (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t));
election_trigger = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t));
election_timeout = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t));
shutdown_escalation_timmer = (fsa_timer_t *)
crm_malloc(sizeof(fsa_timer_t));
interval = interval * 1000;
election_trigger->source_id = -1;
election_trigger->period_ms = interval*4;
election_trigger->fsa_input = I_DC_TIMEOUT;
election_trigger->callback = timer_popped;
dc_heartbeat->source_id = -1;
dc_heartbeat->period_ms = interval;
dc_heartbeat->fsa_input = I_NULL;
dc_heartbeat->callback = do_dc_heartbeat;
election_timeout->source_id = -1;
election_timeout->period_ms = interval*6;
election_timeout->fsa_input = I_ELECTION_DC;
election_timeout->callback = timer_popped;
integration_timer->source_id = -1;
integration_timer->period_ms = interval*6;
integration_timer->fsa_input = I_INTEGRATION_TIMEOUT;
integration_timer->callback = timer_popped;
shutdown_escalation_timmer->source_id = -1;
shutdown_escalation_timmer->period_ms = interval*130;
shutdown_escalation_timmer->fsa_input = I_TERMINATE;
shutdown_escalation_timmer->callback = timer_popped;
/* set up the sub systems */
cib_subsystem = (struct crm_subsystem_s*)
crm_malloc(sizeof(struct crm_subsystem_s));
cib_subsystem->pid = 0;
cib_subsystem->respawn = 1;
cib_subsystem->path = crm_strdup(BIN_DIR);
cib_subsystem->name = crm_strdup(CRM_SYSTEM_CIB);
cib_subsystem->command = BIN_DIR"/cib";
cib_subsystem->flag = R_CIB_CONNECTED;
te_subsystem = (struct crm_subsystem_s*)
crm_malloc(sizeof(struct crm_subsystem_s));
te_subsystem->pid = 0;
te_subsystem->respawn = 1;
te_subsystem->path = crm_strdup(BIN_DIR);
te_subsystem->name = crm_strdup(CRM_SYSTEM_TENGINE);
te_subsystem->command = BIN_DIR"/tengine";
te_subsystem->flag = R_TE_CONNECTED;
pe_subsystem = (struct crm_subsystem_s*)
crm_malloc(sizeof(struct crm_subsystem_s));
pe_subsystem->pid = 0;
pe_subsystem->respawn = 1;
pe_subsystem->path = crm_strdup(BIN_DIR);
pe_subsystem->name = crm_strdup(CRM_SYSTEM_PENGINE);
pe_subsystem->command = BIN_DIR"/pengine";
pe_subsystem->flag = R_PE_CONNECTED;
if(was_error)
FNRET(I_FAIL);
FNRET(I_NULL);
}
/* A_STOP */
enum crmd_fsa_input
do_stop(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n",
fsa_action2string(action), action);
FNRET(I_NULL);
}
/* A_STARTED */
enum crmd_fsa_input
do_started(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
clear_bit_inplace(&fsa_input_register, R_STARTING);
FNRET(I_NULL);
}
/* A_RECOVER */
enum crmd_fsa_input
do_recover(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n",
fsa_action2string(action), action);
FNRET(I_SHUTDOWN);
}
void
crm_shutdown(int nsig)
{
FNIN();
CL_SIGNAL(nsig, crm_shutdown);
if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) {
if(is_set(fsa_input_register, R_SHUTDOWN)) {
cl_log(LOG_WARNING, "Escalating the shutdown");
s_crmd_fsa(C_SHUTDOWN, I_ERROR, NULL);
} else {
set_bit_inplace(&fsa_input_register, R_SHUTDOWN);
// cant rely on this...
startTimer(shutdown_escalation_timmer);
s_crmd_fsa(C_SHUTDOWN, I_SHUTDOWN, NULL);
}
} else {
cl_log(LOG_INFO, "exit from shutdown");
exit(LSB_EXIT_OK);
}
FNOUT();
}
+
+
+IPC_WaitConnection *
+wait_channel_init(char daemonsocket[])
+{
+ IPC_WaitConnection *wait_ch;
+ mode_t mask;
+ char path[] = IPC_PATH_ATTR;
+ GHashTable * attrs;
+
+ FNIN();
+ attrs = g_hash_table_new(g_str_hash,g_str_equal);
+ g_hash_table_insert(attrs, path, daemonsocket);
+
+ mask = umask(0);
+ wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs);
+ if (wait_ch == NULL) {
+ cl_perror("Can't create wait channel of type %s",
+ IPC_ANYTYPE);
+ exit(1);
+ }
+ mask = umask(mask);
+
+ g_hash_table_destroy(attrs);
+
+ FNRET(wait_ch);
+}
+
+int
+init_server_ipc_comms(
+ const char *child,
+ gboolean (*channel_client_connect)(IPC_Channel *newclient,
+ gpointer user_data),
+ void (*channel_input_destroy)(gpointer user_data))
+{
+ /* the clients wait channel is the other source of events.
+ * This source delivers the clients connection events.
+ * listen to this source at a relatively lower priority.
+ */
+
+ char commpath[SOCKET_LEN];
+ IPC_WaitConnection *wait_ch;
+
+ FNIN();
+ sprintf(commpath, WORKING_DIR "/%s", child);
+
+ wait_ch = wait_channel_init(commpath);
+
+ if (wait_ch == NULL) FNRET(1);
+ G_main_add_IPC_WaitConnection(G_PRIORITY_LOW,
+ wait_ch,
+ NULL,
+ FALSE,
+ channel_client_connect,
+ wait_ch, // user data passed to ??
+ channel_input_destroy);
+
+ cl_log(LOG_DEBUG, "Listening on: %s", commpath);
+
+ FNRET(0);
+}
+
+gboolean
+register_with_ha(ll_cluster_t *hb_cluster, const char *client_name,
+ gboolean (*dispatch_method)(int fd, gpointer user_data),
+ void (*message_callback)(const struct ha_msg* msg,
+ void* private_data),
+ GDestroyNotify cleanup_method)
+{
+ const char* ournode = NULL;
+
+ cl_log(LOG_INFO, "Signing in with Heartbeat");
+ if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) {
+ cl_log(LOG_ERR, "Cannot sign on with heartbeat");
+ cl_log(LOG_ERR,
+ "REASON: %s",
+ hb_cluster->llc_ops->errmsg(hb_cluster));
+ return FALSE;
+ }
+
+ cl_log(LOG_DEBUG, "Finding our node name");
+ if ((ournode =
+ hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) {
+ cl_log(LOG_ERR, "get_mynodeid() failed");
+ return FALSE;
+ }
+ cl_log(LOG_INFO, "hostname: %s", ournode);
+
+ cl_log(LOG_DEBUG, "Be informed of CRM messages");
+ if (hb_cluster->llc_ops->set_msg_callback(hb_cluster,
+ "CRM",
+ message_callback,
+ hb_cluster)
+ !=HA_OK){
+ cl_log(LOG_ERR, "Cannot set CRM message callback");
+ cl_log(LOG_ERR,
+ "REASON: %s",
+ hb_cluster->llc_ops->errmsg(hb_cluster));
+ return FALSE;
+ }
+
+
+ G_main_add_fd(G_PRIORITY_HIGH,
+ hb_cluster->llc_ops->inputfd(hb_cluster),
+ FALSE,
+ dispatch_method,
+ hb_cluster, // usrdata
+ cleanup_method);
+
+ /* it seems we need to poke the message receiving stuff in order for it to
+ * start seeing messages. Its like it gets blocked or something.
+ */
+ dispatch_method(0, hb_cluster);
+
+ return TRUE;
+
+}
diff --git a/crm/crmd/crmd.h b/crm/crmd/crmd.h
index 6f98d2a177..eaf8cc8b20 100644
--- a/crm/crmd/crmd.h
+++ b/crm/crmd/crmd.h
@@ -1,35 +1,44 @@
-/* $Id: crmd.h,v 1.5 2004/02/27 13:41:45 andrew Exp $ */
+/* $Id: crmd.h,v 1.6 2004/06/02 12:31:34 andrew Exp $ */
/*
* 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 CRMD__H
#define CRMD__H
-extern GMainLoop* crmd_mainloop;
+#include <ha_msg.h>
-extern const char* crm_system_name;
+extern GMainLoop *crmd_mainloop;
-extern GHashTable *pending_remote_replies;
-extern GHashTable *ipc_clients;
+extern const char *crm_system_name;
+
+extern GHashTable *ipc_clients;
+
+extern GHashTable *pending_remote_replies;
extern void msg_ccm_join(const struct ha_msg *msg, void *foo);
-extern gboolean crmd_client_connect(IPC_Channel *newclient, gpointer user_data);
-extern void crmd_ha_input_callback(const struct ha_msg* msg, void* private_data);
-extern gboolean crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data);
+
+extern gboolean crmd_client_connect(IPC_Channel *newclient,
+ gpointer user_data);
+
+extern void crmd_ha_input_callback(const struct ha_msg* msg,
+ void* private_data);
+
+extern gboolean crmd_ipc_input_callback(IPC_Channel *client,
+ gpointer user_data);
#endif
diff --git a/crm/crmd/crmd.h b/crm/crmd/crmd_callbacks.h
similarity index 57%
copy from crm/crmd/crmd.h
copy to crm/crmd/crmd_callbacks.h
index 6f98d2a177..f9f80aec80 100644
--- a/crm/crmd/crmd.h
+++ b/crm/crmd/crmd_callbacks.h
@@ -1,35 +1,38 @@
-/* $Id: crmd.h,v 1.5 2004/02/27 13:41:45 andrew Exp $ */
/*
* 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 CRMD__H
-#define CRMD__H
-extern GMainLoop* crmd_mainloop;
+#include <hb_api.h>
+#include <clplumbing/ipc.h>
-extern const char* crm_system_name;
-extern GHashTable *pending_remote_replies;
-extern GHashTable *ipc_clients;
+extern void crmd_ha_input_callback(const struct ha_msg* msg,
+ void* private_data);
-extern void msg_ccm_join(const struct ha_msg *msg, void *foo);
-extern gboolean crmd_client_connect(IPC_Channel *newclient, gpointer user_data);
-extern void crmd_ha_input_callback(const struct ha_msg* msg, void* private_data);
-extern gboolean crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data);
-
+/*
+ * Apparently returning TRUE means "stay connected, keep doing stuff".
+ * Returning FALSE means "we're all done, close the connection"
+ */
+extern gboolean crmd_ipc_input_callback(IPC_Channel *client,
+ gpointer user_data);
+
+extern void lrm_op_callback (lrm_op_t* op);
+
+extern void lrm_monitor_callback (lrm_mon_t* monitor);
-#endif
+extern void CrmdClientStatus(const char * node, const char * client,
+ const char * status, void * private);
diff --git a/crm/crmd/crmd_messages.h b/crm/crmd/crmd_messages.h
index dddfa990a6..37eca91fd9 100644
--- a/crm/crmd/crmd_messages.h
+++ b/crm/crmd/crmd_messages.h
@@ -1,82 +1,86 @@
/*
* 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 XML_CRM_MESSAGES__H
#define XML_CRM_MESSAGES__H
#include <crm/crm.h>
-#include <crm/common/ipcutils.h>
+#include <crm/common/ipc.h>
#include <crmd_fsa.h>
#include <libxml/tree.h>
typedef GSList *fsa_message_queue_t;
fsa_message_queue_t put_message(xmlNodePtr new_message);
xmlNodePtr get_message(void);
gboolean is_message(void);
extern gboolean relay_message(xmlNodePtr xml_relay_message,
gboolean originated_locally);
extern void crmd_ha_input_callback(const struct ha_msg* msg,
void* private_data);
extern gboolean crmd_ipc_input_callback(IPC_Channel *client,
gpointer user_data);
extern void process_message(xmlNodePtr root_xml_node,
gboolean originated_locally,
const char *src_node_name);
extern gboolean crm_dc_process_message(xmlNodePtr whole_message,
xmlNodePtr action,
const char *host_from,
const char *sys_from,
const char *sys_to,
const char *op,
gboolean dc_mode);
extern void send_msg_via_ha(xmlNodePtr action, const char *dest_node);
extern void send_msg_via_ipc(xmlNodePtr action, const char *sys);
extern gboolean add_pending_outgoing_reply(const char *originating_node_name,
const char *crm_msg_reference,
const char *sys_to,
const char *sys_from);
extern gboolean crmd_authorize_message(xmlNodePtr root_xml_node,
IPC_Message *client_msg,
crmd_client_t *curr_client);
extern gboolean send_request(xmlNodePtr msg_options,
xmlNodePtr msg_data,
const char *operation,
const char *host_to,
const char *sys_to,
char **msg_reference);
extern gboolean store_request(xmlNodePtr msg_options,
xmlNodePtr msg_data,
const char *operation,
const char *sys_to);
extern enum crmd_fsa_input handle_message(xmlNodePtr stored_msg);
+extern gboolean send_ha_reply(ll_cluster_t *hb_cluster,
+ xmlNodePtr xml_request,
+ xmlNodePtr xml_response_data);
+
extern void lrm_op_callback (lrm_op_t* op);
extern void lrm_monitor_callback (lrm_mon_t* monitor);
#endif
diff --git a/crm/crmd/crmdmain.c b/crm/crmd/crmdmain.c
index adddd34bb6..9cdf802048 100644
--- a/crm/crmd/crmdmain.c
+++ b/crm/crmd/crmdmain.c
@@ -1,209 +1,204 @@
-/* $Id: crmdmain.c,v 1.17 2004/06/01 16:12:49 andrew Exp $ */
+/* $Id: crmdmain.c,v 1.18 2004/06/02 12:31:34 andrew Exp $ */
/*
* 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 <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
-#include <hb_api.h>
#include <apphb.h>
-#include <crm/crm.h>
-
#include <clplumbing/ipc.h>
#include <clplumbing/Gmain_timeout.h>
#include <clplumbing/cl_log.h>
#include <clplumbing/cl_signal.h>
#include <clplumbing/lsb_exitcodes.h>
#include <clplumbing/uids.h>
#include <clplumbing/realtime.h>
#include <clplumbing/GSource.h>
#include <clplumbing/cl_poll.h>
-#include <libxml/tree.h>
-
-const char* crm_system_name = CRM_SYSTEM_CRMD;
-
-#include <crm/common/crmutils.h>
-#include <crm/common/ipcutils.h>
+#include <crm/crm.h>
+#include <crm/common/ctrl.h>
+#include <crm/common/ipc.h>
+#include <crm/common/xml.h>
#include <crmd.h>
-
#include <crmd_fsa.h>
#include <crm/dmalloc_wrapper.h>
+const char* crm_system_name = CRM_SYSTEM_CRMD;
#define PID_FILE WORKING_DIR"/crm.pid"
#define OPTARGS "skrh"
void usage(const char* cmd, int exit_status);
int init_start(void);
void crmd_hamsg_callback(const struct ha_msg* msg, void* private_data);
gboolean crmd_tickle_apphb(gpointer data);
GMainLoop* crmd_mainloop = NULL;
gboolean crm_debug_state = TRUE;
int
main(int argc, char ** argv)
{
int req_restart = FALSE;
int req_status = FALSE;
int req_stop = FALSE;
int argerr = 0;
int flag;
cl_log_set_entity(crm_system_name);
cl_log_enable_stderr(TRUE);
cl_log_set_facility(LOG_USER);
while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
switch(flag) {
case 's': /* Status */
req_status = TRUE;
break;
case 'k': /* Stop (kill) */
req_stop = TRUE;
break;
case 'r': /* Restart */
req_restart = TRUE;
break;
case 'h': /* Help message */
usage(crm_system_name, LSB_EXIT_OK);
break;
default:
++argerr;
break;
}
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name,LSB_EXIT_GENERIC);
}
// read local config file
if (req_status){
FNRET(init_status(PID_FILE, crm_system_name));
}
if (req_stop){
FNRET(init_stop(PID_FILE));
}
if (req_restart) {
init_stop(PID_FILE);
}
FNRET(init_start());
}
int
init_start(void)
{
long pid;
enum crmd_fsa_state state;
if ((pid = get_running_pid(PID_FILE, NULL)) > 0) {
cl_log(LOG_CRIT, "already running: [pid %ld].", pid);
exit(LSB_EXIT_OK);
}
fsa_state = S_PENDING;
state = s_crmd_fsa(C_STARTUP, I_STARTUP, NULL);
if (state == S_PENDING) {
/* Create the mainloop and run it... */
crmd_mainloop = g_main_new(FALSE);
cl_log(LOG_INFO, "Starting %s", crm_system_name);
#ifdef REALTIME_SUPPORT
static int crm_realtime = 1;
if (crm_realtime == 1){
cl_enable_realtime();
}else if (crm_realtime == 0){
cl_disable_realtime();
}
cl_make_realtime(SCHED_RR, 5, 64, 64);
#endif
g_main_run(crmd_mainloop);
return_to_orig_privs();
} else {
cl_log(LOG_ERR, "Startup of CRMd failed. Current state: %s",
fsa_state2string(state));
}
if (unlink(PID_FILE) == 0) {
cl_log(LOG_INFO, "[%s] stopped", crm_system_name);
}
FNRET(state != S_PENDING);
}
void
usage(const char* cmd, int exit_status)
{
FILE* stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-srkh]"
"[-c configure file]\n", cmd);
/* fprintf(stream, "\t-d\tsets debug level\n"); */
/* fprintf(stream, "\t-s\tgets daemon status\n"); */
/* fprintf(stream, "\t-r\trestarts daemon\n"); */
/* fprintf(stream, "\t-k\tstops daemon\n"); */
/* fprintf(stream, "\t-h\thelp message\n"); */
fflush(stream);
exit(exit_status);
}
gboolean
crmd_tickle_apphb(gpointer data)
{
char app_instance[APPNAME_LEN];
int rc = 0;
sprintf(app_instance, "%s_%ld", crm_system_name, (long)getpid());
rc = apphb_hb();
if (rc < 0) {
cl_perror("%s apphb_hb failure", app_instance);
exit(3);
}
return TRUE;
}
diff --git a/crm/crmd/election.c b/crm/crmd/election.c
index 9f498069e9..72231f2772 100644
--- a/crm/crmd/election.c
+++ b/crm/crmd/election.c
@@ -1,389 +1,385 @@
/*
* 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 <portability.h>
-#include <crm/crm.h>
-#include <crmd_fsa.h>
-#include <libxml/tree.h>
-#include <crm/msg_xml.h>
-#include <crm/common/xmlutils.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/msgutils.h>
+#include <heartbeat.h>
+
#include <crm/cib.h>
-#include <string.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/crm.h>
+#include <crmd_fsa.h>
#include <crmd_messages.h>
-#include <heartbeat.h>
-
#include <crm/dmalloc_wrapper.h>
void ghash_count_vote(gpointer key, gpointer value, gpointer user_data);
/* A_ELECTION_VOTE */
enum crmd_fsa_input
do_election_vote(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input election_result = I_NULL;
FNIN();
/* dont vote if we're in one of these states or wanting to shut down */
switch(cur_state) {
case S_RECOVERY:
case S_RECOVERY_DC:
case S_STOPPING:
case S_RELEASE_DC:
case S_TERMINATE:
FNRET(I_NULL);
// log warning
break;
default:
if(is_set(fsa_input_register, R_SHUTDOWN)) {
FNRET(I_NULL);
// log warning
}
break;
}
send_request(NULL, NULL, CRM_OP_VOTE,
NULL, CRM_SYSTEM_CRMD, NULL);
FNRET(election_result);
}
gboolean
do_dc_heartbeat(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
// cl_log(LOG_DEBUG, "#!!#!!# Heartbeat timer just popped!");
gboolean was_sent = send_request(NULL, NULL, CRM_OP_HBEAT,
NULL, CRM_SYSTEM_CRMD, NULL);
if(was_sent == FALSE) {
// this is bad
stopTimer(timer); // dont make it go off again
s_crmd_fsa(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL);
}
return TRUE;
}
struct election_data_s
{
const char *winning_uname;
unsigned int winning_bornon;
};
/* A_ELECTION_COUNT */
enum crmd_fsa_input
do_election_count_vote(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
gboolean we_loose = FALSE;
xmlNodePtr vote = (xmlNodePtr)data;
enum crmd_fsa_input election_result = I_NULL;
const char *vote_from = xmlGetProp(vote, XML_ATTR_HOSTFROM);
FNIN();
if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) {
// dont count our own vote
FNRET(election_result);
}
if(fsa_membership_copy->members_size < 1) {
// if even we are not in the cluster then we should not vote
FNRET(I_FAIL);
}
oc_node_t *our_node = (oc_node_t*)
g_hash_table_lookup(fsa_membership_copy->members, fsa_our_uname);
oc_node_t *your_node = (oc_node_t*)
g_hash_table_lookup(fsa_membership_copy->members, vote_from);
#if 0
cl_log(LOG_DEBUG, "%s (bornon=%d), our bornon (%d)",
vote_from, our_node->born, my_born);
cl_log(LOG_DEBUG, "%s %s %s",
fsa_our_uname,
strcmp(fsa_our_uname, vote_from) < 0?"<":">=",
vote_from);
#endif
if(is_set(fsa_input_register, R_SHUTDOWN)) {
cl_log(LOG_DEBUG,
"Election fail: we are shutting down");
we_loose = TRUE;
} else if(our_node == NULL) {
cl_log(LOG_DEBUG,
"Election fail: we dont exist in the CCM list");
we_loose = TRUE;
} else if(your_node == NULL) {
cl_log(LOG_ERR, "The other side doesnt exist in the CCM list");
} else if(your_node->node_born_on < our_node->node_born_on) {
cl_log(LOG_DEBUG, "Election fail: born_on");
we_loose = TRUE;
} else if(your_node->node_born_on == our_node->node_born_on
&& strcmp(fsa_our_uname, vote_from) > 0) {
cl_log(LOG_DEBUG, "Election fail: uname");
we_loose = TRUE;
} else {
struct election_data_s election_data;
election_data.winning_uname = NULL;
election_data.winning_bornon = -1; // maximum integer
CRM_NOTE("We might win... we should vote (possibly again)");
election_result = I_DC_TIMEOUT; // new "default"
g_hash_table_foreach(fsa_membership_copy->members,
ghash_count_vote, &election_data);
cl_log(LOG_DEBUG, "Election winner should be %s (born_on=%d)",
election_data.winning_uname, election_data.winning_bornon);
if(safe_str_eq(election_data.winning_uname, fsa_our_uname)){
cl_log(LOG_DEBUG, "Election win: lowest born_on and uname");
election_result = I_ELECTION_DC;
}
}
if(we_loose) {
if(fsa_input_register & R_THE_DC) {
cl_log(LOG_DEBUG, "Give up the DC");
election_result = I_RELEASE_DC;
} else {
cl_log(LOG_DEBUG, "We werent the DC anyway");
election_result = I_NOT_DC;
}
}
if(we_loose || election_result == I_ELECTION_DC) {
// cancel timer, its been decided
stopTimer(election_timeout);
}
FNRET(election_result);
}
/* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */
// we won
enum crmd_fsa_input
do_election_timer_ctrl(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
if(action & A_ELECT_TIMER_START) {
startTimer(election_timeout);
} else if(action & A_ELECT_TIMER_STOP || action & A_ELECTION_TIMEOUT) {
stopTimer(election_timeout);
} else {
cl_log(LOG_ERR, "unexpected action %s",
fsa_action2string(action));
}
if(action & A_ELECTION_TIMEOUT) {
CRM_NOTE("The election timer went off, we win!");
FNRET(I_ELECTION_DC);
}
FNRET(I_NULL);
}
/* A_DC_TIMER_STOP, A_DC_TIMER_START */
enum crmd_fsa_input
do_dc_timer_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
gboolean timer_op_ok = TRUE;
FNIN();
if(action & A_DC_TIMER_STOP) {
timer_op_ok = stopTimer(election_trigger);
}
/* dont start a timer that wasnt already running */
if(action & A_DC_TIMER_START && timer_op_ok) {
startTimer(election_trigger);
}
FNRET(I_NULL);
}
/* A_DC_TAKEOVER */
enum crmd_fsa_input
do_dc_takeover(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr update = NULL, fragment = NULL;
FNIN();
CRM_NOTE("################## Taking over the DC ##################");
set_bit_inplace(&fsa_input_register, R_THE_DC);
CRM_DEBUG("Am I the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO);
fsa_our_dc = NULL;
set_bit_inplace(&fsa_input_register, R_JOIN_OK);
set_bit_inplace(&fsa_input_register, R_INVOKE_PE);
clear_bit_inplace(&fsa_input_register, R_CIB_DONE);
clear_bit_inplace(&fsa_input_register, R_HAVE_CIB);
startTimer(dc_heartbeat);
if (fsa_cluster_conn->llc_ops->set_cstatus_callback(
fsa_cluster_conn, CrmdClientStatus, NULL)!=HA_OK){
cl_log(LOG_ERR, "Cannot set client status callback\n");
cl_log(LOG_ERR, "REASON: %s\n",
fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn));
}
/* store our state in the CIB (since some fields will not be
* filled in because the DC doesnt go through the join process
* with itself
*
* bypass the TE for now, it will be informed in good time
*/
update = create_node_state(
fsa_our_uname, NULL, ONLINESTATUS, CRMD_JOINSTATE_MEMBER);
set_xml_property_copy(
update,XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE);
fragment = create_cib_fragment(update, NULL);
store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DCIB);
free_xml(update);
free_xml(fragment);
/* Async get client status information in the cluster */
fsa_cluster_conn->llc_ops->client_status(
fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1);
FNRET(I_NULL);
}
/* A_DC_RELEASE */
enum crmd_fsa_input
do_dc_release(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
FNIN();
CRM_NOTE("################## Releasing the DC ##################");
stopTimer(dc_heartbeat);
if (fsa_cluster_conn->llc_ops->set_cstatus_callback(
fsa_cluster_conn, NULL, NULL)!=HA_OK){
cl_log(LOG_ERR, "Cannot unset client status callback\n");
cl_log(LOG_ERR, "REASON: %s\n",
fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn));
result = I_ERROR;
}
if(action & A_DC_RELEASE) {
clear_bit_inplace(&fsa_input_register, R_THE_DC);
/* get a new CIB from the new DC */
clear_bit_inplace(&fsa_input_register, R_HAVE_CIB);
} else if (action & A_DC_RELEASED) {
if(cur_state == S_STOPPING) {
result = I_SHUTDOWN; // necessary?
result = I_RELEASE_SUCCESS;
}
#if 0
else if( are there errors ) {
// we cant stay up if not healthy
// or perhaps I_ERROR and go to S_RECOVER?
result = I_SHUTDOWN;
}
#endif
else
result = I_RELEASE_SUCCESS;
} else {
cl_log(LOG_ERR, "Warning, do_dc_release invoked for action %s",
fsa_action2string(action));
}
CRM_DEBUG("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO);
FNRET(result);
}
void
ghash_count_vote(gpointer key, gpointer value, gpointer user_data)
{
struct election_data_s *election_data =
(struct election_data_s *)user_data;
oc_node_t *cur_node = (oc_node_t*)value;
const char *node_uname = (const char*)key;
if(election_data->winning_bornon > cur_node->node_born_on) {
election_data->winning_uname = node_uname;
election_data->winning_bornon = cur_node->node_born_on;
} else if(election_data->winning_bornon == cur_node->node_born_on
&& (election_data->winning_uname == NULL
|| strcmp(election_data->winning_uname, node_uname) > 0)) {
election_data->winning_uname = node_uname;
election_data->winning_bornon = cur_node->node_born_on;
}
}
diff --git a/crm/crmd/fsa.c b/crm/crmd/fsa.c
index c9b19922cf..478e9e26f8 100644
--- a/crm/crmd/fsa.c
+++ b/crm/crmd/fsa.c
@@ -1,602 +1,602 @@
/*
* 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 <portability.h>
-#include <crm/crm.h>
-#include <crmd_fsa.h>
-#include <fsa_matrix.h>
-#include <fsa_proto.h>
#include <stdio.h>
+#include <string.h>
+#include <time.h>
-#include <crm/common/xmlutils.h>
-#include <crm/common/msgutils.h>
+#include <crm/crm.h>
#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/common/msg.h>
#include <clplumbing/Gmain_timeout.h>
#include <crmd_messages.h>
-#include <string.h>
-#include <time.h>
+#include <crmd_fsa.h>
+#include <fsa_proto.h>
+#include <fsa_matrix.h>
#include <crm/dmalloc_wrapper.h>
long long
do_state_transition(long long actions,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_state next_state,
enum crmd_fsa_input current_input,
void *data);
// delete this
extern fsa_message_queue_t fsa_message_queue;
#ifdef DOT_FSA_ACTIONS
# ifdef FSA_TRACE
# define IF_FSA_ACTION(x,y) \
if(is_set(actions,x)) { \
CRM_DEBUG("Invoking action %s (%.16llx)", \
fsa_action2string(x), x); \
last_action = x; \
actions = clear_bit(actions, x); \
next_input = y(x, cause, cur_state, last_input, data); \
if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \
fprintf(dot_strm, \
"\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \
fsa_input2string(cur_input), \
fsa_action2string(x), \
data==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES, \
fsa_input2string(next_input)); \
fflush(dot_strm); \
CRM_DEBUG("Result of action %s was %s", \
fsa_action2string(x), fsa_input2string(next_input)); \
}
# else
# define IF_FSA_ACTION(x,y) \
if(is_set(actions,x)) { \
last_action = x; \
actions = clear_bit(actions, x); \
next_input = y(x, cause, cur_state, last_input, data); \
if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \
fprintf(dot_strm, \
"\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \
fsa_input2string(cur_input), \
fsa_action2string(x), \
data==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES, \
fsa_input2string(next_input)); \
fflush(dot_strm); \
}
# endif
#else
# ifdef FSA_TRACE
# define IF_FSA_ACTION(x,y) \
if(is_set(actions,x)) { \
CRM_DEBUG("Invoking action %s (%.16llx)", \
fsa_action2string(x), x); \
last_action = x; \
actions = clear_bit(actions, x); \
next_input = y(x, cause, cur_state, last_input, data); \
CRM_DEBUG("Result of action %s was %s", \
fsa_action2string(x), fsa_input2string(next_input)); \
}
# else
# define IF_FSA_ACTION(x,y) \
if(is_set(actions,x)) { \
last_action = x; \
actions = clear_bit(actions, x); \
next_input = y(x, cause, cur_state, last_input, data); \
}
# endif
#endif
#define ELSEIF_FSA_ACTION(x,y) else IF_FSA_ACTION(x,y)
const char *dot_intro = "digraph \"g\" {\n"
" size = \"30,30\"\n"
" graph [\n"
" fontsize = \"12\"\n"
" fontname = \"Times-Roman\"\n"
" fontcolor = \"black\"\n"
" bb = \"0,0,398.922306,478.927856\"\n"
" color = \"black\"\n"
" ]\n"
" node [\n"
" fontsize = \"12\"\n"
" fontname = \"Times-Roman\"\n"
" fontcolor = \"black\"\n"
" shape = \"ellipse\"\n"
" color = \"black\"\n"
" ]\n"
" edge [\n"
" fontsize = \"12\"\n"
" fontname = \"Times-Roman\"\n"
" fontcolor = \"black\"\n"
" color = \"black\"\n"
" ]\n"
"// special nodes\n"
" \"S_PENDING\" \n"
" [\n"
" color = \"blue\"\n"
" fontcolor = \"blue\"\n"
" ]\n"
" \"S_TERMINATE\" \n"
" [\n"
" color = \"red\"\n"
" fontcolor = \"red\"\n"
" ]\n"
"\n"
"// DC only nodes\n"
" \"S_RECOVERY_DC\" [ fontcolor = \"green\" ]\n"
" \"S_INTEGRATION\" [ fontcolor = \"green\" ]\n"
" \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]\n"
" \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]\n"
" \"S_RELEASE_DC\" [ fontcolor = \"green\" ]\n"
" \"S_IDLE\" [ fontcolor = \"green\" ]\n";
static FILE *dot_strm = NULL;
enum crmd_fsa_state fsa_state;
oc_node_list_t *fsa_membership_copy;
ll_cluster_t *fsa_cluster_conn;
ll_lrm_t *fsa_lrm_conn;
long long fsa_input_register;
long long fsa_actions = A_NOTHING;
const char *fsa_our_uname;
const char *fsa_our_dc;
fsa_timer_t *election_trigger = NULL; /* */
fsa_timer_t *election_timeout = NULL; /* */
fsa_timer_t *shutdown_escalation_timmer = NULL; /* */
fsa_timer_t *integration_timer = NULL;
fsa_timer_t *dc_heartbeat = NULL;
enum crmd_fsa_state
s_crmd_fsa(enum crmd_fsa_cause cause,
enum crmd_fsa_input initial_input,
void *data)
{
long long actions = fsa_actions;
long long new_actions = A_NOTHING;
long long last_action = A_NOTHING;
enum crmd_fsa_input last_input = initial_input;
enum crmd_fsa_input cur_input;
enum crmd_fsa_input next_input;
enum crmd_fsa_state last_state, cur_state, next_state, starting_state;
FNIN();
starting_state = fsa_state;
cur_input = initial_input;
next_input = initial_input;
last_state = starting_state;
cur_state = starting_state;
next_state = starting_state;
#ifdef FSA_TRACE
CRM_DEBUG("FSA invoked with Cause: %s\n\tState: %s, Input: %s",
fsa_cause2string(cause),
fsa_state2string(cur_state),
fsa_input2string(cur_input));
#endif
#ifdef DOT_FSA_ACTIONS
if(dot_strm == NULL) {
dot_strm = fopen("/tmp/live.dot", "w");
fprintf(dot_strm, "%s", dot_intro);
}
#endif
/*
* Process actions in order of priority but do only one
* action at a time to avoid complicating the ordering.
*
* Actions may result in a new I_ event, these are added to
* (not replace) existing actions before the next iteration.
*
*/
while(next_input != I_NULL || actions != A_NOTHING || is_message()) {
if(next_input == I_WAIT_FOR_EVENT) {
/* we may be waiting for an a-sync task to "happen"
* and until it does, we cant do anything else
*
* Re-add the last action
*/
actions |= last_action;
cl_log(LOG_INFO, "Wait until something else happens");
break;
}
#ifdef FSA_TRACE
CRM_DEBUG("FSA while loop:\tState: %s, Input: %s",
fsa_state2string(cur_state),
fsa_input2string(cur_input));
#endif
/* update input variables */
cur_input = next_input;
if(cur_input != I_NULL) {
last_input = cur_input;
}
/* get the next batch of actions */
new_actions = crmd_fsa_actions[cur_input][cur_state];
if(new_actions != A_NOTHING) {
#ifdef FSA_TRACE
CRM_DEBUG("Adding actions %.16llx", new_actions);
#endif
actions |= new_actions;
}
/* logging : *before* the state is changed */
IF_FSA_ACTION(A_ERROR, do_log)
ELSEIF_FSA_ACTION(A_WARN, do_log)
ELSEIF_FSA_ACTION(A_LOG, do_log)
/* update state variables */
next_state = crmd_fsa_state[cur_input][cur_state];
last_state = cur_state;
cur_state = next_state;
fsa_state = next_state;
/* start doing things... */
/*
* Hook for change of state.
* Allows actions to be added or removed when entering a state
*/
if(last_state != cur_state){
actions = do_state_transition(actions, cause,
last_state, cur_state,
last_input, data);
}
/* this is always run, some inputs/states may make various
* actions irrelevant/invalid
*/
actions = clear_flags(actions, cause, cur_state, cur_input);
/* regular action processing in order of action priority
*
* Make sure all actions that connect to required systems
* are performed first
*/
if(actions == A_NOTHING) {
cl_log(LOG_INFO, "Nothing to do");
next_input = I_NULL;
/* // check registers, see if anything is pending
if(is_set(fsa_input_register, R_SHUTDOWN)) {
CRM_DEBUG("(Re-)invoking shutdown");
next_input = I_SHUTDOWN;
} else if(is_set(fsa_input_register, R_INVOKE_PE)) {
CRM_DEBUG("Invoke the PE somehow");
}
*/
}
/* get out of here NOW! before anything worse happens */
ELSEIF_FSA_ACTION(A_EXIT_1, do_exit)
ELSEIF_FSA_ACTION(A_STARTUP, do_startup)
ELSEIF_FSA_ACTION(A_CIB_START, do_cib_control)
ELSEIF_FSA_ACTION(A_HA_CONNECT, do_ha_control)
ELSEIF_FSA_ACTION(A_LRM_CONNECT,do_lrm_control)
ELSEIF_FSA_ACTION(A_CCM_CONNECT,do_ccm_control)
/* sub-system start */
ELSEIF_FSA_ACTION(A_TE_START, do_te_control)
ELSEIF_FSA_ACTION(A_PE_START, do_pe_control)
/* sub-system restart
*/
ELSEIF_FSA_ACTION(O_CIB_RESTART,do_cib_control)
ELSEIF_FSA_ACTION(O_PE_RESTART, do_pe_control)
ELSEIF_FSA_ACTION(O_TE_RESTART, do_te_control)
ELSEIF_FSA_ACTION(A_STARTED, do_started)
/* DC Timer */
ELSEIF_FSA_ACTION(O_DC_TIMER_RESTART, do_dc_timer_control)
ELSEIF_FSA_ACTION(A_DC_TIMER_STOP, do_dc_timer_control)
ELSEIF_FSA_ACTION(A_DC_TIMER_START, do_dc_timer_control)
/*
* Highest priority actions
*/
ELSEIF_FSA_ACTION(A_CIB_BUMPGEN, do_cib_invoke)
ELSEIF_FSA_ACTION(A_TE_COPYTO, do_te_copyto)
ELSEIF_FSA_ACTION(A_MSG_ROUTE, do_msg_route)
ELSEIF_FSA_ACTION(A_RECOVER, do_recover)
ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_lrm_invoke)
ELSEIF_FSA_ACTION(A_JOIN_ACK, do_ack_welcome)
ELSEIF_FSA_ACTION(A_SHUTDOWN_REQ, do_shutdown_req)
ELSEIF_FSA_ACTION(A_ELECTION_VOTE, do_election_vote)
ELSEIF_FSA_ACTION(A_ELECT_TIMER_STOP, do_election_timer_ctrl)
ELSEIF_FSA_ACTION(A_ELECT_TIMER_START, do_election_timer_ctrl)
ELSEIF_FSA_ACTION(A_ELECTION_COUNT, do_election_count_vote)
ELSEIF_FSA_ACTION(A_ELECTION_TIMEOUT, do_election_timer_ctrl)
/*
* "Get this over with" actions
*/
ELSEIF_FSA_ACTION(A_MSG_STORE, do_msg_store)
/*
* High priority actions
* Update the cache first
*/
ELSEIF_FSA_ACTION(A_CCM_UPDATE_CACHE, do_ccm_update_cache)
ELSEIF_FSA_ACTION(A_CCM_EVENT, do_ccm_event)
/*
* Medium priority actions
*/
ELSEIF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover)
ELSEIF_FSA_ACTION(A_DC_RELEASE, do_dc_release)
ELSEIF_FSA_ACTION(A_JOIN_WELCOME_ALL, do_send_welcome_all)
ELSEIF_FSA_ACTION(A_JOIN_WELCOME, do_send_welcome)
ELSEIF_FSA_ACTION(A_JOIN_PROCESS_ACK, do_process_welcome_ack)
/*
* Low(er) priority actions
* Make sure the CIB is always updated before invoking the
* PE, and the PE before the TE
*/
ELSEIF_FSA_ACTION(A_CIB_INVOKE_LOCAL, do_cib_invoke)
ELSEIF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke)
ELSEIF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke)
ELSEIF_FSA_ACTION(A_LRM_EVENT, do_lrm_event)
ELSEIF_FSA_ACTION(A_TE_CANCEL, do_te_invoke)
ELSEIF_FSA_ACTION(A_PE_INVOKE, do_pe_invoke)
ELSEIF_FSA_ACTION(A_TE_INVOKE, do_te_invoke)
ELSEIF_FSA_ACTION(A_ANNOUNCE, do_announce)
/* sub-system stop */
ELSEIF_FSA_ACTION(A_PE_STOP, do_pe_control)
ELSEIF_FSA_ACTION(A_TE_STOP, do_te_control)
ELSEIF_FSA_ACTION(A_DC_RELEASED, do_dc_release)
ELSEIF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control)
ELSEIF_FSA_ACTION(A_CCM_DISCONNECT, do_ccm_control)
ELSEIF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control)
ELSEIF_FSA_ACTION(A_CIB_STOP, do_cib_control)
/* time to go now... */
/* Some of these can probably be consolidated */
ELSEIF_FSA_ACTION(A_SHUTDOWN, do_shutdown)
ELSEIF_FSA_ACTION(A_STOP, do_stop)
/* exit gracefully */
ELSEIF_FSA_ACTION(A_EXIT_0, do_exit)
// ELSEIF_FSA_ACTION(A_, do_)
else if((actions & A_MSG_PROCESS) != 0
|| is_message()) {
xmlNodePtr stored_msg = NULL;
crm_debug("Checking messages... %d",
g_slist_length(fsa_message_queue));
stored_msg = get_message();
if(is_message() == FALSE) {
actions = clear_bit(actions, A_MSG_PROCESS);
}
if(stored_msg == NULL) {
cl_log(LOG_ERR, "Invalid stored message");
continue;
}
/*
* This is where we should clean up old messages
* The problem is that we dont always know the
* type of the data (and therefore the correct way
* to free it). A wrapper is probably required.
*/
data = stored_msg;
#ifdef DOT_FSA_ACTIONS
fprintf(dot_strm,
"\t// %s:\t%s\t(data? %s)",
fsa_input2string(cur_input),
fsa_action2string(A_MSG_PROCESS),
stored_msg==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES);
fflush(dot_strm);
#endif
#ifdef FSA_TRACE
CRM_DEBUG("Invoking action %s (%.16llx)",
fsa_action2string(A_MSG_PROCESS),
A_MSG_PROCESS);
#endif
//#ifdef FSA_TRACE
xml_message_debug(stored_msg,"FSA processing message");
//#endif
next_input = handle_message(stored_msg);
#ifdef DOT_FSA_ACTIONS
fprintf(dot_strm, "\t(result=%s)\n",
fsa_input2string(next_input));
#endif
CRM_DEBUG("Result of action %s was %s",
fsa_action2string(A_MSG_PROCESS),
fsa_input2string(next_input));
/* Error checking and reporting */
} else if(cur_input != I_NULL && is_set(actions, A_NOTHING)) {
cl_log(LOG_WARNING,
"No action specified for input,state (%s,%s)",
fsa_input2string(cur_input),
fsa_state2string(cur_state));
next_input = I_NULL;
} else if(cur_input == I_NULL && is_set(actions, A_NOTHING)) {
#ifdef FSA_TRACE
cl_log(LOG_INFO, "Nothing left to do");
#endif
} else {
cl_log(LOG_ERR, "Action %s (0x%llx) not supported ",
fsa_action2string(actions), actions);
next_input = I_ERROR;
}
if(is_message()) {
actions |= A_MSG_PROCESS;
}
}
#ifdef FSA_TRACE
CRM_DEBUG("################# Exiting the FSA (%s) ##################",
fsa_state2string(fsa_state));
#endif
#ifdef DOT_FSA_ACTIONS
fprintf(dot_strm,
"\t// ### Exiting the FSA (%s)\n",
fsa_state2string(fsa_state));
fflush(dot_strm);
#endif
// cleanup inputs?
fsa_actions = actions;
FNRET(fsa_state);
}
long long
do_state_transition(long long actions,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_state next_state,
enum crmd_fsa_input current_input,
void *data)
{
long long tmp = actions;
const char *state_from = fsa_state2string(cur_state);
const char *state_to = fsa_state2string(next_state);
const char *input = fsa_input2string(current_input);
time_t now = time(NULL);
if(cur_state == next_state) {
cl_log(LOG_ERR,
"%s called in state %s with no transtion",
__FUNCTION__, state_from);
return A_NOTHING;
}
// if(current_input != I_NULL
// && (current_input != I_DC_HEARTBEAT || cur_state != S_NOT_DC)){
fprintf(dot_strm,
"\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s",
state_from, state_to, input,
asctime(localtime(&now)));
fflush(dot_strm);
//}
cl_log(LOG_INFO,
"State transition \"%s\" -> \"%s\" [ cause =\"%s\" %s ]",
state_from, state_to, input, asctime(localtime(&now)));
switch(next_state) {
case S_PENDING:
break;
case S_NOT_DC:
if(is_set(fsa_input_register, R_SHUTDOWN)){
cl_log(LOG_INFO,
"(Re)Issuing shutdown request now"
" that we have a new DC");
tmp = set_bit(tmp, A_SHUTDOWN_REQ);
}
tmp = clear_bit(tmp, A_RECOVER);
break;
case S_RECOVERY_DC:
case S_RECOVERY:
tmp = set_bit(tmp, A_RECOVER);
break;
default:
tmp = clear_bit(tmp, A_RECOVER);
break;
}
if(tmp != actions) {
cl_log(LOG_INFO, "Action b4 %.16llx ", actions);
cl_log(LOG_INFO, "Action after %.16llx ", tmp);
actions = tmp;
}
return actions;
}
long long
clear_flags(long long actions,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input cur_input)
{
if(is_set(fsa_input_register, R_SHUTDOWN)){
clear_bit_inplace(&actions, A_DC_TIMER_START);
}
switch(cur_state) {
case S_IDLE:
break;
case S_ELECTION:
break;
case S_INTEGRATION:
break;
case S_NOT_DC:
break;
case S_POLICY_ENGINE:
break;
case S_RECOVERY:
break;
case S_RECOVERY_DC:
break;
case S_RELEASE_DC:
break;
case S_PENDING:
break;
case S_STOPPING:
break;
case S_TERMINATE:
break;
case S_TRANSITION_ENGINE:
break;
case S_ILLEGAL:
break;
}
return actions;
}
diff --git a/crm/crmd/join.c b/crm/crmd/join.c
index dd801b6c27..6f3250531e 100644
--- a/crm/crmd/join.c
+++ b/crm/crmd/join.c
@@ -1,368 +1,365 @@
/*
* 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 <portability.h>
+
+#include <heartbeat.h>
+
#include <crm/crm.h>
-#include <crmd_fsa.h>
-#include <libxml/tree.h>
+#include <crm/cib.h>
#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
-#include <crm/common/xmlutils.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/msgutils.h>
-#include <crm/cib.h>
-#include <string.h>
+#include <crmd_fsa.h>
#include <crmd_messages.h>
-#include <heartbeat.h>
-
#include <crm/dmalloc_wrapper.h>
GHashTable *joined_nodes = NULL;
/* A_JOIN_WELCOME, A_JOIN_WELCOME_ALL */
enum crmd_fsa_input
do_send_welcome(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
if(action & A_JOIN_WELCOME && data == NULL) {
cl_log(LOG_ERR,
"Attempt to send welcome message "
"without a message to reply to!");
FNRET(I_NULL);
} else if(action & A_JOIN_WELCOME) {
xmlNodePtr welcome = (xmlNodePtr)data;
const char *join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM);
if(join_to != NULL) {
xmlNodePtr update = create_node_state(
join_to, NULL, NULL, CRMD_JOINSTATE_PENDING);
xmlNodePtr tmp1 = create_cib_fragment(update, NULL);
store_request(NULL, tmp1, CRM_OP_UPDATE, CRM_SYSTEM_DCIB);
send_request(NULL, NULL, CRM_OP_WELCOME,
join_to, CRM_SYSTEM_CRMD, NULL);
free_xml(update);
free_xml(tmp1);
} else {
cl_log(LOG_ERR, "No recipient for welcome message");
}
FNRET(I_NULL);
}
FNRET(I_ERROR);
}
// welcome everyone...
enum crmd_fsa_input
do_send_welcome_all(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
// reset everyones status back to down or in_ccm in the CIB
xmlNodePtr update = NULL;
xmlNodePtr cib_copy = get_cib_copy();
xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy);
xmlNodePtr node_entry = tmp1->children;
/* Give everyone a chance to join before invoking the PolicyEngine */
stopTimer(integration_timer);
startTimer(integration_timer);
if(joined_nodes != NULL) {
g_hash_table_destroy(joined_nodes);
joined_nodes = g_hash_table_new(&g_str_hash, &g_str_equal);
}
// catch any nodes that are active in the CIB but not in the CCM list
while(node_entry != NULL){
const char *node_id = xmlGetProp(node_entry, XML_ATTR_ID);
gpointer a_node =
g_hash_table_lookup(fsa_membership_copy->members,
node_id);
node_entry = node_entry->next;
if(a_node != NULL || (safe_str_eq(fsa_our_uname, node_id))) {
/* handled by do_update_cib_node() */
continue;
}
tmp1 = create_node_state(node_id, XML_BOOLEAN_NO, NULL, CRMD_JOINSTATE_DOWN);
if(update == NULL) {
update = tmp1;
} else {
update = xmlAddSibling(update, tmp1);
}
}
// now process the CCM data
free_xml(do_update_cib_nodes(update, TRUE));
free_xml(cib_copy);
/* Avoid ordered message delays caused when the CRMd proc
* isnt running yet (ie. send as a broadcast msg which are never
* sent ordered.
*/
send_request(NULL, NULL, CRM_OP_WELCOME,
NULL, CRM_SYSTEM_CRMD, NULL);
/* No point hanging around in S_INTEGRATION if we're the only ones here! */
if(g_hash_table_size(joined_nodes)
== fsa_membership_copy->members_size) {
// that was the last outstanding join ack)
cl_log(LOG_INFO,"That was the last outstanding join ack");
FNRET(I_SUCCESS);
} else {
cl_log(LOG_DEBUG,
"Still waiting on %d outstanding join acks",
fsa_membership_copy->members_size - g_hash_table_size(joined_nodes));
// dont waste time by invoking the pe yet;
}
FNRET(I_NULL);
}
/* A_JOIN_ACK */
enum crmd_fsa_input
do_ack_welcome(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr welcome = (xmlNodePtr)data;
xmlNodePtr cib_copy;
xmlNodePtr tmp1;
xmlNodePtr tmp2;
FNIN();
#if 0
if(we are sick) {
log error ;
FNRET(I_NULL);
}
#endif
fsa_our_dc = xmlGetProp(welcome, XML_ATTR_HOSTFROM);
if(fsa_our_dc == NULL) {
cl_log(LOG_ERR, "Failed to determin our DC");
FNRET(I_FAIL);
}
/* send our status section to the DC */
cib_copy = get_cib_copy();
tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy);
tmp2 = create_cib_fragment(tmp1, NULL);
send_ha_reply(fsa_cluster_conn, welcome, tmp2);
free_xml(tmp2);
free_xml(cib_copy);
FNRET(I_NULL);
}
/* A_ANNOUNCE */
enum crmd_fsa_input
do_announce(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr msg = (xmlNodePtr)data;
FNIN();
/* Once we hear from the DC, we can stop the timer
*
* This timer was started either on startup or when a node
* left the CCM list
*/
/* dont announce if we're in one of these states */
switch(cur_state) {
case S_RECOVERY:
case S_RECOVERY_DC:
case S_RELEASE_DC:
case S_TERMINATE:
cl_log(LOG_WARNING,
"Do not announce ourselves in state %s",
fsa_state2string(cur_state));
FNRET(I_NULL);
break;
default:
break;
}
if(AM_I_OPERATIONAL) {
const char *from = xmlGetProp(msg, XML_ATTR_HOSTFROM);
if(from == NULL) {
cl_log(LOG_ERR, "Failed to origin of ping message");
FNRET(I_FAIL);
}
send_request(NULL, NULL, CRM_OP_ANNOUNCE,
from, CRM_SYSTEM_DC, NULL);
} else {
/* Delay announce until we have finished local startup */
cl_log(LOG_WARNING,
"Delaying announce until local startup is complete");
FNRET(I_NULL);
}
FNRET(I_NULL);
}
/* A_JOIN_PROCESS_ACK */
enum crmd_fsa_input
do_process_welcome_ack(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr tmp1;
xmlNodePtr tmp2;
xmlNodePtr cib_fragment;
xmlNodePtr msg_cib;
xmlNodePtr join_ack = (xmlNodePtr)data;
int size = 0;
gboolean is_a_member = FALSE;
const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM);
const char *ref = xmlGetProp(join_ack, XML_ATTR_REFERENCE);
FNIN();
gpointer join_node =
g_hash_table_lookup(fsa_membership_copy->members, join_from);
if(join_node != NULL) {
is_a_member = TRUE;
}
cib_fragment = find_xml_node(join_ack, XML_TAG_FRAGMENT);
if(is_a_member == FALSE) {
cl_log(LOG_ERR, "Node %s is not known to us (ref %s)",
join_from, ref);
/* make sure any information from this node is discarded,
* it is invalid
*/
free_xml(cib_fragment);
FNRET(I_FAIL);
}
cl_log(LOG_DEBUG, "Welcoming node %s after ACK (ref %s)",
join_from, ref);
/* add them to our list of CRMD_STATE_ACTIVE nodes
TODO: still used?
*/
g_hash_table_insert(joined_nodes, strdup(join_from),strdup(join_from));
if(cib_fragment == NULL) {
cl_log(LOG_ERR,
"No status information was part of the"
" Welcome ACK from %s",
join_from);
FNRET(I_NULL);
}
/* make sure a node entry exists for the new node
*
* this will add anyone except the first ever node in the cluster
* since it will also be the DC which doesnt go through the
* join process (with itself). We can include a special case
* later if desired.
*/
tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);
set_xml_property_copy(tmp1, XML_ATTR_ID, join_from);
set_xml_property_copy(tmp1, "uname", join_from);
set_xml_property_copy(tmp1, XML_ATTR_TYPE, "node");
tmp2 = create_cib_fragment(tmp1, NULL);
/* do not forward this to the TE */
invoke_local_cib(NULL, tmp2, CRM_OP_UPDATE);
free_xml(tmp2);
free_xml(tmp1);
/* Make changes so that exp_state=active for this node when the update
* is processed by A_CIB_INVOKE
*/
msg_cib = find_xml_node(cib_fragment, XML_TAG_CIB);
tmp1 = get_object_root(XML_CIB_TAG_STATUS, msg_cib);
tmp2 = find_entity(tmp1, XML_CIB_TAG_STATE, join_from, FALSE);
if(tmp2 == NULL) {
cl_log(LOG_ERR,
"Status entry for %s not found in update, adding",
join_from);
tmp2 = create_xml_node(tmp1, XML_CIB_TAG_STATE);
set_xml_property_copy(tmp2, XML_ATTR_ID, join_from);
}
set_xml_property_copy(tmp2, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE);
set_xml_property_copy(tmp2, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_MEMBER);
if(g_hash_table_size(joined_nodes)
== fsa_membership_copy->members_size) {
cl_log(LOG_INFO,"That was the last outstanding join ack");
FNRET(I_SUCCESS);
/* The update isnt lost, the A_CIB_OP action is part of the
* matrix for S_INTEGRATION + I_SUCCESS.
*/
} else {
cl_log(LOG_DEBUG,
"Still waiting on %d outstanding join acks",
size);
/* dont waste time by invoking the pe yet */
}
FNRET(I_CIB_OP);
}
diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c
index 395e05994b..11ffeefac3 100644
--- a/crm/crmd/lrm.c
+++ b/crm/crmd/lrm.c
@@ -1,624 +1,609 @@
/*
* 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 <portability.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 <crm/common/crmutils.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/msgutils.h>
-
-#include <crm/msg_xml.h>
-#include <crm/common/xmlutils.h>
+#include <errno.h>
#include <crm/cib.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
#include <crmd.h>
#include <crmd_messages.h>
-#include <string.h>
-#include <errno.h>
#include <crm/dmalloc_wrapper.h>
xmlNodePtr do_lrm_query(void);
GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth);
gboolean lrm_dispatch(int fd, gpointer user_data);
void do_update_resource(lrm_rsc_t *rsc,
int status,
int rc,
const char *op_type);
/* A_LRM_CONNECT */
enum crmd_fsa_input
do_lrm_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input failed = I_NULL;//I_FAIL;
int ret = HA_OK;
FNIN();
if(action & A_LRM_DISCONNECT) {
fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn);
}
if(action & A_LRM_CONNECT) {
CRM_NOTE("LRM: connect...");
fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM);
if(NULL == fsa_lrm_conn) {
return failed;
}
CRM_NOTE("LRM: sigon...");
ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn,
CRM_SYSTEM_CRMD);
if(ret != HA_OK) {
cl_log(LOG_ERR, "Failed to sign on to the LRM");
return failed;
}
CRM_NOTE("LRM: set_lrm_callback...");
ret = fsa_lrm_conn->lrm_ops->set_lrm_callback(
fsa_lrm_conn, lrm_op_callback, lrm_monitor_callback);
if(ret != HA_OK) {
cl_log(LOG_ERR, "Failed to set LRM callbacks");
return failed;
}
/* TODO: create a destroy handler that causes
* some recovery to happen
*/
G_main_add_fd(G_PRIORITY_LOW,
fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn),
FALSE,
lrm_dispatch, fsa_lrm_conn,
default_ipc_input_destroy);
}
if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) {
cl_log(LOG_ERR, "Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
FNRET(I_NULL);
}
gboolean lrm_dispatch(int fd, gpointer user_data)
{
ll_lrm_t *lrm = (ll_lrm_t*)user_data;
lrm->lrm_ops->rcvmsg(lrm, FALSE);
return TRUE;
}
xmlNodePtr
do_lrm_query(void)
{
GList* lrm_list = NULL;
GList* element = NULL;
GList* op_list = NULL;
xmlNodePtr agent = NULL;
xmlNodePtr data = create_xml_node(NULL, XML_CIB_TAG_LRM);
xmlNodePtr agent_list = create_xml_node(data, "lrm_agents");
xmlNodePtr rsc_list;
char *rsc_type = NULL;
state_flag_t cur_state = 0;
const char *this_op = NULL;
GList* node = NULL;
lrm_list = fsa_lrm_conn->lrm_ops->get_ra_supported(fsa_lrm_conn);
if (NULL != lrm_list) {
GList* element = g_list_first(lrm_list);
while (NULL != element) {
rsc_type = (char*)element->data;
agent =
create_xml_node(agent_list, "lrm_agent");
set_xml_property_copy(agent, "class", rsc_type);
/* we dont have these yet */
set_xml_property_copy(agent, XML_ATTR_TYPE, NULL);
set_xml_property_copy(agent, "version", NULL);
element = g_list_next(element);
}
}
g_list_free(lrm_list);
lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn);
rsc_list = create_xml_node(data, XML_LRM_TAG_RESOURCES);
if (NULL != lrm_list) {
element = g_list_first(lrm_list);
}
while (NULL != element) {
lrm_rsc_t *the_rsc = (lrm_rsc_t*)element->data;
/* const char* ra_type; */
/* GHashTable* params; */
xmlNodePtr xml_rsc = create_xml_node(rsc_list, "rsc_state");
set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id);
set_xml_property_copy(xml_rsc, "rsc_id", the_rsc->name);
set_xml_property_copy(xml_rsc, "node_id",fsa_our_uname);
op_list = the_rsc->ops->get_cur_state(the_rsc,
&cur_state);
CRM_DEBUG("\tcurrent state:%s\n",
cur_state==LRM_RSC_IDLE?"Idle":"Busy");
node = g_list_first(op_list);
while(NULL != node){
lrm_op_t* op = (lrm_op_t*)node->data;
this_op = op->op_type;
if(this_op == NULL
|| strcmp(this_op, "status") != 0){
const char *status_text = "<unknown>";
switch(op->status) {
case LRM_OP_DONE:
status_text = "done";
break;
case LRM_OP_CANCELLED:
status_text = "cancelled";
break;
case LRM_OP_TIMEOUT:
status_text = "timeout";
break;
case LRM_OP_NOTSUPPORTED:
status_text = "not suported";
break;
case LRM_OP_ERROR:
status_text = "error";
break;
}
set_xml_property_copy(xml_rsc,
"op_result",
status_text);
set_xml_property_copy(xml_rsc,
"rsc_op",
this_op);
// we only want the last one
break;
}
node = g_list_next(node);
}
element = g_list_next(element);
}
if (NULL != lrm_list) {
g_list_free(lrm_list);
}
return data;
}
/* A_LRM_INVOKE */
enum crmd_fsa_input
do_lrm_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input next_input = I_NULL;
xmlNodePtr fragment, tmp1;
xmlNodePtr msg;
const char *rsc_path[] =
{
"msg_data",
"rsc_op",
"resource",
"instance_attributes",
"parameters"
};
const char *operation = NULL;
rsc_id_t rid;
const char *id_from_cib = NULL;
const char *crm_op = NULL;
lrm_rsc_t *rsc = NULL;
lrm_mon_t* mon = NULL;
lrm_op_t* op = NULL;
FNIN();
if(action & A_UPDATE_NODESTATUS) {
xmlNodePtr data = NULL;
#ifndef USE_FAKE_LRM
data = do_lrm_query();
#endif
set_xml_property_copy(data, "replace", XML_CIB_TAG_LRM);
tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname);
fragment = create_cib_fragment(tmp1, NULL);
add_node_copy(tmp1, data);
/* this only happens locally. the updates are pushed out
* as part of the join process
*/
store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DC);
free_xml(fragment);
free_xml(tmp1);
free_xml(data);
FNRET(next_input);
}
#ifdef USE_FAKE_LRM
if(data == NULL) {
FNRET(I_ERROR);
}
msg = (xmlNodePtr)data;
operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3,
XML_LRM_ATTR_TASK, TRUE);
id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2,
XML_ATTR_ID, TRUE);
crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE);
if(safe_str_eq(crm_op, "rsc_op")) {
const char *op_status = NULL;
xmlNodePtr update = NULL;
xmlNodePtr state = create_xml_node(NULL, XML_CIB_TAG_STATE);
xmlNodePtr iter = create_xml_node(state, XML_CIB_TAG_LRM);
CRM_DEBUG("performing op %s...", operation);
// so we can identify where to do the update
set_xml_property_copy(state, XML_ATTR_ID, fsa_our_uname);
iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES);
iter = create_xml_node(iter, "lrm_resource");
set_xml_property_copy(iter, XML_ATTR_ID, id_from_cib);
set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, operation);
long int op_code = 0;
#if 0
/* introduce a 10% chance of an action failing */
op_code = random();
#endif
if((op_code % 10) == 1) {
op_code = 1;
} else {
op_code = 0;
}
char *op_code_s = crm_itoa(op_code);
if(op_code) {
// fail
if(safe_str_eq(operation, "start")){
op_status = "stopped";
} else {
op_status = "started";
}
} else {
// pass
if(safe_str_eq(operation, "start")){
op_status = "started";
} else {
op_status = "stopped";
}
}
set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATE,op_status);
set_xml_property_copy(iter, XML_LRM_ATTR_OPCODE, op_code_s);
set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname);
crm_free(op_code_s);
update = create_cib_fragment(state, NULL);
send_request(NULL, update, CRM_OP_UPDATE,
fsa_our_dc, CRM_SYSTEM_DCIB, NULL);
}
FNRET(I_NULL);
#endif
cl_log(LOG_WARNING, "Action %s (%.16llx) only kind of supported\n",
fsa_action2string(action), action);
msg = (xmlNodePtr)data;
operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3,
XML_ATTR_OP, TRUE);
id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2,
XML_ATTR_ID, TRUE);
// only the first 16 chars are used by the LRM
strncpy(rid, id_from_cib, 16);
crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
if(crm_op != NULL && strcmp(crm_op, "lrm_query") == 0) {
xmlNodePtr data, tmp1, tmp2, reply;
tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname);
data = create_cib_fragment(tmp1, NULL);
tmp2 = do_lrm_query();
add_node_copy(tmp1, tmp2);
reply = create_reply(msg, data);
relay_message(reply, TRUE);
free_xml(data);
free_xml(reply);
free_xml(tmp2);
free_xml(tmp1);
} else if(operation != NULL && strcmp(operation, "monitor") == 0) {
if(rsc == NULL) {
cl_log(LOG_ERR, "Could not find resource to monitor");
FNRET(I_FAIL);
}
mon = g_new(lrm_mon_t, 1);
mon->op_type = "status";
mon->params = NULL;
mon->timeout = 0;
mon->user_data = rsc;
mon->mode = LRM_MONITOR_SET;
mon->interval = 2;
mon->target = 1;
rsc->ops->set_monitor(rsc,mon);
mon = g_new(lrm_mon_t, 1);
} else if(operation != NULL) {
if(rsc == NULL) {
// add it to the list
CRM_DEBUG("adding rsc %s before operation", rid);
fsa_lrm_conn->lrm_ops->add_rsc(
fsa_lrm_conn, rid,
get_xml_attr_nested(msg,
rsc_path,
DIMOF(rsc_path) -2,
"class", TRUE),
get_xml_attr_nested(msg,
rsc_path,
DIMOF(rsc_path) -2,
XML_ATTR_TYPE, TRUE),
NULL);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(
fsa_lrm_conn, rid);
}
if(rsc == NULL) {
cl_log(LOG_ERR, "Could not add resource to LRM");
FNRET(I_FAIL);
}
// now do the op
CRM_DEBUG("performing op %s...", operation);
op = g_new(lrm_op_t, 1);
op->op_type = operation;
op->params = xml2list(msg, rsc_path, DIMOF(rsc_path));
op->timeout = 0;
op->user_data = rsc;
rsc->ops->perform_op(rsc, op);
}
FNRET(next_input);
}
GHashTable *
xml2list(xmlNodePtr parent, const char**attr_path, int depth)
{
xmlNodePtr node_iter = NULL;
GHashTable *nvpair_hash =
g_hash_table_new(&g_str_hash, &g_str_equal);
xmlNodePtr nvpair_list =
find_xml_node_nested(parent, attr_path, depth);
if(nvpair_list != NULL){
node_iter = nvpair_list->children;
while(node_iter != NULL) {
const char *key = xmlGetProp(
node_iter, XML_NVPAIR_ATTR_NAME);
const char *value = xmlGetProp(
node_iter, XML_NVPAIR_ATTR_VALUE);
CRM_DEBUG("Added %s=%s", key, value);
g_hash_table_insert (nvpair_hash,
crm_strdup(key),
crm_strdup(value));
node_iter = node_iter->next;
}
}
return nvpair_hash;
}
void
do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type)
{
/*
<status>
<nodes_status id=uname>
<lrm>
<lrm_resources>
<lrm_resource id=>
</...>
*/
xmlNodePtr update, iter;
char *tmp = NULL;
xmlNodePtr fragment, tmp1;
update = create_xml_node(NULL, "node_state");
set_xml_property_copy(update, XML_ATTR_ID, fsa_our_uname);
iter = create_xml_node(update, XML_CIB_TAG_LRM);
iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES);
iter = create_xml_node(iter, "lrm_resource");
set_xml_property_copy(iter, XML_ATTR_ID, rsc->id);
set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, op_type);
tmp = crm_itoa(status);
set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATE, tmp);
crm_free(tmp);
tmp = crm_itoa(rc);
set_xml_property_copy(iter, XML_LRM_ATTR_OPCODE, tmp);
crm_free(tmp);
set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname);
tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname);
add_node_copy(tmp1, update);
fragment = create_cib_fragment(tmp1, NULL);
send_request(NULL, fragment, CRM_OP_UPDATE,
fsa_our_dc, CRM_SYSTEM_DCIB, NULL);
free_xml(fragment);
free_xml(update);
free_xml(tmp1);
}
enum crmd_fsa_input
do_lrm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input cur_input,
void *data)
{
FNIN();
if(cause == C_LRM_MONITOR_CALLBACK) {
lrm_mon_t* monitor = (lrm_mon_t*)data;
lrm_rsc_t* rsc = monitor->rsc;
switch(monitor->status) {
case LRM_OP_DONE:
CRM_NOTE("An LRM monitor operation passed");
FNRET(I_NULL);
break;
case LRM_OP_CANCELLED:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
case LRM_OP_ERROR:
cl_log(LOG_ERR,
"An LRM monitor operation failed"
" or was aborted");
do_update_resource(rsc,
monitor->status,
monitor->rc,
monitor->op_type);
break;
}
} else if(cause == C_LRM_OP_CALLBACK) {
lrm_op_t* op = (lrm_op_t*)data;
lrm_rsc_t* rsc = op->rsc;
switch(op->status) {
case LRM_OP_CANCELLED:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
case LRM_OP_ERROR:
cl_log(LOG_ERR,
"An LRM operation failed"
" or was aborted");
// keep going
case LRM_OP_DONE:
do_update_resource(rsc,
op->status,
op->rc,
op->op_type);
break;
}
} else {
FNRET(I_FAIL);
}
FNRET(I_NULL);
}
diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c
index d52b7a8dce..ad452b0916 100644
--- a/crm/crmd/messages.c
+++ b/crm/crmd/messages.c
@@ -1,939 +1,903 @@
/*
* 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 <portability.h>
#include <crm/crm.h>
#include <string.h>
#include <crmd_fsa.h>
#include <libxml/tree.h>
+#include <hb_api.h>
#include <crm/msg_xml.h>
-#include <crm/common/crmutils.h>
-#include <crm/common/xmlutils.h>
-#include <crm/common/msgutils.h>
+#include <crm/common/xml.h>
+#include <crm/common/msg.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crm/dmalloc_wrapper.h>
-FILE *msg_in_strm = NULL;
+FILE *msg_out_strm = NULL;
FILE *router_strm = NULL;
fsa_message_queue_t fsa_message_queue = NULL;
gboolean relay_message(xmlNodePtr xml_relay_message,
gboolean originated_locally);
+
+gboolean send_ha_reply(ll_cluster_t *hb_cluster,
+ xmlNodePtr xml_request,
+ xmlNodePtr xml_response_data);
+
+gboolean send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root);
+
#ifdef MSG_LOG
# define ROUTER_RESULT(x) char *msg_text = dump_xml(xml_relay_message);\
if(router_strm == NULL) { \
router_strm = fopen("/tmp/router.log", "w"); \
} \
fprintf(router_strm, "[%d RESULT (%s)]\t%s\t%s\n", \
AM_I_DC, \
xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE),\
x, msg_text); \
fflush(router_strm); \
crm_free(msg_text);
#else
# define ROUTER_RESULT(x) CRM_DEBUG(x, NULL);
#endif
/* returns the current head of the FIFO queue */
fsa_message_queue_t
put_message(xmlNodePtr new_message)
{
int old_len = g_slist_length(fsa_message_queue);
// make sure to free it properly later
fsa_message_queue = g_slist_append(fsa_message_queue,
copy_xml_node_recursive(new_message));
CRM_DEBUG("Queue len: %d -> %d", old_len,
g_slist_length(fsa_message_queue));
if(old_len == g_slist_length(fsa_message_queue)){
cl_log(LOG_ERR, "Couldnt add message to the queue");
}
return fsa_message_queue;
}
/* returns the next message */
xmlNodePtr
get_message(void)
{
xmlNodePtr message = g_slist_nth_data(fsa_message_queue, 0);
fsa_message_queue = g_slist_remove(fsa_message_queue, message);
return message;
}
/* returns the current head of the FIFO queue */
gboolean
is_message(void)
{
return (g_slist_length(fsa_message_queue) > 0);
}
/* A_MSG_STORE */
enum crmd_fsa_input
do_msg_store(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
// xmlNodePtr new_message = (xmlNodePtr)data;
FNIN();
// put_message(new_message);
FNRET(I_NULL);
}
/* A_MSG_ROUTE */
enum crmd_fsa_input
do_msg_route(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
xmlNodePtr xml_message = (xmlNodePtr)data;
gboolean routed = FALSE, defer = TRUE, do_process = TRUE;
FNIN();
#if 0
// if(cause == C_IPC_MESSAGE) {
if (crmd_authorize_message(root_xml_node,
msg,
curr_client) == FALSE) {
CRM_DEBUG("Message not authorized");
do_process = FALSE;
}
// }
#endif
if(do_process) {
/* try passing the buck first */
routed = relay_message(xml_message, cause==C_IPC_MESSAGE);
if(routed == FALSE) {
defer = TRUE;
/* calculate defer */
result = handle_message(xml_message);
switch(result) {
case I_NULL:
defer = FALSE;
break;
case I_DC_HEARTBEAT:
defer = FALSE;
break;
/* what else should go here? */
default:
CRM_NOTE("Defering local processing of message");
put_message(xml_message);
result = I_REQUEST;
break;
}
}
}
FNRET(result);
}
-
-void
-crmd_ha_input_callback(const struct ha_msg* msg, void* private_data)
-{
- const char *from = ha_msg_value(msg, F_ORIG);
- const char *to = NULL;
- xmlNodePtr root_xml_node;
-
- FNIN();
-
-#ifdef MSG_LOG
- if(msg_in_strm == NULL) {
- msg_in_strm = fopen("/tmp/inbound.log", "w");
- }
-#endif
-
- if(from == NULL || strcmp(from, fsa_our_uname) == 0) {
-#ifdef MSG_LOG
- fprintf(msg_in_strm,
- "Discarded message [F_SEQ=%s] from ourselves.\n",
- ha_msg_value(msg, F_SEQ));
-#endif
- FNOUT();
- }
-
-#ifdef MSG_LOG
- fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n",
- from,
- ha_msg_value(msg, F_SEQ),
- ha_msg_value(msg, F_TYPE),
- ha_msg_value(msg, "xml")
- );
- fflush(msg_in_strm);
-#endif
-
- root_xml_node = find_xml_in_hamessage(msg);
- to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO);
-
- if(to != NULL && strlen(to) > 0 && strcmp(to, fsa_our_uname) != 0) {
-#ifdef MSG_LOG
- fprintf(msg_in_strm,
- "Discarding message [F_SEQ=%s] for someone else.",
- ha_msg_value(msg, F_SEQ));
-#endif
- FNOUT();
- }
-
- set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from);
- s_crmd_fsa(C_HA_MESSAGE, I_ROUTER, root_xml_node);
-
- free_xml(root_xml_node);
-
- FNOUT();
-}
-
-/*
- * Apparently returning TRUE means "stay connected, keep doing stuff".
- * Returning FALSE means "we're all done, close the connection"
- */
-gboolean
-crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data)
-{
- int lpc = 0;
- char *buffer = NULL;
- IPC_Message *msg = NULL;
- gboolean hack_return_good = TRUE;
- xmlNodePtr root_xml_node;
- crmd_client_t *curr_client = (crmd_client_t*)user_data;
-
- FNIN();
- CRM_DEBUG("Processing IPC message from %s",
- curr_client->table_key);
-
- while(client->ops->is_message_pending(client)) {
- if (client->ch_status == IPC_DISCONNECT) {
- /* The message which was pending for us is that
- * the IPC status is now IPC_DISCONNECT */
- break;
- }
- if (client->ops->recv(client, &msg) != IPC_OK) {
- perror("Receive failure:");
- FNRET(!hack_return_good);
- }
- if (msg == NULL) {
- cl_log(LOG_WARNING, "No message this time");
- continue;
- }
-
- lpc++;
- buffer = (char*)msg->msg_body;
- CRM_DEBUG("Processing xml from %s [text=%s]",
- curr_client->table_key, buffer);
-
- root_xml_node =
- find_xml_in_ipcmessage(msg, FALSE);
- if (root_xml_node != NULL) {
-
- if (crmd_authorize_message(root_xml_node,
- msg,
- curr_client)) {
- s_crmd_fsa(C_IPC_MESSAGE,
- I_ROUTER,
- root_xml_node);
- }
- } else {
- cl_log(LOG_INFO,
- "IPC Message was not valid... discarding.");
- }
- free_xml(root_xml_node);
- msg->msg_done(msg);
-
- msg = NULL;
- buffer = NULL;
- root_xml_node = NULL;
- }
-
- CRM_DEBUG("Processed %d messages", lpc);
-
- if (client->ch_status == IPC_DISCONNECT)
- {
- cl_log(LOG_INFO,
- "received HUP from %s",
- curr_client->table_key);
- if (curr_client != NULL) {
- struct crm_subsystem_s *the_subsystem = NULL;
-
- if (curr_client->sub_sys == NULL) {
- cl_log(LOG_WARNING,
- "Client had not registered with us yet");
- } else if (strcmp(CRM_SYSTEM_PENGINE,
- curr_client->sub_sys) == 0) {
- the_subsystem = pe_subsystem;
- } else if (strcmp(CRM_SYSTEM_TENGINE,
- curr_client->sub_sys) == 0) {
- the_subsystem = te_subsystem;
- } else if (strcmp(CRM_SYSTEM_CIB,
- curr_client->sub_sys) == 0){
- the_subsystem = cib_subsystem;
- }
-
-
- if(the_subsystem != NULL) {
- cleanup_subsystem(the_subsystem);
- } // else that was a transient client
-
- if (curr_client->table_key != NULL) {
- /*
- * Key is destroyed below: curr_client->table_key
- * Value is cleaned up by G_main_del_IPC_Channel
- */
- g_hash_table_remove(ipc_clients,
- curr_client->table_key);
- }
-
-
- if(curr_client->client_source != NULL) {
- gboolean det = G_main_del_IPC_Channel(
- curr_client->client_source);
-
- CRM_DEBUG("crm_client was %s detached",
- det?"successfully":"not");
- }
-
- crm_free(curr_client->table_key);
- crm_free(curr_client->sub_sys);
- crm_free(curr_client->uuid);
- crm_free(curr_client);
- }
- FNRET(!hack_return_good);
- }
-
- FNRET(hack_return_good);
-}
-
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_request(xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *operation, const char *host_to, const char *sys_to,
char **msg_reference)
{
gboolean was_sent = FALSE;
xmlNodePtr request = NULL;
FNIN();
msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS,
XML_ATTR_OP, operation, TRUE);
request = create_request(msg_options,
msg_data,
host_to,
sys_to,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD,
NULL,
NULL);
// xml_message_debug(request, "Final request...");
if(msg_reference != NULL) {
*msg_reference = crm_strdup(xmlGetProp(request, XML_ATTR_REFERENCE));
}
was_sent = relay_message(request, TRUE);
if(was_sent == FALSE) {
put_message(request);
}
free_xml(request);
FNRET(was_sent);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
store_request(xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *operation, const char *sys_to)
{
xmlNodePtr request = NULL;
FNIN();
msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS,
XML_ATTR_OP, operation, TRUE);
crm_debug("Storing op=%s message for later processing", operation);
request = create_request(msg_options,
msg_data,
NULL,
sys_to,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD,
NULL,
NULL);
put_message(request);
free_xml(request);
FNRET(TRUE);
}
gboolean
relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally)
{
int is_for_dc = 0;
int is_for_dcib = 0;
int is_for_crm = 0;
int is_for_cib = 0;
int is_local = 0;
gboolean dont_cc= TRUE;
gboolean processing_complete = FALSE;
const char *host_to = xmlGetProp(xml_relay_message,XML_ATTR_HOSTTO);
const char *sys_to = xmlGetProp(xml_relay_message,XML_ATTR_SYSTO);
FNIN();
if(xml_relay_message == NULL) {
cl_log(LOG_ERR, "Cannot route empty message");
FNRET(TRUE);
}
if(strcmp(CRM_OP_HELLO, xml_relay_message->name) == 0) {
/* quietly ignore */
FNRET(TRUE);
}
if(strcmp(XML_MSG_TAG, xml_relay_message->name) != 0) {
xml_message_debug(xml_relay_message,
"Bad message type, should be crm_message");
cl_log(LOG_ERR, "Ignoring message of type %s",
xml_relay_message->name);
FNRET(TRUE);
}
if(sys_to == NULL) {
xml_message_debug(xml_relay_message,
"Message did not have any value for sys_to");
cl_log(LOG_ERR, "Message did not have any value for %s",
XML_ATTR_SYSTO);
FNRET(TRUE);
}
is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0);
is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0);
is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0);
is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0);
is_local = 0;
if(host_to == NULL || strlen(host_to) == 0) {
if(is_for_dc)
is_local = 0;
else if(is_for_crm && originated_locally)
is_local = 0;
else
is_local = 1;
} else if(strcmp(fsa_our_uname, host_to) == 0) {
is_local=1;
}
#if 0
CRM_DEBUG("is_local %d", is_local);
CRM_DEBUG("is_for_dcib %d", is_for_dcib);
CRM_DEBUG("is_for_dc %d", is_for_dc);
CRM_DEBUG("is_for_crm %d", is_for_crm);
CRM_DEBUG("AM_I_DC %d", AM_I_DC);
CRM_DEBUG("sys_to %s", sys_to);
CRM_DEBUG("host_to %s", host_to);
#endif
if(is_for_dc || is_for_dcib) {
if(AM_I_DC) {
ROUTER_RESULT("Message result: DC/CRMd process");
processing_complete = FALSE; // more to be done by caller
} else if(originated_locally) {
ROUTER_RESULT("Message result: External relay to DC");
send_msg_via_ha(xml_relay_message, NULL);
processing_complete = TRUE;
} else {
ROUTER_RESULT("Message result: Discard, not DC");
processing_complete = TRUE; // discard
}
} else if(is_local && (is_for_crm || is_for_cib)) {
ROUTER_RESULT("Message result: CRMd process");
} else if(is_local) {
if(dont_cc) {
ROUTER_RESULT("Message result: Local relay");
} else {
/* The DC should also get this message */
ROUTER_RESULT("Message result: Local relay with CC");
}
send_msg_via_ipc(xml_relay_message, sys_to);
processing_complete = TRUE & dont_cc;
} else {
if(dont_cc) {
ROUTER_RESULT("Message result: External relay");
} else {
/* The DC should also get this message */
ROUTER_RESULT("Message result: External relay with CC");
}
send_msg_via_ha(xml_relay_message, host_to);
processing_complete = TRUE & dont_cc;
}
FNRET(processing_complete);
}
-void
-send_msg_via_ha(xmlNodePtr action, const char *dest_node)
-{
- FNIN();
- if (action == NULL) FNOUT();
-
- if (validate_crm_message(action, NULL, NULL, NULL) == NULL)
- {
- cl_log(LOG_ERR,
- "Relay message to (%s) via HA was invalid, ignoring",
- dest_node);
- FNOUT();
- }
-// CRM_DEBUG("Relaying message to (%s) via HA", dest_node);
- set_xml_property_copy(action, XML_ATTR_HOSTTO, dest_node);
-
- send_xmlha_message(fsa_cluster_conn, action);
- FNOUT();
-}
-
-
-void
-send_msg_via_ipc(xmlNodePtr action, const char *sys)
-{
- IPC_Channel *client_channel;
-
- FNIN();
-// cl_log(LOG_DEBUG, "relaying msg to sub_sys=%s via IPC", sys);
-
- client_channel =
- (IPC_Channel*)g_hash_table_lookup (ipc_clients, sys);
-
- if (client_channel != NULL) {
- cl_log(LOG_DEBUG, "Sending message via channel %s.", sys);
- send_xmlipc_message(client_channel, action);
- } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) {
- cl_log(LOG_ERR,
- "Sub-system (%s) has been incorporated into the CRMd.",
- sys);
- xml_message_debug(action, "Change the way we handle");
- relay_message(process_cib_message(action, TRUE), TRUE);
-
- } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
-
- do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE,
- fsa_state, I_MESSAGE, action);
-
- } else {
- cl_log(LOG_ERR,
- "Unknown Sub-system (%s)... discarding message.",
- sys);
- }
- FNOUT();
-}
-
gboolean
crmd_authorize_message(xmlNodePtr root_xml_node,
IPC_Message *client_msg,
crmd_client_t *curr_client)
{
// check the best case first
const char *sys_from = xmlGetProp(root_xml_node,
XML_ATTR_SYSFROM);
char *uuid = NULL;
char *client_name = NULL;
char *major_version = NULL;
char *minor_version = NULL;
const char *filtered_from;
gpointer table_key = NULL;
gboolean result;
const char *op = get_xml_attr(root_xml_node, XML_TAG_OPTIONS,
XML_ATTR_OP, TRUE);
FNIN();
if (safe_str_neq(CRM_OP_HELLO, op)) {
if(sys_from == NULL) {
return FALSE;
}
gboolean can_reply = FALSE; // no-one has registered with this id
filtered_from = sys_from;
/* The CIB can have two names on the DC */
if(strcmp(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("Message reply can%s be routed from %s.",
can_reply?"":" not", sys_from);
if(can_reply == FALSE) {
cl_log(LOG_ERR, "Message not authorized");
}
return can_reply;
}
cl_log(LOG_INFO,
"received client join msg: %s",
(char*)client_msg->msg_body);
result = process_hello_message(root_xml_node,
&uuid,
&client_name,
&major_version,
&minor_version);
if (result == TRUE) {
// check version
int mav = atoi(major_version);
int miv = atoi(minor_version);
if (mav < 0 || miv < 0) {
cl_log(LOG_ERR,
"Client version (%d:%d) is not acceptable",
mav,
miv);
result = FALSE;
}
crm_free(major_version);
crm_free(minor_version);
}
struct crm_subsystem_s *the_subsystem = NULL;
if (result == TRUE) {
/* if we already have one of those clients
* only applies to te, pe etc. not admin clients
*/
if (client_name == NULL)
cl_log(LOG_WARNING,
"Client had not registered with us yet");
else if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0)
the_subsystem = pe_subsystem;
else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0)
the_subsystem = te_subsystem;
else if (strcmp(CRM_SYSTEM_CIB, client_name) == 0)
the_subsystem = cib_subsystem;
if (the_subsystem != NULL) {
// do we already have one?
result =(fsa_input_register & the_subsystem->flag)==0;
if(result) {
the_subsystem->ipc =
curr_client->client_channel;
} // else we didnt ask for the client to start
} else if(client_name != NULL && uuid != NULL) {
table_key = (gpointer)
generate_hash_key(client_name, uuid);
} else {
result = FALSE;
cl_log(LOG_ERR,
"Bad client details (client_name=%s, uuid=%s)",
client_name, uuid);
}
}
if(result == TRUE && table_key == NULL) {
table_key = (gpointer)crm_strdup(client_name);
}
if (result == TRUE) {
cl_log(LOG_INFO, "Accepted client %s", (char*)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");
cl_log(LOG_INFO, "Updated client list with %s",
(char*)table_key);
if(the_subsystem != NULL) {
set_bit_inplace(&fsa_input_register,
the_subsystem->flag);
}
s_crmd_fsa(C_SUBSYSTEM_CONNECT, I_NULL, NULL);
} else {
cl_log(LOG_ERR, "Rejected client logon request");
curr_client->client_channel->ch_status = IPC_DISC_PENDING;
}
if(uuid != NULL) crm_free(uuid);
if(client_name != NULL) crm_free(client_name);
/* hello messages should never be processed further */
return FALSE;
}
enum crmd_fsa_input
handle_message(xmlNodePtr stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
- const char *sys_to = get_xml_attr(stored_msg, NULL,
- XML_ATTR_SYSTO, TRUE);
+ const char *sys_to = get_xml_attr(
+ stored_msg, NULL, XML_ATTR_SYSTO, TRUE);
- const char *sys_from = get_xml_attr(stored_msg, NULL,
- XML_ATTR_SYSFROM, TRUE);
+ const char *sys_from = get_xml_attr(
+ stored_msg, NULL, XML_ATTR_SYSFROM, TRUE);
- const char *host_from= get_xml_attr(stored_msg, NULL,
- XML_ATTR_HOSTFROM, TRUE);
+ const char *host_from= get_xml_attr(
+ stored_msg, NULL, XML_ATTR_HOSTFROM, TRUE);
- const char *msg_ref = get_xml_attr(stored_msg, NULL,
- XML_ATTR_REFERENCE, TRUE);
+ const char *msg_ref = get_xml_attr(
+ stored_msg, NULL, XML_ATTR_REFERENCE, TRUE);
- const char *type = get_xml_attr(stored_msg, NULL,
- XML_ATTR_MSGTYPE, TRUE);
+ const char *type = get_xml_attr(
+ stored_msg, NULL, XML_ATTR_MSGTYPE, TRUE);
- const char *op = get_xml_attr(stored_msg, XML_TAG_OPTIONS,
- XML_ATTR_OP, TRUE);
+ const char *op = get_xml_attr(
+ stored_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE);
// xml_message_debug(stored_msg, "Processing message");
cl_log(LOG_DEBUG,
"Received %s %s in state %s",
op, type, fsa_state2string(fsa_state));
if(type == NULL || op == NULL) {
cl_log(LOG_ERR, "Ignoring message (type=%s), (op=%s)",
type, op);
xml_message_debug(stored_msg, "Bad message");
} else if(strcmp(type, XML_ATTR_REQUEST) == 0){
if(strcmp(op, CRM_OP_VOTE) == 0) {
next_input = I_ELECTION;
} else if(AM_I_DC && strcmp(op, CRM_OP_TEABORT) == 0) {
next_input = I_PE_CALC;
} else if(AM_I_DC
&& strcmp(op, CRM_OP_TECOMPLETE) == 0) {
if(fsa_state == S_TRANSITION_ENGINE) {
next_input = I_SUCCESS;
/* silently ignore? probably means the TE is signaling OK too early
} else {
cl_log(LOG_WARNING,
"Op %s is only valid in state %s (%s)",
op,
fsa_state2string(S_TRANSITION_ENGINE),
fsa_state2string(fsa_state));
*/
}
} else if(strcmp(op, CRM_OP_HBEAT) == 0) {
next_input = I_DC_HEARTBEAT;
} else if(strcmp(op, CRM_OP_WELCOME) == 0) {
next_input = I_WELCOME;
} else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
/* create cib fragment and add to message */
/* 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
*/
xmlNodePtr frag = NULL;
time_t now = time(NULL);
char *now_s = crm_itoa((int)now);
xmlNodePtr node_state =
create_xml_node(NULL, XML_CIB_TAG_STATE);
cl_log(LOG_INFO, "Creating shutdown request for %s",
host_from);
set_xml_property_copy(
node_state, XML_ATTR_ID, host_from);
set_xml_property_copy(
node_state, XML_CIB_ATTR_SHUTDOWN, now_s);
set_xml_property_copy(
node_state,
XML_CIB_ATTR_EXPSTATE,
CRMD_STATE_INACTIVE);
frag = create_cib_fragment(node_state, NULL);
xmlAddChild(stored_msg, frag);
free_xml(node_state);
crm_free(now_s);
next_input = I_CIB_OP;
} else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) {
next_input = I_TERMINATE;
} else if(strcmp(op, CRM_OP_ANNOUNCE) == 0) {
next_input = I_NODE_JOIN;
} else if(strcmp(op, CRM_OP_REPLACE) == 0
|| strcmp(op, CRM_OP_ERASE) == 0) {
next_input = I_CIB_OP;
fprintf(router_strm, "Message result: CIB Op\n");
} else if(AM_I_DC
&& (strcmp(op, CRM_OP_CREATE) == 0
|| strcmp(op, CRM_OP_UPDATE) == 0
|| strcmp(op, CRM_OP_DELETE) == 0)) {
/* updates should only be performed on the DC */
next_input = I_CIB_OP;
} else if(strcmp(op, CRM_OP_PING) == 0) {
/* eventually do some stuff to figure out
* if we /are/ ok
*/
xmlNodePtr ping =
createPingAnswerFragment(sys_to, "ok");
xmlNodePtr wrapper = create_reply(stored_msg, ping);
relay_message(wrapper, TRUE);
free_xml(wrapper);
} else {
cl_log(LOG_ERR,
"Unexpected request (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
}
} else if(strcmp(type, XML_ATTR_RESPONSE) == 0) {
if(strcmp(op, CRM_OP_WELCOME) == 0) {
next_input = I_WELCOME_ACK;
} else if(AM_I_DC
&& strcmp(op, CRM_OP_PECALC) == 0) {
if(fsa_state == S_POLICY_ENGINE
&& safe_str_eq(msg_ref, fsa_pe_ref)) {
next_input = I_SUCCESS;
} else if(fsa_state != S_POLICY_ENGINE) {
cl_log(LOG_ERR,
"Reply to %s is only valid in state %s",
op, fsa_state2string(S_POLICY_ENGINE));
} else {
CRM_DEBUG("Skipping superceeded reply from %s",
sys_from);
}
} else if(strcmp(op, CRM_OP_VOTE) == 0
|| strcmp(op, CRM_OP_HBEAT) == 0
|| strcmp(op, CRM_OP_WELCOME) == 0
|| strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcmp(op, CRM_OP_SHUTDOWN) == 0
|| strcmp(op, CRM_OP_ANNOUNCE) == 0) {
next_input = I_NULL;
} else if(strcmp(op, CRM_OP_CREATE) == 0
|| strcmp(op, CRM_OP_UPDATE) == 0
|| strcmp(op, CRM_OP_DELETE) == 0
|| strcmp(op, CRM_OP_REPLACE) == 0
|| strcmp(op, CRM_OP_ERASE) == 0) {
/* perhaps we should do somethign with these replies,
* especially check that the actions passed
*/
/* fprintf(router_strm, "Message result: CIB Reply\n"); */
} else {
cl_log(LOG_ERR,
"Unexpected response (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
next_input = I_NULL;
}
} else {
cl_log(LOG_ERR, "Unexpected message type %s", type);
}
/* CRM_DEBUG("%s: Next input is %s", __FUNCTION__, */
/* fsa_input2string(next_input)); */
return next_input;
}
+gboolean
+send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root)
+{
+ int xml_len = -1;
+ int send_result = -1;
+ char *xml_text = NULL;
+ const char *host_to = NULL;
+ const char *sys_to = NULL;
+ struct ha_msg *msg = NULL;
+ gboolean all_is_good = TRUE;
+ gboolean broadcast = FALSE;
+ int log_level = LOG_DEBUG;
+
+ xmlNodePtr opts = find_xml_node(root, XML_TAG_OPTIONS);
+ const char *op = xmlGetProp(opts, XML_ATTR_OP);
-void lrm_op_callback (lrm_op_t* op)
+#ifdef MSG_LOG
+ char *msg_text = NULL;
+#endif
+
+ FNIN();
+
+ if (root == NULL) {
+ cl_log(LOG_ERR, "Attempt to send NULL Message via HA failed.");
+ all_is_good = FALSE;
+ }
+
+ host_to = xmlGetProp(root, XML_ATTR_HOSTTO);
+ sys_to = xmlGetProp(root, XML_ATTR_SYSTO);
+
+ if (all_is_good) {
+ msg = ha_msg_new(4);
+ ha_msg_add(msg, F_TYPE, "CRM");
+ ha_msg_add(msg, F_COMMENT, "A CRM xml message");
+ xml_text = dump_xml(root);
+ xml_len = strlen(xml_text);
+
+ if (xml_text == NULL || xml_len <= 0) {
+ cl_log(LOG_ERR,
+ "Failed sending an invalid XML Message via HA");
+ all_is_good = FALSE;
+ xml_message_debug(root, "Bad message was");
+
+ } else {
+ if(ha_msg_add(msg, "xml", xml_text) == HA_FAIL) {
+ cl_log(LOG_ERR,
+ "Could not add xml to HA message");
+ all_is_good = FALSE;
+ }
+ }
+ }
+
+ if (all_is_good) {
+ if (sys_to == NULL || strlen(sys_to) == 0)
+ {
+ cl_log(LOG_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) {
+ broadcast = TRUE;
+ send_result =
+ hb_fd->llc_ops->sendclustermsg(hb_fd, msg);
+ }
+ else {
+ send_result = hb_fd->llc_ops->send_ordered_nodemsg(
+ hb_fd, msg, host_to);
+ }
+
+ if(send_result != HA_OK)
+ all_is_good = FALSE;
+ }
+
+ if(all_is_good == FALSE) {
+ log_level = LOG_ERR;
+ }
+
+ if(log_level == LOG_ERR
+ || (safe_str_neq(op, CRM_OP_HBEAT))) {
+ cl_log(log_level,
+ "Sending %s HA message (ref=%s, len=%d) to %s@%s %s.",
+ broadcast?"broadcast":"directed",
+ xmlGetProp(root, XML_ATTR_REFERENCE), xml_len,
+ sys_to, host_to==NULL?"<all>":host_to,
+ all_is_good?"succeeded":"failed");
+ }
+
+#ifdef MSG_LOG
+ msg_text = dump_xml(root);
+ if(msg_out_strm == NULL) {
+ msg_out_strm = fopen("/tmp/outbound.log", "w");
+ }
+ fprintf(msg_out_strm, "[%d HA (%s:%d)]\t%s\n",
+ all_is_good,
+ xmlGetProp(root, XML_ATTR_REFERENCE),
+ send_result,
+ msg_text);
+
+ fflush(msg_out_strm);
+ crm_free(msg_text);
+ if(msg != NULL) {
+ ha_msg_del(msg);
+ }
+#endif
+
+ FNRET(all_is_good);
+}
+
+
+
+// required? or just send to self an let relay_message do its thing?
+/*
+ * This method adds a copy of xml_response_data
+ */
+gboolean
+send_ha_reply(ll_cluster_t *hb_cluster,
+ xmlNodePtr xml_request,
+ xmlNodePtr xml_response_data)
{
- s_crmd_fsa(C_LRM_OP_CALLBACK, I_LRM_EVENT, op);
+ gboolean was_sent = FALSE;
+ xmlNodePtr reply;
+
+ FNIN();
+ was_sent = FALSE;
+ reply = create_reply(xml_request, xml_response_data);
+ if (reply != NULL) {
+ was_sent = send_xmlha_message(hb_cluster, reply);
+ free_xml(reply);
+ }
+ FNRET(was_sent);
}
-void lrm_monitor_callback (lrm_mon_t* monitor)
+
+void
+send_msg_via_ha(xmlNodePtr action, const char *dest_node)
{
- s_crmd_fsa(C_LRM_MONITOR_CALLBACK, I_LRM_EVENT, monitor);
+ FNIN();
+ if (action == NULL) FNOUT();
+
+ if (validate_crm_message(action, NULL, NULL, NULL) == NULL)
+ {
+ cl_log(LOG_ERR,
+ "Relay message to (%s) via HA was invalid, ignoring",
+ dest_node);
+ FNOUT();
+ }
+// CRM_DEBUG("Relaying message to (%s) via HA", dest_node);
+ set_xml_property_copy(action, XML_ATTR_HOSTTO, dest_node);
+
+ send_xmlha_message(fsa_cluster_conn, action);
+ FNOUT();
}
+
+void
+send_msg_via_ipc(xmlNodePtr action, const char *sys)
+{
+ IPC_Channel *client_channel;
+
+ FNIN();
+// cl_log(LOG_DEBUG, "relaying msg to sub_sys=%s via IPC", sys);
+
+ client_channel =
+ (IPC_Channel*)g_hash_table_lookup (ipc_clients, sys);
+
+ if (client_channel != NULL) {
+ cl_log(LOG_DEBUG, "Sending message via channel %s.", sys);
+ send_xmlipc_message(client_channel, action);
+ } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) {
+ cl_log(LOG_ERR,
+ "Sub-system (%s) has been incorporated into the CRMd.",
+ sys);
+ xml_message_debug(action, "Change the way we handle");
+ relay_message(process_cib_message(action, TRUE), TRUE);
+
+ } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
+
+ do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE,
+ fsa_state, I_MESSAGE, action);
+
+ } else {
+ cl_log(LOG_ERR,
+ "Unknown Sub-system (%s)... discarding message.",
+ sys);
+ }
+ FNOUT();
+}
diff --git a/crm/crmd/misc.c b/crm/crmd/misc.c
index 8c258b5896..ff372015c3 100644
--- a/crm/crmd/misc.c
+++ b/crm/crmd/misc.c
@@ -1,97 +1,54 @@
/*
* 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 <portability.h>
+#include <heartbeat.h>
+
#include <crm/crm.h>
-#include <crm/msg_xml.h>
#include <crm/cib.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+
#include <crmd_fsa.h>
#include <crmd_messages.h>
-#include <crm/common/xmlutils.h>
-
-#include <heartbeat.h>
#include <crm/dmalloc_wrapper.h>
/* A_LOG, A_WARN, A_ERROR */
enum crmd_fsa_input
do_log(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
int log_type = LOG_DEBUG;
FNIN();
if(action & A_LOG) log_type = LOG_INFO;
if(action & A_WARN) log_type = LOG_WARNING;
if(action & A_ERROR) log_type = LOG_ERR;
cl_log(log_type,
"[[FSA]] Input (%s) was received while in state (%s)",
fsa_input2string(current_input),
fsa_state2string(cur_state));
FNRET(I_NULL);
}
-void
-CrmdClientStatus(const char * node, const char * client,
- const char * status, void * private)
-{
- const char *join = NULL;
- const char *extra = NULL;
- xmlNodePtr update = NULL;
- xmlNodePtr fragment = NULL;
-
- if(safe_str_eq(status, JOINSTATUS)){
- status = ONLINESTATUS;
- extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
-
- } else if(safe_str_eq(status, LEAVESTATUS)){
- status = OFFLINESTATUS;
- join = CRMD_JOINSTATE_DOWN;
- extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
- }
-
- cl_log(LOG_NOTICE,
- "Status update: Client %s/%s now has status [%s]\n",
- node, client, status);
-
- if(AM_I_DC) {
- update = create_node_state(node, NULL, status, join);
-
- if(extra != NULL) {
- set_xml_property_copy(update, extra, XML_BOOLEAN_TRUE);
- }
-
- fragment = create_cib_fragment(update, NULL);
- store_request(NULL, fragment,
- CRM_OP_UPDATE, CRM_SYSTEM_DCIB);
-
- free_xml(fragment);
- free_xml(update);
-
- s_crmd_fsa(C_CRMD_STATUS_CALLBACK, I_NULL, NULL);
-
- } else {
- cl_log(LOG_ERR, "Got client status callback in non-DC mode");
- }
-}
-
diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c
index 7705a5215e..5d462690f2 100644
--- a/crm/crmd/subsystems.c
+++ b/crm/crmd/subsystems.c
@@ -1,641 +1,635 @@
/*
* 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 <portability.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 <crm/common/crmutils.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/msgutils.h>
+#include <errno.h>
#include <crm/msg_xml.h>
-#include <crm/common/xmlutils.h>
-
+#include <crm/common/xml.h>
+#include <crmd_messages.h>
#include <crm/cib.h>
-
#include <crmd.h>
-#include <crmd_messages.h>
-#include <string.h>
-#include <errno.h>
#include <crm/dmalloc_wrapper.h>
#define CLIENT_EXIT_WAIT 10
static gboolean stop_subsystem (struct crm_subsystem_s *centry);
static gboolean start_subsystem(struct crm_subsystem_s *centry);
struct crm_subsystem_s *cib_subsystem = NULL;
struct crm_subsystem_s *te_subsystem = NULL;
struct crm_subsystem_s *pe_subsystem = NULL;
/* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */
enum crmd_fsa_input
do_cib_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = cib_subsystem;
long long stop_actions = A_CIB_STOP;
long long start_actions = A_CIB_START;
FNIN();
if(action & stop_actions) {
// dont do anything, its embedded now
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(startCib(CIB_FILENAME) == FALSE)
result = I_FAIL;
} else {
cl_log(LOG_INFO,
"Ignoring request to start %s after shutdown",
this_subsys->command);
}
}
FNRET(result);
}
/* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */
enum crmd_fsa_input
do_cib_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr cib_msg = NULL;
xmlNodePtr answer = NULL;
xmlNodePtr new_options = NULL;
const char *section = NULL;
FNIN();
if(data != NULL) {
cib_msg = (xmlNodePtr)data;
}
if(action & A_CIB_INVOKE) {
const char *op = get_xml_attr(cib_msg, XML_TAG_OPTIONS,
XML_ATTR_OP, TRUE);
xml_message_debug(cib_msg, "[CIB] Invoking with");
if(cib_msg == NULL) {
cl_log(LOG_ERR, "No message for CIB command");
FNRET(I_NULL); // I_ERROR
}
set_xml_property_copy(cib_msg, XML_ATTR_SYSTO, "cib");
answer = process_cib_message(cib_msg, TRUE);
if(relay_message(answer, TRUE) == FALSE) {
cl_log(LOG_ERR, "Confused what to do with cib result");
xml_message_debug(answer, "Couldnt route: ");
}
if(op != NULL && AM_I_DC
&& (strcmp(op, CRM_OP_CREATE) == 0
|| strcmp(op, CRM_OP_UPDATE) == 0
|| strcmp(op, CRM_OP_DELETE) == 0
|| strcmp(op, CRM_OP_REPLACE) == 0
|| strcmp(op, CRM_OP_WELCOME) == 0
|| strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcmp(op, CRM_OP_ERASE) == 0)) {
FNRET(I_CIB_UPDATE);
}
if(op == NULL) {
xml_message_debug(cib_msg, "Invalid CIB Message");
}
// check the answer, see if we are interested in it also
#if 0
if(interested in reply) {
put_message(answer);
FNRET(I_REQUEST);
}
#endif
free_xml(answer);
/* experimental */
} else if(action & A_CIB_INVOKE_LOCAL) {
xml_message_debug(cib_msg, "[CIB] Invoking with");
if(cib_msg == NULL) {
cl_log(LOG_ERR, "No message for CIB command");
FNRET(I_NULL); // I_ERROR
}
answer = process_cib_message(cib_msg, TRUE);
put_message(answer);
FNRET(I_REQUEST);
} else if(action & A_CIB_BUMPGEN) {
// check if the response was ok before next bit
section = get_xml_attr(cib_msg, XML_TAG_OPTIONS,
XML_ATTR_FILTER_TYPE, FALSE);
/* set the section so that we dont always send the
* whole thing
*/
if(section != NULL) {
new_options = set_xml_attr(NULL, XML_TAG_OPTIONS,
XML_ATTR_FILTER_TYPE,
section, TRUE);
}
answer = process_cib_request(CRM_OP_BUMP,
new_options, NULL);
free_xml(new_options);
if(answer == NULL) {
cl_log(LOG_ERR, "Result of BUMP in %s was NULL",
__FUNCTION__);
FNRET(I_FAIL);
}
send_request(NULL, answer, CRM_OP_REPLACE,
NULL, CRM_SYSTEM_CRMD, NULL);
free_xml(answer);
} else {
cl_log(LOG_ERR, "Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
FNRET(I_NULL);
}
/* A_PE_START, A_PE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_pe_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = pe_subsystem;
long long stop_actions = A_PE_STOP;
long long start_actions = A_PE_START;
FNIN();
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE)
result = I_FAIL;
else if(this_subsys->pid > 0){
int lpc = CLIENT_EXIT_WAIT;
int pid_status = -1;
while(lpc-- > 0
&& this_subsys->pid > 0
&& CL_PID_EXISTS(this_subsys->pid)) {
sleep(1);
waitpid(this_subsys->pid, &pid_status, WNOHANG);
}
if(CL_PID_EXISTS(this_subsys->pid)) {
cl_log(LOG_ERR,
"Process %s is still active with pid=%d",
this_subsys->command, this_subsys->pid);
result = I_FAIL;
}
}
cleanup_subsystem(this_subsys);
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
result = I_FAIL;
cleanup_subsystem(this_subsys);
}
} else {
cl_log(LOG_INFO,
"Ignoring request to start %s while shutting down",
this_subsys->command);
}
}
FNRET(result);
}
char *fsa_pe_ref = NULL;
/* A_PE_INVOKE */
enum crmd_fsa_input
do_pe_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
stopTimer(integration_timer);
if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){
cl_log(LOG_INFO, "Waiting for the PE to connect");
FNRET(I_WAIT_FOR_EVENT);
}
xmlNodePtr local_cib = get_cib_copy();
CRM_DEBUG("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib);
if(fsa_pe_ref) {
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
}
send_request(NULL, local_cib, CRM_OP_PECALC,
NULL, CRM_SYSTEM_PENGINE, &fsa_pe_ref);
FNRET(I_NULL);
}
/* A_TE_START, A_TE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_te_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = te_subsystem;
long long stop_actions = A_TE_STOP;
long long start_actions = A_TE_START;
FNIN();
/* if(action & stop_actions && cur_state != S_STOPPING */
/* && is_set(fsa_input_register, R_TE_PEND)) { */
/* result = I_WAIT_FOR_EVENT; */
/* FNRET(result); */
/* } */
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE)
result = I_FAIL;
else if(this_subsys->pid > 0){
int lpc = CLIENT_EXIT_WAIT;
int pid_status = -1;
while(lpc-- > 0
&& this_subsys->pid > 0
&& CL_PID_EXISTS(this_subsys->pid)) {
sleep(1);
waitpid(this_subsys->pid, &pid_status, WNOHANG);
}
if(CL_PID_EXISTS(this_subsys->pid)) {
cl_log(LOG_ERR,
"Process %s is still active with pid=%d",
this_subsys->command, this_subsys->pid);
result = I_FAIL;
}
}
cleanup_subsystem(this_subsys);
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
result = I_FAIL;
cleanup_subsystem(this_subsys);
}
} else {
cl_log(LOG_INFO,
"Ignoring request to start %s while shutting down",
this_subsys->command);
}
}
FNRET(result);
}
static xmlNodePtr te_last_input = NULL;
static xmlNodePtr te_lastcc = NULL;
/* A_TE_COPYTO */
enum crmd_fsa_input
do_te_copyto(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr message = NULL;
xmlNodePtr opts = NULL;
const char *true_op = NULL;
FNIN();
if(data != NULL) {
message = copy_xml_node_recursive((xmlNodePtr)data);
opts = find_xml_node(message, XML_TAG_OPTIONS);
true_op = xmlGetProp(opts, XML_ATTR_OP);
set_xml_property_copy(opts, XML_ATTR_OP, CRM_OP_EVENTCC);
set_xml_property_copy(opts, XML_ATTR_TRUEOP, true_op);
set_xml_property_copy(message,
XML_ATTR_SYSTO,
CRM_SYSTEM_TENGINE);
}
if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){
cl_log(LOG_INFO, "Waiting for the TE to connect");
if(data != NULL) {
free_xml(te_lastcc);
te_lastcc = message;
}
FNRET(I_WAIT_FOR_EVENT);
}
if(message == NULL) {
message = te_lastcc;
te_lastcc = NULL;
} else {
free_xml(te_lastcc);
}
relay_message(message, FALSE);
// only free it if it was a local copy
if(data == NULL) {
free_xml(message);
}
FNRET(I_NULL);
}
/* A_TE_INVOKE, A_TE_CANCEL */
enum crmd_fsa_input
do_te_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr graph = NULL;
xmlNodePtr msg = (xmlNodePtr)data;
FNIN();
if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){
cl_log(LOG_INFO, "Waiting for the TE to connect");
if(data != NULL) {
free_xml(te_last_input);
te_last_input = copy_xml_node_recursive(msg);
}
FNRET(I_WAIT_FOR_EVENT);
}
if(msg == NULL) {
msg = te_last_input;
te_last_input = NULL;
} else {
free_xml(te_last_input);
}
if(action & A_TE_INVOKE) {
graph = find_xml_node(msg, "transition_graph");
if(graph == NULL) {
FNRET(I_FAIL);
}
send_request(NULL, graph, CRM_OP_TRANSITION,
NULL, CRM_SYSTEM_TENGINE, NULL);
} else {
send_request(NULL, graph, CRM_OP_ABORT,
NULL, CRM_SYSTEM_TENGINE, NULL);
}
// only free it if it was a local copy
if(data == NULL) {
free_xml(msg);
}
FNRET(I_NULL);
}
gboolean
crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
{
FNIN();
if (client_channel == NULL) {
cl_log(LOG_ERR, "Channel was NULL");
} else if (client_channel->ch_status == IPC_DISCONNECT) {
cl_log(LOG_ERR, "Channel was disconnected");
} else {
crmd_client_t *blank_client =
(crmd_client_t *)crm_malloc(sizeof(crmd_client_t));
if (blank_client == NULL) {
cl_log(LOG_ERR,
"Could not allocate memory for a blank crmd_client_t");
FNRET(FALSE);
}
client_channel->ops->set_recv_qlen(client_channel, 100);
client_channel->ops->set_send_qlen(client_channel, 100);
blank_client->client_channel = client_channel;
blank_client->sub_sys = NULL;
blank_client->uuid = NULL;
blank_client->table_key = NULL;
blank_client->client_source =
G_main_add_IPC_Channel(G_PRIORITY_LOW,
client_channel,
FALSE,
crmd_ipc_input_callback,
blank_client,
default_ipc_input_destroy);
}
FNRET(TRUE);
}
static gboolean
stop_subsystem(struct crm_subsystem_s* centry)
{
cl_log(LOG_INFO, "Stopping sub-system \"%s\"", centry->name);
if (centry->pid <= 0) {
cl_log(LOG_ERR,
"OOPS! client %s not running yet",
centry->command);
} else {
cl_log(LOG_INFO, "Sending quit message to %s.", centry->name);
send_request(NULL, NULL, CRM_OP_QUIT, NULL, centry->name, NULL);
}
return TRUE;
}
static gboolean
start_subsystem(struct crm_subsystem_s* centry)
{
pid_t pid;
struct stat buf;
int s_res;
cl_log(LOG_INFO, "Starting sub-system \"%s\"", centry->command);
if (centry->pid != 0) {
cl_log(LOG_ERR, "OOPS! client %s already running as pid %d"
, centry->command, (int) centry->pid);
}
/*
* We need to ensure that the exec will succeed before
* we bother forking. We don't want to respawn something that
* won't exec in the first place.
*/
if (access(centry->path, F_OK|X_OK) != 0) {
cl_perror("Cannot (access) exec %s", centry->path);
return FALSE;
}
s_res = stat(centry->command, &buf);
if(s_res != 0) {
cl_perror("Cannot (stat) exec %s", centry->command);
return FALSE;
}
/* We need to fork so we can make child procs not real time */
switch(pid=fork()) {
case -1:
cl_log(LOG_ERR, "start_a_child_client: Cannot fork.");
return FALSE;
default: /* Parent */
centry->pid = pid;
return TRUE;
case 0: /* Child */
break;
}
/* Child process: start the managed child */
cl_make_normaltime();
setpgid(0,0);
/* Limit peak resource usage, maximize success chances */
if (centry->shortrcount > 0) {
alarm(0);
sleep(1);
}
cl_log(LOG_INFO, "Executing \"%s\" (pid %d)",
centry->command, (int) getpid());
if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) {
cl_perror("Cannot set interrupt for child process %s",
centry->command);
}else{
const char * devnull = "/dev/null";
unsigned int j;
struct rlimit oflimits;
CL_SIGNAL(SIGCHLD, SIG_DFL);
alarm(0);
CL_IGNORE_SIG(SIGALRM);
/* A precautionary measure */
getrlimit(RLIMIT_NOFILE, &oflimits);
for (j=0; j < oflimits.rlim_cur; ++j) {
close(j);
}
(void)devnull;
(void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
(void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
(void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
(void)execl("/bin/sh", "sh", "-c", centry->command, (const char *)NULL);
/* Should not happen */
cl_perror("Cannot exec %s", centry->command);
}
/* Suppress respawning */
exit(100);
// never reached
return TRUE;
}
diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c
index c87ab7dc99..1b956a4e9d 100644
--- a/crm/crmd/utils.c
+++ b/crm/crmd/utils.c
@@ -1,648 +1,643 @@
/*
* 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 <portability.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
-#include <libxml/tree.h>
-#include <crm/msg_xml.h>
#include <clplumbing/Gmain_timeout.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <crm/common/xmlutils.h>
-#include <crm/common/ipcutils.h>
-#include <crm/common/msgutils.h>
-#include <crm/cib.h>
-#include <string.h>
-#include <crmd_messages.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/common/msg.h>
#include <crm/dmalloc_wrapper.h>
gboolean
timer_popped(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
cl_log(LOG_INFO, "#!!#!!# Timer %s just popped!",
fsa_input2string(timer->fsa_input));
stopTimer(timer); // dont make it go off again
s_crmd_fsa(C_TIMER_POPPED, timer->fsa_input, NULL);
return TRUE;
}
gboolean
startTimer(fsa_timer_t *timer)
{
if(((int)timer->source_id) < 0) {
timer->source_id =
Gmain_timeout_add(timer->period_ms,
timer->callback,
(void*)timer);
/*
CRM_DEBUG("#!!#!!# Started %s timer (%d)",
fsa_input2string(timer->fsa_input),
timer->source_id);
*/
} else {
cl_log(LOG_INFO, "#!!#!!# Timer %s already running (%d)",
fsa_input2string(timer->fsa_input),
timer->source_id);
return FALSE;
}
return TRUE;
}
gboolean
stopTimer(fsa_timer_t *timer)
{
if(((int)timer->source_id) > 0) {
/*
CRM_DEBUG("#!!#!!# Stopping %s timer (%d)",
fsa_input2string(timer->fsa_input),
timer->source_id);
*/
g_source_remove(timer->source_id);
timer->source_id = -2;
} else {
cl_log(LOG_INFO, "#!!#!!# Timer %s already stopped (%d)",
fsa_input2string(timer->fsa_input),
timer->source_id);
return FALSE;
}
return TRUE;
}
long long
toggle_bit(long long action_list, long long action)
{
// CRM_DEBUG("Toggling bit %.16llx", action);
action_list ^= action;
// CRM_DEBUG("Result %.16llx", action_list & action);
return action_list;
}
long long
clear_bit(long long action_list, long long action)
{
// CRM_DEBUG("Clearing bit\t%.16llx", action);
// ensure its set
action_list |= action;
// then toggle
action_list = action_list ^ action;
return action_list;
}
long long
set_bit(long long action_list, long long action)
{
// CRM_DEBUG("Adding bit\t%.16llx", action);
action_list |= action;
return action_list;
}
void
toggle_bit_inplace(long long *action_list, long long action)
{
*action_list = toggle_bit(*action_list, action);
}
void
clear_bit_inplace(long long *action_list, long long action)
{
*action_list = clear_bit(*action_list, action);
}
void
set_bit_inplace(long long *action_list, long long action)
{
*action_list = set_bit(*action_list, action);
}
gboolean
is_set(long long action_list, long long action)
{
// CRM_DEBUG("Checking bit\t%.16llx", action);
return ((action_list & action) == action);
}
xmlNodePtr
create_node_state(const char *node,
const char *ccm_state,
const char *crmd_state,
const char *join_state)
{
xmlNodePtr node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_xml_property_copy(node_state, XML_ATTR_ID, node);
if(ccm_state != NULL) {
set_xml_property_copy(node_state, XML_CIB_ATTR_INCCM, ccm_state);
}
if(crmd_state != NULL) {
set_xml_property_copy(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state);
}
if(join_state != NULL) {
set_xml_property_copy(node_state, XML_CIB_ATTR_JOINSTATE, join_state);
}
/* if(exp_state != NULL) { */
/* set_xml_property_copy(node_state, XML_CIB_ATTR_EXPSTATE, exp_state); */
/* } */
/* if(lrm_data != NULL) { */
/* // set_xml_property_copy(data, "replace", XML_CIB_TAG_LRM); */
/* add_node_copy(node_state, lrm_data); */
/* } */
xml_message_debug(node_state, "created");
return node_state;
}
const char *
fsa_input2string(enum crmd_fsa_input input)
{
const char *inputAsText = NULL;
switch(input){
case I_NULL:
inputAsText = "I_NULL";
break;
case I_CCM_EVENT:
inputAsText = "I_CCM_EVENT";
break;
case I_CIB_OP:
inputAsText = "I_CIB_OP";
break;
case I_CIB_UPDATE:
inputAsText = "I_CIB_UPDATE";
break;
case I_DC_TIMEOUT:
inputAsText = "I_DC_TIMEOUT";
break;
case I_ELECTION:
inputAsText = "I_ELECTION";
break;
case I_PE_CALC:
inputAsText = "I_PE_CALC";
break;
case I_RELEASE_DC:
inputAsText = "I_RELEASE_DC";
break;
case I_ELECTION_DC:
inputAsText = "I_ELECTION_DC";
break;
case I_ERROR:
inputAsText = "I_ERROR";
break;
case I_FAIL:
inputAsText = "I_FAIL";
break;
case I_INTEGRATION_TIMEOUT:
inputAsText = "I_INTEGRATION_TIMEOUT";
break;
case I_NODE_JOIN:
inputAsText = "I_NODE_JOIN";
break;
case I_NODE_LEFT:
inputAsText = "I_NODE_LEFT";
break;
case I_NOT_DC:
inputAsText = "I_NOT_DC";
break;
case I_RECOVERED:
inputAsText = "I_RECOVERED";
break;
case I_RELEASE_FAIL:
inputAsText = "I_RELEASE_FAIL";
break;
case I_RELEASE_SUCCESS:
inputAsText = "I_RELEASE_SUCCESS";
break;
case I_RESTART:
inputAsText = "I_RESTART";
break;
case I_REQUEST:
inputAsText = "I_REQUEST";
break;
case I_ROUTER:
inputAsText = "I_ROUTER";
break;
case I_SHUTDOWN:
inputAsText = "I_SHUTDOWN";
break;
case I_STARTUP:
inputAsText = "I_STARTUP";
break;
case I_SUCCESS:
inputAsText = "I_SUCCESS";
break;
case I_TERMINATE:
inputAsText = "I_TERMINATE";
break;
case I_WELCOME:
inputAsText = "I_WELCOME";
break;
case I_WELCOME_ACK:
inputAsText = "I_WELCOME_ACK";
break;
case I_DC_HEARTBEAT:
inputAsText = "I_DC_HEARTBEAT";
break;
case I_WAIT_FOR_EVENT:
inputAsText = "I_WAIT_FOR_EVENT";
break;
case I_LRM_EVENT:
inputAsText = "I_LRM_EVENT";
break;
case I_ILLEGAL:
inputAsText = "I_ILLEGAL";
break;
}
if(inputAsText == NULL) {
cl_log(LOG_ERR, "Input %d is unknown", input);
inputAsText = "<UNKNOWN_INPUT>";
}
return inputAsText;
}
const char *
fsa_state2string(enum crmd_fsa_state state)
{
const char *stateAsText = NULL;
switch(state){
case S_IDLE:
stateAsText = "S_IDLE";
break;
case S_ELECTION:
stateAsText = "S_ELECTION";
break;
case S_INTEGRATION:
stateAsText = "S_INTEGRATION";
break;
case S_NOT_DC:
stateAsText = "S_NOT_DC";
break;
case S_POLICY_ENGINE:
stateAsText = "S_POLICY_ENGINE";
break;
case S_RECOVERY:
stateAsText = "S_RECOVERY";
break;
case S_RECOVERY_DC:
stateAsText = "S_RECOVERY_DC";
break;
case S_RELEASE_DC:
stateAsText = "S_RELEASE_DC";
break;
case S_PENDING:
stateAsText = "S_PENDING";
break;
case S_STOPPING:
stateAsText = "S_STOPPING";
break;
case S_TERMINATE:
stateAsText = "S_TERMINATE";
break;
case S_TRANSITION_ENGINE:
stateAsText = "S_TRANSITION_ENGINE";
break;
case S_ILLEGAL:
stateAsText = "S_ILLEGAL";
break;
}
if(stateAsText == NULL) {
cl_log(LOG_ERR, "State %d is unknown", state);
stateAsText = "<UNKNOWN_STATE>";
}
return stateAsText;
}
const char *
fsa_cause2string(enum crmd_fsa_cause cause)
{
const char *causeAsText = NULL;
switch(cause){
case C_UNKNOWN:
causeAsText = "C_UNKNOWN";
break;
case C_STARTUP:
causeAsText = "C_STARTUP";
break;
case C_IPC_MESSAGE:
causeAsText = "C_IPC_MESSAGE";
break;
case C_HA_MESSAGE:
causeAsText = "C_HA_MESSAGE";
break;
case C_CCM_CALLBACK:
causeAsText = "C_CCM_CALLBACK";
break;
case C_TIMER_POPPED:
causeAsText = "C_TIMER_POPPED";
break;
case C_SHUTDOWN:
causeAsText = "C_SHUTDOWN";
break;
case C_HEARTBEAT_FAILED:
causeAsText = "C_HEARTBEAT_FAILED";
break;
case C_SUBSYSTEM_CONNECT:
causeAsText = "C_SUBSYSTEM_CONNECT";
break;
case C_LRM_OP_CALLBACK:
causeAsText = "C_LRM_OP_CALLBACK";
break;
case C_LRM_MONITOR_CALLBACK:
causeAsText = "C_LRM_MONITOR_CALLBACK";
break;
case C_CRMD_STATUS_CALLBACK:
causeAsText = "C_CRMD_STATUS_CALLBACK";
break;
case C_ILLEGAL:
causeAsText = "C_ILLEGAL";
break;
}
if(causeAsText == NULL) {
cl_log(LOG_ERR, "Cause %d is unknown", cause);
causeAsText = "<UNKNOWN_CAUSE>";
}
return causeAsText;
}
const char *
fsa_action2string(long long action)
{
const char *actionAsText = NULL;
switch(action){
case A_NOTHING:
actionAsText = "A_NOTHING";
break;
case O_SHUTDOWN:
actionAsText = "O_SHUTDOWN";
break;
case O_RELEASE:
actionAsText = "O_RELEASE";
break;
case A_STARTUP:
actionAsText = "A_STARTUP";
break;
case A_STARTED:
actionAsText = "A_STARTED";
break;
case A_HA_CONNECT:
actionAsText = "A_HA_CONNECT";
break;
case A_HA_DISCONNECT:
actionAsText = "A_HA_DISCONNECT";
break;
case A_LRM_CONNECT:
actionAsText = "A_LRM_CONNECT";
break;
case A_LRM_DISCONNECT:
actionAsText = "A_LRM_DISCONNECT";
break;
case O_DC_TIMER_RESTART:
actionAsText = "O_DC_TIMER_RESTART";
break;
case A_DC_TIMER_STOP:
actionAsText = "A_DC_TIMER_STOP";
break;
case A_DC_TIMER_START:
actionAsText = "A_DC_TIMER_START";
break;
case A_ELECTION_COUNT:
actionAsText = "A_ELECTION_COUNT";
break;
case A_ELECTION_TIMEOUT:
actionAsText = "A_ELECTION_TIMEOUT";
break;
case A_ELECT_TIMER_START:
actionAsText = "A_ELECT_TIMER_START";
break;
case A_ELECT_TIMER_STOP:
actionAsText = "A_ELECT_TIMER_STOP";
break;
case A_ELECTION_VOTE:
actionAsText = "A_ELECTION_VOTE";
break;
case A_ANNOUNCE:
actionAsText = "A_ANNOUNCE";
break;
case A_JOIN_ACK:
actionAsText = "A_JOIN_ACK";
break;
case A_JOIN_WELCOME:
actionAsText = "A_JOIN_WELCOME";
break;
case A_JOIN_WELCOME_ALL:
actionAsText = "A_JOIN_WELCOME_ALL";
break;
case A_JOIN_PROCESS_ACK:
actionAsText = "A_JOIN_PROCESS_ACK";
break;
case A_MSG_PROCESS:
actionAsText = "A_MSG_PROCESS";
break;
case A_MSG_ROUTE:
actionAsText = "A_MSG_ROUTE";
break;
case A_MSG_STORE:
actionAsText = "A_MSG_STORE";
break;
case A_RECOVER:
actionAsText = "A_RECOVER";
break;
case A_DC_RELEASE:
actionAsText = "A_DC_RELEASE";
break;
case A_DC_RELEASED:
actionAsText = "A_DC_RELEASED";
break;
case A_DC_TAKEOVER:
actionAsText = "A_DC_TAKEOVER";
break;
case A_SHUTDOWN:
actionAsText = "A_SHUTDOWN";
break;
case A_SHUTDOWN_REQ:
actionAsText = "A_SHUTDOWN_REQ";
break;
case A_STOP:
actionAsText = "A_STOP ";
break;
case A_EXIT_0:
actionAsText = "A_EXIT_0";
break;
case A_EXIT_1:
actionAsText = "A_EXIT_1";
break;
case A_CCM_CONNECT:
actionAsText = "A_CCM_CONNECT";
break;
case A_CCM_DISCONNECT:
actionAsText = "A_CCM_DISCONNECT";
break;
case A_CCM_EVENT:
actionAsText = "A_CCM_EVENT";
break;
case A_CCM_UPDATE_CACHE:
actionAsText = "A_CCM_UPDATE_CACHE";
break;
case A_CIB_BUMPGEN:
actionAsText = "A_CIB_BUMPGEN";
break;
case A_CIB_INVOKE:
actionAsText = "A_CIB_INVOKE";
break;
case O_CIB_RESTART:
actionAsText = "O_CIB_RESTART";
break;
case A_CIB_START:
actionAsText = "A_CIB_START";
break;
case A_CIB_STOP:
actionAsText = "A_CIB_STOP";
break;
case A_TE_INVOKE:
actionAsText = "A_TE_INVOKE";
break;
case O_TE_RESTART:
actionAsText = "O_TE_RESTART";
break;
case A_TE_START:
actionAsText = "A_TE_START";
break;
case A_TE_STOP:
actionAsText = "A_TE_STOP";
break;
case A_TE_CANCEL:
actionAsText = "A_TE_CANCEL";
break;
case A_TE_COPYTO:
actionAsText = "A_TE_COPYTO";
break;
case A_PE_INVOKE:
actionAsText = "A_PE_INVOKE";
break;
case O_PE_RESTART:
actionAsText = "O_PE_RESTART";
break;
case A_PE_START:
actionAsText = "A_PE_START";
break;
case A_PE_STOP:
actionAsText = "A_PE_STOP";
break;
case A_NODE_BLOCK:
actionAsText = "A_NODE_BLOCK";
break;
case A_UPDATE_NODESTATUS:
actionAsText = "A_UPDATE_NODESTATUS";
break;
case A_LOG:
actionAsText = "A_LOG ";
break;
case A_ERROR:
actionAsText = "A_ERROR ";
break;
case A_WARN:
actionAsText = "A_WARN ";
break;
}
if(actionAsText == NULL) {
cl_log(LOG_ERR, "Action %.16llx is unknown", action);
actionAsText = "<UNKNOWN_ACTION>";
}
return actionAsText;
}
void
cleanup_subsystem(struct crm_subsystem_s *the_subsystem)
{
int pid_status = -1;
the_subsystem->ipc = NULL;
clear_bit_inplace(&fsa_input_register,
the_subsystem->flag);
/* Forcing client to die */
kill(the_subsystem->pid, -9);
// cleanup the ps entry
waitpid(the_subsystem->pid, &pid_status, WNOHANG);
the_subsystem->pid = -1;
}
enum crmd_fsa_input
invoke_local_cib(xmlNodePtr msg_options,
xmlNodePtr msg_data,
const char *operation)
{
enum crmd_fsa_input result = I_NULL;
xmlNodePtr request = NULL;
FNIN();
msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS,
XML_ATTR_OP, operation, TRUE);
request = create_request(msg_options,
msg_data,
NULL,
CRM_SYSTEM_CIB,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD,
NULL,
NULL);
result = do_cib_invoke(A_CIB_INVOKE_LOCAL,
C_UNKNOWN,
fsa_state,
I_CIB_OP,
request);
free_xml(request);
FNRET(result);
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 4, 6:23 AM (6 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1845448
Default Alt Text
(167 KB)

Event Timeline