diff --git a/crm/tengine/Makefile.am b/crm/tengine/Makefile.am index 5f36b697ee..a1ed5e0350 100644 --- a/crm/tengine/Makefile.am +++ b/crm/tengine/Makefile.am @@ -1,72 +1,72 @@ # # 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` crmdir = $(havarlibdir)/crm COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/$(CRM_DIR)/common/libcrmcommon.la \ $(top_builddir)/lib/$(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) ## binary progs halib_PROGRAMS = ttest tengine ## SOURCES noinst_HEADERS = tengine.h -tengine_SOURCES = tengine.c unpack.c utils.c main.c +tengine_SOURCES = tengine.c unpack.c utils.c callbacks.c main.c tengine_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' tengine_LDFLAGS = $(XML_LIBS) tengine_LDADD = $(COMMONLIBS) -ttest_SOURCES = tengine.c unpack.c utils.c ttest.c +ttest_SOURCES = tengine.c unpack.c utils.c callbacks.c ttest.c ttest_CFLAGS = $(XML_FLAGS) -DTESTING=1 -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' ttest_LDFLAGS = $(XML_LIBS) ttest_LDADD = $(COMMONLIBS) clean-generic: rm -f *.log *.debug *~ install-exec-local: uninstall-local: diff --git a/crm/tengine/main.c b/crm/tengine/main.c index 2a1e4debbd..dda36cf1a8 100644 --- a/crm/tengine/main.c +++ b/crm/tengine/main.c @@ -1,239 +1,246 @@ -/* $Id: main.c,v 1.8 2004/12/10 20:03:20 andrew Exp $ */ +/* $Id: main.c,v 1.9 2004/12/14 14:46:45 andrew Exp $ */ /* * 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.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 #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYS_NAME CRM_SYSTEM_TENGINE #define OPTARGS "skrhVc" #define PID_FILE WORKING_DIR "/" SYS_NAME ".pid" #define DAEMON_LOG DEVEL_DIR"/"SYS_NAME".log" #define DAEMON_DEBUG DEVEL_DIR"/"SYS_NAME".debug" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; +extern cib_t *te_cib_conn; void usage(const char* cmd, int exit_status); int init_start(void); void tengine_shutdown(int nsig); +extern void te_update_confirm(const char *event, struct ha_msg *msg); int main(int argc, char ** argv) { - gboolean allow_cores = TRUE; - int req_restart = FALSE; - int req_status = FALSE; - int req_stop = FALSE; - int argerr = 0; - int flag; - - /* Redirect messages from glib functions to our handler */ - g_log_set_handler(NULL, - G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL - | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE - | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG - | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, - cl_glib_msg_handler, NULL); - /* and for good measure... */ - g_log_set_always_fatal((GLogLevelFlags)0); + gboolean allow_cores = TRUE; + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + + /* Redirect messages from glib functions to our handler */ + g_log_set_handler(NULL, + G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL + | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE + | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG + | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, + cl_glib_msg_handler, NULL); + /* and for good measure... */ + g_log_set_always_fatal((GLogLevelFlags)0); - cl_log_set_entity(crm_system_name); - cl_log_set_facility(LOG_USER); - cl_log_set_logfile(DAEMON_LOG); - cl_log_set_debugfile(DAEMON_DEBUG); + cl_log_set_entity(crm_system_name); + cl_log_set_facility(LOG_LOCAL7); + cl_log_set_logfile(DAEMON_LOG); + cl_log_set_debugfile(DAEMON_DEBUG); + CL_SIGNAL(SIGTERM, tengine_shutdown); - crm_debug("Begining option processing"); + crm_debug("Begining option processing"); - while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; 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; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } - } + } - crm_debug("Option processing complete"); + crm_debug("Option processing complete"); - if (optind > argc) { + if (optind > argc) { ++argerr; - } + } - if (argerr) { + if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); - } + } - /* read local config file */ - - if(allow_cores) { - crm_debug("Enabling coredumps"); - cl_set_corerootdir(DEVEL_DIR); - cl_enable_coredumps(1); - cl_cdtocoredir(); - crm_debug("Coredump processing complete"); - } + /* read local config file */ + + if(allow_cores) { + crm_debug("Enabling coredumps"); + cl_set_corerootdir(DEVEL_DIR); + cl_enable_coredumps(1); + cl_cdtocoredir(); + crm_debug("Coredump processing complete"); + } - if (req_status){ + if (req_status){ return init_status(PID_FILE, crm_system_name); - } + } - if (req_stop){ + if (req_stop){ return init_stop(PID_FILE); - } + } - if (req_restart) { + if (req_restart) { init_stop(PID_FILE); - } + } - crm_debug("Starting..."); - return init_start(); + crm_debug("Starting..."); + return init_start(); } int init_start(void) { - ll_cluster_t* hb_fd = NULL; - int facility; -#ifdef REALTIME_SUPPORT - static int crm_realtime = 1; -#endif - - /* change the logging facility to the one used by heartbeat daemon */ - hb_fd = ll_cluster_new("heartbeat"); - - crm_info("Switching to Heartbeat logger"); - if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { - cl_log_set_facility(facility); - } - - crm_info("Register PID"); - register_pid(PID_FILE, FALSE, tengine_shutdown); - - init_client_ipc_comms( - CRM_SYSTEM_CRMD, subsystem_msg_dispatch, - (void*)process_te_message, &crm_ch); - - if(crm_ch != NULL) { - send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); - - /* Create the mainloop and run it... */ - mainloop = g_main_new(FALSE); - crm_info("Starting %s", crm_system_name); - -#ifdef REALTIME_SUPPORT - 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(mainloop); - - } else { - crm_err("Could not connect to the CRMd"); - } - - return_to_orig_privs(); - - if (unlink(PID_FILE) == 0) { - crm_info("[%s] stopped", crm_system_name); - } - - if(crm_ch != NULL) - return 0; - - return 1; + int init_ok = TRUE; + + init_client_ipc_comms( + CRM_SYSTEM_CRMD, subsystem_msg_dispatch, + (void*)process_te_message, &crm_ch); + + if(crm_ch != NULL) { + send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); + } else { + init_ok = FALSE; + crm_err("Could not connect to the CRMd"); + } + + if(init_ok) { + crm_trace("Creating CIB connection"); + te_cib_conn = cib_new(); + if(te_cib_conn == NULL) { + init_ok = FALSE; + } + } + + if(init_ok) { + crm_trace("Connecting to the CIB"); + if(te_cib_conn->cmds->signon( + te_cib_conn, cib_command) != cib_ok) { + init_ok = FALSE; + } + } + + if(init_ok) { + crm_trace("Setting CIB notification callback"); + if(te_cib_conn->cmds->add_notify_callback( + te_cib_conn, T_CIB_UPDATE_CONFIRM, + te_update_confirm) != cib_ok) { + init_ok = FALSE; + } + } + + if(init_ok) { + /* Create the mainloop and run it... */ + crm_info("Starting %s", crm_system_name); + + mainloop = g_main_new(FALSE); + g_main_run(mainloop); + return_to_orig_privs(); + + crm_info("Exiting %s", crm_system_name); + + } else { + crm_warn("Initialization errors, %s not starting.", + crm_system_name); + } + + if(init_ok) { + return 0; + } + return 1; } - void usage(const char* cmd, int exit_status) { - FILE* stream; + FILE* stream; - stream = exit_status ? stderr : stdout; + stream = exit_status ? stderr : stdout; - fprintf(stream, "usage: %s [-srkh]" - "[-c configure file]\n", cmd); + 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); + fflush(stream); - exit(exit_status); + exit(exit_status); } void tengine_shutdown(int nsig) { - static int shuttingdown = 0; - CL_SIGNAL(nsig, tengine_shutdown); + static int shuttingdown = 0; + CL_SIGNAL(nsig, tengine_shutdown); - if (!shuttingdown) { + if (!shuttingdown) { shuttingdown = 1; - } - if (mainloop != NULL && g_main_is_running(mainloop)) { + } + if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); - }else{ + }else{ exit(LSB_EXIT_OK); - } + } } diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h index cfb1fd61af..9271631c1d 100644 --- a/crm/tengine/tengine.h +++ b/crm/tengine/tengine.h @@ -1,111 +1,112 @@ -/* $Id: tengine.h,v 1.11 2004/11/12 17:14:34 andrew Exp $ */ +/* $Id: tengine.h,v 1.12 2004/12/14 14:46:45 andrew Exp $ */ /* * 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.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef TENGINE__H #define TENGINE__H #include extern FILE *msg_te_strm; extern IPC_Channel *crm_ch; extern GListPtr graph; extern GMainLoop* mainloop; extern gboolean in_transition; typedef enum { action_type_pseudo, action_type_rsc, action_type_crm } action_type_e; typedef struct synapse_s { int id; gboolean triggers_complete; gboolean complete; gboolean confirmed; GListPtr actions; /* action_t* */ GListPtr inputs; /* action_t* */ } synapse_t; typedef struct te_timer_s te_timer_t; typedef struct action_s { int id; int timeout; te_timer_t *timer; action_type_e type; gboolean invoked; gboolean complete; gboolean can_fail; xmlNodePtr xml; } action_t; enum timer_reason { timeout_action, timeout_timeout, timeout_fuzz }; struct te_timer_s { int source_id; int timeout; enum timer_reason reason; action_t *action; }; /* tengine */ extern gboolean initialize_graph(void); extern gboolean process_graph_event(xmlNodePtr event); /* const char *event_node, const char *event_rsc, const char *rsc_state, * const char *event_action, const char *event_rc, const char *op_status); */ extern int match_graph_event(action_t *action, xmlNodePtr event); extern gboolean initiate_transition(void); /* utils */ extern void print_state(gboolean to_file); extern void send_success(const char *text); +/*extern void send_abort(const char *text, struct ha_msg *msg); */ extern void send_abort(const char *text, xmlNodePtr msg); extern gboolean stop_te_timer(te_timer_t *timer); extern gboolean start_te_timer(te_timer_t *timer); extern gboolean do_update_cib(xmlNodePtr xml_action, int status); /* unpack */ extern gboolean unpack_graph(xmlNodePtr xml_graph); extern gboolean extract_event(xmlNodePtr msg); extern gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); extern uint transition_timeout; extern uint transition_fuzz_timeout; extern uint default_transition_timeout; extern te_timer_t *transition_timer; extern te_timer_t *transition_fuzz_timer; extern const char *actiontype2text(action_type_e type); #endif diff --git a/crm/tengine/unpack.c b/crm/tengine/unpack.c index ca7466782b..5a6736ff27 100644 --- a/crm/tengine/unpack.c +++ b/crm/tengine/unpack.c @@ -1,494 +1,346 @@ -/* $Id: unpack.c,v 1.11 2004/12/05 16:32:03 andrew Exp $ */ +/* $Id: unpack.c,v 1.12 2004/12/14 14:46:45 andrew Exp $ */ /* * 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.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 #include #include #include #include #include #include #include #include #include #include -gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); +cib_t *te_cib_conn = NULL; +extern gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); action_t* unpack_action(xmlNodePtr xml_action); xmlNodePtr create_shutdown_event(const char *node, int op_status); void set_timer_value(te_timer_t *timer, const char *time, int time_default); extern int transition_counter; void set_timer_value(te_timer_t *timer, const char *time, int time_default) { if(timer == NULL) { return; } timer->timeout = time_default; if(time != NULL) { int tmp_time = atoi(time); if(tmp_time > 0) { timer->timeout = tmp_time; } } } gboolean unpack_graph(xmlNodePtr xml_graph) { /* timeout; time = xmlGetProp(xml_graph, "transition_fuzz"); set_timer_value(transition_fuzz_timer, time, transition_fuzz_timeout); transition_counter++; crm_info("Beginning transition %d - timeout set to %d", transition_counter, transition_timer->timeout); xml_child_iter( xml_graph, synapse, "synapse", synapse_t *new_synapse = NULL; crm_debug("looking in synapse %s", xmlGetProp(synapse, "id")); crm_malloc(new_synapse, sizeof(synapse_t)); new_synapse->id = num_synapses++; new_synapse->complete = FALSE; new_synapse->confirmed = FALSE; new_synapse->actions = NULL; new_synapse->inputs = NULL; graph = g_list_append(graph, new_synapse); crm_debug("look for actions in synapse %s", xmlGetProp(synapse, "id")); xml_child_iter( synapse, actions, "action_set", xml_child_iter( actions, action, NULL, action_t *new_action = unpack_action(action); num_actions++; if(new_action == NULL) { action = action->next; break; } crm_debug("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_debug("look for inputs in synapse %s", xmlGetProp(synapse, "id")); xml_child_iter( synapse, inputs, "inputs", xml_child_iter( inputs, trigger, NULL, xml_child_iter( trigger, input, NULL, action_t *new_input = unpack_action(input); if(new_input == NULL) { input = input->next; break; } crm_debug("Adding input %d to synapse %d", new_input->id, new_synapse->id); new_synapse->inputs = g_list_append( new_synapse->inputs, new_input); ); ); ); ); crm_info("Unpacked %d actions in %d synapses", num_actions, num_synapses); if(num_actions > 0) { return TRUE; } else { /* indicate to caller that there's nothing to do */ return FALSE; } } action_t* unpack_action(xmlNodePtr xml_action) { const char *tmp = xmlGetProp(xml_action, "id"); action_t *action = NULL; xmlNodePtr action_copy = NULL; if(tmp == NULL) { crm_err("Actions must have an id!"); crm_xml_devel(xml_action, "Action with missing id"); return NULL; } action_copy = copy_xml_node_recursive(xml_action); crm_malloc(action, sizeof(action_t)); if(action == NULL) { return NULL; } action->id = atoi(tmp); action->timeout = 0; action->timer = NULL; action->invoked = FALSE; action->complete = FALSE; action->can_fail = FALSE; action->type = action_type_rsc; action->xml = action_copy; if(safe_str_eq(action_copy->name, "rsc_op")) { action->type = action_type_rsc; } else if(safe_str_eq(action_copy->name, "pseudo_event")) { action->type = action_type_pseudo; } else if(safe_str_eq(action_copy->name, "crm_event")) { action->type = action_type_crm; } tmp = xmlGetProp(action_copy, "timeout"); if(tmp != NULL) { action->timeout = atoi(tmp); } crm_debug("Action %d has timer set to %d", action->id, action->timeout); crm_malloc(action->timer, sizeof(te_timer_t)); action->timer->timeout = action->timeout; action->timer->source_id = -1; action->timer->reason = timeout_action; action->timer->action = action; tmp = xmlGetProp(action_copy, "can_fail"); if(safe_str_eq(tmp, "true")) { action->can_fail = TRUE; } return action; } gboolean extract_event(xmlNodePtr msg) { - gboolean abort = FALSE; - xmlNodePtr iter = NULL; - xmlNodePtr cib = NULL; - const char *section = NULL; - const char *event_node = NULL; + gboolean abort = FALSE; + xmlNodePtr iter = NULL; + const char *event_node = NULL; /* [cib fragment] ... */ crm_trace("Extracting event"); - iter = find_xml_node(msg, XML_TAG_FRAGMENT); - section = xmlGetProp(iter, XML_ATTR_SECTION); - - if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { - /* ignore - for the moment */ - crm_debug("Ignoring changes to the %s section", - XML_CIB_TAG_CRMCONFIG); - return TRUE; - - } else if(safe_str_neq(section, XML_CIB_TAG_STATUS)) { - /* these too are never expected */ - crm_debug("Ignoring changes outside the %s section", - XML_CIB_TAG_STATUS); - return FALSE; - } - - cib = find_xml_node(iter, XML_TAG_CIB); - iter = get_object_root(XML_CIB_TAG_STATUS, cib); - if(iter != NULL) { - iter = iter->children; - } else { - crm_xml_warn(cib, XML_CIB_TAG_STATUS " section missing?"); - } - + iter = msg; while(abort == FALSE && iter != NULL) { xmlNodePtr node_state = iter; xmlNodePtr child = iter->children; xmlNodePtr shutdown = NULL; const char *state = xmlGetProp( node_state, XML_CIB_ATTR_CRMDSTATE); iter = iter->next; crm_xml_devel(node_state,"Processing"); if(xmlGetProp(node_state, XML_CIB_ATTR_SHUTDOWN) != NULL) { crm_trace("Aborting on %s attribute", XML_CIB_ATTR_SHUTDOWN); abort = TRUE; } else if(xmlGetProp(node_state, XML_CIB_ATTR_STONITH) != NULL) { /* node marked for STONITH * possibly by us when a shutdown timmed out */ crm_trace("Checking for STONITH"); event_node = xmlGetProp(node_state, XML_ATTR_UNAME); shutdown = create_shutdown_event( event_node, LRM_OP_TIMEOUT); process_graph_event(shutdown); free_xml(shutdown); } else if(state != NULL && child == NULL) { /* simple node state update... * possibly from a shutdown we requested */ crm_trace("Processing simple state update"); if(safe_str_neq(state, OFFLINESTATUS)) { /* always recompute */ abort = TRUE; continue; } event_node = xmlGetProp(node_state, XML_ATTR_UNAME); shutdown = create_shutdown_event( event_node, LRM_OP_DONE); process_graph_event(shutdown); free_xml(shutdown); } else if(state == NULL && child != NULL) { /* LRM resource update... */ crm_trace("Processing LRM resource update"); child = find_xml_node(node_state, XML_CIB_TAG_LRM); child = find_xml_node(child, XML_LRM_TAG_RESOURCES); if(child != NULL) { child = child->children; } else { abort = TRUE; } event_node = xmlGetProp(node_state, XML_ATTR_UNAME); while(abort == FALSE && child != NULL) { process_graph_event(child); child = child->next; } } else if(state != NULL && child != NULL) { /* this is a complex event and could not be completely * due to any request we made */ crm_trace("Aborting on complex update"); abort = TRUE; } else { /* ignore */ crm_err("Ignoring message"); } } return !abort; } -gboolean -process_te_message(xmlNodePtr msg, IPC_Channel *sender) -{ - xmlNodePtr graph = NULL; - const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO); - const char *ref = xmlGetProp(msg, XML_ATTR_REFERENCE); - const char *op = get_xml_attr( - msg, XML_TAG_OPTIONS, XML_ATTR_OP, FALSE); - - - crm_debug("Recieved %s (%s) message", op, ref); - - if (MSG_LOG) { - struct stat buf; - char *xml; - if(stat(DEVEL_DIR, &buf) != 0) { - cl_perror("Stat of %s failed... exiting", DEVEL_DIR); - exit(100); - } - - if(msg_te_strm == NULL) { - msg_te_strm = fopen(DEVEL_DIR"/te.log", "w"); - } - xml = dump_xml_formatted(msg); - fprintf(msg_te_strm, "[Input %s]\t%s\n", - op, xml); - fflush(msg_te_strm); - crm_free(xml); - } - - if(safe_str_eq(xmlGetProp(msg, XML_ATTR_MSGTYPE), XML_ATTR_RESPONSE) - && safe_str_neq(op, CRM_OP_EVENTCC)) { -#ifdef MSG_LOG - fprintf(msg_te_strm, "[Result ]\tDiscarded\n"); - fflush(msg_te_strm); -#endif - crm_info("Message was a response not a request. Discarding"); - return TRUE; - } - - crm_debug("Processing %s (%s) message", op, ref); - - if(op == NULL){ - /* error */ - } else if(strcmp(op, CRM_OP_HELLO) == 0) { - /* ignore */ - - } else if(sys_to == NULL || strcmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { - crm_verbose("Bad sys-to %s", crm_str(sys_to)); - return FALSE; - - } else if(strcmp(op, CRM_OP_TRANSITION) == 0) { - - crm_trace("Initializing graph..."); - initialize_graph(); - - graph = find_xml_node(msg, "transition_graph"); - crm_trace("Unpacking graph..."); - unpack_graph(graph); - crm_trace("Initiating transition..."); - - in_transition = TRUE; - - if(initiate_transition() == FALSE) { - /* nothing to be done.. means we're done. */ - crm_info("No actions to be taken..." - " transition compelte."); - } - crm_trace("Processing complete..."); - - } else if(strcmp(op, CRM_OP_TEABORT) == 0) { - initialize_graph(); - - } else if(strcmp(op, CRM_OP_QUIT) == 0) { - crm_err("Received quit message, terminating"); - exit(0); - - } else if(in_transition == FALSE) { - crm_info("Received event_cc while not in a transition..." - " Poking the Policy Engine"); - send_abort("Initiate a transition", NULL); - - } else if(strcmp(op, CRM_OP_EVENTCC) == 0) { - const char *true_op = get_xml_attr (msg, XML_TAG_OPTIONS, - XML_ATTR_TRUEOP, TRUE); - crm_trace("Processing %s...", CRM_OP_EVENTCC); - if(true_op == NULL) { - crm_err( - "Illegal update," - " the original operation must be specified"); - send_abort("Illegal update", msg); - - } else if(strcmp(true_op, CRM_OP_CIB_CREATE) == 0 - || strcmp(true_op, CRM_OP_CIB_DELETE) == 0 - || strcmp(true_op, CRM_OP_CIB_REPLACE) == 0 - || strcmp(true_op, CRM_OP_WELCOME) == 0 - || strcmp(true_op, CRM_OP_SHUTDOWN_REQ) == 0 - || strcmp(true_op, CRM_OP_CIB_ERASE) == 0) { - - /* these are always unexpected, trigger the PE */ - send_abort("Config update", msg); - - } else if(strcmp(true_op, CRM_OP_CIB_UPDATE) == 0) { - /* this may not be un-expected */ -/* if( */ - extract_event(msg); -/* == FALSE){ - send_abort(msg); - } */ - - } else { - crm_err( - "Did not expect copy of action %s", op); - } - - } - - crm_debug("finished processing message"); - print_state(FALSE); - - return TRUE; -} - - xmlNodePtr create_shutdown_event(const char *node, int op_status) { xmlNodePtr event = create_xml_node(NULL, XML_CIB_TAG_STATE); char *code = crm_itoa(op_status); set_xml_property_copy(event, XML_LRM_ATTR_TARGET, node); /* event_rsc = set_xml_property_copy(event, XML_ATTR_ID); */ set_xml_property_copy(event, XML_LRM_ATTR_RC, "0"); set_xml_property_copy( event, XML_LRM_ATTR_LASTOP, XML_CIB_ATTR_SHUTDOWN); set_xml_property_copy( event, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_GENERIC_OK); set_xml_property_copy(event, XML_LRM_ATTR_OPSTATUS, code); crm_free(code); return event; } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index ccf8a91a64..a8fd11d21f 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,443 +1,443 @@ -/* $Id: utils.c,v 1.8 2004/12/05 16:32:03 andrew Exp $ */ +/* $Id: utils.c,v 1.9 2004/12/14 14:46:45 andrew Exp $ */ /* * 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.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 #include #include #include #include #include #include #include #include #include +extern cib_t *te_cib_conn; extern int global_transition_timer; FILE *msg_te_strm = NULL; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); gboolean timer_callback(gpointer data); void +/* send_abort(const char *text, struct ha_msg *msg) */ send_abort(const char *text, xmlNodePtr msg) { xmlNodePtr options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_info("Sending \"abort\" message... details follow"); crm_xml_info(msg, text); #ifdef MSG_LOG fprintf(msg_te_strm, "[Result ]\tTransition aborted\n"); fflush(msg_te_strm); #endif print_state(TRUE); initialize_graph(); #ifdef TESTING g_main_quit(mainloop); return; #endif set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_TEABORT); send_ipc_request(crm_ch, options, msg, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL, NULL); free_xml(options); } void send_success(const char *text) { xmlNodePtr options = create_xml_node(NULL, XML_TAG_OPTIONS); if(in_transition == FALSE) { crm_warn("Not in transition, not sending message"); return; } in_transition = FALSE; crm_info("Sending \"complete\" message: %s", text); #ifdef MSG_LOG - if(msg_te_strm != NULL) { - fprintf(msg_te_strm, "[Result ]\tTransition complete\n"); - fflush(msg_te_strm); - } + fprintf(msg_te_strm, "[Result ]\tTransition complete\n"); + fflush(msg_te_strm); #endif print_state(TRUE); initialize_graph(); #ifdef TESTING g_main_quit(mainloop); return; #endif set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_TECOMPLETE); set_xml_property_copy(options, "message", text); send_ipc_request(crm_ch, options, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL, NULL); free_xml(options); } void print_state(gboolean to_file) { FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif if(to_file) { fprintf(output, "Start Transitioner state\n"); } crm_debug("#!!#!!# Start Transitioner state"); if(graph == NULL) { crm_debug("\tEmpty transition graph"); crm_debug("#!!#!!# End Transitioner state"); if(to_file) { fprintf(output, "\tEmpty transition graph\n" "End Transitioner state\n"); } return; } slist_iter( synapse, synapse_t, graph, lpc, crm_debug("Synapse %d %s", synapse->id, synapse->complete?"has completed":"is pending"); if(to_file) { fprintf(output, "Synapse %d %s\n", synapse->id, synapse->complete?"has completed":"is pending"); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, to_file); ); } slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, to_file); ); ); crm_debug("#!!#!!# End Transitioner state"); if(to_file) { fprintf(output, "End Transitioner state\n"); } } void print_input(const char *prefix, action_t *input, gboolean to_file) { FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif crm_debug("%s[Input %d] %s (%s)", prefix, input->id, input->complete?"Satisfied":"Pending", actiontype2text(input->type)); crm_xml_trace(input->xml, "\t Raw input"); if(to_file) { fprintf(output, "%s[Input %d] %s\n", prefix, input->id, input->complete?"Satisfied":"Pending"); fflush(msg_te_strm); } } void print_action(const char *prefix, action_t *action, gboolean to_file) { FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif crm_debug("%s[Action %d] %s (%d - %s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->type, action->can_fail?"can":"cannot"); crm_debug("%s timeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); crm_xml_trace(action->xml, "\t Raw action"); if(to_file) { fprintf(output, "%s[Action %d] %s (%s: %s %s on %s)\n", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", actiontype2text(action->type), xmlGetProp(action->xml, XML_LRM_ATTR_TASK), xmlGetProp(action->xml, XML_LRM_ATTR_RSCID), xmlGetProp(action->xml, XML_LRM_ATTR_TARGET)); fflush(msg_te_strm); } } gboolean do_update_cib(xmlNodePtr xml_action, int status) { char *code; char since_epoch[64]; xmlNodePtr fragment = NULL; - xmlNodePtr options = NULL; xmlNodePtr state = NULL; xmlNodePtr rsc = NULL; - const char *sys_to = CRM_SYSTEM_DCIB; + enum cib_errors rc = cib_ok; + const char *task = xmlGetProp(xml_action, XML_LRM_ATTR_TASK); const char *rsc_id = xmlGetProp(xml_action, XML_LRM_ATTR_RSCID); const char *target = xmlGetProp(xml_action, XML_LRM_ATTR_TARGET); const char *target_uuid = xmlGetProp(xml_action, XML_LRM_ATTR_TARGET_UUID); + + int call_options = cib_scope_local|cib_discard_reply|cib_sync_call; + call_options |= cib_inhibit_notify; if(status == LRM_OP_TIMEOUT) { if(xmlGetProp(xml_action, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", xml_action->name, task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", xml_action->name, task, target); } } /* update the CIB */ fragment = NULL; - options = create_xml_node(NULL, XML_TAG_OPTIONS); state = create_xml_node(NULL, XML_CIB_TAG_STATE); #ifdef TESTING /* turn the "pending" notification into a "op completed" notification * when testing... exercises more code this way. */ if(status == -1) { status = 0; } - sys_to = CRM_SYSTEM_TENGINE; - set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_EVENTCC); - set_xml_property_copy(options, XML_ATTR_TRUEOP, CRM_OP_CIB_UPDATE); -#else - set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_CIB_UPDATE); #endif set_xml_property_copy(state, XML_ATTR_UUID, target_uuid); set_xml_property_copy(state, XML_ATTR_UNAME, target); if(status != -1 && (safe_str_eq(task, "shutdown_crm"))) { sprintf(since_epoch, "%ld", (unsigned long)time(NULL)); set_xml_property_copy(rsc, "stonith", since_epoch); } else { code = crm_itoa(status); rsc = create_xml_node(state, "lrm"); rsc = create_xml_node(rsc, "lrm_resources"); rsc = create_xml_node(rsc, "lrm_resource"); set_xml_property_copy(rsc, XML_ATTR_ID, rsc_id); set_xml_property_copy(rsc, XML_LRM_ATTR_TARGET, target); set_xml_property_copy( rsc, XML_LRM_ATTR_TARGET_UUID, target_uuid); if(safe_str_eq(CRMD_RSCSTATE_START, task)) { set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_START_PENDING); } else if(safe_str_eq(CRMD_RSCSTATE_STOP, task)) { set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_STOP_PENDING); } else { crm_warn("Using status \"pending\" for op \"%s\"..." " this is still in the experimental stage.", crm_str(task)); set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_GENERIC_PENDING); } set_xml_property_copy(rsc, XML_LRM_ATTR_OPSTATUS, code); set_xml_property_copy(rsc, XML_LRM_ATTR_RC, code); set_xml_property_copy(rsc, XML_LRM_ATTR_LASTOP, task); crm_free(code); } fragment = create_cib_fragment(state, NULL); #ifdef MSG_LOG fprintf(msg_te_strm, "[Result ]\tUpdate CIB with \"%s\" (%s): %s %s on %s\n", status<0?"new action":"timeout", xml_action->name, crm_str(task), rsc_id, target); fprintf(msg_te_strm, "[Sent ]\t%s\n", dump_xml_formatted(fragment)); fflush(msg_te_strm); #endif - send_ipc_request(crm_ch, options, fragment, - NULL, sys_to, CRM_SYSTEM_TENGINE, - NULL, NULL); + rc = te_cib_conn->cmds->modify( + te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); + free_xml(fragment); - free_xml(options); free_xml(state); - + + if(rc != cib_ok) { + return FALSE; + } + return TRUE; } gboolean timer_callback(gpointer data) { te_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (te_timer_t*)data; if(timer->source_id > 0) { g_source_remove(timer->source_id); } timer->source_id = -1; if(timer->reason == timeout_fuzz) { crm_info("Transition timeout reached..." " marking transition complete."); send_success("success"); return TRUE; } else if(timer->reason == timeout_timeout) { /* global timeout - abort the transition */ crm_info("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); send_success("timeout"); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } else { /* fail the action * - which may or may not abort the transition */ /* TODO: send a cancel notice to the LRM */ /* TODO: use the ack from above to update the CIB */ return do_update_cib(timer->action->xml, LRM_OP_TIMEOUT); } } gboolean start_te_timer(te_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->timeout > 0) { timer->source_id = Gmain_timeout_add( timer->timeout, timer_callback, (void*)timer); return TRUE; } else if(timer->timeout < 0) { crm_err("Tried to start timer with -ve period"); } else { crm_info("#!!#!!# Timer already running (%d)", timer->source_id); } return FALSE; } gboolean stop_te_timer(te_timer_t *timer) { if(timer == NULL) { return FALSE; } if(((int)timer->source_id) > 0) { g_source_remove(timer->source_id); timer->source_id = -2; } else { return FALSE; } return TRUE; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; }