diff --git a/crm/crmd/Makefile.am b/crm/crmd/Makefile.am index d0c53a1ced..764936c440 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_SOURCES = crmdmain.c crmd.c \ fsa.c control.c messages.c ccm.c \ - election.c subsystems.c misc.c + election.c subsystems.c misc.c lrm.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/subsystems.c b/crm/crmd/subsystems.c index 390cfd1036..eac62e664d 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,1256 +1,681 @@ /* * 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 // for access #include #include #include // for calls to open #include // for calls to open #include // for calls to open #include // for getpwuid #include // for initgroups #include // for getrlimit #include // for getrlimit #include #include #include #include #include #include #include #include #include #include #include #define CLIENT_EXIT_WAIT 10 static gboolean stop_subsystem (struct crm_subsystem_s *centry); static gboolean start_subsystem(struct crm_subsystem_s *centry); -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); - struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; 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; } /* 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 tmp1 = NULL; xmlNodePtr tmp2 = NULL; xmlNodePtr new_options = NULL; const char *req_from; 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 } if(safe_str_eq(op, CRM_OPERATION_SHUTDOWN_REQ)){ // create update section tmp2 = create_xml_node(NULL, XML_CIB_TAG_STATE); req_from = xmlGetProp(cib_msg, XML_ATTR_HOSTFROM); set_xml_property_copy(tmp1, "id", req_from); set_xml_property_copy(tmp1, "exp_state", "shutdown"); // create fragment tmp1 = create_cib_fragment(tmp2, NULL); // add to cib_msg add_node_copy(cib_msg, tmp1); free_xml(tmp2); free_xml(tmp1); } 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_OPERATION_CREATE) == 0 || strcmp(op, CRM_OPERATION_UPDATE) == 0 || strcmp(op, CRM_OPERATION_DELETE) == 0 || strcmp(op, CRM_OPERATION_REPLACE) == 0 || strcmp(op, CRM_OPERATION_WELCOME) == 0 || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OPERATION_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_OPERATION_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_OPERATION_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, "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, "options"); true_op = xmlGetProp(opts, XML_ATTR_OP); set_xml_property_copy(opts, XML_ATTR_OP, "event"); set_xml_property_copy(opts, "true_op", 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, "transition", NULL, CRM_SYSTEM_TENGINE, NULL); } else { send_request(NULL, graph, "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(); CRM_DEBUG("A client tried to connect... and there was much rejoicing."); 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; CRM_DEBUG("Adding IPC Channel to main thread."); 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, "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; } -/* 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_DEBUG("LRM: connect..."); - fsa_lrm_conn = ll_lrm_new("lrm"); - if(NULL == fsa_lrm_conn) { - return failed; - } - - CRM_DEBUG("LRM: sigon..."); - ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn, - "crmd"); - - if(ret != HA_OK) { - cl_log(LOG_ERR, "Failed to sign on to the LRM"); - return failed; - } - - CRM_DEBUG("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, "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, "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, "lrm_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, "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); - - CRM_DEBUG("get_cur_state..."); - - op_list = the_rsc->ops->get_cur_state(the_rsc, - &cur_state); - CRM_DEBUG("\tcurrent state:%s\n", - cur_state==LRM_RSC_IDLE?"Idel":"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 = ""; - 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_lrm", "true"); - - tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); - set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); - // if we are doing this we are active - set_xml_property_copy(tmp1, "state", "active"); - - // either active or shutdown if R_SHUTDOWN is set - set_xml_property_copy(tmp1, "exp_state", "active"); - - fragment = create_cib_fragment(tmp1, NULL); - - set_xml_property_copy(data, "replace_lrm", "true"); - add_node_copy(tmp1, data); - - send_request(NULL, fragment, CRM_OPERATION_UPDATE, - NULL, CRM_SYSTEM_DC, NULL); - - 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, - "task", TRUE); - - id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, - "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, "lrm"); - - CRM_DEBUG("performing op %s...", operation); - - // so we can identify where to do the update - set_xml_property_copy(state, "id", fsa_our_uname); - - iter = create_xml_node(iter, "lrm_resources"); - iter = create_xml_node(iter, "lrm_resource"); - - set_xml_property_copy(iter, XML_ATTR_ID, id_from_cib); - set_xml_property_copy(iter, "last_op", 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, "op_status", op_status); - set_xml_property_copy(iter, "op_code", op_code_s); - set_xml_property_copy(iter, "op_node", fsa_our_uname); - - crm_free(op_code_s); - - update = create_cib_fragment(state, NULL); - - send_request(NULL, update, "update", - NULL, 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, - "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("add_rsc..."); - 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, - "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, "name"); - const char *value = xmlGetProp(node_iter, "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) -{ -/* - - - - - - -*/ - 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, "lrm"); - iter = create_xml_node(iter, "lrm_resources"); - iter = create_xml_node(iter, "lrm_resource"); - - set_xml_property_copy(iter, XML_ATTR_ID, rsc->id); - set_xml_property_copy(iter, "last_op", op_type); - - tmp = crm_itoa(status); - set_xml_property_copy(iter, "op_status", tmp); - crm_free(tmp); - - tmp = crm_itoa(rc); - set_xml_property_copy(iter, "op_code", tmp); - crm_free(tmp); - - set_xml_property_copy(iter, "op_node", 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_OPERATION_UPDATE, - NULL, 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_DEBUG("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); -} -