Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/common/crmutils.c b/crm/common/crmutils.c
index 1bdc5f8d97..48a97eebdd 100644
--- a/crm/common/crmutils.c
+++ b/crm/common/crmutils.c
@@ -1,393 +1,390 @@
-/* $Id: crmutils.c,v 1.14 2004/05/10 21:52:57 andrew Exp $ */
+/* $Id: crmutils.c,v 1.15 2004/05/12 14:27:16 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <apphb.h>
#include <clplumbing/cl_log.h>
#include <clplumbing/Gmain_timeout.h>
#include <crmutils.h>
#include <xmlutils.h>
#include <crm/dmalloc_wrapper.h>
static int wdt_interval_ms = 10000;
gboolean
tickle_apphb_template(gpointer data)
{
char app_instance[APPNAME_LEN];
int rc = 0;
sprintf(app_instance, "%s_%ld", "our_system_name", (long)getpid());
rc = apphb_hb();
if (rc < 0) {
cl_perror("%s apphb_hb failure", app_instance);
exit(3);
}
return TRUE;
}
void
register_pid(const char *pid_file,
gboolean do_fork,
void (*shutdown)(int nsig))
{
int j;
long pid;
FILE * lockfd;
if (do_fork) {
pid = fork();
if (pid < 0) {
cl_log(LOG_CRIT, "cannot start daemon");
exit(LSB_EXIT_GENERIC);
}else if (pid > 0) {
exit(LSB_EXIT_OK);
}
}
lockfd = fopen(pid_file, "w");
if (lockfd == NULL) {
cl_log(LOG_CRIT, "cannot create pid file: %s", pid_file);
exit(LSB_EXIT_GENERIC);
}else{
pid = getpid();
fprintf(lockfd, "%ld\n", pid);
fclose(lockfd);
}
umask(022);
for (j=0; j < 3; ++j) {
close(j);
(void)open("/dev/null", j == 0 ? O_RDONLY : O_RDONLY);
}
// CL_IGNORE_SIG(SIGINT);
// CL_IGNORE_SIG(SIGHUP);
CL_SIGNAL(SIGTERM, shutdown);
}
long
get_running_pid(const char *pid_file, gboolean* anypidfile)
{
long pid;
FILE * lockfd;
lockfd = fopen(pid_file, "r");
if (anypidfile) {
*anypidfile = (lockfd != NULL);
}
if (lockfd != NULL
&& fscanf(lockfd, "%ld", &pid) == 1 && pid > 0) {
if (CL_PID_EXISTS((pid_t)pid)) {
fclose(lockfd);
return(pid);
}
}
if (lockfd != NULL) {
fclose(lockfd);
}
return(-1L);
}
int
init_stop(const char *pid_file)
{
long pid;
int rc = LSB_EXIT_OK;
FNIN();
if (pid_file == NULL) {
cl_log(LOG_ERR, "No pid file specified to kill process");
return LSB_EXIT_GENERIC;
}
pid = get_running_pid(pid_file, NULL);
if (pid > 0) {
if (CL_KILL((pid_t)pid, SIGTERM) < 0) {
rc = (errno == EPERM
? LSB_EXIT_EPERM : LSB_EXIT_GENERIC);
fprintf(stderr, "Cannot kill pid %ld\n", pid);
}else{
cl_log(LOG_INFO,
"Signal sent to pid=%ld,"
" waiting for process to exit",
pid);
while (CL_PID_EXISTS(pid)) {
sleep(1);
}
}
}
FNRET(rc);
}
int
init_status(const char *pid_file, const char *client_name)
{
gboolean anypidfile;
long pid = get_running_pid(pid_file, &anypidfile);
if (pid > 0) {
fprintf(stderr, "%s is running [pid: %ld]\n"
, client_name, pid);
return LSB_STATUS_OK;
}
if (anypidfile) {
fprintf(stderr, "%s is stopped [pidfile exists]\n"
, client_name);
return LSB_STATUS_VAR_PID;
}
fprintf(stderr, "%s is stopped.\n", client_name);
return LSB_STATUS_STOPPED;
}
gboolean
register_with_ha(ll_cluster_t *hb_cluster, const char *client_name,
gboolean (*dispatch_method)(int fd, gpointer user_data),
void (*message_callback)(const struct ha_msg* msg,
void* private_data),
GDestroyNotify cleanup_method)
{
const char* ournode = NULL;
cl_log(LOG_INFO, "Signing in with Heartbeat");
if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) {
cl_log(LOG_ERR, "Cannot sign on with heartbeat");
cl_log(LOG_ERR,
"REASON: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
cl_log(LOG_DEBUG, "Finding our node name");
if ((ournode =
hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) {
cl_log(LOG_ERR, "get_mynodeid() failed");
return FALSE;
}
cl_log(LOG_INFO, "hostname: %s", ournode);
cl_log(LOG_DEBUG, "Be informed of CRM messages");
if (hb_cluster->llc_ops->set_msg_callback(hb_cluster,
"CRM",
message_callback,
hb_cluster)
!=HA_OK){
cl_log(LOG_ERR, "Cannot set CRM message callback");
cl_log(LOG_ERR,
"REASON: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
G_main_add_fd(G_PRIORITY_HIGH,
hb_cluster->llc_ops->inputfd(hb_cluster),
FALSE,
dispatch_method,
hb_cluster, // usrdata
cleanup_method);
/* it seems we need to poke the message receiving stuff in order for it to
* start seeing messages. Its like it gets blocked or something.
*/
dispatch_method(0, hb_cluster);
return TRUE;
}
void
register_with_apphb(const char *client_name,
gboolean(*tickle_fn)(gpointer data))
{
char app_instance[APPNAME_LEN];
int hb_intvl_ms = wdt_interval_ms * 2;
int rc = 0;
// Register with apphb
cl_log(LOG_INFO, "Signing in with AppHb");
sprintf(app_instance, "%s_%ld", client_name, (long)getpid());
cl_log(LOG_INFO, "Client %s registering with apphb", app_instance);
rc = apphb_register(client_name, app_instance);
if (rc < 0) {
cl_perror("%s registration failure", app_instance);
exit(1);
}
cl_log(LOG_DEBUG, "Client %s registered with apphb", app_instance);
cl_log(LOG_INFO,
"Client %s setting %d ms apphb heartbeat interval"
, app_instance, hb_intvl_ms);
rc = apphb_setinterval(hb_intvl_ms);
if (rc < 0) {
cl_perror("%s setinterval failure", app_instance);
exit(2);
}
// regularly tell apphb that we are alive
cl_log(LOG_INFO, "Setting up AppHb Heartbeat");
Gmain_timeout_add(wdt_interval_ms, tickle_fn, NULL);
}
char *
crm_itoa(int an_int)
{
int len = 32;
char *buffer = cl_malloc(sizeof(char)*(len+1));
snprintf(buffer, len, "%d", an_int);
return buffer;
}
gboolean
subsystem_input_dispatch(IPC_Channel *sender, void *user_data)
{
int lpc = 0;
char *buffer = NULL;
xmlDocPtr doc = NULL;
IPC_Message *msg = NULL;
gboolean all_is_well = TRUE;
xmlNodePtr answer = NULL, root_xml_node = NULL;
const char *sys_to;
const char *type;
FNIN();
while(sender->ops->is_message_pending(sender)) {
if (sender->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
if (sender->ops->recv(sender, &msg) != IPC_OK) {
perror("Receive failure:");
FNRET(!all_is_well);
}
if (msg == NULL) {
cl_log(LOG_ERR, "No message this time");
continue;
}
lpc++;
/* the docs say only do this once, but in their code
* they do it every time!
*/
// xmlInitParser();
buffer = (char*)msg->msg_body;
cl_log(LOG_DEBUG, "Message %d [text=%s]", lpc, buffer);
doc = xmlParseMemory(cl_strdup(buffer), strlen(buffer));
if(doc == NULL) {
cl_log(LOG_INFO,
"XML Buffer was not valid...\n Buffer: (%s)",
buffer);
}
root_xml_node = xmlDocGetRootElement(doc);
sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO);
type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE);
if (root_xml_node == NULL) {
cl_log(LOG_ERR, "Root node was NULL!!");
- } else if (safe_str_eq(root_xml_node->name, "hello")) {
- cl_log(LOG_WARNING, "HACK: Ignore hello messages");
-
} else if(sys_to == NULL) {
cl_log(LOG_ERR, "Value of %s was NULL!!",
XML_ATTR_SYSTO);
} else if(type == NULL) {
cl_log(LOG_ERR, "Value of %s was NULL!!",
XML_ATTR_MSGTYPE);
} else if(strcmp(type, XML_ATTR_REQUEST) != 0) {
cl_log(LOG_INFO,
"Message was a response not a request."
" Discarding");
} else {
gboolean (*process_function)(xmlNodePtr msg, IPC_Channel *sender) = NULL;
process_function = user_data;
if(process_function(root_xml_node, sender) == FALSE) {
cl_log(LOG_WARNING,
"Received a message destined for %s"
" by mistake", sys_to);
}
}
if(answer != NULL)
free_xml(answer);
answer = NULL;
msg->msg_done(msg);
msg = NULL;
}
// clean up after a break
if(msg != NULL)
msg->msg_done(msg);
if(root_xml_node != NULL)
free_xml(root_xml_node);
CRM_DEBUG("Processed %d messages", lpc);
if (sender->ch_status == IPC_DISCONNECT) {
cl_log(LOG_ERR, "The server has left us: Shutting down...NOW");
exit(1); // shutdown properly later
FNRET(!all_is_well);
}
FNRET(all_is_well);
}
diff --git a/crm/common/msgutils.c b/crm/common/msgutils.c
index e41ecb5fff..d0a73b49f5 100644
--- a/crm/common/msgutils.c
+++ b/crm/common/msgutils.c
@@ -1,738 +1,731 @@
-/* $Id: msgutils.c,v 1.28 2004/05/10 21:52:57 andrew Exp $ */
+/* $Id: msgutils.c,v 1.29 2004/05/12 14:27:16 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <crm/crm.h>
#include <clplumbing/cl_log.h>
#include <time.h>
#include <msgutils.h>
#include <ha_msg.h>
#include <ipcutils.h>
#include <xmlutils.h>
#include <crm/msg_xml.h>
#include <crm/dmalloc_wrapper.h>
xmlNodePtr
create_common_message(xmlNodePtr original_request,
xmlNodePtr xml_response_data);
xmlNodePtr
createPingAnswerFragment(const char *from, const char *status)
{
xmlNodePtr ping = NULL;
FNIN();
ping = create_xml_node(NULL, XML_CRM_TAG_PING);
set_xml_property_copy(ping, XML_PING_ATTR_STATUS, status);
set_xml_property_copy(ping, XML_PING_ATTR_SYSFROM, from);
FNRET(ping);
}
xmlNodePtr
createPingRequest(const char *crm_msg_reference, const char *to)
{
xmlNodePtr root_xml_node = NULL;
int sub_type_len;
int msg_type_len;
char *sub_type_target;
char *msg_type_target;
FNIN();
// 2 = "_" + '\0'
sub_type_len = strlen(to) + strlen(XML_ATTR_REQUEST) + 2;
sub_type_target =
(char*)cl_malloc(sizeof(char)*(sub_type_len));
sprintf(sub_type_target, "%s_%s", to, XML_ATTR_REQUEST);
root_xml_node = create_xml_node(NULL, sub_type_target);
set_xml_property_copy(root_xml_node,
XML_ATTR_REFERENCE,
crm_msg_reference);
msg_type_len = strlen(to) + 10 + 1; // + "_operation" + '\0'
msg_type_target =
(char*)cl_malloc(sizeof(char)*(msg_type_len));
sprintf(msg_type_target, "%s_operation", to);
set_xml_property_copy(root_xml_node, msg_type_target, CRM_OPERATION_PING);
cl_free(msg_type_target);
FNRET(root_xml_node);
}
static uint ref_counter = 0;
const char *
generateReference(const char *custom1, const char *custom2)
{
const char *local_cust1 = custom1;
const char *local_cust2 = custom2;
int reference_len = 4;
char *since_epoch = NULL;
FNIN();
reference_len += 20; // too big
reference_len += 40; // too big
if(local_cust1 == NULL) local_cust1 = "_empty_";
reference_len += strlen(local_cust1);
if(local_cust2 == NULL) local_cust2 = "_empty_";
reference_len += strlen(local_cust2);
since_epoch = (char*)cl_malloc(reference_len*(sizeof(char)));
FNIN();
sprintf(since_epoch, "%s-%s-%ld-%u",
local_cust1, local_cust2,
(unsigned long)time(NULL), ref_counter++);
FNRET(since_epoch);
}
xmlNodePtr
validate_crm_message(xmlNodePtr root_xml_node,
const char *sys,
const char *uuid,
const char *msg_type)
{
const char *from = NULL;
const char *to = NULL;
const char *type = NULL;
const char *crm_msg_reference = NULL;
xmlNodePtr action = NULL;
const char *true_sys;
FNIN();
if (root_xml_node == NULL)
FNRET(NULL);
from = xmlGetProp(root_xml_node, XML_ATTR_SYSFROM);
to = xmlGetProp(root_xml_node, XML_ATTR_SYSTO);
type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE);
crm_msg_reference = xmlGetProp(root_xml_node,
XML_ATTR_REFERENCE);
/*
cl_log(LOG_DEBUG, "Recieved XML message with (version=%s)",
xmlGetProp(root_xml_node, XML_ATTR_VERSION));
cl_log(LOG_DEBUG, "Recieved XML message with (from=%s)", from);
cl_log(LOG_DEBUG, "Recieved XML message with (to=%s)" , to);
cl_log(LOG_DEBUG, "Recieved XML message with (type=%s)", type);
cl_log(LOG_DEBUG, "Recieved XML message with (ref=%s)" ,
crm_msg_reference);
*/
action = root_xml_node;
true_sys = sys;
if (uuid != NULL) true_sys = generate_hash_key(sys, uuid);
if (to == NULL) {
cl_log(LOG_INFO, "No sub-system defined.");
action = NULL;
} else if (true_sys != NULL && strcmp(to, true_sys) != 0) {
cl_log(LOG_DEBUG,
"The message is not for this sub-system (%s != %s).",
to,
true_sys);
action = NULL;
}
if (type == NULL) {
cl_log(LOG_INFO, "No message type defined.");
FNRET(NULL);
} else if (msg_type != NULL && strcmp(msg_type, type) != 0) {
cl_log(LOG_INFO,
"Expecting a (%s) message but receieved a (%s).",
msg_type, type);
action = NULL;
}
if (crm_msg_reference == NULL) {
cl_log(LOG_INFO, "No message crm_msg_reference defined.");
action = NULL;
}
/*
if(action != NULL)
cl_log(LOG_DEBUG,
"XML is valid and node with message type (%s) found.",
type);
cl_log(LOG_DEBUG, "Returning node (%s)", xmlGetNodePath(action));
*/
FNRET(action);
}
gboolean
decodeNVpair(const char *srcstring, char separator, char **name, char **value)
{
int lpc = 0;
int len = 0;
const char *temp = NULL;
FNIN();
CRM_DEBUG("Attempting to decode: [%s]", srcstring);
if (srcstring != NULL) {
len = strlen(srcstring);
while(lpc < len) {
if (srcstring[lpc++] == separator) {
*name = (char*)cl_malloc(sizeof(char)*lpc);
CRM_DEBUG("Malloc ok %d", lpc);
strncpy(*name, srcstring, lpc-1);
CRM_DEBUG("Strcpy ok %d", lpc-1);
(*name)[lpc-1] = '\0';
CRM_DEBUG("Found token [%s]", *name);
// this sucks but as the strtok *is* a bug
len = len-lpc+1;
*value = (char*)cl_malloc(sizeof(char)*len);
CRM_DEBUG("Malloc ok %d", len);
temp = srcstring+lpc;
CRM_DEBUG("Doing str copy");
strncpy(*value, temp, len-1);
(*value)[len-1] = '\0';
CRM_DEBUG("Found token [%s]", *value);
FNRET(TRUE);
}
}
}
*name = NULL;
*value = NULL;
FNRET(FALSE);
}
char *
generate_hash_key(const char *crm_msg_reference, const char *sys)
{
- int ref_len = strlen(sys) + strlen(crm_msg_reference) + 2;
+ int ref_len = strlen(sys?sys:"none") + strlen(crm_msg_reference) + 2;
char *hash_key = (char*)cl_malloc(sizeof(char)*(ref_len));
FNIN();
- sprintf(hash_key, "%s_%s", sys, crm_msg_reference);
+ sprintf(hash_key, "%s_%s", sys?sys:"none", crm_msg_reference);
hash_key[ref_len-1] = '\0';
cl_log(LOG_INFO, "created hash key: (%s)", hash_key);
FNRET(hash_key);
}
char *
generate_hash_value(const char *src_node, const char *src_subsys)
{
int ref_len;
char *hash_value;
FNIN();
if (src_node == NULL || src_subsys == NULL) {
FNRET(NULL);
}
if (strcmp("dc", src_subsys) == 0) {
hash_value = cl_strdup(src_subsys);
if (!hash_value) {
cl_log(LOG_ERR,
"memory allocation failed in "
"generate_hash_value()\n");
FNRET(NULL);
}
FNRET(hash_value);
}
ref_len = strlen(src_subsys) + strlen(src_node) + 2;
hash_value = (char*)cl_malloc(sizeof(char)*(ref_len));
if (!hash_value) {
cl_log(LOG_ERR,
"memory allocation failed in "
"generate_hash_value()\n");
FNRET(NULL);
}
snprintf(hash_value, ref_len-1, "%s_%s", src_node, src_subsys);
hash_value[ref_len-1] = '\0';// make sure it is null terminated
cl_log(LOG_INFO, "created hash value: (%s)", hash_value);
FNRET(hash_value);
}
gboolean
decode_hash_value(gpointer value, char **node, char **subsys)
{
char *char_value = (char*)value;
int value_len = strlen(char_value);
FNIN();
cl_log(LOG_INFO, "Decoding hash value: (%s:%d)",
char_value,
value_len);
if (strcmp("dc", (char*)value) == 0) {
*node = NULL;
*subsys = (char*)cl_strdup(char_value);
if (!*subsys) {
cl_log(LOG_ERR, "memory allocation failed in "
"decode_hash_value()\n");
FNRET(FALSE);
}
cl_log(LOG_INFO, "Decoded value: (%s:%d)", *subsys,
(int)strlen(*subsys));
FNRET(TRUE);
}
else if (char_value != NULL) {
if (decodeNVpair(char_value, '_', node, subsys)) {
FNRET(TRUE);
} else {
*node = NULL;
*subsys = NULL;
FNRET(FALSE);
}
}
FNRET(FALSE);
}
void
send_hello_message(IPC_Channel *ipc_client,
const char *uuid,
const char *client_name,
const char *major_version,
const char *minor_version)
{
xmlNodePtr hello_node = NULL;
FNIN();
if (uuid == NULL || strlen(uuid) == 0
|| client_name == NULL || strlen(client_name) == 0
|| major_version == NULL || strlen(major_version) == 0
|| minor_version == NULL || strlen(minor_version) == 0) {
cl_log(LOG_ERR,
"Missing fields, Hello message will not be valid.");
return;
}
- hello_node = create_xml_node(NULL, "hello");
+ hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
set_xml_property_copy(hello_node, "major_version", major_version);
set_xml_property_copy(hello_node, "minor_version", minor_version);
set_xml_property_copy(hello_node, "client_name", client_name);
set_xml_property_copy(hello_node, "client_uuid", uuid);
+ set_xml_property_copy(hello_node, "operation", "hello");
- send_xmlipc_message(ipc_client, hello_node);
+ send_ipc_request(ipc_client,
+ hello_node, NULL,
+ NULL, NULL,
+ client_name, uuid,
+ NULL);
free_xml(hello_node);
}
gboolean
-process_hello_message(IPC_Message *hello_message,
+process_hello_message(xmlNodePtr hello,
char **uuid,
char **client_name,
char **major_version,
char **minor_version)
{
- xmlNodePtr hello;
- xmlDocPtr hello_doc;
- char *local_uuid;
- char *local_client_name;
- char *local_major_version;
- char *local_minor_version;
+ xmlNodePtr opts = NULL;
+ const char *op = NULL;
+ const char *local_uuid;
+ const char *local_client_name;
+ const char *local_major_version;
+ const char *local_minor_version;
FNIN();
*uuid = NULL;
*client_name = NULL;
*major_version = NULL;
*minor_version = NULL;
- if (hello_message == NULL || hello_message->msg_body == NULL) {
- FNRET(FALSE);
- }
+ opts = find_xml_node(hello, XML_TAG_OPTIONS);
+
+ op = xmlGetProp(opts, "operation");
+ local_uuid = xmlGetProp(opts, "client_uuid");
+ local_client_name = xmlGetProp(opts, "client_name");
+ local_major_version = xmlGetProp(opts, "major_version");
+ local_minor_version = xmlGetProp(opts, "minor_version");
- hello_doc = xmlParseMemory(
- hello_message->msg_body,
- strlen(hello_message->msg_body));
- if (hello_doc == NULL) {
- cl_log(LOG_ERR,
- "Expected a Hello message, Got: %s",
- (char*)hello_message->msg_body);
- FNRET(FALSE);
- }
-
- hello = xmlDocGetRootElement(hello_doc);
- if (hello == NULL) {
+ if (op == NULL || strcmp("hello", op) != 0) {
FNRET(FALSE);
- } else if (strcmp("hello", hello->name) != 0) {
- FNRET(FALSE);
- }
-
- local_uuid = xmlGetProp(hello, "client_uuid");
- local_client_name = xmlGetProp(hello, "client_name");
- local_major_version = xmlGetProp(hello, "major_version");
- local_minor_version = xmlGetProp(hello, "minor_version");
- if (local_uuid == NULL || strlen(local_uuid) == 0) {
+ } else if (local_uuid == NULL || strlen(local_uuid) == 0) {
cl_log(LOG_ERR,
- "Hello message was not valid (field %s not found): %s",
- "uuid", (char*)hello_message->msg_body);
+ "Hello message was not valid (field %s not found)",
+ "uuid");
FNRET(FALSE);
+
} else if (local_client_name==NULL || strlen(local_client_name)==0){
cl_log(LOG_ERR,
- "Hello message was not valid (field %s not found): %s",
- "client name", (char*)hello_message->msg_body);
+ "Hello message was not valid (field %s not found)",
+ "client name");
FNRET(FALSE);
+
} else if(local_major_version == NULL
|| strlen(local_major_version) == 0){
cl_log(LOG_ERR,
- "Hello message was not valid (field %s not found): %s",
- "major version", (char*)hello_message->msg_body);
+ "Hello message was not valid (field %s not found)",
+ "major version");
FNRET(FALSE);
+
} else if (local_minor_version == NULL
|| strlen(local_minor_version) == 0){
cl_log(LOG_ERR,
- "Hello message was not valid (field %s not found): %s",
- "minor version", (char*)hello_message->msg_body);
+ "Hello message was not valid (field %s not found)",
+ "minor version");
FNRET(FALSE);
}
- *uuid = cl_strdup(local_uuid);
+ *uuid = cl_strdup(local_uuid);
*client_name = cl_strdup(local_client_name);
*major_version = cl_strdup(local_major_version);
*minor_version = cl_strdup(local_minor_version);
FNRET(TRUE);
}
gboolean
forward_ipc_request(IPC_Channel *ipc_channel,
xmlNodePtr xml_request, xmlNodePtr xml_response_data,
const char *sys_to, const char *sys_from)
{
gboolean was_sent = FALSE;
xmlNodePtr forward;
FNIN();
forward = create_forward(xml_request,
xml_response_data,
sys_to);
if (forward != NULL)
{
was_sent = send_xmlipc_message(ipc_channel, forward);
free_xml(forward);
}
FNRET(was_sent);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_ipc_request(IPC_Channel *ipc_channel,
xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference)
{
gboolean was_sent = FALSE;
xmlNodePtr request = NULL;
FNIN();
request = create_request(msg_options, msg_data,
host_to, sys_to,
sys_from, uuid_from,
crm_msg_reference);
// xml_message_debug(request, "Final request...");
was_sent = send_xmlipc_message(ipc_channel, request);
free_xml(request);
FNRET(was_sent);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_ha_request(ll_cluster_t *hb_fd,
xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference)
{
gboolean was_sent = FALSE;
xmlNodePtr request = NULL;
FNIN();
request = create_request(msg_options, msg_data,
host_to, sys_to,
sys_from, uuid_from,
crm_msg_reference);
// xml_message_debug(request, "Final request...");
was_sent = send_xmlha_message(hb_fd, request);
free_xml(request);
FNRET(was_sent);
}
xmlNodePtr
create_request(xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference)
{
const char *true_from = sys_from;
xmlNodePtr request;
FNIN();
if (uuid_from != NULL)
true_from = generate_hash_key(sys_from, uuid_from);
// else make sure we are internal
else {
if (strcmp(CRM_SYSTEM_LRMD, sys_from) != 0
&& strcmp(CRM_SYSTEM_PENGINE, sys_from) != 0
&& strcmp(CRM_SYSTEM_TENGINE, sys_from) != 0
&& strcmp(CRM_SYSTEM_DC, sys_from) != 0
&& strcmp(CRM_SYSTEM_CRMD, sys_from) != 0) {
cl_log(LOG_ERR,
"only internal systems can leave uuid_from blank");
FNRET(FALSE);
}
}
if (crm_msg_reference == NULL) {
crm_msg_reference =
generateReference(
xmlGetProp(msg_options,XML_ATTR_OP),sys_from);
}
// host_from will get set for us if necessary by CRMd when routed
request = create_xml_node(NULL, XML_MSG_TAG);
set_node_tstamp(request);
set_xml_property_copy(request, XML_ATTR_VERSION, CRM_VERSION);
set_xml_property_copy(request, XML_ATTR_MSGTYPE, XML_ATTR_REQUEST);
set_xml_property_copy(request, XML_ATTR_SYSTO, sys_to);
set_xml_property_copy(request, XML_ATTR_SYSFROM, true_from);
set_xml_property_copy(request, XML_ATTR_REFERENCE, crm_msg_reference);
if(host_to != NULL && strlen(host_to) > 0)
set_xml_property_copy(request, XML_ATTR_HOSTTO, host_to);
if (msg_options != NULL) {
add_node_copy(request, msg_options);
}
if (msg_data != NULL) {
add_node_copy(request, msg_data);
}
FNRET(request);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_ipc_reply(IPC_Channel *ipc_channel,
xmlNodePtr xml_request,
xmlNodePtr xml_response_data)
{
gboolean was_sent = FALSE;
xmlNodePtr reply;
FNIN();
reply = create_reply(xml_request, xml_response_data);
// xml_message_debug(reply, "Final reply...");
if (reply != NULL) {
was_sent = send_xmlipc_message(ipc_channel, reply);
free_xml(reply);
}
FNRET(was_sent);
}
// required? or just send to self an let relay_message do its thing?
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_ha_reply(ll_cluster_t *hb_cluster,
xmlNodePtr xml_request,
xmlNodePtr xml_response_data)
{
gboolean was_sent = FALSE;
xmlNodePtr reply;
FNIN();
was_sent = FALSE;
reply = create_reply(xml_request, xml_response_data);
if (reply != NULL) {
was_sent = send_xmlha_message(hb_cluster, reply);
free_xml(reply);
}
FNRET(was_sent);
}
/*
* This method adds a copy of xml_response_data
*/
xmlNodePtr
create_reply(xmlNodePtr original_request,
xmlNodePtr xml_response_data)
{
const char *host_from = NULL;
const char *sys_from = NULL;
const char *sys_to = NULL;
xmlNodePtr reply;
FNIN();
host_from = xmlGetProp(original_request, XML_ATTR_HOSTFROM);
sys_from = xmlGetProp(original_request, XML_ATTR_SYSFROM);
sys_to = xmlGetProp(original_request, XML_ATTR_SYSTO);
reply = create_common_message(original_request,
xml_response_data);
set_xml_property_copy(reply, XML_ATTR_MSGTYPE, XML_ATTR_RESPONSE);
/* since this is a reply, we reverse the from and to */
// HOSTTO will be ignored if it is to the DC anyway.
if(host_from != NULL && strlen(host_from) > 0)
set_xml_property_copy(reply, XML_ATTR_HOSTTO, host_from);
set_xml_property_copy(reply, XML_ATTR_SYSTO, sys_from);
set_xml_property_copy(reply, XML_ATTR_SYSFROM, sys_to);
FNRET(reply);
}
/*
* This method adds a copy of xml_response_data
*/
xmlNodePtr
create_forward(xmlNodePtr original_request,
xmlNodePtr xml_response_data,
const char *sys_to)
{
const char *host_from = NULL;
const char *host_to = NULL;
const char *sys_from = NULL;
xmlNodePtr forward;
FNIN();
host_from = xmlGetProp(original_request, XML_ATTR_HOSTFROM);
host_to = xmlGetProp(original_request, XML_ATTR_HOSTTO);
sys_from = xmlGetProp(original_request, XML_ATTR_SYSFROM);
forward = create_common_message(original_request,
xml_response_data);
set_xml_property_copy(forward,
XML_ATTR_MSGTYPE,
XML_ATTR_REQUEST);
// HOSTTO will be ignored if it is to the DC anyway.
if(host_to != NULL && strlen(host_to) > 0)
set_xml_property_copy(forward, XML_ATTR_HOSTTO, host_to);
if(host_from != NULL)
set_xml_property_copy(forward, XML_ATTR_HOSTFROM, host_from);
set_xml_property_copy(forward, XML_ATTR_SYSTO, sys_to);
set_xml_property_copy(forward, XML_ATTR_SYSFROM, sys_from);
FNRET(forward);
}
xmlNodePtr
create_common_message(xmlNodePtr original_request,
xmlNodePtr xml_response_data)
{
const char *crm_msg_reference = NULL;
const char *type = NULL;
const char *operation = NULL;
xmlNodePtr options = NULL;
xmlNodePtr new_message;
FNIN();
crm_msg_reference = xmlGetProp(original_request,
XML_ATTR_REFERENCE);
type = xmlGetProp(original_request, XML_ATTR_MSGTYPE);
operation = xmlGetProp(original_request, XML_ATTR_OP);
if (type == NULL) {
cl_log(LOG_ERR,
"Cannot create new_message,"
" no message type in original message");
FNRET(NULL);
#if 0
} else if (strcmp(XML_ATTR_REQUEST, type) != 0) {
cl_log(LOG_ERR,
"Cannot create new_message,"
" original message was not a request");
FNRET(NULL);
#endif
}
new_message = create_xml_node(NULL, XML_MSG_TAG);
set_node_tstamp(new_message);
set_xml_property_copy(new_message, XML_ATTR_VERSION, CRM_VERSION);
set_xml_property_copy(new_message, XML_ATTR_OP, operation);
set_xml_property_copy(new_message,
XML_ATTR_REFERENCE,
crm_msg_reference);
if (xml_response_data != NULL) {
add_node_copy(new_message, xml_response_data);
}
options = find_xml_node(original_request, XML_TAG_OPTIONS);
if (options != NULL) {
add_node_copy(new_message, options);
}
FNRET(new_message);
}
diff --git a/crm/common/msgutils.h b/crm/common/msgutils.h
index 87b1f447ef..e7a7cfb45c 100644
--- a/crm/common/msgutils.h
+++ b/crm/common/msgutils.h
@@ -1,108 +1,108 @@
-/* $Id: msgutils.h,v 1.10 2004/03/24 09:59:05 andrew Exp $ */
+/* $Id: msgutils.h,v 1.11 2004/05/12 14:27:16 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MSG_UTILS__H
#define MSG_UTILS__H
#include <libxml/tree.h>
#include <clplumbing/ipc.h>
#include <hb_api.h>
extern const char *generateReference(const char *custom1, const char *custom2);
extern xmlNodePtr validate_crm_message(xmlNodePtr root,
const char *sys,
const char *uuid,
const char *msg_type);
extern xmlNodePtr createPingAnswerFragment(const char *from,
const char *status);
extern xmlNodePtr createPingRequest(const char *crm_msg_reference,
const char *to);
gboolean decodeNVpair(const char *srcstring,
char separator,
char **name,
char **value);
extern void send_hello_message(IPC_Channel *ipc_client,
const char *uuid,
const char *client_name,
const char *major_version,
const char *minor_version);
-extern gboolean process_hello_message(IPC_Message *hello_message,
+extern gboolean process_hello_message(xmlNodePtr hello,
char **uuid,
char **client_name,
char **major_version,
char **minor_version);
extern gboolean forward_ipc_request(IPC_Channel *ipc_channel,
xmlNodePtr xml_request,
xmlNodePtr xml_response_data,
const char *sys_to,
const char *sys_from);
extern gboolean
send_ipc_request(IPC_Channel *ipc_channel,
xmlNodePtr xml_options, xmlNodePtr xml_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference);
extern gboolean
send_ha_request(ll_cluster_t *hb_fd,
xmlNodePtr xml_options, xmlNodePtr xml_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference);
extern gboolean send_ha_reply(ll_cluster_t *hb_cluster,
xmlNodePtr xml_request,
xmlNodePtr xml_response_data);
extern gboolean send_ipc_reply(IPC_Channel *ipc_channel,
xmlNodePtr xml_request,
xmlNodePtr xml_response_data);
extern xmlNodePtr create_forward(xmlNodePtr xml_request,
xmlNodePtr xml_response_data,
const char *sys_to);
extern xmlNodePtr createCrmMsg(xmlNodePtr data,
gboolean is_request);
extern xmlNodePtr create_reply(xmlNodePtr xml_request,
xmlNodePtr xml_response_data);
extern char *generate_hash_key(const char *crm_msg_reference,
const char *sys);
extern char *generate_hash_value(const char *src_node,
const char *src_subsys);
extern gboolean decode_hash_value(gpointer value,
char **node,
char **subsys);
extern xmlNodePtr
create_request(xmlNodePtr xml_options, xmlNodePtr xml_data,
const char *host_to, const char *sys_to,
const char *sys_from, const char *uuid_from,
const char *crm_msg_reference);
#endif
diff --git a/crm/crmd/election.c b/crm/crmd/election.c
index 92b44d83eb..ce199387ef 100644
--- a/crm/crmd/election.c
+++ b/crm/crmd/election.c
@@ -1,608 +1,586 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <libxml/tree.h>
#include <crm/msg_xml.h>
#include <crm/common/xmlutils.h>
#include <crm/common/ipcutils.h>
#include <crm/common/msgutils.h>
#include <crm/cib.h>
#include <string.h>
#include <crmd_messages.h>
#include <crm/dmalloc_wrapper.h>
GHashTable *joined_nodes = NULL;
/* A_ELECTION_VOTE */
enum crmd_fsa_input
do_election_vote(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input election_result = I_NULL;
FNIN();
/* dont vote if we're in one of these states or wanting to shut down */
switch(cur_state) {
case S_RECOVERY:
case S_RECOVERY_DC:
case S_STOPPING:
case S_RELEASE_DC:
case S_TERMINATE:
FNRET(I_NULL);
// log warning
break;
default:
if(is_set(fsa_input_register, R_SHUTDOWN)) {
FNRET(I_NULL);
// log warning
}
break;
}
send_request(NULL, NULL, CRM_OPERATION_VOTE, NULL, CRM_SYSTEM_CRMD);
FNRET(election_result);
}
gboolean
timer_popped(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
cl_log(LOG_INFO, "#!!#!!# Timer %s just popped!",
fsa_input2string(timer->fsa_input));
stopTimer(timer); // dont make it go off again
s_crmd_fsa(C_TIMER_POPPED, timer->fsa_input, NULL);
return TRUE;
}
gboolean
do_dc_heartbeat(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
// cl_log(LOG_DEBUG, "#!!#!!# Heartbeat timer just popped!");
gboolean was_sent = send_request(NULL, NULL, CRM_OPERATION_HBEAT,
NULL, CRM_SYSTEM_CRMD);
if(was_sent == FALSE) {
// this is bad
stopTimer(timer); // dont make it go off again
s_crmd_fsa(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL);
}
return TRUE;
}
/* A_ELECTION_COUNT */
enum crmd_fsa_input
do_election_count_vote(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
gboolean we_loose = FALSE;
xmlNodePtr vote = (xmlNodePtr)data;
unsigned int my_born = -1, your_born = -1;
int lpc = 0, my_index = -1, your_index = -1;
enum crmd_fsa_input election_result = I_NULL;
const char *vote_from = xmlGetProp(vote, XML_ATTR_HOSTFROM);
const char *lowest_uname = NULL;
int lowest_bornon = 0;
FNIN();
if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) {
// dont count our own vote
FNRET(election_result);
}
if(fsa_membership_copy->members_size < 1) {
// if even we are not in the cluster then we should not vote
FNRET(I_FAIL);
}
lowest_uname = fsa_membership_copy->members[0].node_uname;
lowest_bornon = fsa_membership_copy->members[0].node_born_on;
for(; lpc < fsa_membership_copy->members_size; lpc++) {
const char *node_uname =
fsa_membership_copy->members[lpc].node_uname;
int this_born_on =
fsa_membership_copy->members[lpc].node_born_on;
if(node_uname == NULL) {
continue;
}
if(strcmp(vote_from, node_uname) == 0) {
your_born = this_born_on;
your_index = lpc;
} else if (strcmp(fsa_our_uname, node_uname) == 0) {
my_born = this_born_on;
my_index = lpc;
}
if(lowest_bornon > this_born_on) {
lowest_uname = node_uname;
lowest_bornon = this_born_on;
} else if(lowest_bornon == this_born_on
&& strcmp(lowest_uname, node_uname) > 0) {
lowest_uname = node_uname;
lowest_bornon = this_born_on;
}
}
#if 0
cl_log(LOG_DEBUG, "%s (bornon=%d), our bornon (%d)",
vote_from, your_born, my_born);
cl_log(LOG_DEBUG, "%s %s %s",
fsa_our_uname,
strcmp(fsa_our_uname, vote_from) < 0?"<":">=",
vote_from);
#endif
cl_log(LOG_DEBUG, "Election winner should be %s (born_on=%d)",
lowest_uname, lowest_bornon);
if(lowest_uname != NULL && strcmp(lowest_uname, fsa_our_uname) == 0){
cl_log(LOG_DEBUG, "Election win: lowest born_on and uname");
election_result = I_ELECTION_DC;
} else if(your_born < my_born) {
cl_log(LOG_DEBUG, "Election fail: born_on");
we_loose = TRUE;
} else if(your_born == my_born
&& strcmp(fsa_our_uname, vote_from) > 0) {
cl_log(LOG_DEBUG, "Election fail: uname");
we_loose = TRUE;
} else {
CRM_DEBUG("We might win... we should vote (possibly again)");
election_result = I_DC_TIMEOUT;
}
if(we_loose) {
if(fsa_input_register & R_THE_DC) {
cl_log(LOG_DEBUG, "Give up the DC");
election_result = I_RELEASE_DC;
} else {
cl_log(LOG_DEBUG, "We werent the DC anyway");
election_result = I_NOT_DC;
}
}
if(we_loose || election_result == I_ELECTION_DC) {
// cancel timer, its been decided
stopTimer(election_timeout);
}
FNRET(election_result);
}
/* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */
// we won
enum crmd_fsa_input
do_election_timer_ctrl(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
if(action & A_ELECT_TIMER_START) {
CRM_DEBUG("Starting the election timer...");
startTimer(election_timeout);
} else if(action & A_ELECT_TIMER_STOP || action & A_ELECTION_TIMEOUT) {
CRM_DEBUG("Stopping the election timer...");
stopTimer(election_timeout);
} else {
cl_log(LOG_ERR, "unexpected action %s",
fsa_action2string(action));
}
if(action & A_ELECTION_TIMEOUT) {
CRM_DEBUG("The election timer went off, we win!");
FNRET(I_ELECTION_DC);
}
FNRET(I_NULL);
}
/* A_DC_TIMER_STOP, A_DC_TIMER_START */
enum crmd_fsa_input
do_dc_timer_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
gboolean timer_op_ok = TRUE;
FNIN();
if(action & A_DC_TIMER_STOP) {
timer_op_ok = stopTimer(election_trigger);
}
/* dont start a timer that wasnt already running */
if(action & A_DC_TIMER_START && timer_op_ok) {
startTimer(election_trigger);
}
FNRET(I_NULL);
}
/* A_DC_TAKEOVER */
enum crmd_fsa_input
do_dc_takeover(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
CRM_DEBUG("################## Taking over the DC ##################");
set_bit_inplace(&fsa_input_register, R_THE_DC);
CRM_DEBUG("Am I the DC? %s", AM_I_DC?"yes":"no");
set_bit_inplace(&fsa_input_register, R_JOIN_OK);
set_bit_inplace(&fsa_input_register, R_INVOKE_PE);
clear_bit_inplace(&fsa_input_register, R_CIB_DONE);
clear_bit_inplace(&fsa_input_register, R_HAVE_CIB);
startTimer(dc_heartbeat);
- /* Update the CIB to indicate we are the DC
- *
- * Has the side benefit of setting our state to active
- * if we are the only node around
- */
- xmlNodePtr tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE);
-
- set_node_tstamp(tmp1);
- set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname);
- set_xml_property_copy(tmp1, "source", fsa_our_uname);
- set_xml_property_copy(tmp1, "state", "active");
- set_xml_property_copy(tmp1, "exp_state", "active");
- set_xml_property_copy(tmp1, "is_dc", "true");
-
- xmlNodePtr fragment = create_cib_fragment(tmp1, NULL);
-
- send_request(NULL, fragment, CRM_OPERATION_UPDATE,
- NULL, CRM_SYSTEM_DCIB);
-
- free_xml(fragment);
- free_xml(tmp1);
-
FNRET(I_NULL);
}
/* A_DC_RELEASE */
enum crmd_fsa_input
do_dc_release(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
FNIN();
CRM_DEBUG("################## Releasing the DC ##################");
stopTimer(dc_heartbeat);
if(action & A_DC_RELEASE) {
clear_bit_inplace(&fsa_input_register, R_THE_DC);
/* get a new CIB from the new DC */
clear_bit_inplace(&fsa_input_register, R_HAVE_CIB);
} else if (action & A_DC_RELEASED) {
if(cur_state == S_STOPPING) {
result = I_SHUTDOWN; // necessary?
result = I_RELEASE_SUCCESS;
}
#if 0
else if( are there errors ) {
// we cant stay up if not healthy
// or perhaps I_ERROR and go to S_RECOVER?
result = I_SHUTDOWN;
}
#endif
else
result = I_RELEASE_SUCCESS;
} else {
cl_log(LOG_ERR, "Warning, do_dc_release invoked for action %s",
fsa_action2string(action));
}
CRM_DEBUG("Am I still the DC? %s", AM_I_DC?"yes":"no");
FNRET(result);
}
/* A_JOIN_WELCOME, A_JOIN_WELCOME_ALL */
enum crmd_fsa_input
do_send_welcome(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
int lpc = 0, size = 0, num_sent = 0;
oc_node_t *members;
gboolean was_sent = TRUE;
FNIN();
if(action & A_JOIN_WELCOME && data == NULL) {
cl_log(LOG_ERR,
"Attempt to send welcome message "
"without a message to reply to!");
FNRET(I_NULL);
} else if(action & A_JOIN_WELCOME) {
xmlNodePtr welcome = (xmlNodePtr)data;
const char *join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM);
if(join_to != NULL) {
send_request(NULL, NULL, CRM_OPERATION_WELCOME,
join_to, CRM_SYSTEM_CRMD);
}
FNRET(I_NULL);
}
// welcome everyone...
/* Give everyone a chance to join before invoking the PolicyEngine */
stopTimer(integration_timer);
startTimer(integration_timer);
members = fsa_membership_copy->members;
size = fsa_membership_copy->members_size;
if(joined_nodes != NULL) {
g_hash_table_destroy(joined_nodes);
joined_nodes = g_hash_table_new(&g_str_hash, &g_str_equal);
}
for(; members != NULL && lpc < size; lpc++) {
const char *new_node = members[lpc].node_uname;
if(strcmp(fsa_our_uname, new_node) == 0) {
// dont send one to ourselves
continue;
}
CRM_DEBUG("Sending welcome message to %s (%d)",
new_node, was_sent);
num_sent++;
was_sent = was_sent
&& send_request(NULL, NULL, CRM_OPERATION_WELCOME,
new_node, CRM_SYSTEM_CRMD);
CRM_DEBUG("Sent welcome message to %s (%d)",
new_node, was_sent);
}
if(was_sent == FALSE)
FNRET(I_FAIL);
/* No point hanging around in S_INTEGRATION if we're the only ones here! */
if(num_sent == 0) {
// that was the last outstanding join ack)
cl_log(LOG_INFO,"That was the last outstanding join ack");
FNRET(I_SUCCESS);
} else {
cl_log(LOG_DEBUG,
"Still waiting on %d outstanding join acks",
num_sent);
//dont waste time by invoking the pe yet;
}
FNRET(I_NULL);
}
/* A_JOIN_ACK */
enum crmd_fsa_input
do_ack_welcome(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr welcome = (xmlNodePtr)data;
xmlNodePtr cib_copy;
xmlNodePtr tmp1;
xmlNodePtr tmp2;
FNIN();
#if 0
if(we are sick) {
log error ;
FNRET(I_NULL);
}
#endif
cib_copy = get_cib_copy();
tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy);
tmp2 = create_cib_fragment(tmp1, NULL);
send_ha_reply(fsa_cluster_conn, welcome, tmp2);
free_xml(tmp2);
free_xml(cib_copy);
FNRET(I_NULL);
}
/* A_ANNOUNCE */
enum crmd_fsa_input
do_announce(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
/* Once we hear from the DC, we can stop the timer
*
* This timer was started either on startup or when a node
* left the CCM list
*/
/* dont announce if we're in one of these states */
switch(cur_state) {
case S_RECOVERY:
case S_RECOVERY_DC:
case S_RELEASE_DC:
case S_TERMINATE:
FNRET(I_NULL);
// log warning
break;
default:
break;
}
if(AM_I_OPERATIONAL) {
send_request(NULL, NULL, CRM_OPERATION_ANNOUNCE,
NULL, CRM_SYSTEM_DC);
} else {
/* Delay announce until we have finished local startup */
FNRET(I_NULL);
}
FNRET(I_NULL);
}
/* A_JOIN_PROCESS_ACK */
enum crmd_fsa_input
do_process_welcome_ack(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
int lpc = 0, size = 0;
oc_node_t *members;
gboolean is_a_member = FALSE;
xmlNodePtr tmp1;
xmlNodePtr join_ack = (xmlNodePtr)data;
xmlNodePtr cib_fragment;
const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM);
FNIN();
FNIN();
members = fsa_membership_copy->members;
size = fsa_membership_copy->members_size;
for(; lpc < size; lpc++) {
const char *new_node = members[lpc].node_uname;
if(strcmp(join_from, new_node) == 0) {
is_a_member = TRUE;
}
}
cib_fragment = find_xml_node(join_ack, XML_TAG_FRAGMENT);
if(is_a_member == FALSE) {
cl_log(LOG_ERR, "Node %s is not known to us", join_from);
/* make sure any information from this node is discarded,
* it is invalid
*/
free_xml(cib_fragment);
FNRET(I_FAIL);
}
cl_log(LOG_DEBUG, "Welcoming node %s after ACK", join_from);
// add them to our list of "active" nodes
g_hash_table_insert(joined_nodes, strdup(join_from),strdup(join_from));
if(cib_fragment == NULL) {
cl_log(LOG_ERR,
"No status information was part of the"
" Welcome ACK from %s",
join_from);
FNRET(I_NULL);
}
/* TODO: check the fragment is only for the status section
= get_xml_attr(cib_fragment, NULL,
XML_ATTR_FILTER_TYPE, TRUE); */
/* Make changes so that state=active for this node when the update
* is processed by A_CIB_INVOKE
*/
tmp1 = find_xml_node(cib_fragment, XML_TAG_CIB);
tmp1 = get_object_root(XML_CIB_TAG_STATUS, tmp1);
tmp1 = find_entity(tmp1, XML_CIB_TAG_STATE, join_from, FALSE);
set_xml_property_copy(tmp1, "state", "active");
if(g_hash_table_size(joined_nodes)
== fsa_membership_copy->members_size) {
// that was the last outstanding join ack)
cl_log(LOG_INFO,"That was the last outstanding join ack");
FNRET(I_SUCCESS);
} else {
cl_log(LOG_DEBUG,
"Still waiting on %d outstanding join acks",
size);
//dont waste time by invoking the pe yet;
}
FNRET(I_CIB_OP);
}
diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c
index b1e6036c35..d4f8441f6b 100644
--- a/crm/crmd/messages.c
+++ b/crm/crmd/messages.c
@@ -1,866 +1,872 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <portability.h>
#include <crm/crm.h>
#include <string.h>
#include <crmd_fsa.h>
#include <libxml/tree.h>
#include <crm/msg_xml.h>
#include <crm/common/xmlutils.h>
#include <crm/common/msgutils.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crm/dmalloc_wrapper.h>
FILE *msg_in_strm = NULL;
FILE *router_strm = NULL;
fsa_message_queue_t fsa_message_queue = NULL;
gboolean relay_message(xmlNodePtr xml_relay_message,
gboolean originated_locally);
#ifdef MSG_LOG
# define ROUTER_RESULT(x) char *msg_text = dump_xml(xml_relay_message);\
if(router_strm == NULL) { \
router_strm = fopen("/tmp/router.log", "w"); \
} \
fprintf(router_strm, "[%d RESULT (%s)]\t%s\t%s\n", \
AM_I_DC, \
xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE),\
x, msg_text); \
fflush(router_strm); \
cl_free(msg_text);
#else
# define ROUTER_RESULT(x) CRM_DEBUG(x);
#endif
/* returns the current head of the FIFO queue */
fsa_message_queue_t
put_message(xmlNodePtr new_message)
{
fsa_message_queue_t next_message = (fsa_message_queue_t)
cl_malloc(sizeof(struct fsa_message_queue_s));
CRM_DEBUG("Adding msg to queue");
// make sure to free it properly later
next_message->message = copy_xml_node_recursive(new_message);
next_message->next = NULL;
if(fsa_message_queue == NULL) {
fsa_message_queue = next_message;
} else {
fsa_message_queue->next = next_message;
}
CRM_DEBUG("Added msg to queue");
return fsa_message_queue;
}
/* returns the next message */
fsa_message_queue_t
get_message(void)
{
fsa_message_queue_t next_message = NULL;
if(fsa_message_queue != NULL) {
next_message = fsa_message_queue;
fsa_message_queue = fsa_message_queue->next;
next_message->next = NULL;
}
return next_message;
}
/* returns the current head of the FIFO queue */
gboolean
is_message(void)
{
return (fsa_message_queue != NULL
&& fsa_message_queue->message != NULL);
}
/* A_MSG_STORE */
enum crmd_fsa_input
do_msg_store(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
// xmlNodePtr new_message = (xmlNodePtr)data;
FNIN();
// put_message(new_message);
FNRET(I_NULL);
}
/* A_MSG_ROUTE */
enum crmd_fsa_input
do_msg_route(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
xmlNodePtr xml_message = (xmlNodePtr)data;
gboolean routed = FALSE, defer = TRUE, do_process = TRUE;
FNIN();
#if 0
// if(cause == C_IPC_MESSAGE) {
if (crmd_authorize_message(root_xml_node,
msg,
curr_client) == FALSE) {
CRM_DEBUG("Message not authorized");
do_process = FALSE;
}
// }
#endif
if(do_process) {
/* try passing the buck first */
routed = relay_message(xml_message, cause==C_IPC_MESSAGE);
if(routed == FALSE) {
defer = TRUE;
/* calculate defer */
result = handle_message(xml_message);
switch(result) {
case I_NULL:
defer = FALSE;
break;
case I_DC_HEARTBEAT:
defer = FALSE;
break;
/* what else should go here? */
default:
CRM_DEBUG("Defering local processing of message");
put_message(xml_message);
result = I_REQUEST;
break;
}
}
}
FNRET(result);
}
void
crmd_ha_input_callback(const struct ha_msg* msg, void* private_data)
{
const char *from = ha_msg_value(msg, F_ORIG);
const char *to = NULL;
xmlNodePtr root_xml_node;
FNIN();
#ifdef MSG_LOG
if(msg_in_strm == NULL) {
msg_in_strm = fopen("/tmp/inbound.log", "w");
}
#endif
if(from == NULL || strcmp(from, fsa_our_uname) == 0) {
#ifdef MSG_LOG
fprintf(msg_in_strm,
"Discarded message [F_SEQ=%s] from ourselves.\n",
ha_msg_value(msg, F_SEQ));
#endif
FNOUT();
}
#ifdef MSG_LOG
fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n",
from,
ha_msg_value(msg, F_SEQ),
ha_msg_value(msg, F_TYPE),
ha_msg_value(msg, "xml")
);
fflush(msg_in_strm);
#endif
root_xml_node = find_xml_in_hamessage(msg);
to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO);
if(to != NULL && strlen(to) > 0 && strcmp(to, fsa_our_uname) != 0) {
#ifdef MSG_LOG
fprintf(msg_in_strm,
"Discarding message [F_SEQ=%s] for someone else.",
ha_msg_value(msg, F_SEQ));
#endif
FNOUT();
}
set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from);
s_crmd_fsa(C_HA_MESSAGE, I_ROUTER, root_xml_node);
free_xml(root_xml_node);
FNOUT();
}
/*
* Apparently returning TRUE means "stay connected, keep doing stuff".
* Returning FALSE means "we're all done, close the connection"
*/
gboolean
crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data)
{
int lpc = 0;
char *buffer = NULL;
IPC_Message *msg = NULL;
gboolean hack_return_good = TRUE;
xmlNodePtr root_xml_node;
crmd_client_t *curr_client = (crmd_client_t*)user_data;
FNIN();
CRM_DEBUG("Processing IPC message from %s",
curr_client->table_key);
while(client->ops->is_message_pending(client)) {
if (client->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
if (client->ops->recv(client, &msg) != IPC_OK) {
perror("Receive failure:");
FNRET(!hack_return_good);
}
if (msg == NULL) {
CRM_DEBUG("No message this time");
continue;
}
lpc++;
buffer = (char*)msg->msg_body;
CRM_DEBUG("Processing xml from %s [text=%s]",
curr_client->table_key, buffer);
root_xml_node =
find_xml_in_ipcmessage(msg, FALSE);
if (root_xml_node != NULL) {
+
if (crmd_authorize_message(root_xml_node,
msg,
curr_client)) {
CRM_DEBUG("Message authorized,about to relay");
s_crmd_fsa(C_IPC_MESSAGE,
I_ROUTER,
root_xml_node);
} else {
CRM_DEBUG("Message not authorized");
}
} else {
cl_log(LOG_INFO,
"IPC Message was not valid... discarding.");
}
free_xml(root_xml_node);
msg->msg_done(msg);
msg = NULL;
buffer = NULL;
root_xml_node = NULL;
}
CRM_DEBUG("Processed %d messages", lpc);
if (client->ch_status == IPC_DISCONNECT)
{
cl_log(LOG_INFO,
"received HUP from %s",
curr_client->table_key);
if (curr_client != NULL) {
struct crm_subsystem_s *the_subsystem = NULL;
if (curr_client->sub_sys == NULL)
CRM_DEBUG("Client had not registered with us yet");
else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0)
the_subsystem = pe_subsystem;
else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0)
the_subsystem = te_subsystem;
else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0)
the_subsystem = cib_subsystem;
if(the_subsystem != NULL) {
cleanup_subsystem(the_subsystem);
} // else that was a transient client
if (curr_client->table_key != NULL) {
/*
* Key is destroyed below: curr_client->table_key
* Value is cleaned up by G_main_del_IPC_Channel
*/
g_hash_table_remove(ipc_clients,
curr_client->table_key);
}
if(curr_client->client_source != NULL) {
gboolean det =
G_main_del_IPC_Channel(curr_client->client_source);
CRM_DEBUG("crm_client was %s detached",
det?"successfully":"not");
}
cl_free(curr_client->table_key);
cl_free(curr_client->sub_sys);
cl_free(curr_client->uuid);
cl_free(curr_client);
}
CRM_DEBUG("this client has now left the building.");
FNRET(!hack_return_good);
}
FNRET(hack_return_good);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
send_request(xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *operation, const char *host_to, const char *sys_to)
{
gboolean was_sent = FALSE;
xmlNodePtr request = NULL;
FNIN();
msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS,
XML_ATTR_OP, operation, TRUE);
request = create_request(msg_options,
msg_data,
host_to,
sys_to,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD,
NULL,
NULL);
// xml_message_debug(request, "Final request...");
was_sent = relay_message(request, TRUE);
if(was_sent == FALSE) {
put_message(request);
}
free_xml(request);
FNRET(was_sent);
}
/*
* This method adds a copy of xml_response_data
*/
gboolean
store_request(xmlNodePtr msg_options, xmlNodePtr msg_data,
const char *operation, const char *host_to, const char *sys_to)
{
xmlNodePtr request = NULL;
FNIN();
msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS,
XML_ATTR_OP, operation, TRUE);
request = create_request(msg_options,
msg_data,
host_to,
sys_to,
AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD,
NULL,
NULL);
put_message(request);
FNRET(TRUE);
}
gboolean
relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally)
{
int is_for_dc = 0;
int is_for_dcib = 0;
int is_for_crm = 0;
int is_for_cib = 0;
int is_local = 0;
gboolean dont_cc= TRUE;
gboolean processing_complete = FALSE;
const char *host_to = xmlGetProp(xml_relay_message,XML_ATTR_HOSTTO);
const char *sys_to = xmlGetProp(xml_relay_message,XML_ATTR_SYSTO);
FNIN();
if(xml_relay_message == NULL) {
cl_log(LOG_ERR, "Cannot route empty message");
FNRET(TRUE);
}
if(strcmp("hello", xml_relay_message->name) == 0) {
/* quietly ignore */
FNRET(TRUE);
}
if(strcmp(XML_MSG_TAG, xml_relay_message->name) != 0) {
xml_message_debug(xml_relay_message,
"Bad message type, should be crm_message");
cl_log(LOG_ERR, "Ignoring message of type %s",
xml_relay_message->name);
FNRET(TRUE);
}
if(sys_to == NULL) {
xml_message_debug(xml_relay_message,
"Message did not have any value for sys_to");
cl_log(LOG_ERR, "Message did not have any value for %s",
XML_ATTR_SYSTO);
FNRET(TRUE);
}
is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0);
is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0);
is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0);
is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0);
is_local = 0;
if(host_to == NULL || strlen(host_to) == 0) {
if(is_for_dc)
is_local = 0;
else if(is_for_crm && originated_locally)
is_local = 0;
else
is_local = 1;
} else if(strcmp(fsa_our_uname, host_to) == 0) {
is_local=1;
}
#if 0
CRM_DEBUG("is_local %d", is_local);
CRM_DEBUG("is_for_dcib %d", is_for_dcib);
CRM_DEBUG("is_for_dc %d", is_for_dc);
CRM_DEBUG("is_for_crm %d", is_for_crm);
CRM_DEBUG("AM_I_DC %d", AM_I_DC);
CRM_DEBUG("sys_to %s", sys_to);
CRM_DEBUG("host_to %s", host_to);
#endif
if(is_for_dc || is_for_dcib) {
if(AM_I_DC) {
ROUTER_RESULT("Message result: DC/CRMd process");
processing_complete = FALSE; // more to be done by caller
} else if(originated_locally) {
ROUTER_RESULT("Message result: External relay to DC");
send_msg_via_ha(xml_relay_message, NULL);
processing_complete = TRUE;
} else {
ROUTER_RESULT("Message result: Discard, not DC");
processing_complete = TRUE; // discard
}
} else if(is_local && (is_for_crm || is_for_cib)) {
ROUTER_RESULT("Message result: CRMd process");
} else if(is_local) {
if(dont_cc) {
ROUTER_RESULT("Message result: Local relay");
} else {
/* The DC should also get this message */
ROUTER_RESULT("Message result: Local relay with CC");
}
send_msg_via_ipc(xml_relay_message, sys_to);
processing_complete = TRUE & dont_cc;
} else {
if(dont_cc) {
ROUTER_RESULT("Message result: External relay");
} else {
/* The DC should also get this message */
ROUTER_RESULT("Message result: External relay with CC");
}
send_msg_via_ha(xml_relay_message, host_to);
processing_complete = TRUE & dont_cc;
}
FNRET(processing_complete);
}
void
send_msg_via_ha(xmlNodePtr action, const char *dest_node)
{
FNIN();
if (action == NULL) FNOUT();
if (validate_crm_message(action, NULL, NULL, NULL) == NULL)
{
cl_log(LOG_ERR,
"Relay message to (%s) via HA was invalid, ignoring",
dest_node);
FNOUT();
}
// CRM_DEBUG("Relaying message to (%s) via HA", dest_node);
set_xml_property_copy(action, XML_ATTR_HOSTTO, dest_node);
send_xmlha_message(fsa_cluster_conn, action);
FNOUT();
}
void
send_msg_via_ipc(xmlNodePtr action, const char *sys)
{
IPC_Channel *client_channel;
FNIN();
// cl_log(LOG_DEBUG, "relaying msg to sub_sys=%s via IPC", sys);
client_channel =
(IPC_Channel*)g_hash_table_lookup (ipc_clients, sys);
if (client_channel != NULL) {
cl_log(LOG_DEBUG, "Sending message via channel %s.", sys);
send_xmlipc_message(client_channel, action);
} else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) {
cl_log(LOG_ERR,
"Sub-system (%s) has been incorporated into the CRMd.",
sys);
xml_message_debug(action, "Change the way we handle");
relay_message(process_cib_message(action, TRUE), TRUE);
} else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE,
fsa_state, I_MESSAGE, action);
} else {
cl_log(LOG_ERR,
"Unknown Sub-system (%s)... discarding message.",
sys);
}
FNOUT();
}
gboolean
crmd_authorize_message(xmlNodePtr root_xml_node,
IPC_Message *client_msg,
crmd_client_t *curr_client)
{
// check the best case first
const char *sys_from = xmlGetProp(root_xml_node,
XML_ATTR_SYSFROM);
char *uuid = NULL;
char *client_name = NULL;
char *major_version = NULL;
char *minor_version = NULL;
const char *filtered_from;
gpointer table_key = NULL;
gboolean result;
+ const char *op = get_xml_attr(root_xml_node, XML_TAG_OPTIONS,
+ XML_ATTR_OP, FALSE);
FNIN();
- if (sys_from != NULL) {
+ if (safe_str_neq("hello", op)) {
+
+ if(sys_from == NULL) {
+ return FALSE;
+ }
+
gboolean can_reply = FALSE; // no-one has registered with this id
filtered_from = sys_from;
/* The CIB can have two names on the DC */
if(strcmp(sys_from, CRM_SYSTEM_DCIB) == 0)
filtered_from = CRM_SYSTEM_CIB;
if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL)
can_reply = TRUE; // reply can be routed
CRM_DEBUG("Message reply can%s be routed from %s.",
can_reply?"":" not", sys_from);
- FNRET(can_reply);
+ return can_reply;
}
-
- // otherwise, check if it was a hello message
-
+
cl_log(LOG_INFO,
"received client join msg: %s",
(char*)client_msg->msg_body);
- result = process_hello_message(client_msg,
+ result = process_hello_message(root_xml_node,
&uuid,
&client_name,
&major_version,
&minor_version);
if (result == TRUE) {
// check version
int mav = atoi(major_version);
int miv = atoi(minor_version);
if (mav < 0 || miv < 0) {
cl_log(LOG_ERR,
"Client version (%d:%d) is not acceptable",
mav,
miv);
result = FALSE;
}
cl_free(major_version);
cl_free(minor_version);
}
struct crm_subsystem_s *the_subsystem = NULL;
if (result == TRUE) {
/* if we already have one of those clients
* only applies to te, pe etc. not admin clients
*/
if (client_name == NULL)
CRM_DEBUG("Client had not registered with us yet");
else if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0)
the_subsystem = pe_subsystem;
else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0)
the_subsystem = te_subsystem;
else if (strcmp(CRM_SYSTEM_CIB, client_name) == 0)
the_subsystem = cib_subsystem;
if (the_subsystem != NULL) {
// do we already have one?
result =(fsa_input_register & the_subsystem->flag)==0;
if(result) {
the_subsystem->ipc =
curr_client->client_channel;
} // else we didnt ask for the client to start
} else if(client_name != NULL && uuid != NULL) {
table_key = (gpointer)
generate_hash_key(client_name, uuid);
} else {
result = FALSE;
cl_log(LOG_ERR,
"Bad client details (client_name=%s, uuid=%s)",
client_name, uuid);
}
}
if(result == TRUE && table_key == NULL)
table_key = (gpointer)cl_strdup(client_name);
if (result == TRUE) {
cl_log(LOG_INFO, "Accepted client %s", (char*)table_key);
curr_client->table_key = table_key;
curr_client->sub_sys = cl_strdup(client_name);
curr_client->uuid = cl_strdup(uuid);
g_hash_table_insert (ipc_clients,
table_key,
curr_client->client_channel);
send_hello_message(curr_client->client_channel,
"n/a", CRM_SYSTEM_CRMD,
"0", "1");
cl_log(LOG_INFO, "Updated client list with %s",
(char*)table_key);
if(the_subsystem != NULL) {
set_bit_inplace(&fsa_input_register,
the_subsystem->flag);
}
s_crmd_fsa(C_SUBSYSTEM_CONNECT, I_NULL, NULL);
} else {
cl_log(LOG_ERR, "Rejected client logon request");
curr_client->client_channel->ch_status = IPC_DISC_PENDING;
}
if(uuid != NULL) cl_free(uuid);
if(client_name != NULL) cl_free(client_name);
/* hello messages should never be processed further */
- FNRET(FALSE);
+ return FALSE;
}
enum crmd_fsa_input
handle_message(xmlNodePtr stored_msg)
{
enum crmd_fsa_input next_input = I_NULL;
const char *sys_to = get_xml_attr(stored_msg, NULL,
XML_ATTR_SYSTO, TRUE);
// const char *sys_from = get_xml_attr(stored_msg, NULL,
// XML_ATTR_SYSFROM, TRUE);
const char *type = get_xml_attr(stored_msg, NULL,
XML_ATTR_MSGTYPE, TRUE);
const char *op = get_xml_attr(stored_msg, XML_TAG_OPTIONS,
XML_ATTR_OP, TRUE);
// xml_message_debug(stored_msg, "Processing message");
if(type == NULL || op == NULL) {
cl_log(LOG_ERR, "Ignoring message (type=%s), (op=%s)",
type, op);
xml_message_debug(stored_msg, "Bad message");
} else if(strcmp(type, XML_ATTR_REQUEST) == 0){
if(strcmp(op, CRM_OPERATION_VOTE) == 0) {
next_input = I_ELECTION;
} else if(AM_I_DC && strcmp(op, "te_abort") == 0) {
next_input = I_PE_CALC;
} else if(AM_I_DC
&& fsa_state == S_TRANSITION_ENGINE
&& strcmp(op, "te_complete") == 0) {
next_input = I_SUCCESS;
} else if(strcmp(op, CRM_OPERATION_HBEAT) == 0) {
next_input = I_DC_HEARTBEAT;
} else if(strcmp(op, CRM_OPERATION_WELCOME) == 0) {
next_input = I_WELCOME;
} else if(strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0) {
next_input = I_CIB_OP;
} else if(strcmp(op, CRM_OPERATION_SHUTDOWN) == 0) {
next_input = I_TERMINATE;
} else if(strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) {
next_input = I_NODE_JOIN;
} else if(strcmp(op, CRM_OPERATION_REPLACE) == 0
|| strcmp(op, CRM_OPERATION_ERASE) == 0) {
next_input = I_CIB_OP;
fprintf(router_strm, "Message result: CIB Op\n");
} else if(AM_I_DC
&& (strcmp(op, CRM_OPERATION_CREATE) == 0
|| strcmp(op, CRM_OPERATION_UPDATE) == 0
|| strcmp(op, CRM_OPERATION_DELETE) == 0)) {
/* updates should only be performed on the DC */
next_input = I_CIB_OP;
} else if(strcmp(op, CRM_OPERATION_PING) == 0) {
/* eventually do some stuff to figure out
* if we /are/ ok
*/
xmlNodePtr ping =
createPingAnswerFragment(sys_to, "ok");
xmlNodePtr wrapper = create_reply(stored_msg, ping);
relay_message(wrapper, TRUE);
free_xml(wrapper);
} else {
cl_log(LOG_ERR,
"Unexpected request (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
}
} else if(strcmp(type, XML_ATTR_RESPONSE) == 0) {
if(strcmp(op, CRM_OPERATION_WELCOME) == 0) {
next_input = I_WELCOME_ACK;
} else if(strcmp(op, "pecalc") == 0) {
// results int eh TE being invoked
next_input = I_SUCCESS;
} else if(strcmp(op, CRM_OPERATION_VOTE) == 0
|| strcmp(op, CRM_OPERATION_HBEAT) == 0
|| strcmp(op, CRM_OPERATION_WELCOME) == 0
|| strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0
|| strcmp(op, CRM_OPERATION_SHUTDOWN) == 0
|| strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) {
next_input = I_NULL;
/* } else if(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_ERASE) == 0)) { */
/* // perhaps we should do somethign with these replies */
/* fprintf(router_strm, "Message result: CIB Reply\n"); */
} else {
cl_log(LOG_ERR,
"Unexpected response (op=%s) sent to the %s",
op, AM_I_DC?"DC":"CRMd");
next_input = I_NULL;
}
} else {
cl_log(LOG_ERR, "Unexpected message type %s", type);
}
/* CRM_DEBUG("%s: Next input is %s", __FUNCTION__, */
/* fsa_input2string(next_input)); */
return next_input;
}
void lrm_op_callback (lrm_op_t* op)
{
CRM_DEBUG("In lrm_op_callback()");
s_crmd_fsa(C_LRM_OP_CALLBACK, I_LRM_EVENT, op);
}
void lrm_monitor_callback (lrm_mon_t* monitor)
{
CRM_DEBUG("In lrm_monitor_callback()");
s_crmd_fsa(C_LRM_MONITOR_CALLBACK, I_LRM_EVENT, monitor);
}
diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c
index 06fe248df5..001717c926 100644
--- a/crm/crmd/subsystems.c
+++ b/crm/crmd/subsystems.c
@@ -1,1183 +1,1203 @@
/*
* 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)
+ 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);
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);
}
/* 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);
send_request(NULL, local_cib, "pecalc",
NULL, CRM_SYSTEM_PENGINE);
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);
}
/* 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 = copy_xml_node_recursive((xmlNodePtr)data);
xmlNodePtr opts = find_xml_node(message, "options");
const char *true_op = xmlGetProp(opts, XML_ATTR_OP);
FNIN();
set_xml_property_copy(opts, XML_ATTR_OP, "event");
set_xml_property_copy(message, XML_ATTR_SYSTO, CRM_SYSTEM_TENGINE);
set_xml_property_copy(opts, "true_op", true_op);
relay_message(message, FALSE);
free_xml(message);
FNRET(I_NULL);
}
static xmlNodePtr te_last_input = 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;
} 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);
} else {
send_request(NULL, graph, "abort",
NULL, CRM_SYSTEM_TENGINE);
}
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);
}
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);
+ 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);
+
+ 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);
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");
- set_xml_property_copy(iter, "id", fsa_our_uname);
+ set_xml_property_copy(state, "id", fsa_our_uname);
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");
} else {
set_xml_property_copy(iter, "op_status", "stopped");
}
set_xml_property_copy(iter, "op_code", "0");
set_xml_property_copy(iter, "op_node", fsa_our_uname);
update = create_cib_fragment(state, NULL);
send_request(NULL, update, "update",
NULL, CRM_SYSTEM_DCIB);
}
FNRET(I_NULL);
#endif
- if(action & A_UPDATE_NODESTATUS) {
-
- xmlNodePtr data = do_lrm_query();
- 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);
- 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);
-
- free_xml(fragment);
- free_xml(tmp1);
- free_xml(data);
-
- FNRET(next_input);
- }
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);
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);
}
diff --git a/crm/pengine/pengine.c b/crm/pengine/pengine.c
index 3cb03e4e61..8676183d9c 100755
--- a/crm/pengine/pengine.c
+++ b/crm/pengine/pengine.c
@@ -1,1890 +1,1894 @@
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xmlutils.h>
#include <crm/common/crmutils.h>
#include <crm/common/msgutils.h>
#include <crm/cib.h>
#include <glib.h>
#include <libxml/tree.h>
#include <pengine.h>
#include <pe_utils.h>
xmlNodePtr do_calculations(xmlNodePtr cib_object);
gboolean process_pe_message(xmlNodePtr msg, IPC_Channel *sender);
void color_resource(resource_t *lh_resource,
GSListPtr *colors,
GSListPtr resources);
gboolean create_rsc_to_rsc(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh);
gboolean create_ordering(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh,
GSListPtr *action_constraints);
gboolean unpack_constraints(xmlNodePtr xml_constraints,
GSListPtr nodes, GSListPtr resources,
GSListPtr *node_constraints,
GSListPtr *action_constraints);
gboolean unpack_resources(xmlNodePtr xml_resources,
GSListPtr *resources,
GSListPtr *actions,
GSListPtr *action_cons,
GSListPtr all_nodes);
gboolean unpack_nodes(xmlNodePtr xml_nodes, GSListPtr *nodes);
gboolean unpack_status(xmlNodePtr status,
GSListPtr nodes,
GSListPtr rsc_list,
GSListPtr *node_constraints);
gboolean apply_node_constraints(GSListPtr constraints,
GSListPtr resources,
GSListPtr nodes);
gboolean is_active(rsc_to_node_t *cons);
gboolean choose_node_from_list(GSListPtr colors,
color_t *color,
GSListPtr nodes);
gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr node_list,
GSListPtr *node_constraints);
gboolean unpack_rsc_to_node(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr node_list,
GSListPtr *node_constraints);
gboolean unpack_rsc_to_rsc(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr *action_constraints);
gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors);
gboolean strict_postproc(rsc_to_rsc_t *constraint,
color_t *local_color,
color_t *other_color,
GSListPtr *colors,
GSListPtr resources);
gboolean strict_preproc(rsc_to_rsc_t *constraint,
color_t *local_color,
color_t *other_color,
GSListPtr *colors,
GSListPtr resources);
gboolean update_node_weight(rsc_to_node_t *cons, char *id, GSListPtr nodes);
gboolean process_node_lrm_state(node_t *node,
xmlNodePtr lrm_state,
GSListPtr rsc_list,
GSListPtr nodes,
GSListPtr *node_constraints);
GSListPtr match_attrs(xmlNodePtr attr_exp, GSListPtr node_list);
gboolean update_runnable(GSListPtr actions);
GSListPtr create_action_set(action_t *action);
/*
GSListPtr rsc_list = NULL;
GSListPtr node_list = NULL;
GSListPtr node_cons_list = NULL;
GSListPtr rsc_cons_list = NULL;
GSListPtr action_list = NULL;
GSListPtr action_set_list = NULL;
GSListPtr action_cons_list = NULL;
GSListPtr colors = NULL;
GSListPtr stonith_list = NULL;
GSListPtr shutdown_list = NULL;
color_t *current_color = NULL;
xmlNodePtr xml_set_of_sets = NULL;
*/
color_t *no_color = NULL;
int max_valid_nodes = 0;
int order_id = 1;
int action_id = 1;
gboolean pe_debug = FALSE;
gboolean pe_debug_saved = FALSE;
/*
* Unpack everything
* At the end you'll have:
* - A list of nodes
* - A list of resources (each with any dependancies on other resources)
* - A list of constraints between resources and nodes
* - A list of constraints between start/stop actions
* - A list of nodes that need to be stonith'd
* - A list of nodes that need to be shutdown
* - A list of the possible stop/start actions (without dependancies)
*/
gboolean
stage0(xmlNodePtr cib,
GSListPtr *resources,
GSListPtr *nodes, GSListPtr *node_constraints,
GSListPtr *actions, GSListPtr *action_constraints,
GSListPtr *stonith_list, GSListPtr *shutdown_list)
{
int lpc = 0;
xmlNodePtr cib_nodes = get_object_root("nodes", cib);
xmlNodePtr cib_status = get_object_root("status", cib);
xmlNodePtr cib_resources = get_object_root("resources", cib);
xmlNodePtr cib_constraints = get_object_root("constraints", cib);
unpack_nodes(safe_val(NULL, cib_nodes, children), nodes);
unpack_resources(safe_val(NULL, cib_resources, children),
resources, actions, action_constraints, *nodes);
unpack_status(safe_val(NULL, cib_status, children),
*nodes, *resources, node_constraints);
unpack_constraints(safe_val(NULL, cib_constraints, children),
*nodes, *resources,
node_constraints, action_constraints);
slist_iter(
node, node_t, *nodes, lpc,
if(node->details->shutdown) {
*shutdown_list = g_slist_append(*shutdown_list, node);
} else if(node->details->unclean) {
*stonith_list = g_slist_append(*stonith_list, node);
}
);
return TRUE;
}
/*
* Count how many valid nodes we have (so we know the maximum number of
* colors we can resolve).
*
* Apply node constraints (ie. filter the "allowed_nodes" part of resources
*/
gboolean
stage1(GSListPtr node_constraints, GSListPtr nodes, GSListPtr resources)
{
int lpc = 0;
slist_iter(
node, node_t, nodes, lpc,
if(node == NULL) {
// error
} else if(node->weight >= 0.0
&& node->details->online
&& node->details->type == node_member) {
max_valid_nodes++;
}
);
apply_node_constraints(node_constraints, nodes, resources);
return TRUE;
}
/*
* Choose a color for all resources from highest priority and "must"
* dependancies to lowest, creating new colors as necessary (returned
* as "colors").
*
* Some nodes may be colored as a "no_color" meaning that it was unresolvable
* given the current node stati and constraints.
*/
gboolean
stage2(GSListPtr sorted_rscs, GSListPtr sorted_nodes, GSListPtr *colors)
{
int lpc = 0;
color_t *current_color = NULL;
// Set initial color
// Set color.candidate_nodes = all active nodes
no_color = create_color(colors, NULL, NULL);
current_color = create_color(colors, sorted_nodes, sorted_rscs);
// Set resource.color = color (all resources)
// Set resource.provisional = TRUE (all resources)
slist_iter(
this_resource, resource_t, sorted_rscs, lpc,
this_resource->color = current_color;
this_resource->provisional = TRUE;
);
pdebug("initialized resources to default color");
// Take (next) highest resource
slist_iter(
lh_resource, resource_t, sorted_rscs, lpc,
// if resource.provisional == FALSE, repeat
if(lh_resource->provisional == FALSE) {
// already processed this resource
continue;
}
color_resource(lh_resource, colors, sorted_rscs);
// next resource
);
return TRUE;
}
/*
* not sure if this is a good idea or not, but eventually we might like
* to utilize as many nodes as possible... and this might be a convienient
* hook
*/
gboolean
stage3(GSListPtr colors)
{
// not sure if this is a good idea or not
if(g_slist_length(colors) > max_valid_nodes) {
// we need to consolidate some
} else if(g_slist_length(colors) < max_valid_nodes) {
// we can create a few more
}
return TRUE;
}
#define color_n_nodes color_n->details->candidate_nodes
#define color_n_plus_1_nodes color_n_plus_1->details->candidate_nodes
/*
* Choose a node for each (if possible) color
*/
gboolean
stage4(GSListPtr colors)
{
int lpc = 0;
color_t *color_n = NULL;
color_t *color_n_plus_1 = NULL;
for(lpc = 0; lpc < g_slist_length(colors); lpc++) {
color_n = color_n_plus_1;
color_n_plus_1 = (color_t*)g_slist_nth_data(colors, lpc);
pdebug_action(print_color("Choose node for...", color_n, FALSE));
if(color_n == NULL) {
continue;
}
GSListPtr xor = node_list_xor(color_n_nodes,
color_n_plus_1_nodes);
GSListPtr minus = node_list_minus(color_n_nodes,
color_n_plus_1_nodes);
if(g_slist_length(xor) == 0 || g_slist_length(minus) == 0) {
pdebug("Choose any node from our list");
choose_node_from_list(colors, color_n, color_n_nodes);
} else {
pdebug("Choose a node not in n+1");
choose_node_from_list(colors, color_n, minus);
}
}
// choose last color
if(color_n_plus_1 != NULL) {
pdebug_action(print_color("Choose node for last color...",
color_n_plus_1,
FALSE));
choose_node_from_list(colors,
color_n_plus_1,
color_n_plus_1_nodes);
}
pdebug("done %s", __FUNCTION__);
return TRUE;
}
/*
* Attach nodes to the actions that need to be taken
*
* Mark actions "optional" if possible (Ie. if the start and stop are
* for the same node)
*
* Mark unrunnable actions
*/
gboolean
stage5(GSListPtr resources)
{
pdebug("filling in the nodes to perform the actions on");
int lpc = 0;
slist_iter(
rsc, resource_t, resources, lpc,
print_resource("Processing", rsc, FALSE);
if(safe_val(NULL, rsc, stop) == NULL
|| safe_val(NULL, rsc, start) == NULL) {
// error
continue;
}
if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) {
rsc->stop->node = safe_val(NULL, rsc, cur_node);
rsc->start->node = NULL;
} else if(safe_str_eq(safe_val4(NULL, rsc, cur_node, details, id),
safe_val6(NULL, rsc, color ,details,
chosen_node, details, id))){
cl_log(LOG_DEBUG,
"No change for Resource %s (%s)",
safe_val(NULL, rsc, id),
safe_val4(NULL, rsc, cur_node, details, id));
rsc->stop->optional = TRUE;
rsc->start->optional = TRUE;
rsc->stop->node = safe_val(NULL, rsc, cur_node);
rsc->start->node = safe_val4(NULL, rsc, color,
details, chosen_node);
} else if(safe_val4(NULL, rsc, cur_node, details, id) == NULL) {
rsc->stop->optional = TRUE;
rsc->start->node = safe_val4(NULL, rsc, color,
details, chosen_node);
} else {
rsc->stop->node = safe_val(NULL, rsc, cur_node);
rsc->start->node = safe_val4(NULL, rsc, color,
details, chosen_node);
}
if(rsc->stop->node != NULL) {
rsc->stop->runnable = TRUE;
}
if(rsc->start->node != NULL) {
rsc->start->runnable = TRUE;
}
);
return TRUE;
}
/*
* Create dependacies for stonith and shutdown operations
*/
gboolean
stage6(GSListPtr *actions, GSListPtr *action_constraints,
GSListPtr stonith_nodes, GSListPtr shutdown_nodes)
{
int lpc = 0;
int llpc = 0;
slist_iter(
node, node_t, shutdown_nodes, lpc,
action_t *down_node =
action_new(action_id++, NULL, shutdown_crm);
down_node->node = node;
down_node->runnable = TRUE;
*actions = g_slist_append(*actions, down_node);
slist_iter(
rsc, resource_t, node->details->running_rsc, llpc,
order_constraint_t *order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
/* stop resources before shutdown */
order->id = order_id++;
order->lh_action = rsc->stop;
order->rh_action = down_node;
order->strength = must;
*action_constraints =
g_slist_append(*action_constraints, order);
);
);
slist_iter(
node, node_t, stonith_nodes, lpc,
action_t *stonith_node =
action_new(action_id++, NULL, stonith_op);
stonith_node->node = node;
stonith_node->runnable = TRUE;
*actions = g_slist_append(*actions, stonith_node);
slist_iter(
rsc, resource_t, node->details->running_rsc, llpc,
order_constraint_t *order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
/* try stopping the resource before stonithing the node
*
* if the stop succeeds, the transitioner can then
* decided if stonith is needed
*/
order->id = order_id++;
order->lh_action = rsc->stop;
order->rh_action = stonith_node;
order->strength = must;
*action_constraints =
g_slist_append(*action_constraints, order);
/* stonith before start */
order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
// try stopping the node first
order->id = order_id++;
order->lh_action = stonith_node;
order->rh_action = rsc->start;
order->strength = must;
*action_constraints =
g_slist_append(*action_constraints, order);
);
);
return TRUE;
}
/*
* Determin the sets of independant actions and the correct order for the
* actions in each set.
*
* Mark dependancies f un-runnable actions un-runnable
*
*/
gboolean
stage7(GSListPtr resources, GSListPtr actions, GSListPtr action_constraints,
GSListPtr *action_sets)
{
int lpc = 0;
slist_iter(
order, order_constraint_t, action_constraints, lpc,
action_wrapper_t *wrapper = (action_wrapper_t*)
cl_malloc(sizeof(action_wrapper_t));
wrapper->action = order->rh_action;
wrapper->strength = order->strength;
order->lh_action->actions_after =
g_slist_append(order->lh_action->actions_after,
wrapper);
wrapper = (action_wrapper_t*)
cl_malloc(sizeof(action_wrapper_t));
wrapper->action = order->lh_action;
wrapper->strength = order->strength;
order->rh_action->actions_before =
g_slist_append(order->rh_action->actions_before,
wrapper);
);
update_runnable(actions);
slist_iter(
rsc, resource_t, resources, lpc,
GSListPtr action_set = NULL;
if(rsc->stop->runnable) {
action_set = create_action_set(rsc->stop);
if(action_set != NULL) {
*action_sets = g_slist_append(*action_sets,
action_set);
} else {
pdebug("No actions resulting from %s->stop",
rsc->id);
}
}
if(rsc->start->runnable) {
action_set = create_action_set(rsc->start);
if(action_set != NULL) {
*action_sets = g_slist_append(*action_sets,
action_set);
} else {
pdebug("No actions resulting from %s->start",
rsc->id);
}
}
);
return TRUE;
}
/*
* Create a dependancy graph to send to the transitioner (via the CRMd)
*/
gboolean
stage8(GSListPtr action_sets, xmlNodePtr *graph)
{
int lpc = 0;
xmlNodePtr xml_action_set = NULL;
*graph = create_xml_node(NULL, "transition_graph");
/* errors...
slist_iter(action, action_t, action_list, lpc,
if(action->optional == FALSE && action->runnable == FALSE) {
print_action("Ignoring", action, TRUE);
}
);
*/
int lpc2;
slist_iter(action_set, GSList, action_sets, lpc,
pdebug("Processing Action Set %d", lpc);
xml_action_set = create_xml_node(NULL, "actions");
set_xml_property_copy(xml_action_set, "id", crm_itoa(lpc));
slist_iter(action, action_t, action_set, lpc2,
xmlNodePtr xml_action = action2xml(action);
xmlAddChild(xml_action_set, xml_action);
)
xmlAddChild(*graph, xml_action_set);
);
xml_message_debug(*graph, "created action list");
return TRUE;
}
/*
* Print a nice human readable high-level summary of what we're going to do
*/
gboolean
summary(GSListPtr resources)
{
int lpc = 0;
slist_iter(
rsc, resource_t, resources, lpc,
char *rsc_id = safe_val(NULL, rsc, id);
char *node_id = safe_val4(NULL, rsc, cur_node, details, id);
char *new_node_id = safe_val6(NULL, rsc, color, details,
chosen_node, details, id);
if(rsc->runnable == FALSE) {
cl_log(LOG_ERR,
"Resource %s was not runnable",
rsc_id);
if(node_id != NULL) {
cl_log(LOG_WARNING,
"Stopping Resource (%s) on node %s",
rsc_id,
node_id);
}
} else if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) {
cl_log(LOG_ERR,
"Could not allocate Resource %s",
rsc_id);
if(node_id != NULL) {
cl_log(LOG_WARNING,
"Stopping Resource (%s) on node %s",
rsc_id,
node_id);
}
} else if(safe_str_eq(node_id, new_node_id)){
cl_log(LOG_DEBUG,
"No change for Resource %s (%s)",
rsc_id,
safe_val4(NULL, rsc, cur_node, details, id));
} else if(node_id == NULL) {
cl_log(LOG_INFO,
"Starting Resource %s on %s",
rsc_id,
new_node_id);
} else {
cl_log(LOG_INFO,
"Moving Resource %s from %s to %s",
rsc_id,
node_id,
new_node_id);
}
);
return TRUE;
}
gboolean
choose_node_from_list(GSListPtr colors, color_t *color, GSListPtr nodes)
{
/*
1. Sort by weight
2. color.chosen_node = highest wieghted node
3. remove color.chosen_node from all other colors
*/
int lpc = 0;
nodes = g_slist_sort(nodes, sort_node_weight);
color->details->chosen_node = (node_t*)g_slist_nth_data(nodes, 0);
if(color->details->chosen_node == NULL) {
cl_log(LOG_ERR, "Could not allocate a node for color %d", color->id);
return FALSE;
}
slist_iter(
color_n, color_t, colors, lpc,
node_t *other_node = pe_find_node(color_n->details->candidate_nodes,
color->details->chosen_node->details->id);
color_n->details->candidate_nodes =
g_slist_remove(color_n->details->candidate_nodes,
other_node);
);
return TRUE;
}
gboolean
unpack_nodes(xmlNodePtr xml_nodes, GSListPtr *nodes)
{
pdebug("Begining unpack... %s", __FUNCTION__);
while(xml_nodes != NULL) {
pdebug("Processing node...");
xmlNodePtr xml_obj = xml_nodes;
xmlNodePtr attrs = xml_obj->children;
const char *id = xmlGetProp(xml_obj, "id");
const char *type = xmlGetProp(xml_obj, "type");
if(attrs != NULL) {
attrs = attrs->children;
}
xml_nodes = xml_nodes->next;
if(id == NULL) {
cl_log(LOG_ERR, "Must specify id tag in <node>");
continue;
}
if(type == NULL) {
cl_log(LOG_ERR, "Must specify type tag in <node>");
continue;
}
node_t *new_node = cl_malloc(sizeof(node_t));
new_node->weight = 1.0;
new_node->fixed = FALSE;
new_node->details = (struct node_shared_s*)
cl_malloc(sizeof(struct node_shared_s*));
new_node->details->online = FALSE;
new_node->details->unclean = FALSE;
new_node->details->shutdown = FALSE;
new_node->details->running_rsc = NULL;
new_node->details->id = cl_strdup(id);
new_node->details->attrs =
g_hash_table_new(g_str_hash, g_str_equal);
new_node->details->type = node_ping;
if(safe_str_eq(type, "node")) {
new_node->details->type = node_member;
}
while(attrs != NULL){
const char *name = xmlGetProp(attrs, "name");
const char *value = xmlGetProp(attrs, "value");
if(name != NULL && value != NULL) {
g_hash_table_insert(new_node->details->attrs,
cl_strdup(name),
cl_strdup(value));
}
attrs = attrs->next;
}
pdebug_action(print_node("Added", new_node, FALSE));
*nodes = g_slist_append(*nodes, new_node);
}
*nodes = g_slist_sort(*nodes, sort_node_weight);
return TRUE;
}
gboolean
unpack_resources(xmlNodePtr xml_resources,
GSListPtr *resources,
GSListPtr *actions,
GSListPtr *action_cons,
GSListPtr all_nodes)
{
pdebug("Begining unpack... %s", __FUNCTION__);
while(xml_resources != NULL) {
xmlNodePtr xml_obj = xml_resources;
const char *id = xmlGetProp(xml_obj, "id");
const char *priority = xmlGetProp(xml_obj, "priority");
float priority_f = atof(priority);
xml_resources = xml_resources->next;
pdebug("Processing resource...");
if(id == NULL) {
cl_log(LOG_ERR, "Must specify id tag in <resource>");
continue;
}
resource_t *new_rsc = cl_malloc(sizeof(resource_t));
new_rsc->xml = xml_obj; // copy first
new_rsc->priority = priority_f;
new_rsc->candidate_colors = NULL;
new_rsc->color = NULL;
new_rsc->runnable = TRUE;
new_rsc->provisional = TRUE;
new_rsc->allowed_nodes = node_list_dup(all_nodes);
new_rsc->rsc_cons = NULL;
new_rsc->node_cons = NULL;
new_rsc->id = cl_strdup(id);
new_rsc->cur_node = NULL;
action_t *action_stop = action_new(action_id++, new_rsc,
stop_rsc);
action_t *action_start = action_new(action_id++, new_rsc,
start_rsc);
new_rsc->stop = action_stop;
*actions = g_slist_append(*actions, action_stop);
new_rsc->start = action_start;
*actions = g_slist_append(*actions, action_start);
order_constraint_t *order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
order->id = order_id++;
order->lh_action = action_stop;
order->rh_action = action_start;
order->strength = startstop;
*action_cons = g_slist_append(*action_cons, order);
pdebug_action(print_resource("Added", new_rsc, FALSE));
*resources = g_slist_append(*resources, new_rsc);
}
*resources = g_slist_sort(*resources, sort_rsc_priority);
return TRUE;
}
gboolean
unpack_constraints(xmlNodePtr xml_constraints,
GSListPtr nodes, GSListPtr resources,
GSListPtr *node_constraints,
GSListPtr *action_constraints)
{
pdebug("Begining unpack... %s", __FUNCTION__);
while(xml_constraints != NULL) {
const char *id = xmlGetProp(xml_constraints, "id");
xmlNodePtr xml_obj = xml_constraints;
xml_constraints = xml_constraints->next;
if(id == NULL) {
cl_log(LOG_ERR, "Constraint must have an id");
continue;
}
pdebug("Processing constraint %s %s",
xml_obj->name,id);
if(safe_str_eq("rsc_to_rsc", xml_obj->name)) {
unpack_rsc_to_rsc(xml_obj, resources,
action_constraints);
} else if(safe_str_eq("rsc_to_node", xml_obj->name)) {
unpack_rsc_to_node(xml_obj, resources, nodes,
node_constraints);
} else if(safe_str_eq("rsc_to_attr", xml_obj->name)) {
unpack_rsc_to_attr(xml_obj, resources, nodes,
node_constraints);
} else {
cl_log(LOG_ERR, "Unsupported constraint type: %s",
xml_obj->name);
}
}
return TRUE;
}
gboolean
apply_node_constraints(GSListPtr constraints,
GSListPtr resources,
GSListPtr nodes)
{
pdebug("Applying constraints... %s", __FUNCTION__);
int lpc = 0;
slist_iter(
cons, rsc_to_node_t, constraints, lpc,
pdebug_action(print_rsc_to_node("Applying", cons, FALSE));
// take "lifetime" into account
if(cons == NULL) {
cl_log(LOG_ERR, "Constraint (%d) is NULL", lpc);
continue;
} else if(is_active(cons) == FALSE) {
cl_log(LOG_INFO, "Constraint (%d) is not active", lpc);
// warning
continue;
}
resource_t *rsc_lh = cons->rsc_lh;
if(rsc_lh == NULL) {
cl_log(LOG_ERR, "LHS of rsc_to_node (%s) is NULL", cons->id);
continue;
}
cons->rsc_lh->node_cons =
g_slist_append(cons->rsc_lh->node_cons, cons);
if(cons->node_list_rh == NULL) {
cl_log(LOG_ERR,
"RHS of rsc_to_node (%s) is NULL",
cons->id);
continue;
} else {
int llpc = 0;
slist_iter(node_rh, node_t, cons->node_list_rh, llpc,
update_node_weight(cons,
node_rh->details->id,
nodes));
}
/* dont add it to the resource,
* the information is in the resouce's node list
*/
);
return TRUE;
}
// remove nodes that are down, stopping
// create +ve rsc_to_node constraints between resources and the nodes they are running on
// anything else?
gboolean
unpack_status(xmlNodePtr status,
GSListPtr nodes,
GSListPtr rsc_list,
GSListPtr *node_constraints)
{
pdebug("Begining unpack %s", __FUNCTION__);
while(status != NULL) {
const char *id = xmlGetProp(status, "id");
const char *state = xmlGetProp(status, "state");
const char *exp_state = xmlGetProp(status, "exp_state");
xmlNodePtr lrm_state = find_xml_node(status, "lrm");
xmlNodePtr attrs = find_xml_node(status, "attributes");
lrm_state = find_xml_node(lrm_state, "lrm_resources");
lrm_state = find_xml_node(lrm_state, "rsc_state");
status = status->next;
pdebug("Processing node %s", id);
if(id == NULL){
// error
continue;
}
pdebug("Processing node attrs");
node_t *this_node = pe_find_node(nodes, id);
while(attrs != NULL){
const char *name = xmlGetProp(attrs, "name");
const char *value = xmlGetProp(attrs, "value");
if(name != NULL && value != NULL
&& safe_val(NULL, this_node, details) != NULL) {
pdebug("Adding %s => %s",
name, value);
g_hash_table_insert(this_node->details->attrs,
cl_strdup(name),
cl_strdup(value));
}
attrs = attrs->next;
}
pdebug("determining node state");
if(safe_str_eq(exp_state, "active")
&& safe_str_eq(state, "active")) {
// process resource, make +ve preference
this_node->details->online = TRUE;
} else {
pdebug("remove %s", __FUNCTION__);
// remove node from contention
this_node->weight = -1;
this_node->fixed = TRUE;
pdebug("state %s, expected %s",
state, exp_state);
if(safe_str_eq(state, "shutdown")){
// create shutdown req
this_node->details->shutdown = TRUE;
} else if(safe_str_eq(exp_state, "active")
&& safe_str_neq(state, "active")) {
// mark unclean in the xml
this_node->details->unclean = TRUE;
// remove any running resources from being allocated
}
}
pdebug("Processing node lrm state");
process_node_lrm_state(this_node, lrm_state,
rsc_list, nodes,
node_constraints);
}
return TRUE;
}
gboolean
is_active(rsc_to_node_t *cons)
{
return TRUE;
}
gboolean
strict_preproc(rsc_to_rsc_t *constraint,
color_t *local_color,
color_t *other_color,
GSListPtr *colors,
GSListPtr resources)
{
resource_t * lh_resource = constraint->rsc_lh;
switch(constraint->strength) {
case must:
if(constraint->rsc_rh->runnable == FALSE) {
cl_log(LOG_WARNING,
"Resource %s must run on the same node"
" as %s (cons %s), but %s is not"
" runnable.",
constraint->rsc_lh->id,
constraint->rsc_rh->id,
constraint->id,
constraint->rsc_rh->id);
constraint->rsc_lh->runnable = FALSE;
}
break;
// x * should * should_not = x
case should:
if(constraint->rsc_rh->provisional == FALSE) {
local_color->local_weight =
local_color->local_weight * 2.0;
}
break;
case should_not:
if(constraint->rsc_rh->provisional == FALSE) {
local_color->local_weight =
local_color->local_weight * 0.5;
}
pdebug("# Colors %d, Nodes %d",
g_slist_length(*colors),
max_valid_nodes);
if(g_slist_length(*colors) < max_valid_nodes
// && g_slist_length(lh_resource->candidate_colors)==1
) {
create_color(colors,
lh_resource->allowed_nodes,
resources);
}
break;
case must_not:
if(constraint->rsc_rh->provisional == FALSE) {
lh_resource->candidate_colors =
g_slist_remove(
lh_resource->candidate_colors,
local_color);
}
break;
default:
// error
break;
}
return TRUE;
}
gboolean
strict_postproc(rsc_to_rsc_t *constraint,
color_t *local_color,
color_t *other_color,
GSListPtr *colors,
GSListPtr resources)
{
print_rsc_to_rsc("Post processing", constraint, FALSE);
switch(constraint->strength) {
case must:
if(constraint->rsc_rh->provisional == TRUE) {
constraint->rsc_rh->color = other_color;
constraint->rsc_rh->provisional = FALSE;
color_resource(constraint->rsc_rh,
colors, resources);
}
// else check for error
if(constraint->rsc_lh->runnable == FALSE) {
cl_log(LOG_WARNING,
"Resource %s must run on the same node"
" as %s (cons %s), but %s is not"
" runnable.",
constraint->rsc_rh->id,
constraint->rsc_lh->id,
constraint->id,
constraint->rsc_lh->id);
constraint->rsc_rh->runnable = FALSE;
}
break;
case should:
break;
case should_not:
break;
case must_not:
if(constraint->rsc_rh->provisional == TRUE) {
// check for error
}
break;
default:
// error
break;
}
return TRUE;
}
gboolean
choose_color(resource_t *lh_resource, GSListPtr candidate_colors)
{
int lpc = 0;
if(lh_resource->runnable == FALSE) {
lh_resource->color = no_color;
lh_resource->provisional = FALSE;
} else {
GSListPtr sorted_colors = g_slist_sort(candidate_colors,
sort_color_weight);
lh_resource->candidate_colors = sorted_colors;
pdebug( "Choose a color from %d possibilities",
g_slist_length(sorted_colors));
}
if(lh_resource->provisional) {
slist_iter(
this_color, color_t,lh_resource->candidate_colors, lpc,
GSListPtr intersection = node_list_and(
this_color->details->candidate_nodes,
lh_resource->allowed_nodes);
if(g_slist_length(intersection) != 0) {
// TODO: merge node weights
g_slist_free(this_color->details->candidate_nodes);
this_color->details->candidate_nodes = intersection;
lh_resource->color = this_color;
lh_resource->provisional = FALSE;
break;
}
);
}
return !lh_resource->provisional;
}
gboolean
unpack_rsc_to_node(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr node_list,
GSListPtr *node_constraints)
{
xmlNodePtr node_ref = xml_obj->children;
rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t));
const char *id_lh = xmlGetProp(xml_obj, "from");
const char *id = xmlGetProp(xml_obj, "id");
const char *mod = xmlGetProp(xml_obj, "modifier");
const char *weight = xmlGetProp(xml_obj, "weight");
float weight_f = atof(weight);
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
if(rsc_lh == NULL) {
cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)",
id, id_lh);
}
new_con->id = cl_strdup(id);
new_con->rsc_lh = rsc_lh;
new_con->weight = weight_f;
if(safe_str_eq(mod, "set")){
new_con->modifier = set;
} else if(safe_str_eq(mod, "inc")){
new_con->modifier = inc;
} else if(safe_str_eq(mod, "dec")){
new_con->modifier = dec;
} else {
// error
}
/*
<rsc_to_node>
<node_ref id= type= name=/>
<node_ref id= type= name=/>
<node_ref id= type= name=/>
*/
//
while(node_ref != NULL) {
const char *id_rh = xmlGetProp(node_ref, "name");
node_t *node_rh = pe_find_node(node_list, id_rh);
if(node_rh == NULL) {
// error
cl_log(LOG_ERR,
"node %s (from %s) not found",
id_rh, node_ref->name);
continue;
}
new_con->node_list_rh =
g_slist_append(new_con->node_list_rh,
node_rh);
/* dont add it to the resource,
* the information is in the resouce's node list
*/
node_ref = node_ref->next;
}
*node_constraints = g_slist_append(*node_constraints, new_con);
return TRUE;
}
gboolean
unpack_rsc_to_attr(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr node_list,
GSListPtr *node_constraints)
{
/*
<rsc_to_attr id="cons4" from="rsc2" weight="20.0" modifier="inc">
<attr_expression id="attr_exp_1"/>
<node_match id="node_match_1" type="has_attr" target="cpu"/>
<node_match id="node_match_2" type="attr_value" target="kernel" value="2.6"/>
</attr_expression>
<attr_expression id="attr_exp_2"/>
<node_match id="node_match_3" type="has_attr" target="hdd"/>
<node_match id="node_match_4" type="attr_value" target="kernel" value="2.4"/>
</attr_expression>
Translation:
give any node a +ve weight of 20.0 to run rsc2 if:
attr "cpu" is set _and_ "kernel"="2.6", _or_
attr "hdd" is set _and_ "kernel"="2.4"
Further translation:
2 constraints that give any node a +ve weight of 20.0 to run rsc2
cons1: attr "cpu" is set and "kernel"="2.6"
cons2: attr "hdd" is set and "kernel"="2.4"
*/
xmlNodePtr attr_exp = xml_obj->children;
const char *id_lh = xmlGetProp(xml_obj, "from");
const char *mod = xmlGetProp(xml_obj, "modifier");
const char *weight = xmlGetProp(xml_obj, "weight");
const char *id = xmlGetProp(attr_exp, "id");
float weight_f = atof(weight);
enum con_modifier a_modifier = modifier_none;
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
if(rsc_lh == NULL) {
cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)",
id, id_lh);
return FALSE;
}
if(safe_str_eq(mod, "set")){
a_modifier = set;
} else if(safe_str_eq(mod, "inc")){
a_modifier = inc;
} else if(safe_str_eq(mod, "dec")){
a_modifier = dec;
} else {
// error
}
if(attr_exp == NULL) {
cl_log(LOG_WARNING, "no attrs for constraint %s", id);
}
while(attr_exp != NULL) {
const char *id_rh = xmlGetProp(attr_exp, "name");
const char *id = xmlGetProp(attr_exp, "id");
rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t));
new_con->id = cl_strdup(id);
new_con->rsc_lh = rsc_lh;
new_con->weight = weight_f;
new_con->modifier = a_modifier;
new_con->node_list_rh = match_attrs(attr_exp, node_list);
if(new_con->node_list_rh == NULL) {
// error
cl_log(LOG_ERR,
"node %s (from %s) not found",
id_rh, attr_exp->name);
}
pdebug_action(print_rsc_to_node("Added", new_con, FALSE));
*node_constraints = g_slist_append(*node_constraints, new_con);
/* dont add it to the resource,
* the information is in the resouce's node list
*/
attr_exp = attr_exp->next;
}
return TRUE;
}
gboolean
update_node_weight(rsc_to_node_t *cons, char *id, GSListPtr nodes)
{
node_t *node_rh = pe_find_node(cons->rsc_lh->allowed_nodes, id);
if(node_rh == NULL) {
node_t *node_tmp = pe_find_node(nodes, id);
node_rh = node_copy(node_tmp);
cons->rsc_lh->allowed_nodes =
g_slist_append(cons->rsc_lh->allowed_nodes,
node_rh);
}
if(node_rh == NULL) {
// error
return FALSE;
}
if(node_rh->fixed) {
// warning
cl_log(LOG_WARNING,
"Constraint %s is irrelevant as the"
" weight of node %s is fixed as %f.",
cons->id,
node_rh->details->id,
node_rh->weight);
return TRUE;
}
pdebug( "Constraint %s: node %s weight %s %f.",
cons->id,
node_rh->details->id,
modifier2text(cons->modifier),
node_rh->weight);
switch(cons->modifier) {
case set:
node_rh->weight = cons->weight;
node_rh->fixed = TRUE;
break;
case inc:
node_rh->weight += cons->weight;
break;
case dec:
node_rh->weight -= cons->weight;
break;
case modifier_none:
// warning
break;
}
return TRUE;
}
gboolean
process_node_lrm_state(node_t *node, xmlNodePtr lrm_state,
GSListPtr rsc_list, GSListPtr nodes,
GSListPtr *node_constraints)
{
pdebug("here %s", __FUNCTION__);
while(lrm_state != NULL) {
const char *id = xmlGetProp(lrm_state, "id");
const char *rsc_id = xmlGetProp(lrm_state, "rsc_id");
const char *node_id = xmlGetProp(lrm_state, "node_id");
const char *rsc_state = xmlGetProp(lrm_state, "rsc_state");
resource_t *rsc_lh = pe_find_resource(rsc_list, rsc_id);
rsc_lh->cur_node = node;
node->details->running_rsc =
g_slist_append(node->details->running_rsc, rsc_lh);
/* it is runnable, but depends on a stonith op
if(safe_val3(FALSE, node, details, unclean)) {
rsc_lh->runnable = FALSE;
}
*/
if((safe_str_eq(rsc_state, "starting"))
|| (safe_str_eq(rsc_state, "started"))) {
node_t *node_rh;
rsc_to_node_t *new_cons =
cl_malloc(sizeof(rsc_to_node_t));
new_cons->id = cl_strdup(id); // genereate one
new_cons->weight = 100.0;
new_cons->modifier = inc;
new_cons->rsc_lh = rsc_lh;
node_rh = pe_find_node(nodes, node_id);
new_cons->node_list_rh = g_slist_append(NULL, node_rh);
*node_constraints =
g_slist_append(*node_constraints, new_cons);
pdebug_action(print_rsc_to_node(
"Added", new_cons, FALSE));
} else if(safe_str_eq(rsc_state, "stop_fail")) {
// do soemthing
} // else no preference
lrm_state = lrm_state->next;
}
return TRUE;
}
GSListPtr
match_attrs(xmlNodePtr attr_exp, GSListPtr node_list)
{
int lpc = 0;
GSListPtr result = NULL;
slist_iter(
node, node_t, node_list, lpc,
xmlNodePtr node_match = attr_exp->children;
gboolean accept = TRUE;
while(accept && node_match != NULL) {
const char *type =xmlGetProp(node_match, "type");
const char *value=xmlGetProp(node_match, "value");
const char *name =xmlGetProp(node_match, "target");
node_match = node_match->next;
if(name == NULL || type == NULL) {
// error
continue;
}
const char *h_val = (const char*)
g_hash_table_lookup(node->details->attrs, name);
if(h_val != NULL && safe_str_eq(type, "has_attr")){
accept = TRUE;
} else if(h_val == NULL
&& safe_str_eq(type, "not_attr")) {
accept = TRUE;
} else if(h_val != NULL
&& safe_str_eq(type, "attr_value")
&& safe_str_eq(h_val, value)) {
accept = TRUE;
} else {
accept = FALSE;
}
}
if(accept) {
result = g_slist_append(result, node);
}
);
return result;
}
gboolean
create_rsc_to_rsc(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh)
{
if(rsc_lh == NULL || rsc_rh == NULL){
// error
return FALSE;
}
rsc_to_rsc_t *new_con = cl_malloc(sizeof(rsc_to_node_t));
rsc_to_rsc_t *inverted_con = NULL;
new_con->id = cl_strdup(id);
new_con->rsc_lh = rsc_lh;
new_con->rsc_rh = rsc_rh;
new_con->strength = strength;
inverted_con = invert_constraint(new_con);
rsc_lh->rsc_cons = g_slist_insert_sorted(rsc_lh->rsc_cons,
inverted_con, sort_cons_strength);
rsc_rh->rsc_cons = g_slist_insert_sorted(rsc_rh->rsc_cons,
new_con, sort_cons_strength);
return TRUE;
}
gboolean
create_ordering(const char *id, enum con_strength strength,
resource_t *rsc_lh, resource_t *rsc_rh,
GSListPtr *action_constraints)
{
if(rsc_lh == NULL || rsc_rh == NULL){
// error
return FALSE;
}
action_t *lh_stop = rsc_lh->stop;
action_t *lh_start = rsc_lh->start;
action_t *rh_stop = rsc_rh->stop;
action_t *rh_start = rsc_rh->start;
order_constraint_t *order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
order->id = order_id++;
order->lh_action = lh_stop;
order->rh_action = rh_stop;
order->strength = strength;
*action_constraints = g_slist_append(*action_constraints, order);
order = (order_constraint_t*)
cl_malloc(sizeof(order_constraint_t));
order->id = order_id++;
order->lh_action = rh_start;
order->rh_action = lh_start;
order->strength = strength;
*action_constraints = g_slist_append(*action_constraints, order);
return TRUE;
}
gboolean
unpack_rsc_to_rsc(xmlNodePtr xml_obj,
GSListPtr rsc_list,
GSListPtr *action_constraints)
{
const char *id_lh = xmlGetProp(xml_obj, "from");
const char *id = xmlGetProp(xml_obj, "id");
resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh);
const char *id_rh = xmlGetProp(xml_obj, "to");
resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh);
const char *strength = xmlGetProp(xml_obj, "strength");
const char *type = xmlGetProp(xml_obj, "type");
enum con_strength strength_e = ignore;
if(rsc_lh == NULL) {
cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)",
id, id_lh);
return FALSE;
}
if(safe_str_eq(strength, "must")) {
strength_e = must;
} else if(safe_str_eq(strength, "should")) {
strength_e = should;
} else if(safe_str_eq(strength, "should_not")) {
strength_e = should_not;
} else if(safe_str_eq(strength, "must_not")) {
strength_e = must_not;
} else {
// error
}
if(safe_str_eq(type, "ordering")) {
// make an action_cons instead
return create_ordering(id, strength_e, rsc_lh, rsc_rh,
action_constraints);
}
return create_rsc_to_rsc(id, strength_e, rsc_lh, rsc_rh);
}
GSListPtr
create_action_set(action_t *action)
{
int lpc = 0;
GSListPtr result = NULL;
GSListPtr tmp = NULL;
if(action->processed) {
return NULL;
}
pdebug_action(print_action("Create action set for", action, FALSE));
// process actions_before
if(action->seen_count == 0) {
pdebug("Processing \"before\" for action %d", action->id);
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
tmp = create_action_set(other->action);
pdebug("%d (%d total) \"before\" actions for %d)",
g_slist_length(tmp), g_slist_length(result),action->id);
result = g_slist_concat(result, tmp);
);
// add ourselves
pdebug("Adding self %d", action->id);
if(action->processed == FALSE) {
result = g_slist_append(result, action);
action->processed = TRUE;
}
} else {
pdebug("Already seen action %d", action->id);
pdebug("Processing \"before\" for action %d", action->id);
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
if(other->action->seen_count > action->seen_count
&& other->strength == must) {
tmp = create_action_set(other->action);
pdebug("%d (%d total) \"before\" actions for %d)",
g_slist_length(tmp), g_slist_length(result),action->id);
result = g_slist_concat(result, tmp);
}
);
// add ourselves
pdebug("Adding self %d", action->id);
if(action->processed == FALSE) {
result = g_slist_append(result, action);
action->processed = TRUE;
}
// add strength == !MUST
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
tmp = create_action_set(other->action);
pdebug("%d (%d total) post-self \"before\" actions for %d)",
g_slist_length(tmp), g_slist_length(result),action->id);
result = g_slist_concat(result, tmp);
);
}
action->seen_count = action->seen_count + 1;
// process actions_after
pdebug("Processing \"after\" for action %d", action->id);
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
tmp = create_action_set(other->action);
pdebug("%d (%d total) \"after\" actions for %d)",
g_slist_length(tmp), g_slist_length(result),action->id);
result = g_slist_concat(result, tmp);
);
return result;
}
gboolean
update_runnable(GSListPtr actions)
{
int lpc = 0, lpc2 = 0;
gboolean change = TRUE;
while(change) {
change = FALSE;
slist_iter(
action, action_t, actions, lpc,
if(action->runnable) {
continue;
} else if(action->optional) {
continue;
}
slist_iter(
other, action_wrapper_t, action->actions_before, lpc2,
if(other->action->runnable) {
change = TRUE;
}
other->action->runnable = FALSE;
);
);
}
return TRUE;
}
void
color_resource(resource_t *lh_resource, GSListPtr *colors, GSListPtr resources)
{
int lpc = 0;
pdebug_action(print_resource("Coloring", lh_resource, FALSE));
if(lh_resource->provisional == FALSE) {
// already processed this resource
return;
}
lh_resource->rsc_cons = g_slist_sort(lh_resource->rsc_cons,
sort_cons_strength);
pdebug("=== Pre-processing");
//------ Pre-processing
slist_iter(
constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc,
color_t *other_color = NULL;
color_t *local_color = NULL;
if(lh_resource->runnable == FALSE) {
break;
}
pdebug_action(print_rsc_to_rsc(
"Processing constraint",
constraint, FALSE));
if(constraint->rsc_rh == NULL) {
cl_log(LOG_ERR,
"rsc_rh was NULL for %s",
constraint->id);
continue;
}
other_color = constraint->rsc_rh->color;
local_color = find_color(lh_resource->candidate_colors,
other_color);
strict_preproc(constraint, local_color, other_color,
colors, resources);
);
// filter out nodes with a negative weight
filter_nodes(lh_resource);
/* Choose a color from the candidates or,
* create a new one if no color is suitable
* (this may need modification pending further napkin drawings)
*/
choose_color(lh_resource, lh_resource->candidate_colors);
pdebug("* Colors %d, Nodes %d",
g_slist_length(*colors),
max_valid_nodes);
if(lh_resource->provisional
&& g_slist_length(*colors) < max_valid_nodes) {
// Create new color
pdebug("Create a new color");
lh_resource->color = create_color(colors,
lh_resource->allowed_nodes,
resources);
lh_resource->provisional = FALSE;
} else if(lh_resource->provisional) {
cl_log(LOG_ERR, "Could not color resource %s", lh_resource->id);
print_resource("ERROR: No color", lh_resource, FALSE);
lh_resource->color = no_color;
lh_resource->provisional = FALSE;
}
pdebug_action(print_resource("Post-processing", lh_resource, FALSE));
//------ Post-processing
color_t *local_color = lh_resource->color;
slist_iter(
constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc,
color_t *other_color =
find_color(constraint->rsc_rh->candidate_colors,
local_color);
strict_postproc(constraint, local_color, other_color,
colors, resources);
);
pdebug_action(print_resource("Colored", lh_resource, FALSE));
}
gboolean
process_pe_message(xmlNodePtr msg, IPC_Channel *sender)
{
const char *op = get_xml_attr (msg, XML_TAG_OPTIONS,
XML_ATTR_OP, TRUE);
const char *ref = xmlGetProp(msg, XML_ATTR_REFERENCE);
CRM_DEBUG("Processing %s op (ref=%s)...", op, ref);
const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO);
if(op == NULL){
// error
+
+ } else if(strcmp(op, "hello") == 0) {
+ // ignore
+
} else if(sys_to == NULL || strcmp(sys_to, "pengine") != 0) {
CRM_DEBUG("Bad sys-to %s", sys_to);
return FALSE;
} else if(strcmp(op, "pecalc") == 0) {
xmlNodePtr input_cib = find_xml_node(msg, XML_TAG_CIB);
if (send_ipc_reply(sender, msg,
do_calculations(input_cib)) ==FALSE) {
cl_log(LOG_WARNING,
"Answer could not be sent");
}
} else if(strcmp(op, "quit") == 0) {
cl_log(LOG_WARNING, "Received quit message, terminating");
exit(0);
}
return TRUE;
}
xmlNodePtr
do_calculations(xmlNodePtr cib_object)
{
int lpc, lpc2;
GSListPtr resources = NULL;
GSListPtr nodes = NULL;
GSListPtr node_constraints = NULL;
GSListPtr actions = NULL;
GSListPtr action_constraints = NULL;
GSListPtr stonith_list = NULL;
GSListPtr shutdown_list = NULL;
GSListPtr colors = NULL;
GSListPtr action_sets = NULL;
xmlNodePtr graph = NULL;
// pe_debug_on();
pdebug("=#=#=#=#= Stage 0 =#=#=#=#=");
stage0(cib_object,
&resources,
&nodes, &node_constraints,
&actions, &action_constraints,
&stonith_list, &shutdown_list);
pdebug("=#=#=#=#= Stage 1 =#=#=#=#=");
stage1(node_constraints, nodes, resources);
pdebug("=#=#=#=#= Stage 2 =#=#=#=#=");
stage2(resources, nodes, &colors);
pdebug("========= Nodes =========");
pdebug_action(
slist_iter(node, node_t, nodes, lpc,
print_node(NULL, node, TRUE)
)
);
pdebug("========= Resources =========");
pdebug_action(
slist_iter(resource, resource_t, resources, lpc,
print_resource(NULL, resource, TRUE)
)
);
pdebug("=#=#=#=#= Stage 3 =#=#=#=#=");
stage3(colors);
pdebug("=#=#=#=#= Stage 4 =#=#=#=#=");
stage4(colors);
pdebug("========= Colors =========");
pdebug_action(
slist_iter(color, color_t, colors, lpc,
print_color(NULL, color, FALSE)
)
);
pdebug("=#=#=#=#= Stage 5 =#=#=#=#=");
stage5(resources);
pdebug("=#=#=#=#= Stage 6 =#=#=#=#=");
stage6(&actions, &action_constraints,
stonith_list, shutdown_list);
pdebug("========= Action List =========");
pdebug_action(
slist_iter(action, action_t, actions, lpc,
print_action(NULL, action, TRUE)
)
);
pdebug("=#=#=#=#= Stage 7 =#=#=#=#=");
stage7(resources, actions, action_constraints, &action_sets);
pdebug("=#=#=#=#= Summary =#=#=#=#=");
summary(resources);
pdebug("========= Action Sets =========");
pdebug("\t========= Set %d (Un-runnable) =========", -1);
pdebug_action(
slist_iter(action, action_t, actions, lpc,
if(action->optional == FALSE
&& action->runnable == FALSE) {
print_action("\t", action, TRUE);
}
)
);
pdebug_action(
slist_iter(action_set, GSList, action_sets, lpc,
pdebug("\t========= Set %d =========", lpc);
slist_iter(action, action_t, action_set, lpc2,
print_action("\t", action, TRUE);
)
)
);
pdebug("========= Stonith List =========");
pdebug_action(
slist_iter(node, node_t, stonith_list, lpc,
print_node(NULL, node, FALSE);
)
);
pdebug("========= Shutdown List =========");
pdebug_action(
slist_iter(node, node_t, shutdown_list, lpc,
print_node(NULL, node, FALSE);
)
);
pdebug("=#=#=#=#= Stage 8 =#=#=#=#=");
stage8(action_sets, &graph);
return graph;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 8, 6:44 PM (2 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2002779
Default Alt Text
(149 KB)

Event Timeline