Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c
index 1f9872c888..da4d7dddb1 100644
--- a/crm/crmd/subsystems.c
+++ b/crm/crmd/subsystems.c
@@ -1,1256 +1,1284 @@
/*
* 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 <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);
static gboolean run_command (struct crm_subsystem_s *centry,
const char *options,
gboolean update_pid);
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) {
cl_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 *)cl_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)
{
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);
}
return run_command(centry, "-r", TRUE);
}
static gboolean
run_command(struct crm_subsystem_s *centry,
const char *options,
gboolean update_pid)
{
pid_t pid;
struct stat buf;
int s_res,size;
char *cmd_with_options = NULL;
/*
* 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 */
#if 0
NewTrackedProc(pid, 1, PT_LOGVERBOSE
, centry, &ManagedChildTrackOps);
#else
if(update_pid)
centry->pid = pid;
#endif
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);
}
size = strlen(options);
size += strlen(centry->command);
size += 2; // ' ' + \0
cmd_with_options = cl_malloc((1+size)*sizeof(char));
sprintf(cmd_with_options, "%s %s", centry->command, options);
cmd_with_options[size] = 0;
cl_log(LOG_INFO, "Executing \"%s\" (pid %d)",
cmd_with_options, (int) getpid());
if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) {
cl_perror("Cannot set interrupt for child process %s",
cmd_with_options);
}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", cmd_with_options, (const char *)NULL);
/* Should not happen */
cl_perror("Cannot exec %s", cmd_with_options);
}
/* 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 = "<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_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")) {
-
- CRM_DEBUG("performing op %s...", operation);
+
+ 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");
- iter = create_xml_node(iter, "lrm_resources");
- iter = create_xml_node(iter, "lrm_resource");
+ 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);
- if(safe_str_eq(operation, "start")){
- set_xml_property_copy(iter, "op_status", "started");
+ 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 {
- set_xml_property_copy(iter, "op_status", "stopped");
+ // pass
+ if(safe_str_eq(operation, "start")){
+ op_status = "started";
+ } else {
+ op_status = "stopped";
+ }
}
- set_xml_property_copy(iter, "op_code", "0");
- set_xml_property_copy(iter, "op_node", fsa_our_uname);
+ 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);
+ cl_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,
cl_strdup(key),
cl_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, "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);
cl_free(tmp);
tmp = crm_itoa(rc);
set_xml_property_copy(iter, "op_code", tmp);
cl_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);
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 21, 7:07 PM (16 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1665366
Default Alt Text
(30 KB)

Event Timeline