diff --git a/crm/admin/adminmain.c b/crm/admin/adminmain.c index e7d6331c80..06b3539e0c 100644 --- a/crm/admin/adminmain.c +++ b/crm/admin/adminmain.c @@ -1,628 +1,637 @@ -/* $Id: adminmain.c,v 1.20 2004/03/26 14:14:25 andrew Exp $ */ +/* $Id: adminmain.c,v 1.21 2004/04/26 12:36:05 msoffen Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include + #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?i:o:D:C:S:HA:U:M:I:EWRFt:m:a:d:w:c:r:p:s:" #include #include GMainLoop *mainloop = NULL; const char *crm_system_name = "crmadmin"; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); xmlNodePtr handleCibMod(void); gboolean DO_DAEMON = FALSE; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean DO_HEALTH = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_RECALC_TREE = FALSE; gboolean DO_FLUSH_RECALC = FALSE; const char *cib_action = NULL; xmlNodePtr msg_options = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; const char *verbose = "false"; char *id = NULL; char *this_msg_reference = NULL; char *obj_type = NULL; char *clear = NULL; char *status = NULL; char *disconnect = NULL; char *unload_ha = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int operation_status = 0; const char *sys_to = NULL;; int main(int argc, char **argv) { + int option_index = 0; + int argerr = 0; + int flag; + ll_cluster_t *hb_cluster = NULL; + + static struct option long_options[] = { + // Top-level Options + {"daemon", 0, 0, 0}, + {CRM_OPERATION_ERASE, 0, 0, 0}, + {CRM_OPERATION_QUERY, 0, 0, 0}, + {CRM_OPERATION_CREATE, 0, 0, 0}, + {CRM_OPERATION_REPLACE, 0, 0, 0}, + {CRM_OPERATION_STORE, 0, 0, 0}, + {CRM_OPERATION_UPDATE, 0, 0, 0}, + {CRM_OPERATION_DELETE, 0, 0, 0}, + {"verbose", 0, 0, 'V'}, + {"help", 0, 0, '?'}, + {"reference", 1, 0, 0}, + + // common options + {"id", 1, 0, 'i'}, + {"obj_type", 1, 0, 'o'}, + + // daemon options + {"reset", 1, 0, 'C'}, + {"status", 1, 0, 'S'}, + {"health", 0, 0, 'H'}, + {"disconnect", 1, 0, 'A'}, + {"unload_ha", 1, 0, 'U'}, + {"migrate_from", 1, 0, 'M'}, + {"migrate_res", 1, 0, 'I'}, + {"elect_dc", 0, 0, 'E'}, + {"whois_dc", 0, 0, 'W'}, + {"recalc_tree", 0, 0, 'R'}, + {"flush_recalc_tree", 0, 0, 'F'}, + + {0, 0, 0, 0} + }; cl_log_set_entity(crm_system_name); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); - int argerr = 0; - int flag; - while (1) { - int option_index = 0; - static struct option long_options[] = { - // Top-level Options - {"daemon", 0, 0, 0}, - {CRM_OPERATION_ERASE, 0, 0, 0}, - {CRM_OPERATION_QUERY, 0, 0, 0}, - {CRM_OPERATION_CREATE, 0, 0, 0}, - {CRM_OPERATION_REPLACE, 0, 0, 0}, - {CRM_OPERATION_STORE, 0, 0, 0}, - {CRM_OPERATION_UPDATE, 0, 0, 0}, - {CRM_OPERATION_DELETE, 0, 0, 0}, - {"verbose", 0, 0, 'V'}, - {"help", 0, 0, '?'}, - {"reference", 1, 0, 0}, - - // common options - {"id", 1, 0, 'i'}, - {"obj_type", 1, 0, 'o'}, - - // daemon options - {"reset", 1, 0, 'C'}, - {"status", 1, 0, 'S'}, - {"health", 0, 0, 'H'}, - {"disconnect", 1, 0, 'A'}, - {"unload_ha", 1, 0, 'U'}, - {"migrate_from", 1, 0, 'M'}, - {"migrate_res", 1, 0, 'I'}, - {"elect_dc", 0, 0, 'E'}, - {"whois_dc", 0, 0, 'W'}, - {"recalc_tree", 0, 0, 'R'}, - {"flush_recalc_tree", 0, 0, 'F'}, - - {0, 0, 0, 0} - }; - flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcmp("daemon", long_options[option_index].name) == 0) DO_DAEMON = TRUE; else if (strcmp(CRM_OPERATION_ERASE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_CREATE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_UPDATE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_DELETE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_REPLACE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_STORE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_QUERY, long_options[option_index].name) == 0){ cib_action = cl_strdup(long_options[option_index].name); } else if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = cl_strdup(optarg); } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': BE_VERBOSE = TRUE; verbose = "true"; break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': CRM_DEBUG3("Option %c => %s", flag, optarg); id = cl_strdup(optarg); break; case 'o': CRM_DEBUG3("Option %c => %s", flag, optarg); obj_type = cl_strdup(optarg); break; case 'C': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'S': DO_HEALTH = TRUE; status = cl_strdup(optarg); break; case 'H': DO_HEALTH = TRUE; break; case 'A': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'U': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'M': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'I': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'E': DO_ELECT_DC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'W': DO_WHOIS_DC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'R': DO_RECALC_TREE = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'F': DO_FLUSH_RECALC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } - ll_cluster_t *hb_cluster = do_init(); + hb_cluster = do_init(); if (hb_cluster != NULL) { if (do_work(hb_cluster) > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "%s waiting for reply from the local CRM", crm_system_name); g_main_run(mainloop); return_to_orig_privs(); } else { cl_log(LOG_ERR, "No message to send"); operation_status = -1; } } else { cl_log(LOG_ERR, "Init failed, could not perform requested operations"); operation_status = -2; } cl_log(LOG_DEBUG, "%s exiting normally", crm_system_name); return operation_status; } xmlNodePtr handleCibMod(void) { + const char *attr_name = NULL; + const char *attr_value = NULL; + xmlNodePtr fragment = NULL; xmlNodePtr cib_object = file2xml(stdin); if(cib_object == NULL) { return NULL; } if(strcmp(cib_object->name, obj_type) != 0) { cl_log(LOG_ERR, "Mismatching xml." " Expected root element <%s>, got <%s>", obj_type, cib_object->name); return NULL; } - const char *attr_name = NULL; - const char *attr_value = NULL; - attr_name = XML_ATTR_ID; attr_value = xmlGetProp(cib_object, attr_name); if(attr_name == NULL || strlen(attr_name) == 0) { cl_log(LOG_ERR, "No value for %s specified.", attr_name); return NULL; } CRM_DEBUG("Object creation complete"); // create the cib request - xmlNodePtr fragment = NULL; fragment = create_cib_fragment(cib_object, NULL); set_xml_property_copy(msg_options, XML_ATTR_OP, cib_action); return fragment; } int do_work(ll_cluster_t * hb_cluster) { /* construct the request */ xmlNodePtr msg_data = NULL; const char *dest_node = NULL; gboolean all_is_good = TRUE; + char *obj_type_parent = NULL; + const char *ping_type = NULL; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(msg_options, XML_ATTR_VERBOSE, verbose); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_DAEMON == TRUE && cib_action != NULL) { if(strcmp(CRM_OPERATION_QUERY, cib_action) == 0) { cl_log(LOG_DEBUG, "Querying the CIB"); - char *obj_type_parent = pluralSection(obj_type); + obj_type_parent = pluralSection(obj_type); CRM_DEBUG2("Querying the CIB for section: %s", obj_type_parent); set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OPERATION_QUERY); set_xml_property_copy(msg_options, XML_ATTR_FILTER_ID, obj_type_parent); dest_node = status; CRM_DEBUG2("CIB query creation %s", msg_data == NULL ? "failed." : "passed."); sys_to = CRM_SYSTEM_DCIB; } else if (strcmp(CRM_OPERATION_ERASE, cib_action) == 0) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OPERATION_ERASE); dest_node = status; CRM_DEBUG("CIB Erase op in progress"); sys_to = CRM_SYSTEM_DCIB; } else { cl_log(LOG_ERR, "Unknown daemon options"); all_is_good = FALSE; } } else if(cib_action != NULL) { msg_data = handleCibMod(); sys_to = CRM_SYSTEM_DCIB; if(msg_data == NULL) all_is_good = FALSE; } else if (DO_DAEMON == TRUE && DO_HEALTH == TRUE) { CRM_DEBUG("Querying the system"); sys_to = CRM_SYSTEM_DC; if (status != NULL) { sys_to = CRM_SYSTEM_CRMD; - const char *ping_type = CRM_OPERATION_PING; + ping_type = CRM_OPERATION_PING; if (BE_VERBOSE) { ping_type = "ping_deep"; if (status != NULL) expected_responses = 2; // 5; // CRM/DC, LRMD, CIB, PENGINE, TENGINE else expected_responses = -1;// wait until timeout instead } set_xml_property_copy(msg_options, XML_ATTR_OP, ping_type); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = status; } else { cl_log(LOG_INFO, "Cluster-wide health not available yet"); all_is_good = FALSE; } } else { cl_log(LOG_ERR, "Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { cl_log(LOG_ERR, "Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { cl_log(LOG_ERR, "The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) sys_to = CRM_SYSTEM_CRMD; else sys_to = CRM_SYSTEM_DC; } send_ipc_request(crmd_channel, msg_options, msg_data, dest_node, sys_to, crm_system_name, admin_uuid, this_msg_reference); return 1; } ll_cluster_t * do_init(void) { + int facility; + ll_cluster_t *hb_cluster = NULL; /* docs say only do this once, but in their code they do it every time! */ xmlInitParser (); /* change the logging facility to the one used by heartbeat daemon */ - ll_cluster_t *hb_cluster = ll_cluster_new("heartbeat"); + hb_cluster = ll_cluster_new("heartbeat"); - int facility; cl_log(LOG_INFO, "Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } admin_uuid = cl_malloc(sizeof(char) * 11); snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; crmd_channel = init_client_ipc_comms(CRM_SYSTEM_CRMD, admin_msg_callback, NULL); if(crmd_channel != NULL) { send_hello_message(crmd_channel, admin_uuid, crm_system_name, "0", "1"); return hb_cluster; } return NULL; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } const char *ournode; gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { - FNIN(); int lpc = 0; IPC_Message *msg = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; + char *filename; + int filename_len = 0; + const char *result = NULL; + xmlNodePtr options = NULL; + xmlNodePtr xml_root_node = NULL; + char *buffer = NULL; + + FNIN(); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(!hack_return_good); } if (msg == NULL) { CRM_DEBUG("No message this time"); continue; } lpc++; - char *buffer =(char *) msg->msg_body; + buffer =(char *) msg->msg_body; CRM_DEBUG2("Got xml [text=%s]", buffer); - xmlNodePtr xml_root_node = + xml_root_node = find_xml_in_ipcmessage(msg, TRUE); if (xml_root_node == NULL) { cl_log(LOG_INFO, "XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message(xml_root_node, crm_system_name, admin_uuid, "response") == FALSE) { cl_log(LOG_INFO, "Message was not a CRM response. Discarding."); continue; } - xmlNodePtr options = find_xml_node(xml_root_node, + options = find_xml_node(xml_root_node, XML_TAG_OPTIONS); - const char *result = xmlGetProp(options, XML_ATTR_RESULT); + result = xmlGetProp(options, XML_ATTR_RESULT); if(result == NULL || strcmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } received_responses++; // do stuff if (this_msg_reference != NULL) { // in testing mode... - char *filename; /* 31 = "test-_.xml" + an_int_as_string + '\0' */ - int filename_len = 31 + strlen(this_msg_reference); + filename_len = 31 + strlen(this_msg_reference); filename = cl_malloc(sizeof(char) * filename_len); sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (xmlSaveFormatFile(filename, xml_root_node->doc, 1) < 0) { cl_log(LOG_CRIT, "Could not save response %s_%s_%d.xml", this_msg_reference, result, received_responses); } } } if (server->ch_status == IPC_DISCONNECT) { cl_log(LOG_INFO, "admin_msg_callback: received HUP"); FNRET(!hack_return_good); } if (received_responses >= expected_responses) { cl_log(LOG_INFO, "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } FNRET(hack_return_good); } diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c index 29a2f64405..cf9dbef36a 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,1060 +1,1069 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include // for access #include #include #include // for calls to open #include // for calls to open #include // for calls to open #include // for getpwuid #include // for initgroups #include // for getrlimit #include // for getrlimit #include #include #include #include #include #include #include #include #include #include #include #define CLIENT_EXIT_WAIT 10 static gboolean stop_subsystem (struct crm_subsystem_s *centry); static gboolean start_subsystem(struct crm_subsystem_s *centry); static gboolean run_command (struct crm_subsystem_s *centry, const char *options, gboolean update_pid); xmlNodePtr do_lrm_query(void); GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth); gboolean lrm_dispatch(int fd, gpointer user_data); void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type); struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; void cleanup_subsystem(struct crm_subsystem_s *the_subsystem) { int pid_status = -1; the_subsystem->ipc = NULL; clear_bit_inplace(&fsa_input_register, the_subsystem->flag); /* Forcing client to die */ kill(the_subsystem->pid, -9); // cleanup the ps entry waitpid(the_subsystem->pid, &pid_status, WNOHANG); the_subsystem->pid = -1; } /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; FNIN(); if(action & stop_actions) { // dont do anything, its embedded now } if(action & start_actions) { if(cur_state != S_STOPPING) { if(startCib(CIB_FILENAME) == FALSE) result = I_FAIL; } else { cl_log(LOG_INFO, "Ignoring request to start %s after shutdown", this_subsys->command); } } FNRET(result); } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr cib_msg = NULL; xmlNodePtr answer = NULL; xmlNodePtr tmp1 = NULL; xmlNodePtr tmp2 = NULL; xmlNodePtr new_options = NULL; const char *req_from; const char *section = NULL; FNIN(); if(data != NULL) cib_msg = (xmlNodePtr)data; if(action & A_CIB_INVOKE) { const char *op = xmlGetProp(cib_msg, XML_ATTR_OP); 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(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); } // 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) { 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); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); 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_INVOKE */ 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) { FNIN(); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); 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); - xmlNodePtr rsc_list = create_xml_node(data, "lrm_resources"); + 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); - state_flag_t cur_state = 0; - CRM_DEBUG("get_cur_state..."); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); CRM_DEBUG2("\tcurrent state:%s\n", cur_state==LRM_RSC_IDLE?"Idel":"Busy"); - const char *this_op = NULL; - GList* node = g_list_first(op_list); + node = g_list_first(op_list); while(NULL != node){ lrm_op_t* op = (lrm_op_t*)node->data; this_op = op->op_type; if(this_op == NULL || strcmp(this_op, "status") != 0){ const char *status_text = ""; switch(op->status) { case LRM_OP_DONE: status_text = "done"; break; case LRM_OP_CANCELLED: status_text = "cancelled"; break; case LRM_OP_TIMEOUT: status_text = "timeout"; break; case LRM_OP_NOTSUPPORTED: status_text = "not suported"; break; case LRM_OP_ERROR: status_text = "error"; break; } set_xml_property_copy(xml_rsc, "op_result", status_text); set_xml_property_copy(xml_rsc, "rsc_op", this_op); // we only want the last one break; } node = g_list_next(node); } element = g_list_next(element); } if (NULL != lrm_list) { g_list_free(lrm_list); } return data; } /* A_LRM_INVOKE */ enum crmd_fsa_input do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; + xmlNodePtr fragment, tmp1; + xmlNodePtr msg; + const char *rsc_path[] = + { + "msg_data", + "rsc_op", + "resource", + "instance_attributes", + "parameters" + }; + const char *operation = NULL; + rsc_id_t rid; + const char *id_from_cib = NULL; + const char *crm_op = NULL; + lrm_rsc_t *rsc = NULL; + lrm_mon_t* mon = NULL; + lrm_op_t* op = NULL; + FNIN(); if(action & A_UPDATE_NODESTATUS) { xmlNodePtr data = do_lrm_query(); set_xml_property_copy(data, "replace_lrm", "true"); - xmlNodePtr fragment, tmp1; - 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_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); - xmlNodePtr msg = (xmlNodePtr)data; - const char *rsc_path[] = - { - "msg_data", - "rsc_op", - "resource", - "instance_attributes", - "parameters" - }; + msg = (xmlNodePtr)data; - const char *operation = get_xml_attr_nested(msg, + operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3, "operation", TRUE); - rsc_id_t rid; - const char *id_from_cib = get_xml_attr_nested(msg, + 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); - const char *crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, "operation", TRUE); + crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, "operation", TRUE); - lrm_rsc_t *rsc = fsa_lrm_conn->lrm_ops->get_rsc( + 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); } - lrm_mon_t* mon = g_new(lrm_mon_t, 1); + 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_DEBUG2("performing op %s...", operation); - lrm_op_t* op = g_new(lrm_op_t, 1); + 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_DEBUG3("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) { /* */ 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); - char *tmp = crm_itoa(status); + 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); - xmlNodePtr fragment, tmp1; - 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 54695a2715..43ac3921a6 100755 --- a/crm/pengine/pengine.c +++ b/crm/pengine/pengine.c @@ -1,1136 +1,1192 @@ +#include + #include #include #include #include #include #include #include color_t *create_color(GSListPtr nodes); void add_color_to_rsc(resource_t *rsc, color_t *color); gint sort_rsc_priority(gconstpointer a, gconstpointer b); gint sort_cons_strength(gconstpointer a, gconstpointer b); gint sort_color_weight(gconstpointer a, gconstpointer b); gint sort_node_weight(gconstpointer a, gconstpointer b); gboolean unpack_constraints(xmlNodePtr constraints); gboolean unpack_resources(xmlNodePtr resources); gboolean unpack_nodes(xmlNodePtr nodes); gboolean unpack_status(xmlNodePtr status); gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes); void color_resource(resource_t *lh_resource, GSListPtr sorted_rsc, GSListPtr colors); gboolean is_active(rsc_constraint_t *cons); rsc_constraint_t *invert_constraint(rsc_constraint_t *constraint); gboolean filter_nodes(resource_t *rsc); color_t *find_color(GSListPtr candidate_colors, color_t *other_color); resource_t *pe_find_resource(GSListPtr rsc_list, const char *id_rh); node_t *pe_find_node(GSListPtr node_list, const char *id); gboolean choose_node_from_list(GSListPtr colors, color_t *color, GSListPtr nodes); rsc_constraint_t *copy_constraint(rsc_constraint_t *constraint); GSListPtr node_list_dup(GSListPtr list1); GSListPtr node_list_and(GSListPtr list1, GSListPtr list2); GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2); GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2); gboolean node_list_eq(GSListPtr list1, GSListPtr list2); node_t *node_copy(node_t *this_node) ; node_t *find_list_node(GSListPtr list, const char *id); GSListPtr rsc_list = NULL; GSListPtr node_list = NULL; GSListPtr cons_list = NULL; GSListPtr colors = NULL; GSListPtr stonith_list = NULL; color_t *current_color = NULL; gboolean stage1(xmlNodePtr cib) { xmlNodePtr cib_nodes = get_object_root("nodes", cib); xmlNodePtr cib_resources = get_object_root("resources", cib); xmlNodePtr cib_constraints = get_object_root("constraints", cib); xmlNodePtr cib_status = get_object_root("status", cib); /* rsc_list = g_slist_alloc(); */ /* node_list = create_slist(); */ /* cons_list = g_slist_alloc(); */ /* colors = g_slist_alloc(); */ /* stonith_list = g_slist_alloc(); */ unpack_nodes(cib_nodes->children); unpack_resources(cib_resources->children); unpack_status(cib_status); unpack_constraints(cib_constraints->children); apply_node_constraints(cons_list, node_list, rsc_list); // filter_nodes(rsc_list); return TRUE; } void color_resource(resource_t *lh_resource, GSListPtr sorted_rsc, GSListPtr colors) { int lpc = 0; + GSListPtr intersection = NULL; cl_log(LOG_DEBUG, "Coloring resource"); print_resource(lh_resource, FALSE); lh_resource->constraints = g_slist_sort(lh_resource->constraints, sort_cons_strength); cl_log(LOG_DEBUG, "Pre-processing"); //------ Pre-processing for(; lpc < g_slist_length(lh_resource->constraints); lpc++) { rsc_constraint_t *constraint = (rsc_constraint_t*)g_slist_nth_data(lh_resource->constraints, lpc); color_t *other_color = NULL; color_t *local_color = NULL; cl_log(LOG_DEBUG, "Processing constraint %d", lpc); print_cons(constraint, FALSE); if(constraint->is_placement == FALSE) { continue; } if(constraint->type != rsc_to_rsc) { continue; } 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); switch(constraint->strength) { case must: /// not yet... 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; } 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; } } // 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) */ lh_resource->candidate_colors = g_slist_sort(lh_resource->candidate_colors, sort_color_weight); cl_log(LOG_DEBUG, "Choose a color from %d possibilities", g_slist_length(lh_resource->candidate_colors )); for(lpc = 0; lpc < g_slist_length(lh_resource->candidate_colors) && lh_resource->provisional; lpc++) { color_t *this_color = (color_t*)g_slist_nth_data(lh_resource->candidate_colors, lpc); print_color(this_color, FALSE); - GSListPtr intersection = node_list_and(this_color->details->candidate_nodes, + intersection = node_list_and(this_color->details->candidate_nodes, lh_resource->allowed_nodes); cl_log(LOG_DEBUG, "Checking the node intersection %d", g_slist_length(intersection)); 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; } } if(lh_resource->provisional) { // Create new color cl_log(LOG_DEBUG, "Create a new color"); current_color = create_color(lh_resource->allowed_nodes); lh_resource->color = current_color; lh_resource->provisional = FALSE; } cl_log(LOG_DEBUG, "Post-processing"); //------ Post-processing for(lpc = 0; lpc < g_slist_length(lh_resource->constraints); lpc++) { rsc_constraint_t *constraint = (rsc_constraint_t*)g_slist_nth_data(lh_resource->constraints, lpc); color_t *local_color = lh_resource->color; color_t *other_color = NULL; if(constraint->is_placement == FALSE) { continue; } else if(constraint->type != rsc_to_rsc) { continue; } other_color = find_color(constraint->rsc_rh->candidate_colors, local_color); 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, sorted_rsc, colors); } // else check for error break; // x * should * should_not = x case should: /* will be taken care of in the pre-processing stage of coloring rsc_rh if(constraint->rsc_rh->provisional == TRUE) { other_color->weight = other_color->weight * 2.0; } */ break; case should_not: /* will be taken care of in the pre-processing stage of coloring rsc_rh if(constraint->rsc_rh->provisional == TRUE) { other_color->weight = other_color->weight * 0.5; } */ break; case must_not: /* will be taken care of in the pre-processing stage of coloring rsc_rh if(constraint->rsc_rh->provisional == FALSE) { g_slist_remove(constraint->rsc_rh->candidate_colors, other_color); } */ if(constraint->rsc_rh->provisional == TRUE) { // check for error } break; default: // error break; } } } gboolean stage2(GSListPtr sorted_rsc, GSListPtr sorted_nodes, GSListPtr operations) { + resource_t *lh_resource = NULL; int lpc = 0; + // Set initial color // Set color.candidate_nodes = all active nodes current_color = cl_malloc(sizeof(color_t)); cl_log(LOG_DEBUG, "setup"); current_color = create_color(node_list); // Set resource.color = color (all resources) // Set resource.provisional = TRUE (all resources) for(lpc = 0; lpc < g_slist_length(sorted_rsc); lpc++) { resource_t *this_resource = (resource_t*)g_slist_nth_data(sorted_rsc, lpc); this_resource->color = current_color; this_resource->provisional = TRUE; } cl_log(LOG_DEBUG, "initialized resources to default color"); // Take (next) highest resource for(lpc = 0; lpc < g_slist_length(sorted_rsc); lpc++) { cl_log(LOG_DEBUG, "Processing resource %d", lpc); - resource_t *lh_resource = (resource_t*)g_slist_nth_data(sorted_rsc, lpc); + lh_resource = (resource_t*)g_slist_nth_data(sorted_rsc, lpc); // if resource.provisional == FALSE, repeat if(lh_resource->provisional == FALSE) { // already processed this resource continue; } color_resource(lh_resource, sorted_rsc, colors); // next resource } return TRUE; } #define color_n_nodes color_n->details->candidate_nodes #define color_n_plus_1_nodes color_n_plus_1->details->candidate_nodes gboolean stage3(GSListPtr colors) { int lpc = 0; color_t *color_n = NULL; color_t *color_n_plus_1 = NULL; + GSListPtr xor = NULL; + GSListPtr minus = 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); cl_log(LOG_DEBUG, "Choose node for..."); print_color(color_n, FALSE); print_color(color_n_plus_1, FALSE); if(color_n == NULL) { continue; } - GSListPtr xor = node_list_xor(color_n_nodes, + xor = node_list_xor(color_n_nodes, color_n_plus_1_nodes); - GSListPtr minus = node_list_minus(color_n_nodes, + minus = node_list_minus(color_n_nodes, color_n_plus_1_nodes); if(g_slist_length(xor) == 0 || g_slist_length(minus) == 0) { cl_log(LOG_DEBUG, "Choose any node from our list"); choose_node_from_list(colors, color_n, color_n_nodes); } else { cl_log(LOG_DEBUG, "Choose a node not in n+1"); choose_node_from_list(colors, color_n, minus); } } // chose last color if(color_n_plus_1 != NULL) { cl_log(LOG_DEBUG, "Choose node for last color..."); print_color(color_n, FALSE); choose_node_from_list(colors, color_n_plus_1, color_n_plus_1_nodes); } 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 */ + color_t *color_n = NULL; + node_t *other_node = NULL; 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; } for(lpc = 0; lpc < g_slist_length(colors); lpc++) { - color_t *color_n = (color_t*)g_slist_nth_data(colors, lpc); - node_t *other_node = pe_find_node(color_n->details->candidate_nodes, + color_n = (color_t*)g_slist_nth_data(colors, lpc); + other_node = pe_find_node(color_n->details->candidate_nodes, color->details->chosen_node->id); color_n->details->candidate_nodes = g_slist_remove(color_n->details->candidate_nodes, other_node); } return TRUE; } /* only for rsc_to_rsc constraints */ rsc_constraint_t * invert_constraint(rsc_constraint_t *constraint) { + rsc_constraint_t *inverted_con = NULL; cl_log(LOG_DEBUG, "Inverting constraint"); - rsc_constraint_t *inverted_con = + inverted_con = cl_malloc(sizeof(rsc_constraint_t)); inverted_con->id = cl_strdup(constraint->id); inverted_con->type = constraint->type; inverted_con->strength = constraint->strength; inverted_con->is_placement = constraint->is_placement; // swap the direction inverted_con->rsc_lh = constraint->rsc_rh; inverted_con->rsc_rh = constraint->rsc_lh; inverted_con->node_rh = NULL; inverted_con->modifier = modifier_none; inverted_con->weight = 0.0; cl_log(LOG_DEBUG, "Inverted constraint"); print_cons(inverted_con, FALSE); return inverted_con; } rsc_constraint_t * copy_constraint(rsc_constraint_t *constraint) { rsc_constraint_t *copied_con = cl_malloc(sizeof(rsc_constraint_t)); copied_con->id = cl_strdup(constraint->id); copied_con->type = constraint->type; copied_con->strength = constraint->strength; copied_con->is_placement = constraint->is_placement; // swap the direction copied_con->rsc_lh = constraint->rsc_lh; copied_con->rsc_rh = constraint->rsc_rh; copied_con->node_rh = constraint->node_rh; copied_con->modifier = constraint->modifier; copied_con->weight = constraint->weight; return copied_con; } /* are the contents of list1 and list2 equal */ /* nodes with weight < 0 are ignored */ gboolean node_list_eq(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; if(g_slist_length(list1) != g_slist_length(list2)) { return FALSE; } // do stuff return g_slist_length(result) != 0; } /* the intersection of list1 and list2 */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_and(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; + node_t *node = NULL; + node_t *new_node = NULL; + node_t *other_node = NULL; cl_log(LOG_DEBUG, "Len 1: %d, len 2: %d", g_slist_length(list1), g_slist_length(list2)); for(lpc = 0; lpc < g_slist_length(list1); lpc++) { - node_t *node = (node_t*)g_slist_nth_data(list1, lpc); - node_t *new_node = node_copy(node); - node_t *other_node = (node_t*)find_list_node(list2, node->id); + node = (node_t*)g_slist_nth_data(list1, lpc); + new_node = node_copy(node); + other_node = (node_t*)find_list_node(list2, node->id); if(node == NULL || other_node == NULL) { continue; // merge node weights } else if(node->weight < 0 || other_node->weight < 0) { new_node->weight = -1; } else { new_node->weight = node->weight + other_node->weight; if(new_node->weight != 0) { new_node->weight = new_node->weight /2.0; } } result = g_slist_append(result, new_node); } return result; } node_t * find_list_node(GSListPtr list, const char *id) { + node_t *thing = NULL; int lpc = 0; + for(lpc = 0; lpc < g_slist_length(list); lpc++) { - node_t *thing = (node_t *)g_slist_nth_data(list, lpc); + thing = (node_t *)g_slist_nth_data(list, lpc); if(safe_str_eq(thing->id, id)) { return thing; } } return NULL; } /* list1 - list2 */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; + node_t *node = NULL; + node_t *other_node = NULL; + node_t *new_node = NULL; for(lpc = 0; lpc < g_slist_length(list1); lpc++) { - node_t *node = (node_t*)g_slist_nth_data(list1, lpc); - node_t *other_node = (node_t*)find_list_node(list2, node->id); + node = (node_t*)g_slist_nth_data(list1, lpc); + other_node = (node_t*)find_list_node(list2, node->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } - node_t *new_node = node_copy(node); + new_node = node_copy(node); result = g_slist_append(result, new_node); } cl_log(LOG_DEBUG, "Minus result len: %d", g_slist_length(result)); return result; } /* list1 + list2 - (intersection of list1 and list2) */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; + node_t *node = NULL; + node_t *other_node = NULL; + node_t *new_node = NULL; for(lpc = 0; lpc < g_slist_length(list1); lpc++) { - node_t *node = (node_t*)g_slist_nth_data(list1, lpc); - node_t *other_node = (node_t*)find_list_node(list2, node->id); + node = (node_t*)g_slist_nth_data(list1, lpc); + other_node = (node_t*)find_list_node(list2, node->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } - node_t *new_node = node_copy(node); + new_node = node_copy(node); result = g_slist_append(result, new_node); } for(lpc = 0; lpc < g_slist_length(list2); lpc++) { node_t *node = (node_t*)g_slist_nth_data(list2, lpc); node_t *other_node = (node_t*)find_list_node(list1, node->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } - node_t *new_node = node_copy(node); + new_node = node_copy(node); result = g_slist_append(result, new_node); } cl_log(LOG_DEBUG, "Xor result len: %d", g_slist_length(result)); return result; } GSListPtr node_list_dup(GSListPtr list1) { GSListPtr result = NULL; int lpc = 0; if(list1 == NULL) { return NULL; } for(lpc = 0; lpc < g_slist_length(list1); lpc++) { node_t *this_node = (node_t*)g_slist_nth_data(list1, lpc); node_t *new_node = node_copy(this_node); if(new_node != NULL) { result = g_slist_append(result, new_node); } } return result; } node_t * node_copy(node_t *this_node) { + node_t *new_node = NULL; + if(this_node == NULL) { print_node(this_node); return NULL; } - node_t *new_node = cl_malloc(sizeof(node_t)); + new_node = cl_malloc(sizeof(node_t)); new_node->id = cl_strdup(this_node->id); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; return new_node; } static int color_id = 0; color_t * create_color(GSListPtr nodes) { int lpc = 0; color_t *new_color = cl_malloc(sizeof(color_t)); new_color->id = color_id++; new_color->local_weight = 0; // not used here new_color->details = cl_malloc(sizeof(struct color_shared_s)); new_color->details->chosen_node = NULL; new_color->details->candidate_nodes = node_list_dup(nodes); colors = g_slist_append(colors, new_color); print_color(new_color, FALSE); /* Add any new color to the list of candidate_colors for * resources that havent been decided yet */ for(lpc = 0; lpc < g_slist_length(rsc_list); lpc++) { resource_t *rh_resource = (resource_t*)g_slist_nth_data(rsc_list, lpc); add_color_to_rsc(rh_resource, new_color); } return new_color; } void add_color_to_rsc(resource_t *rsc, color_t *color) { + color_t *color_copy = NULL; if(rsc->provisional) { - color_t *color_copy = cl_malloc(sizeof(color_t)); + color_copy = cl_malloc(sizeof(color_t)); color_copy->id = color->id; color_copy->local_weight = 1.0; color_copy->details = color->details; rsc->candidate_colors = g_slist_append(rsc->candidate_colors, color_copy); } } gboolean unpack_nodes(xmlNodePtr nodes) { + int lpc = 1; + node_t *new_node = NULL; + xmlNodePtr xml_obj = NULL; + const char *id = NULL; + cl_log(LOG_DEBUG, "Begining unpack... %s", __FUNCTION__); cl_log(LOG_DEBUG, "Number of nodes... %d", g_slist_length(node_list)); - int lpc = 1; while(nodes != NULL) { cl_log(LOG_DEBUG, "Processing node..."); - xmlNodePtr xml_obj = nodes; - const char *id = xmlGetProp(xml_obj, "id"); nodes = nodes->next; + xml_obj = nodes; + id = xmlGetProp(xml_obj, "id"); if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } - node_t *new_node = cl_malloc(sizeof(node_t)); + new_node = cl_malloc(sizeof(node_t)); new_node->weight = 1.0 * lpc++; new_node->fixed = FALSE; new_node->id = cl_strdup(id); cl_log(LOG_DEBUG, "Adding node id... %s (%p)", id, new_node); node_list = g_slist_append(node_list, new_node); cl_log(LOG_DEBUG, "Number of nodes... %d", g_slist_length(node_list)); } cl_log(LOG_DEBUG, "Sorting nodes... %s", __FUNCTION__); node_list = g_slist_sort(node_list, sort_node_weight); return TRUE; } gboolean unpack_resources(xmlNodePtr resources) { + resource_t *new_rsc = NULL; cl_log(LOG_DEBUG, "Begining unpack... %s", __FUNCTION__); while(resources != NULL) { xmlNodePtr xml_obj = resources; const char *id = xmlGetProp(xml_obj, "id"); const char *priority = xmlGetProp(xml_obj, "priority"); float priority_f = atof(priority); resources = resources->next; cl_log(LOG_DEBUG, "Processing resource..."); if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } - resource_t *new_rsc = cl_malloc(sizeof(resource_t)); + new_rsc = NULL; + new_rsc = cl_malloc(sizeof(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->provisional = TRUE; new_rsc->allowed_nodes = node_list_dup(node_list); new_rsc->constraints = NULL; new_rsc->id = cl_strdup(id); cl_log(LOG_DEBUG, "Adding resource %s (%p)...", id, new_rsc); rsc_list = g_slist_append(rsc_list, new_rsc); } rsc_list = g_slist_sort(rsc_list, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(xmlNodePtr constraints) { + const char *id = NULL; + xmlNodePtr xml_obj = NULL; + rsc_constraint_t *new_con = NULL; + rsc_constraint_t *inverted_con = NULL; + const char *id_lh = NULL; + resource_t *rsc_lh = NULL; + const char *strength = NULL; + const char *type = NULL; + const char *id_rh = NULL; + const char *mod = NULL; + const char *weight = NULL; + rsc_constraint_t *cons_copy = NULL; + float weight_f; + resource_t *rsc_rh; + int lpc = 0; + cl_log(LOG_DEBUG, "Begining unpack... %s", __FUNCTION__); while(constraints != NULL) { - const char *id = xmlGetProp(constraints, "id"); - xmlNodePtr xml_obj = constraints; + id = xmlGetProp(constraints, "id"); + xml_obj = constraints; constraints = constraints->next; if(id == NULL) { cl_log(LOG_ERR, "Constraint must have an id"); continue; } cl_log(LOG_DEBUG, "Processing constraint %s", id); - rsc_constraint_t *new_con = cl_malloc(sizeof(rsc_constraint_t)); - rsc_constraint_t *inverted_con = NULL; - const char *id_lh = xmlGetProp(xml_obj, "from"); + + new_con = cl_malloc(sizeof(rsc_constraint_t)); + inverted_con = NULL; + id_lh = xmlGetProp(xml_obj, "from"); cl_log(LOG_DEBUG, "Looking up resource..."); - resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); + 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); continue; } new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; if(safe_str_eq("rsc_to_rsc", xml_obj->name)) { new_con->type = rsc_to_rsc; - const char *strength = xmlGetProp(xml_obj, "strength"); + strength = xmlGetProp(xml_obj, "strength"); if(safe_str_eq(strength, "must")) { new_con->strength = must; } else if(safe_str_eq(strength, "should")) { new_con->strength = should; } else if(safe_str_eq(strength, "should_not")) { new_con->strength = should_not; } else if(safe_str_eq(strength, "must_not")) { new_con->strength = must_not; } else { // error } - const char *type = xmlGetProp(xml_obj, "type"); + type = xmlGetProp(xml_obj, "type"); if(safe_str_eq(type, "ordering")) { new_con->is_placement = FALSE; } else if (safe_str_eq(type, "placement")) { new_con->is_placement = TRUE; } else { // error } new_con->node_rh = NULL; - const char *id_rh = xmlGetProp(xml_obj, "to"); - resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); + + + id_rh = xmlGetProp(xml_obj, "to"); + rsc_rh = pe_find_resource(rsc_list, id_rh); if(rsc_rh == NULL) { cl_log(LOG_ERR, "No rh resource found with id %s", id_rh); continue; } new_con->rsc_rh = rsc_rh; inverted_con = invert_constraint(new_con); cons_list = g_slist_insert_sorted(cons_list, inverted_con, sort_cons_strength); cons_list = g_slist_insert_sorted(cons_list, new_con, sort_cons_strength); } else if(safe_str_eq("rsc_to_node", xml_obj->name)) { xmlNodePtr node_ref = xml_obj->children; new_con->type = rsc_to_node; new_con->rsc_rh = NULL; - const char *mod = xmlGetProp(xml_obj, "modifier"); - const char *weight = xmlGetProp(xml_obj, "weight"); - float weight_f = atof(weight); + mod = xmlGetProp(xml_obj, "modifier"); + weight = xmlGetProp(xml_obj, "weight"); + weight_f = atof(weight); new_con->weight = weight_f; cl_log(LOG_DEBUG, "Mod: %s", mod); 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 } /* */ // while(node_ref != NULL) { - const char *id_rh = xmlGetProp(node_ref, "name"); - rsc_constraint_t *cons_copy = copy_constraint(new_con); + id_rh = xmlGetProp(node_ref, "name"); + cons_copy = copy_constraint(new_con); cons_copy->node_rh = pe_find_node(rsc_lh->allowed_nodes, id_rh); if(cons_copy->node_rh == NULL) { // error cl_log(LOG_ERR, "node %s (from %s) not found", id_rh, node_ref->name); } else { cons_list = g_slist_insert_sorted(cons_list, cons_copy, sort_cons_strength); } /* dont add it to the resource, * the information is in the resouce's node list */ node_ref = node_ref->next; } cl_free(new_con->id); cl_free(new_con); } else { // error } } - int lpc = 0; cl_log(LOG_INFO, "========= Constraints ========="); slist_iter(resource, rsc_constraint_t, cons_list, lpc, print_cons(resource, FALSE)); return TRUE; } gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes) { - cl_log(LOG_DEBUG, "Applying constraints... %s", __FUNCTION__); + resource_t *rsc_lh = NULL; + GSListPtr rsc_cons_list = NULL; int lpc = 0; + + cl_log(LOG_DEBUG, "Applying constraints... %s", __FUNCTION__); for(lpc = 0; lpc < g_slist_length(constraints); lpc++) { rsc_constraint_t *cons = (rsc_constraint_t *) g_slist_nth_data(constraints, lpc); cl_log(LOG_DEBUG, "Processing constraint %d", lpc); // 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; + rsc_lh = cons->rsc_lh; if(rsc_lh == NULL) { cl_log(LOG_ERR, "LHS of rsc_to_node (%s) is NULL", cons->id); continue; } - GSListPtr rsc_cons_list = cons->rsc_lh->constraints; + rsc_cons_list = cons->rsc_lh->constraints; rsc_lh->constraints = g_slist_append(rsc_cons_list, cons); if(cons->type == rsc_to_rsc) { // nothing cl_log(LOG_DEBUG, "nothing to do"); continue; } else if(cons->type == rsc_to_node) { if(cons->node_rh == NULL) { cl_log(LOG_ERR, "RHS of rsc_to_node (%s) is NULL", cons->id); continue; } else if(cons->node_rh->fixed) { // warning cl_log(LOG_WARNING, "Constraint %s is irrelevant as the" " weight of node %s is fixed as %f.", cons->id, cons->node_rh->id, cons->node_rh->weight); } else { node_t *node_rh = pe_find_node(cons->rsc_lh->allowed_nodes, cons->node_rh->id); cl_log(LOG_DEBUG, "Constraint %s: node %s weight %s %f.", cons->id, cons->node_rh->id, modifier2text(cons->modifier), cons->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; } } /* dont add it to the resource, * the information is in the resouce's node list */ } else { // error } } return TRUE; } gboolean filter_nodes(resource_t *rsc) { + int lpc2 = 0; + node_t *node = NULL; + cl_log(LOG_DEBUG, "Filtering nodes... %s", __FUNCTION__); - int lpc2 = 0; print_resource(rsc, FALSE); for(lpc2 = 0; lpc2 < g_slist_length(rsc->allowed_nodes); lpc2++) { - node_t *node = g_slist_nth_data(rsc->allowed_nodes, lpc2); + node = g_slist_nth_data(rsc->allowed_nodes, lpc2); print_node(node); if(node == NULL) { cl_log(LOG_ERR, "Invalid NULL node"); } else if(node->weight < 0.0) { cl_log(LOG_DEBUG, "removing:"); print_node(node); rsc->allowed_nodes = g_slist_remove(rsc->allowed_nodes,node); } } return TRUE; } resource_t * pe_find_resource(GSListPtr rsc_list, const char *id_rh) { int lpc = 0; for(lpc = 0; lpc < g_slist_length(rsc_list); lpc++) { resource_t *rsc = g_slist_nth_data(rsc_list, lpc); if(rsc != NULL && safe_str_eq(rsc->id, id_rh)){ cl_log(LOG_DEBUG, "Resource %s found at %d...", id_rh, lpc); return rsc; } } // error return NULL; } node_t * pe_find_node(GSListPtr nodes, const char *id) { int lpc = 0; for(lpc = 0; lpc < g_slist_length(nodes); lpc++) { node_t *node = g_slist_nth_data(nodes, lpc); if(safe_str_eq(node->id, id)) { return node; } } // error return NULL; } // 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) { cl_log(LOG_DEBUG, "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"); lrm_state = find_xml_node(lrm_state, "lrm_resource"); lrm_state = find_xml_node(lrm_state, "rsc_state"); status = status->next; if(id == NULL) { // error continue; } if(safe_str_eq(exp_state, "active") && safe_str_eq(state, "active")) { // process resource, make +ve preference while(lrm_state != NULL) { 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"); if((safe_str_eq(rsc_state, "starting")) || (safe_str_eq(rsc_state, "started"))) { rsc_constraint_t *new_cons = cl_malloc(sizeof(rsc_constraint_t)); new_cons->id = cl_strdup(""); // genereate one new_cons->rsc_lh = pe_find_resource(rsc_list, rsc_id); new_cons->type = rsc_to_node; new_cons->weight = 100.0; new_cons->node_rh = pe_find_node(new_cons->rsc_lh->allowed_nodes, node_id); new_cons->modifier = inc; cons_list = g_slist_append(cons_list, new_cons); } else if(safe_str_eq(rsc_state, "stop_fail")) { // do soemthing } // else no preference lrm_state = lrm_state->next; } } else { // remove node from contention node_t *node = NULL; int lpc = 0; for(; lpc < g_slist_length(node_list); lpc++) { node_t *node = (node_t*)g_slist_nth_data(node_list, lpc); if(safe_str_eq(node->id, id)){ node->weight = -1; node->fixed = TRUE; } } if(safe_str_eq(exp_state, "down") && safe_str_eq(state, "shutdown")) { // create shutdown req } else if(safe_str_eq(exp_state, "active") && safe_str_neq(state, "active")) { // create stonith // mark unclean // remove any running resources from being allocated } if(safe_str_eq(state, "unclean")) { stonith_list = g_slist_append(stonith_list, node); } } } cons_list = g_slist_sort(cons_list, sort_cons_strength); return TRUE; } color_t * find_color(GSListPtr candidate_colors, color_t *other_color) { int lpc = 0; slist_iter(color, color_t, candidate_colors, lpc, if(color->id == other_color->id) { return color; } ); return NULL; } gboolean is_active(rsc_constraint_t *cons) { return TRUE; } gint sort_rsc_priority(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(resource1->priority > resource2->priority) return -1; if(resource1->priority < resource2->priority) return 1; return 0; } gint sort_cons_strength(gconstpointer a, gconstpointer b) { const rsc_constraint_t *rsc_constraint1 = (const rsc_constraint_t*)a; const rsc_constraint_t *rsc_constraint2 = (const rsc_constraint_t*)b; if(rsc_constraint1->strength > rsc_constraint2->strength) return 1; if(rsc_constraint1->strength < rsc_constraint2->strength) return -1; return 0; } gint sort_color_weight(gconstpointer a, gconstpointer b) { const color_t *color1 = (const color_t*)a; const color_t *color2 = (const color_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(color1->local_weight > color2->local_weight) return -1; if(color1->local_weight < color2->local_weight) return 1; return 0; } gint sort_node_weight(gconstpointer a, gconstpointer b) { const node_t *node1 = (const node_t*)a; const node_t *node2 = (const node_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(node1->weight > node2->weight) return -1; if(node1->weight < node2->weight) return 1; return 0; } diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c index 634a7247bf..8a0aadc9df 100644 --- a/crm/pengine/ptest.c +++ b/crm/pengine/ptest.c @@ -1,363 +1,364 @@ -/* $Id: ptest.c,v 1.1 2004/04/23 15:32:11 andrew Exp $ */ +/* $Id: ptest.c,v 1.2 2004/04/26 12:36:20 msoffen Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?i:o:D:C:S:HA:U:M:I:EWRFt:m:a:d:w:c:r:p:s:" #include #include #include void print_node(node_t *node); void print_resource(resource_t *rsc, gboolean details); void print_cons(rsc_constraint_t *cons, gboolean details); void print_color(color_t *color, gboolean details); void print_color_details(struct color_shared_s *color, gboolean details); int main(int argc, char **argv) { + xmlNodePtr cib_object = NULL; + int lpc = 0; int argerr = 0; int flag; cl_log_set_entity("ptest"); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); xmlInitParser(); while (1) { int option_index = 0; static struct option long_options[] = { // Top-level Options {"daemon", 0, 0, 0}, {0, 0, 0, 0} }; flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': printf("option %d", flag); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { cl_log(LOG_ERR, "%d errors in option parsing", argerr); } cl_log(LOG_INFO, "=#=#=#=#= Getting XML =#=#=#=#="); - xmlNodePtr cib_object = file2xml(stdin); + cib_object = file2xml(stdin); cl_log(LOG_INFO, "=#=#=#=#= Stage 1 =#=#=#=#="); stage1(cib_object); - int lpc = 0; cl_log(LOG_INFO, "========= Nodes ========="); slist_iter(node, node_t, node_list, lpc, print_node(node)); cl_log(LOG_INFO, "========= Resources ========="); slist_iter(resource, resource_t, rsc_list, lpc, print_resource(resource, FALSE)); cl_log(LOG_INFO, "========= Constraints ========="); slist_iter(constraint, rsc_constraint_t, cons_list, lpc, print_cons(constraint, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 2 =#=#=#=#="); stage2(rsc_list, node_list, NULL); cl_log(LOG_INFO, "========= Nodes ========="); slist_iter(node, node_t, node_list, lpc, print_node(node)); cl_log(LOG_INFO, "========= Resources ========="); slist_iter(resource, resource_t, rsc_list, lpc, print_resource(resource, FALSE)); cl_log(LOG_INFO, "========= Colors ========="); slist_iter(color, color_t, colors, lpc, print_color(color, FALSE)); cl_log(LOG_INFO, "========= Stonith List ========="); slist_iter(node, node_t, stonith_list, lpc, print_node(node)); cl_log(LOG_INFO, "========= Current Color ========="); print_color(current_color, FALSE); cl_log(LOG_INFO, "=#=#=#=#= Stage 3 =#=#=#=#="); stage3(colors); cl_log(LOG_INFO, "========= Colors ========="); slist_iter(color, color_t, colors, lpc, print_color(color, FALSE)); return 0; } const char * contype2text(enum con_type type) { const char *result = ""; switch(type) { case none: result = "none"; break; case rsc_to_rsc: result = "rsc_to_rsc"; break; case rsc_to_node: result = "rsc_to_node"; break; case base_weight: result = "base_weight"; break; } return result; }; const char * strength2text(enum con_strength strength) { const char *result = ""; switch(strength) { case must: result = "must"; break; case should: result = "should"; break; case should_not: result = "should_not"; break; case must_not: result = "must_not"; break; } return result; }; const char * modifier2text(enum con_modifier modifier) { const char *result = ""; switch(modifier) { case modifier_none: result = "modifier_none"; break; case set: result = "set"; break; case inc: result = "inc"; break; case dec: result = "dec"; break; } return result; }; void print_node(node_t *node) { if(node == NULL) { cl_log(LOG_DEBUG, "%s: ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "Node %s: (weight=%f, fixed=%s)", node->id, node->weight, node->fixed?"True":"False"); }; void print_color_details(struct color_shared_s *color, gboolean details) { if(color == NULL) { cl_log(LOG_DEBUG, "%s: ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "Color %d: node=%s (from %d candidates)", color->id, color->chosen_node->id, g_slist_length(color->candidate_nodes)); if(details) { int lpc = 0; slist_iter(node, node_t, color->candidate_nodes, lpc, print_node(node)); } } void print_color(color_t *color, gboolean details) { if(color == NULL) { cl_log(LOG_DEBUG, "%s: ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "Color %d: (weight=%f, node=%s, possible=%d)", color->id, color->local_weight, color->details->chosen_node==NULL?"":color->details->chosen_node->id, g_slist_length(color->details->candidate_nodes)); if(details) { print_color_details(color->details, details); } } void print_cons(rsc_constraint_t *cons, gboolean details) { if(cons == NULL) { cl_log(LOG_DEBUG, "%s: ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s Constraint %s (%p):", contype2text(cons->type), cons->id, cons); if(details == FALSE) { switch(cons->type) { case none: cl_log(LOG_ERR, "must specify a type"); break; case rsc_to_rsc: cl_log(LOG_DEBUG, "\t%s --> %s, %s (%s rule)", cons->rsc_lh==NULL?"null":cons->rsc_lh->id, cons->rsc_rh==NULL?"null":cons->rsc_rh->id, strength2text(cons->strength), cons->is_placement?"placement":"ordering"); break; case rsc_to_node: cl_log(LOG_DEBUG, "\t%s --> %s, %s %f (node placement rule)", cons->rsc_lh->id, cons->node_rh->id, modifier2text(cons->modifier), cons->weight); break; case base_weight: cl_log(LOG_ERR, "not supported"); break; } } }; void print_resource(resource_t *rsc, gboolean details) { if(rsc == NULL) { cl_log(LOG_DEBUG, "%s: ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%sResource %s: (priority=%f, color=%d)", rsc->provisional?"Provisional ":"", rsc->id, (double)rsc->priority, rsc->color==NULL?-1:rsc->color->id); if(details == FALSE) { cl_log(LOG_DEBUG, "\t%d candidate colors, %d allowed nodes and %d constraints", g_slist_length(rsc->candidate_colors), g_slist_length(rsc->allowed_nodes), g_slist_length(rsc->constraints)); } } diff --git a/crm/tengine/tenginemain.c b/crm/tengine/tenginemain.c index 89a77765fa..30d3bd9dea 100644 --- a/crm/tengine/tenginemain.c +++ b/crm/tengine/tenginemain.c @@ -1,233 +1,236 @@ -/* $Id: tenginemain.c,v 1.11 2004/04/21 18:50:28 andrew Exp $ */ +/* $Id: tenginemain.c,v 1.12 2004/04/26 12:36:24 msoffen Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include - -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "skrh" #define PID_FILE WORKING_DIR "/transitioner.pid" #define DAEMON_LOG "/var/log/transitioner.log" #define DAEMON_DEBUG "/var/log/transitioner.debug" GMainLoop* mainloop = NULL; const char* crm_system_name = "transitioner"; void usage(const char* cmd, int exit_status); int init_start(void); void tengine_shutdown(int nsig); int main(int argc, char ** argv) { - - cl_log_set_entity(crm_system_name); - cl_log_enable_stderr(TRUE); - cl_log_set_facility(LOG_USER); - int req_restart = FALSE; int req_status = FALSE; int req_stop = FALSE; int argerr = 0; int flag; + cl_log_set_entity(crm_system_name); + cl_log_enable_stderr(TRUE); + cl_log_set_facility(LOG_USER); + + if (0) { send_ipc_message(NULL, NULL); } while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 's': /* Status */ req_status = TRUE; break; case 'k': /* Stop (kill) */ req_stop = TRUE; break; case 'r': /* Restart */ req_restart = TRUE; break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } // read local config file if (req_status){ return init_status(PID_FILE, crm_system_name); } if (req_stop){ return init_stop(PID_FILE); } if (req_restart) { init_stop(PID_FILE); } return init_start(); } int init_start(void) { long pid; + ll_cluster_t* hb_fd = NULL; + int facility; + IPC_Channel *crm_ch = NULL; +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; +#endif if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { cl_log(LOG_CRIT, "already running: [pid %ld].", pid); exit(LSB_EXIT_OK); } cl_log_set_logfile(DAEMON_LOG); // if (crm_debug()) { cl_log_set_debugfile(DAEMON_DEBUG); // } /* change the logging facility to the one used by heartbeat daemon */ - ll_cluster_t* hb_fd = ll_cluster_new("heartbeat"); + hb_fd = ll_cluster_new("heartbeat"); - int facility; cl_log(LOG_INFO, "Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } cl_log(LOG_INFO, "Register PID"); register_pid(PID_FILE, FALSE, tengine_shutdown); - IPC_Channel *crm_ch = init_client_ipc_comms("crmd", + crm_ch = init_client_ipc_comms("crmd", default_ipc_input_dispatch, NULL); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "Starting %s", crm_system_name); #ifdef REALTIME_SUPPORT - static int crm_realtime = 1; if (crm_realtime == 1){ cl_enable_realtime(); }else if (crm_realtime == 0){ cl_disable_realtime(); } cl_make_realtime(SCHED_RR, 5, 64, 64); #endif g_main_run(mainloop); } else { cl_log(LOG_ERR, "Could not connect to the CRMd"); } return_to_orig_privs(); if (unlink(PID_FILE) == 0) { cl_log(LOG_INFO, "[%s] stopped", crm_system_name); } if(crm_ch != NULL) return 0; return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } void tengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, tengine_shutdown); if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); }else{ exit(LSB_EXIT_OK); } }