Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4624735
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
149 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment