diff --git a/crm/tengine/Makefile.am b/crm/tengine/Makefile.am index bcbefcd709..f2693623b7 100644 --- a/crm/tengine/Makefile.am +++ b/crm/tengine/Makefile.am @@ -1,69 +1,65 @@ # # 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) +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` +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 +crmdir = $(havarlibdir)/crm -COMMONLIBS = $(CRM_DEBUG_LIBS) \ - $(top_builddir)/lib/clplumbing/libplumb.la \ - $(top_builddir)/$(CRM_DIR)/common/libcrmcommon.la \ - $(top_builddir)/lib/apphb/libapphb.la \ - $(top_builddir)/lib/hbclient/libhbclient.la \ - $(GLIBLIB) \ - $(LIBRT) +COMMONLIBS = $(CRM_DEBUG_LIBS) \ + $(top_builddir)/lib/clplumbing/libplumb.la \ + $(top_builddir)/$(CRM_DIR)/common/libcrmcommon.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) +LIBRT = @LIBRT@ +AM_CFLAGS = @CFLAGS@ -DPIDFILE='"$(PIDFILE)"' $(CRM_DEBUG_FLAGS) ## binary progs -halib_PROGRAMS = tengine - +halib_PROGRAMS = tengine ## SOURCES -#noinst_HEADERS = config.h control.h crmd.h -noinst_HEADERS = +#noinst_HEADERS = config.h control.h crmd.h +noinst_HEADERS = -tengine_SOURCES = tenginemain.c -tengine_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' -tengine_LDFLAGS = $(XML_LIBS) -tengine_LDADD = $(COMMONLIBS) +tengine_SOURCES = tengine.c tenginemain.c +tengine_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' +tengine_LDFLAGS = $(XML_LIBS) +tengine_LDADD = $(COMMONLIBS) clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c new file mode 100644 index 0000000000..094f528f60 --- /dev/null +++ b/crm/tengine/tengine.c @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include + +GSListPtr graph = NULL; +IPC_Channel *crm_ch = NULL; + +typedef struct action_list_s +{ + int index; + int index_max; + GSListPtr actions; +} action_list_t; + +gboolean initiate_action(xmlNodePtr xml_action); +gboolean process_graph_event(const char *event_node, + const char *event_rsc, + const char *event_action, + const char *event_status, + const char *event_rc); + +gboolean +initialize_graph(void) +{ + while(g_slist_length(graph) > 0) { + action_list_t *action_list = g_slist_nth_data(graph, 0); + while(g_slist_length(action_list->actions) > 0) { + GSListPtr action = g_slist_nth(action_list->actions, 0); + g_slist_remove(action_list->actions, action); + cl_free(action->data); + } + g_slist_remove(graph, action_list); + } + + graph = NULL; + + return TRUE; +} + + +gboolean +unpack_graph(xmlNodePtr xml_graph) +{ +/* + + + + + +*/ + + xmlNodePtr xml_action_list = xml_graph->children; + while(xml_action_list != NULL) { + xmlNodePtr xml_obj = xml_action_list; + xmlNodePtr xml_action = xml_obj->children; + action_list_t *action_list = (action_list_t*) + cl_malloc(sizeof(action_list_t)); + + xml_action_list = xml_action_list->next; + + action_list->index = 0; + action_list->index_max = 0; + + while(xml_action != NULL) { + xmlNodePtr action = copy_xml_node_recursive(xml_action); + + action_list->actions = + g_slist_append(action_list->actions, action); + + action_list->index_max++; + } + + graph = g_slist_append(graph, action_list); + } + + + return TRUE; +} + +gboolean +process_event(xmlNodePtr msg) +{ + const char *event_action = NULL; + const char *event_node = NULL; + const char *event_rsc = NULL; + const char *event_status = NULL; + const char *event_rc = NULL; + + xmlNodePtr data = find_xml_node(msg, "lrm_resource"); + + if(data != NULL) { + event_action = xmlGetProp(data, "last_op"); + event_node = xmlGetProp(data, "op_node"); + event_rsc = xmlGetProp(data, "id"); + event_status = xmlGetProp(data, "op_status"); + event_rc = xmlGetProp(data, "op_code"); + + return process_graph_event(event_node, event_rsc, event_action, + event_status, event_rc); + } + + data = find_xml_node(msg, "crm_events"); + + if(data != NULL) { + event_node = xmlGetProp(data->children, XML_ATTR_ID); + event_status = xmlGetProp(data->children, "state"); + event_rc = xmlGetProp(data->children, "op_code"); + if(safe_str_eq(event_status, "down")) { + event_action = "shutdown"; + } + + + return process_graph_event(event_node, event_rsc, event_action, + event_status, event_rc); + } + + // error: not (yet?) supported + + return FALSE; +} + + +gboolean +process_graph_event(const char *event_node, + const char *event_rsc, + const char *event_action, + const char *event_status, + const char *event_rc) +{ + int lpc; + xmlNodePtr action = NULL; // or + xmlNodePtr next_action = NULL; + +// Find the action corresponding to this event + slist_iter( + action_list, action_list_t, graph, lpc, + action = g_slist_nth_data(action_list->actions, + action_list->index); +/* + + + +*/ + const char *this_action = xmlGetProp(action, "task"); + const char *this_node = xmlGetProp(action, "on_node"); + const char *this_rsc = xmlGetProp(action->children, "id"); + + if(safe_str_neq(this_node, event_node)) { + continue; + + } else if(safe_str_neq(this_action, event_action)) { + continue; + + } else if(safe_str_eq(action->name, "rsc_op") + && safe_str_eq(this_rsc, event_rsc)) { + action_list->index++; + next_action = g_slist_nth_data(action_list->actions, + action_list->index); + + } else if(safe_str_eq(action->name, "crm_event")) { + action_list->index++; + next_action = g_slist_nth_data(action_list->actions, + action_list->index); + + } + ); + + // for the moment all actions succeed + + if(action == NULL) { + // unexpected event, trigger a pe-recompute + // possibly do this only for certain types of actions + + xmlNodePtr options = create_xml_node(NULL, "options"); + set_xml_property_copy(options, "op", "pe_restart"); + + send_ipc_request(crm_ch, options, NULL, + NULL, "dc", "tengine", + NULL, NULL); + + free_xml(options); + + } else if(next_action == NULL) { + /* last action in that list, check if there are + * anymore actions at all + */ + gboolean more_to_do = FALSE; + slist_iter( + action_list, action_list_t, graph, lpc, + if(action_list->index <= action_list->index_max){ + more_to_do = TRUE; + break; + } + ); + if(more_to_do == FALSE) { + // indicate to the CRMd that we're done + xmlNodePtr options = create_xml_node(NULL, "options"); + set_xml_property_copy(options, "op", "te_complete"); + + send_ipc_request(crm_ch, options, NULL, + NULL, "dc", "tengine", + NULL, NULL); + + free_xml(options); + + return TRUE; + } // else wait for the next event + + } else { + return initiate_action(next_action); + } + + return FALSE; +} + +gboolean +initiate_transition(void) +{ + int lpc; + xmlNodePtr action = NULL; + + FNIN(); + + slist_iter( + action_list, action_list_t, graph, lpc, + action = g_slist_nth_data(action_list->actions, + action_list->index); + + initiate_action(action); + + action_list->index++; + ); + + FNRET(TRUE); +} + +gboolean +initiate_action(xmlNodePtr xml_action) +{ + // initiate the next action + + const char *on_node = xmlGetProp(xml_action, "on_node"); + const char *id = xmlGetProp(xml_action, "id"); +// const char *runnable = xmlGetProp(xml_action, "runnable"); +// const char *optional = xmlGetProp(xml_action, "optional"); + const char *task = xmlGetProp(xml_action, "task"); + + FNIN(); + + + cl_log(LOG_INFO, "Invoking action %s (id=%s) on %s", task, id, on_node); + + + if(id == NULL || strlen(id) == 0 + || on_node == NULL || strlen(on_node) == 0 + || task == NULL || strlen(task) == 0) { + // error + cl_log(LOG_ERR, + "Command: \"%s (id=%s) on %s\" was corrupted.", + task, id, on_node); + + FNRET(FALSE); + +// } else if(safe_str_eq(xml_action->name, "pseduo_event")){ + + } else if(safe_str_eq(xml_action->name, "crm_event")){ + /* + + */ + xmlNodePtr options = create_xml_node(NULL, "options"); + set_xml_property_copy(options, "op", task); + + send_ipc_request(crm_ch, options, NULL, + on_node, "crmd", "tengine", + NULL, NULL); + + free_xml(options); + + } else if(safe_str_eq(xml_action->name, "rsc_op")){ + /* + + + ... + */ + xmlNodePtr options = create_xml_node(NULL, "options"); + xmlNodePtr data = create_xml_node(NULL, "msg_data"); + xmlNodePtr rsc_op = create_xml_node(data, "rsc_op"); + + set_xml_property_copy(options, "op", "rsc_op"); + + set_xml_property_copy(rsc_op, "id", id); + set_xml_property_copy(rsc_op, "task", task); + set_xml_property_copy(rsc_op, "on_node", on_node); + + add_node_copy(rsc_op, xml_action->children); + + send_ipc_request(crm_ch, options, data, + on_node, "lrmd", "tengine", + NULL, NULL); + + free_xml(options); + free_xml(data); + + } else { + // error + cl_log(LOG_ERR, "Action %s is not (yet?) supported", + xml_action->name); + + FNRET(FALSE); + } + + FNRET(TRUE); + +} + +void +process_te_message(xmlNodePtr msg) +{ + const char *op = get_xml_attr (msg, XML_TAG_OPTIONS,XML_ATTR_OP, TRUE); + + if(op == NULL){ + // error + } else if(strcmp(op, "transition")) { + initialize_graph(); + unpack_graph(msg); + initiate_transition(); + + } else if(strcmp(op, "event")) { + process_event(msg); + + } else if(strcmp(op, "abort")) { + initialize_graph(); + + } else if(strcmp(op, "quit")) { + cl_log(LOG_WARNING, "Received quit message, terminating"); + exit(0); + } + +/* + answer = process_te_message(root_xml_node); + if (send_xmlipc_message(sender, answer)==FALSE) + cl_log(LOG_WARNING, "Cib answer could not be sent"); +*/ +// return NULL; +} diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h new file mode 100644 index 0000000000..0b7e97b511 --- /dev/null +++ b/crm/tengine/tengine.h @@ -0,0 +1,15 @@ +#ifndef TENGINE__H +#define TENGINE__H + +extern gboolean initialize_graph(void); +extern gboolean unpack_graph(xmlNodePtr xml_graph); +extern gboolean process_event(xmlNodePtr msg); +extern gboolean initiate_transition(void); +extern gboolean te_input_dispatch(IPC_Channel *sender, void *user_data); +extern void process_te_message(xmlNodePtr msg); + +extern IPC_Channel *crm_ch; + +#endif + + diff --git a/crm/tengine/tenginemain.c b/crm/tengine/tenginemain.c index 30d3bd9dea..7d988e4ea2 100644 --- a/crm/tengine/tenginemain.c +++ b/crm/tengine/tenginemain.c @@ -1,236 +1,237 @@ -/* $Id: tenginemain.c,v 1.12 2004/04/26 12:36:24 msoffen Exp $ */ +/* $Id: tenginemain.c,v 1.13 2004/05/06 12:11:59 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 #include #include #include #include #include #include +#include + #include #define OPTARGS "skrh" #define PID_FILE WORKING_DIR "/transitioner.pid" #define DAEMON_LOG "/var/log/transitioner.log" #define DAEMON_DEBUG "/var/log/transitioner.debug" GMainLoop* mainloop = NULL; const char* crm_system_name = "transitioner"; void usage(const char* cmd, int exit_status); int init_start(void); void tengine_shutdown(int nsig); 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); if (0) { send_ipc_message(NULL, NULL); } 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){ return init_status(PID_FILE, crm_system_name); } if (req_stop){ return init_stop(PID_FILE); } if (req_restart) { init_stop(PID_FILE); } return init_start(); } int init_start(void) { long pid; ll_cluster_t* hb_fd = NULL; int facility; - IPC_Channel *crm_ch = NULL; #ifdef REALTIME_SUPPORT static int crm_realtime = 1; #endif if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { cl_log(LOG_CRIT, "already running: [pid %ld].", pid); exit(LSB_EXIT_OK); } cl_log_set_logfile(DAEMON_LOG); // if (crm_debug()) { cl_log_set_debugfile(DAEMON_DEBUG); // } /* change the logging facility to the one used by heartbeat daemon */ hb_fd = ll_cluster_new("heartbeat"); cl_log(LOG_INFO, "Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } cl_log(LOG_INFO, "Register PID"); register_pid(PID_FILE, FALSE, tengine_shutdown); crm_ch = init_client_ipc_comms("crmd", - default_ipc_input_dispatch, - NULL); + subsystem_input_dispatch, + (void*)process_te_message); 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); cl_log(LOG_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 { cl_log(LOG_ERR, "Could not connect to the CRMd"); } return_to_orig_privs(); if (unlink(PID_FILE) == 0) { cl_log(LOG_INFO, "[%s] stopped", crm_system_name); } if(crm_ch != NULL) return 0; return 1; } 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); } void tengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, tengine_shutdown); if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); }else{ exit(LSB_EXIT_OK); } }