diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index 989ae0c21c..89cb9620a2 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,616 +1,615 @@ -/* $Id: cibadmin.c,v 1.39 2005/06/27 08:17:06 andrew Exp $ */ +/* $Id: cibadmin.c,v 1.40 2005/06/30 14:08:14 andrew 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 #ifdef HAVE_GETOPT_H # include #endif #include /* someone complaining about _ha_msg_mod not being found */ #include int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; const char *crm_system_name = "cibadmin"; IPC_Channel *crmd_channel = NULL; const char *host = NULL; void usage(const char *cmd, int exit_status); enum cib_errors do_init(void); int do_work(const char *xml_text, int command_options, crm_data_t **output); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); crm_data_t *handleCibMod(const char *xml); gboolean admin_message_timeout(gpointer data); void cib_connection_destroy(gpointer user_data); void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); int command_options = 0; const char *cib_action = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; char *id = NULL; char *this_msg_reference = NULL; char *obj_type = NULL; -char *clear = NULL; char *status = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int request_id = 0; int operation_status = 0; cib_t *the_cib = NULL; #define OPTARGS "V?i:o:QDUCEX:t:Srwlsh:MBfbd" int main(int argc, char **argv) { int argerr = 0; int flag; char *admin_input_xml = NULL; crm_data_t *output = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {CIB_OP_ERASE, 0, 0, 'E'}, {CIB_OP_QUERY, 0, 0, 'Q'}, {CIB_OP_CREATE, 0, 0, 'C'}, {CIB_OP_REPLACE, 0, 0, 'R'}, {CIB_OP_UPDATE, 0, 0, 'U'}, {CIB_OP_DELETE, 0, 0, 'D'}, {CIB_OP_DELETE_ALT, 0, 0, 'd'}, {CIB_OP_BUMP, 0, 0, 'B'}, {CIB_OP_SYNC, 0, 0, 'S'}, {CIB_OP_SLAVE, 0, 0, 'r'}, {CIB_OP_MASTER, 0, 0, 'w'}, {CIB_OP_ISMASTER,0, 0, 'M'}, {"force-quorum",0, 0, 'f'}, {"local", 0, 0, 'l'}, {"sync-call", 0, 0, 's'}, {"no-bcast", 0, 0, 'b'}, {"host", 0, 0, 'h'}, {F_CRM_DATA, 1, 0, 'X'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, {"timeout", 1, 0, 't'}, /* common options */ {XML_ATTR_ID, 1, 0, 'i'}, {"obj_type", 1, 0, 'o'}, {0, 0, 0, 0} }; #endif crm_log_init(crm_system_name); cl_log_set_facility(LOG_USER); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (safe_str_eq("reference", long_options[option_index].name)) { this_msg_reference = crm_strdup(optarg); } else { printf("Long option (--%s) is not (yet?) properly supported\n", long_options[option_index].name); ++argerr; } break; #endif case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case 'E': cib_action = CIB_OP_ERASE; break; case 'Q': cib_action = CIB_OP_QUERY; break; case 'S': cib_action = CIB_OP_SYNC; break; case 'U': cib_action = CIB_OP_UPDATE; break; case 'R': cib_action = CIB_OP_REPLACE; break; case 'C': cib_action = CIB_OP_CREATE; break; case 'D': cib_action = CIB_OP_DELETE; break; case 'd': cib_action = CIB_OP_DELETE_ALT; break; case 'M': cib_action = CIB_OP_ISMASTER; command_options |= cib_scope_local; break; case 'B': cib_action = CIB_OP_BUMP; break; case 'r': cib_action = CIB_OP_SLAVE; break; case 'w': cib_action = CIB_OP_MASTER; command_options |= cib_scope_local; break; case 'V': command_options = command_options | cib_verbose; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); id = crm_strdup(optarg); break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'X': admin_input_xml = crm_strdup(optarg); break; case 'h': host = crm_strdup(optarg); break; case 'l': command_options |= cib_scope_local; break; case 'b': command_options |= cib_inhibit_bcast; command_options |= cib_scope_local; break; case 's': command_options |= cib_sync_call; break; case 'f': command_options |= cib_quorum_override; break; default: printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, 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(cib_action == NULL) { usage(crm_system_name, cib_operation); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } exit_code = do_init(); if(exit_code != cib_ok) { crm_err("Init failed, could not perform requested operations"); fprintf(stderr, "Init failed, could not perform requested operations\n"); return -exit_code; } exit_code = do_work(admin_input_xml, command_options, &output); if (exit_code > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ request_id = exit_code; add_cib_op_callback( request_id, FALSE, NULL, cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug("Setting operation timeout to %dms for call %d", message_timeout_ms, request_id); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); crm_debug_3("%s waiting for reply from the local CIB", crm_system_name); crm_info("Starting mainloop"); g_main_run(mainloop); } else if(exit_code < 0) { crm_err("Call failed: %s", cib_error2string(exit_code)); fprintf(stderr, "Call failed: %s\n", cib_error2string(exit_code)); operation_status = exit_code; } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } crm_data_t* handleCibMod(const char *xml) { const char *attr_name = NULL; const char *attr_value = NULL; crm_data_t *fragment = NULL; crm_data_t *cib_object = NULL; if(xml == NULL) { cib_object = stdin2xml(); } else { cib_object = string2xml(xml); } if(cib_object == NULL) { return NULL; } attr_name = XML_ATTR_ID; attr_value = crm_element_value(cib_object, attr_name); if(attr_name == NULL || strlen(attr_name) == 0) { crm_err("No value for %s specified.", attr_name); return NULL; } crm_debug_4("Object creation complete"); /* create the cib request */ fragment = create_cib_fragment(cib_object, NULL); return fragment; } int do_work(const char *admin_input_xml, int call_options, crm_data_t **output) { /* construct the request */ crm_data_t *msg_data = NULL; char *obj_type_parent = NULL; obj_type_parent = cib_pluralSection(obj_type); if(strcmp(CIB_OP_QUERY, cib_action) == 0) { crm_debug_2("Querying the CIB for section: %s", obj_type_parent); return the_cib->cmds->query_from( the_cib, host, obj_type_parent, output, call_options); } else if (strcmp(CIB_OP_ERASE, cib_action) == 0) { crm_debug_4("CIB Erase op in progress"); return the_cib->cmds->erase(the_cib, output, call_options); } else if (strcmp(CIB_OP_CREATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->create( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CIB_OP_UPDATE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->modify( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CIB_OP_DELETE_ALT, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); msg_data = handleCibMod(admin_input_xml); rc = the_cib->cmds->delete_absolute( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CIB_OP_DELETE, cib_action) == 0) { enum cib_errors rc = cib_ok; crm_debug_4("Performing %s op...", cib_action); if(admin_input_xml == NULL) { msg_data = stdin2xml(); } else { msg_data = string2xml(admin_input_xml); } rc = the_cib->cmds->delete( the_cib, obj_type_parent, msg_data, output, call_options); free_xml(msg_data); return rc; } else if (strcmp(CIB_OP_SYNC, cib_action) == 0) { crm_debug_4("Performing %s op...", cib_action); return the_cib->cmds->sync_from( the_cib, host, obj_type_parent, call_options); } else if (strcmp(CIB_OP_SLAVE, cib_action) == 0 && (call_options ^ cib_scope_local) ) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_slave_all(the_cib, call_options); } else if (strcmp(CIB_OP_MASTER, cib_action) == 0) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_master(the_cib, call_options); } else if(cib_action != NULL) { crm_debug_4("Passing \"%s\" to variant_op...", cib_action); return the_cib->cmds->variant_op( the_cib, cib_action, host, obj_type_parent, NULL, output, call_options); } else { crm_err("You must specify an operation"); } return cib_operation; } enum cib_errors do_init(void) { enum cib_errors rc = cib_ok; the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [%s] command\n" "\twhere necessary, XML data will be expected using -X" " or on STDIN if -X isnt specified\n", cmd, OPTARGS); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); fprintf(stream, "\t\tValid values are: node, resource, node_state, constraint, nvpair\n"); fprintf(stream, "\t--%s (-%c)\tturn on debug info." " additional instance increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); fprintf(stream, "\t\t\tDelete the first object matching the supplied criteria\n"); fprintf(stream, "\t\t\tEg. \n"); fprintf(stream, "\t\t\tThe tagname and all attributes must match in order for the element to be deleted\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE_ALT, 'd'); fprintf(stream, "\t\t\tDelete the object at specified fully qualified location\n"); fprintf(stream, "\t\t\tEg. ...\n"); fprintf(stream, "\t\t\tRequires -o\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \t\n", F_CRM_DATA, 'X'); fprintf(stream, "\nAdvanced Options\n"); fprintf(stream, "\t--%s (-%c)\tsend command to specified host." " Applies to %s and %s commands only\n", "host", 'h', CIB_OP_QUERY, CIB_OP_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" " it altered the CIB\n", "no-bcast", 'b'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); fflush(stream); exit(exit_status); } gboolean admin_message_timeout(gpointer data) { if(safe_str_eq(cib_action, CIB_OP_SLAVE)) { exit_code = cib_ok; fprintf(stdout, "CIB service(s) are in slave mode.\n"); } else { exit_code = cib_reply_failed; fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); } g_main_quit(mainloop); return FALSE; } void cib_connection_destroy(gpointer user_data) { crm_err("Connection to the CIB terminated... exiting"); g_main_quit(mainloop); return; } void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { char *admin_input_xml = NULL; crm_info("our callback was invoked"); crm_log_message(LOG_MSG, msg); exit_code = rc; if(output != NULL) { admin_input_xml = dump_xml_formatted(output); } if(safe_str_eq(cib_action, CIB_OP_ISMASTER) && rc != cib_ok) { crm_info("CIB on %s is _not_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s is _not_ the master instance", host?host:"localhost"); } else if(safe_str_eq(cib_action, CIB_OP_ISMASTER)) { crm_info("CIB on %s _is_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s _is_ the master instance", host?host:"localhost"); } else if(rc != 0) { crm_warn("Call %s failed (%d): %s", cib_action, rc, cib_error2string(rc)); fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, cib_error2string(rc)); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } else if(safe_str_eq(cib_action, CIB_OP_QUERY) && output==NULL) { crm_err("Output expected in query response"); crm_log_message(LOG_ERR, msg); } else if(output == NULL) { crm_info("Call passed"); } else { crm_info("Call passed"); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } crm_free(admin_input_xml); if(call_id == request_id) { g_main_quit(mainloop); } else { crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id); } } diff --git a/crm/admin/crm_mon.c b/crm/admin/crm_mon.c index 3bb470386b..3ca2def47f 100644 --- a/crm/admin/crm_mon.c +++ b/crm/admin/crm_mon.c @@ -1,308 +1,308 @@ -/* $Id: crm_mon.c,v 1.1 2005/06/29 11:02:58 andrew Exp $ */ +/* $Id: crm_mon.c,v 1.2 2005/06/30 14:08:14 andrew 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 #ifdef HAVE_GETOPT_H # include #endif #include /* GMainLoop *mainloop = NULL; */ const char *crm_system_name = "crm_mon"; #define OPTARGS "V?i:nr" -#if HAVE_LIBNCURSES +#if CURSES_ENABLED void usage(const char *cmd, int exit_status); void blank_screen(void); int print_status(crm_data_t *cib); #define printw_at(line, fmt...) move(line, 0); printw(fmt); line++ void wait_for_refresh(int offset, const char *prefix, int seconds); gboolean group_by_node = FALSE; gboolean inactive_resources = FALSE; int main(int argc, char **argv) { int interval = 15; int failed_connections = 0; int options = cib_scope_local|cib_sync_call; crm_data_t *xml_frag = NULL; cib_t *cib_conn = NULL; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"interval", 1, 0, 'i'}, {"group-by-node", 0, 0, 'n'}, {"inactive", 0, 0, 'r'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); crm_log_level = 0; while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 'i': interval = atoi(optarg); break; case 'n': group_by_node = TRUE; break; case 'r': inactive_resources = TRUE; break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } initscr(); cbreak(); noecho(); while(1) { int offset = 0; const char *prefix = NULL; int rc = cib_ok; if(cib_conn == NULL || cib_conn->state != cib_connected_query){ crm_free(cib_conn); crm_debug_4("Creating CIB connection"); cib_conn = cib_new(); if(cib_conn != NULL) { crm_debug_4("Connecting to the CIB"); if(cib_ok == cib_conn->cmds->signon( cib_conn, crm_system_name, cib_query)) { failed_connections = 0; } } } blank_screen(); if(cib_conn == NULL || cib_conn->state != cib_connected_query){ failed_connections++; refresh(); wait_for_refresh(0, "Not connected: ", 2*interval); continue; } rc = cib_conn->cmds->query(cib_conn, NULL, &xml_frag, options); /* add_cib_op_callback(rc, FALSE, crm_strdup(max_generation_from), */ /* finalize_sync_callback); */ if(rc == cib_ok) { crm_data_t *cib = NULL; cib = find_xml_node(xml_frag,XML_TAG_CIB,TRUE); offset = print_status(cib); free_xml(xml_frag); cib_conn->cmds->signoff(cib_conn); } else { crm_err("Query failed: %s", cib_error2string(rc)); prefix = "Query failed! "; } wait_for_refresh(0, prefix, interval); } echo(); nocbreak(); endwin(); return 0; } void wait_for_refresh(int offset, const char *prefix, int seconds) { int lpc = seconds; while(lpc > 0) { move(offset, 0); /* printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */ printw("%sRefresh in %ds...", prefix?prefix:"", lpc); clrtoeol(); refresh(); lpc--; sleep(1); } move(offset, 0); printw("Updating..."); clrtoeol(); refresh(); } int print_status(crm_data_t *cib) { static int updates = 0; int lpc = 0; pe_working_set_t data_set; node_t *dc = NULL; updates++; set_working_set_defaults(&data_set); data_set.input = cib; stage0(&data_set); dc = data_set.dc_node; lpc++; printw_at(lpc, "============"); if(dc == NULL) { printw_at(lpc, "Current DC: NONE"); } else { printw_at(lpc, "Current DC: %s (%s)", dc->details->uname, dc->details->id); } printw_at(lpc, "%d Nodes configured.", g_list_length(data_set.nodes)); printw_at(lpc, "%d Resources configured.", g_list_length(data_set.resources)); printw_at(lpc, "============"); lpc++; slist_iter(node, node_t, data_set.nodes, lpc2, printw_at(lpc, "Node: %s (%s): %s", node->details->uname, node->details->id, node->details->online?"online":"OFFLINE"); if(group_by_node) { slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, common_printw(rsc, "\t", &lpc); /* rsc->fns->printw(rsc, "\t", &lpc); */ lpc++; ); } ); lpc++; if(group_by_node && inactive_resources) { printw_at(lpc, "Full list of resources:"); } if(group_by_node == FALSE || inactive_resources) { slist_iter(rsc, resource_t, data_set.resources, lpc2, rsc->fns->printw(rsc, NULL, &lpc); lpc++; ); } move(lpc, 0); refresh(); cleanup_calculations(&data_set); return lpc; } void blank_screen(void) { int lpc = 0; for(lpc = 0; lpc < LINES; lpc++) { move(lpc, 0); clrtoeol(); } move(0, 0); } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fflush(stream); exit(exit_status); } #else int main(int argc, char **argv) { fprintf(stderr, "The use of %s requires ncurses to be available" " during the build process\n", crm_system_name); exit(1); } #endif diff --git a/crm/pengine/complex.c b/crm/pengine/complex.c index cc41f24f3c..7b5fabd423 100644 --- a/crm/pengine/complex.c +++ b/crm/pengine/complex.c @@ -1,483 +1,483 @@ -/* $Id: complex.c,v 1.42 2005/06/30 13:18:48 andrew Exp $ */ +/* $Id: complex.c,v 1.43 2005/06/30 14:08:14 andrew 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 gboolean update_node_weight(rsc_to_node_t *cons,const char *id,GListPtr nodes); gboolean is_active(rsc_to_node_t *cons); gboolean constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); void order_actions(action_t *lh, action_t *rh, order_constraint_t *order); gboolean has_agent(node_t *a_node, lrm_agent_t *an_agent); extern gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); extern rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, double weight, node_t *node, pe_working_set_t *data_set); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_child, native_num_allowed_nodes, native_color, native_create_actions, native_internal_constraints, native_agent_constraints, native_rsc_colocation_lh, native_rsc_colocation_rh, native_rsc_order_lh, native_rsc_order_rh, native_rsc_location, native_expand, native_dump, native_printw, native_free }, { group_unpack, group_find_child, group_num_allowed_nodes, group_color, group_create_actions, group_internal_constraints, group_agent_constraints, group_rsc_colocation_lh, group_rsc_colocation_rh, group_rsc_order_lh, group_rsc_order_rh, group_rsc_location, group_expand, group_dump, group_printw, group_free }, { incarnation_unpack, incarnation_find_child, incarnation_num_allowed_nodes, incarnation_color, incarnation_create_actions, incarnation_internal_constraints, incarnation_agent_constraints, incarnation_rsc_colocation_lh, incarnation_rsc_colocation_rh, incarnation_rsc_order_lh, incarnation_rsc_order_rh, incarnation_rsc_location, incarnation_expand, incarnation_dump, incarnation_printw, incarnation_free } }; /* resource_object_functions_t resource_variants[] = resource_class_functions; */ int get_resource_type(const char *name) { if(safe_str_eq(name, "resource")) { return pe_native; } else if(safe_str_eq(name, "resource_group")) { return pe_group; } else if(safe_str_eq(name, XML_RSC_ATTR_INCARNATION)) { return pe_incarnation; } return pe_unknown; } gboolean is_active(rsc_to_node_t *cons) { /* todo: check constraint lifetime */ return TRUE; } void inherit_parent_attributes( crm_data_t *parent, crm_data_t *child, gboolean overwrite) { int lpc = 0; const char *attributes[] = { XML_RSC_ATTR_STOPFAIL, XML_RSC_ATTR_RESTART, "multiple_active", "start_prereq", "resource_stickiness", "is_managed" }; for(lpc = 0; lpc < DIMOF(attributes); lpc++) { const char *attr_p = crm_element_value(parent, attributes[lpc]); const char *attr_c = crm_element_value(child, attributes[lpc]); if(attr_c != NULL && safe_str_neq(attr_p, attr_c)) { if(overwrite == FALSE) { crm_debug_2("Resource %s: ignoring parent value for %s", ID(child), attributes[lpc]); continue; } pe_warn("Resource %s: Overwriting attribute %s: %s->%s", ID(child), attributes[lpc], attr_c, attr_p); } if(attr_p != NULL) { crm_xml_add(child, attributes[lpc], attr_p); } } } gboolean common_unpack( crm_data_t * xml_obj, resource_t **rsc, pe_working_set_t *data_set) { const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *restart = crm_element_value(xml_obj, XML_RSC_ATTR_RESTART); const char *multiple = crm_element_value(xml_obj, "multiple_active"); const char *placement= crm_element_value(xml_obj, "resource_stickiness"); const char *priority = NULL; const char *is_managed = NULL; crm_log_xml_debug_2(xml_obj, "Processing resource input..."); if(id == NULL) { pe_err("Must specify id tag in "); return FALSE; } else if(rsc == NULL) { pe_err("Nowhere to unpack resource into"); return FALSE; } crm_malloc0(*rsc, sizeof(resource_t)); if(*rsc == NULL) { return FALSE; } (*rsc)->id = id; (*rsc)->xml = xml_obj; (*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE); (*rsc)->variant = get_resource_type(crm_element_name(xml_obj)); if((*rsc)->variant == pe_unknown) { pe_err("Unknown resource type: %s", crm_element_name(xml_obj)); crm_free(*rsc); return FALSE; } (*rsc)->fns = &resource_class_functions[(*rsc)->variant]; crm_debug_3("Unpacking resource..."); (*rsc)->parameters = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); unpack_instance_attributes(xml_obj, (*rsc)->parameters); priority = get_rsc_param(*rsc, XML_CIB_ATTR_PRIORITY); (*rsc)->priority = atoi(priority?priority:"0"); (*rsc)->effective_priority = (*rsc)->priority; (*rsc)->recovery_type = recovery_stop_start; (*rsc)->runnable = TRUE; (*rsc)->provisional = TRUE; (*rsc)->start_pending = FALSE; (*rsc)->starting = FALSE; (*rsc)->stopping = FALSE; (*rsc)->candidate_colors = NULL; (*rsc)->rsc_cons = NULL; (*rsc)->actions = NULL; (*rsc)->is_managed = TRUE; (*rsc)->stickiness = data_set->default_resource_stickiness; is_managed = crm_element_value((*rsc)->xml, "is_managed"); if(is_managed != NULL && crm_is_true(is_managed) == FALSE) { (*rsc)->is_managed = FALSE; crm_warn("Resource %s is currently not managed", (*rsc)->id); #if 0 rsc_to_node_t *new_con = NULL; /* prevent this resource from running anywhere */ new_con = rsc2node_new( "is_managed_default", *rsc, -INFINITY, NULL, data_set); new_con->node_list_rh = node_list_dup(data_set->nodes, FALSE); #endif } else if((*rsc)->is_managed && data_set->symmetric_cluster) { rsc_to_node_t *new_con = rsc2node_new( "symmetric_default", *rsc, 0, NULL, data_set); new_con->node_list_rh = node_list_dup(data_set->nodes, FALSE); } crm_debug_2("Options for %s", id); if(safe_str_eq(restart, "restart")) { (*rsc)->restart_type = pe_restart_restart; crm_debug_2("\tDependancy restart handling: restart"); } else { (*rsc)->restart_type = pe_restart_ignore; crm_debug_2("\tDependancy restart handling: ignore"); } if(safe_str_eq(multiple, "stop_only")) { (*rsc)->recovery_type = recovery_stop_only; crm_debug_2("\tMultiple running resource recovery: stop only"); } else if(safe_str_eq(multiple, "block")) { (*rsc)->recovery_type = recovery_block; crm_debug_2("\tMultiple running resource recovery: block"); } else { (*rsc)->recovery_type = recovery_stop_start; crm_debug_2("\tMultiple running resource recovery: stop/start"); } if(placement != NULL) { if(safe_str_eq(placement, "INFINITY")) { (*rsc)->stickiness = INFINITY; } else if(safe_str_eq(placement, "-INFINITY")) { (*rsc)->stickiness = -INFINITY; } else { (*rsc)->stickiness = atoi(placement); } } if((*rsc)->stickiness > 0) { crm_debug_2("\tPlacement: prefer current location%s", placement == NULL?" (default)":""); } else if((*rsc)->stickiness < 0) { crm_warn("\tPlacement: always move from the current location%s", placement == NULL?" (default)":""); } else { crm_debug_2("\tPlacement: optimal%s", placement == NULL?" (default)":""); } (*rsc)->fns->unpack(*rsc, data_set); return TRUE; } void order_actions(action_t *lh_action, action_t *rh_action, order_constraint_t *order) { action_wrapper_t *wrapper = NULL; GListPtr list = NULL; crm_debug_2("Ordering %d: Action %d before %d", order?order->id:-1, lh_action->id, rh_action->id); log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE); log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE); crm_malloc0(wrapper, sizeof(action_wrapper_t)); if(wrapper != NULL) { wrapper->action = rh_action; wrapper->type = order->type; list = lh_action->actions_after; list = g_list_append(list, wrapper); lh_action->actions_after = list; wrapper = NULL; } if(order->type != pe_ordering_recover) { crm_malloc0(wrapper, sizeof(action_wrapper_t)); if(wrapper != NULL) { wrapper->action = lh_action; wrapper->type = order->type; list = rh_action->actions_before; list = g_list_append(list, wrapper); rh_action->actions_before = list; } } } void common_printw(resource_t *rsc, const char *pre_text, int *index) { -#ifdef CURSES_ENABLED +#if CURSES_ENABLED const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); move(*index, 0); printw("%s%s %s (%s%s%s:%s):\t", pre_text?pre_text:"", crm_element_name(rsc->xml), rsc->id, prov?prov:"", prov?"::":"", crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), crm_element_value(rsc->xml, XML_ATTR_TYPE)); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void common_dump(resource_t *rsc, const char *pre_text, gboolean details) { crm_debug_4("%s%s%s%sResource %s: (variant=%s, priority=%f)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", rsc->provisional?"Provisional ":"", rsc->runnable?"":"(Non-Startable) ", rsc->id, crm_element_name(rsc->xml), (double)rsc->priority); } void common_free(resource_t *rsc) { if(rsc == NULL) { return; } crm_debug_5("Freeing %s", rsc->id); while(rsc->rsc_cons) { pe_free_rsc_colocation( (rsc_colocation_t*)rsc->rsc_cons->data); rsc->rsc_cons = rsc->rsc_cons->next; } if(rsc->rsc_cons != NULL) { g_list_free(rsc->rsc_cons); } if(rsc->parameters != NULL) { g_hash_table_destroy(rsc->parameters); } pe_free_shallow_adv(rsc->candidate_colors, TRUE); crm_free(rsc->variant_opaque); crm_free(rsc); crm_debug_5("Resource freed"); } void common_agent_constraints( GListPtr node_list, lrm_agent_t *agent, const char *id) { #if 0 slist_iter( node, node_t, node_list, lpc, crm_debug_5("Checking if %s supports %s/%s (%s)", node->details->uname, agent->class, agent->type, agent->version); if(has_agent(node, agent) == FALSE) { /* remove node from contention */ crm_debug_5("Marking node %s unavailable for %s", node->details->uname, id); node->weight = -1.0; node->fixed = TRUE; } ); #endif } void unpack_instance_attributes(crm_data_t *xml_obj, GHashTable *hash) { const char *name = NULL; const char *value = NULL; if(xml_obj == NULL) { crm_debug_4("No instance attributes"); return; } xml_child_iter( xml_obj, attr_set, XML_TAG_ATTR_SETS, xml_child_iter( attr_set, attrs, XML_TAG_ATTRS, /* todo: check any rules */ xml_child_iter( attrs, an_attr, XML_CIB_TAG_NVPAIR, name = crm_element_value( an_attr, XML_NVPAIR_ATTR_NAME); value = crm_element_value( an_attr, XML_NVPAIR_ATTR_VALUE); add_hash_param(hash, name, value); ); ); ); } void add_rsc_param(resource_t *rsc, const char *name, const char *value) { CRM_DEV_ASSERT(rsc != NULL); if(crm_assert_failed) { return; } add_hash_param(rsc->parameters, name, value); } void add_hash_param(GHashTable *hash, const char *name, const char *value) { CRM_DEV_ASSERT(hash != NULL); if(crm_assert_failed) { return; } crm_debug_3("adding: name=%s value=%s", crm_str(name), crm_str(value)); if(name == NULL || value == NULL) { return; } else if(g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value)); } } const char * get_rsc_param(resource_t *rsc, const char *name) { CRM_DEV_ASSERT(rsc != NULL); if(crm_assert_failed) { return NULL; } return g_hash_table_lookup(rsc->parameters, name); } void hash2nvpair(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; crm_data_t *xml_node = user_data; crm_data_t *xml_child = create_xml_node(xml_node, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_child, XML_NVPAIR_ATTR_NAME, name); crm_xml_add(xml_child, XML_NVPAIR_ATTR_VALUE, s_value); crm_debug_3("dumped: name=%s value=%s", name, s_value); } diff --git a/crm/pengine/group.c b/crm/pengine/group.c index ac48e22e9a..b8eb6916d3 100644 --- a/crm/pengine/group.c +++ b/crm/pengine/group.c @@ -1,467 +1,467 @@ -/* $Id: group.c,v 1.27 2005/06/30 13:18:48 andrew Exp $ */ +/* $Id: group.c,v 1.28 2005/06/30 14:08:14 andrew 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); typedef struct group_variant_data_s { int num_children; GListPtr child_list; /* resource_t* */ resource_t *self; resource_t *first_child; resource_t *last_child; gboolean child_starting; gboolean child_stopping; } group_variant_data_t; #define get_group_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_group); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (group_variant_data_t *)rsc->variant_opaque; \ void group_unpack(resource_t *rsc, pe_working_set_t *data_set) { crm_data_t * xml_obj = rsc->xml; crm_data_t * xml_self = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); group_variant_data_t *group_data = NULL; resource_t *self = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(group_data, sizeof(group_variant_data_t)); group_data->num_children = 0; group_data->self = NULL; group_data->child_list = NULL; group_data->first_child = NULL; group_data->last_child = NULL; /* this is a bit of a hack - but simplifies everything else */ copy_in_properties(xml_self, xml_obj); if(common_unpack(xml_self, &self, data_set)) { group_data->self = self; self->restart_type = pe_restart_restart; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } xml_child_iter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; set_id(xml_native_rsc, rsc->id, -1); inherit_parent_attributes(xml_self, xml_native_rsc, TRUE); if(common_unpack(xml_native_rsc, &new_rsc, data_set)) { group_data->num_children++; group_data->child_list = g_list_append( group_data->child_list, new_rsc); group_data->last_child = new_rsc; if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } rsc_colocation_new("pe_group_internal_colo", pecs_must, group_data->self, new_rsc); crm_action_debug_3( print_resource("Added", new_rsc, FALSE)); } else { pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); } ); crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id); rsc->variant_opaque = group_data; } resource_t * group_find_child(resource_t *rsc, const char *id) { group_variant_data_t *group_data = NULL; if(rsc->variant == pe_group) { group_data = (group_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"group\" variant", rsc->id); return NULL; } return pe_find_resource(group_data->child_list, id); } int group_num_allowed_nodes(resource_t *rsc) { group_variant_data_t *group_data = NULL; if(rsc->variant == pe_native) { group_data = (group_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"native\" variant", rsc->id); return 0; } if(group_data->self == NULL) { return 0; } return group_data->self->fns->num_allowed_nodes(group_data->self); } void group_color(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } group_data->self->fns->color(group_data->self, data_set); } void group_update_pseudo_status(resource_t *parent, resource_t *child); void group_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *op = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); group_update_pseudo_status(rsc, child_rsc); ); op = start_action(group_data->self, NULL, !group_data->child_starting); op->pseudo = TRUE; op = custom_action(group_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !group_data->child_starting, data_set); op->pseudo = TRUE; op = stop_action(group_data->self, NULL, !group_data->child_stopping); op->pseudo = TRUE; op = custom_action(group_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !group_data->child_stopping, data_set); op->pseudo = TRUE; } void group_update_pseudo_status(resource_t *parent, resource_t *child) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, parent); if(group_data->child_stopping && group_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { group_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { group_data->child_starting = TRUE; } ); } void group_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); custom_action_order( group_data->self, stopped_key(group_data->self), NULL, group_data->self, start_key(group_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, order_restart(child_rsc); if(last_rsc != NULL) { order_start_start( last_rsc, child_rsc, pe_ordering_optional); order_stop_stop( child_rsc, last_rsc, pe_ordering_optional); } else { custom_action_order( child_rsc, stop_key(child_rsc), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); order_start_start(group_data->self, child_rsc, pe_ordering_optional); } last_rsc = child_rsc; ); if(last_rsc != NULL) { custom_action_order( last_rsc, start_key(last_rsc), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); order_stop_stop( group_data->self, last_rsc, pe_ordering_optional); } } void group_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; group_variant_data_t *group_data = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_colocation_rh(group_data->self, constraint); } void group_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { resource_t *rsc_lh = rsc; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing RH of constraint %s", constraint->id); crm_action_debug_3(print_resource("LHS", rsc_lh, TRUE)); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_colocation_rh(group_data->self, constraint); } void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); group_data->self->fns->rsc_order_lh(group_data->self, order); } void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } group_data->self->fns->rsc_order_rh(lh_action, group_data->self, order); } void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); if(group_data->self != NULL) { group_data->self->fns->rsc_location(group_data->self, constraint); } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } void group_expand(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); group_data->self->fns->expand(group_data->self, data_set); if(group_data->self == NULL) { return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->expand(child_rsc, data_set); ); } void group_printw(resource_t *rsc, const char *pre_text, int *index) { -#ifdef CURSES_ENABLED +#if CURSES_ENABLED const char *child_text = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } move(*index, 0); printw("Resource Group: %s\n", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, (*index)++; group_data->self->fns->printw(child_rsc, child_text, index); ); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void group_dump(resource_t *rsc, const char *pre_text, gboolean details) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->self == NULL) { return; } common_dump(rsc, pre_text, details); group_data->self->fns->dump(group_data->self, pre_text, details); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->dump(child_rsc, pre_text, details); ); } void group_free(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(group_data->child_list, FALSE); free_xml(group_data->self->xml); if(group_data->self != NULL) { group_data->self->fns->free(group_data->self); } common_free(rsc); } void group_agent_constraints(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } diff --git a/crm/pengine/incarnation.c b/crm/pengine/incarnation.c index 4188ef94f4..fc436066ed 100644 --- a/crm/pengine/incarnation.c +++ b/crm/pengine/incarnation.c @@ -1,739 +1,739 @@ -/* $Id: incarnation.c,v 1.33 2005/06/30 13:18:48 andrew Exp $ */ +/* $Id: incarnation.c,v 1.34 2005/06/30 14:08:14 andrew 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); typedef struct incarnation_variant_data_s { resource_t *self; int incarnation_max; int incarnation_max_node; int active_incarnation; gboolean interleave; gboolean ordered; GListPtr child_list; /* resource_t* */ gboolean child_starting; gboolean child_stopping; } incarnation_variant_data_t; void child_stopping_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_incarnation_variant_data(data, rsc) \ if(rsc->variant == pe_incarnation) { \ data = (incarnation_variant_data_t *)rsc->variant_opaque; \ } else { \ pe_err("Resource %s was not an \"incarnation\" variant", \ rsc->id); \ return; \ } void incarnation_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; crm_data_t * xml_obj_child = NULL; crm_data_t * xml_obj = rsc->xml; crm_data_t * xml_self = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); incarnation_variant_data_t *incarnation_data = NULL; resource_t *self = NULL; char *inc_max = NULL; const char *ordered = crm_element_value(xml_obj, XML_RSC_ATTR_ORDERED); const char *interleave = crm_element_value(xml_obj, XML_RSC_ATTR_INTERLEAVE); const char *max_incarn = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_MAX); const char *max_incarn_node = get_rsc_param(rsc, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(incarnation_data, sizeof(incarnation_variant_data_t)); incarnation_data->child_list = NULL; incarnation_data->interleave = FALSE; incarnation_data->ordered = FALSE; incarnation_data->active_incarnation = 0; incarnation_data->incarnation_max = crm_atoi(max_incarn, "1"); incarnation_data->incarnation_max_node = crm_atoi(max_incarn_node,"1"); /* this is a bit of a hack - but simplifies everything else */ copy_in_properties(xml_self, xml_obj); xml_obj_child = find_xml_node(xml_obj, "resource_group", FALSE); if(xml_obj_child == NULL) { xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } CRM_DEV_ASSERT(xml_obj_child != NULL); if(crm_assert_failed) { return; } xml_obj_child = copy_xml(xml_obj_child); if(common_unpack(xml_self, &self, data_set)) { incarnation_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } if(crm_is_true(interleave)) { incarnation_data->interleave = TRUE; } if(crm_is_true(ordered)) { incarnation_data->ordered = TRUE; } inherit_parent_attributes(xml_self, xml_obj_child, FALSE); inc_max = crm_itoa(incarnation_data->incarnation_max); for(lpc = 0; lpc < incarnation_data->incarnation_max; lpc++) { resource_t *child_rsc = NULL; crm_data_t * child_copy = copy_xml(xml_obj_child); set_id(child_copy, rsc->id, lpc); if(common_unpack(child_copy, &child_rsc, data_set)) { char *inc_num = crm_itoa(lpc); incarnation_data->child_list = g_list_append( incarnation_data->child_list, child_rsc); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION, inc_num); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION_MAX, inc_max); crm_action_debug_3( print_resource("Added", child_rsc, FALSE)); crm_free(inc_num); } else { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); } } crm_free(inc_max); free_xml(xml_obj_child); crm_debug_3("Added %d children to resource %s...", incarnation_data->incarnation_max, rsc->id); rsc->variant_opaque = incarnation_data; } resource_t * incarnation_find_child(resource_t *rsc, const char *id) { incarnation_variant_data_t *incarnation_data = NULL; if(rsc->variant == pe_incarnation) { incarnation_data = (incarnation_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"incarnation\" variant", rsc->id); return NULL; } return pe_find_resource(incarnation_data->child_list, id); } int incarnation_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; incarnation_variant_data_t *incarnation_data = NULL; if(rsc->variant == pe_incarnation) { incarnation_data = (incarnation_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not an \"incarnation\" variant", rsc->id); return 0; } /* what *should* we return here? */ slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, int tmp_num_nodes = child_rsc->fns->num_allowed_nodes(child_rsc); if(tmp_num_nodes > num_nodes) { num_nodes = tmp_num_nodes; } ); return num_nodes; } void incarnation_color(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0, lpc2 = 0, max_nodes = 0; resource_t *child_0 = NULL; resource_t *child_lh = NULL; resource_t *child_rh = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); if(incarnation_data->self->is_managed == FALSE) { return; } child_0 = g_list_nth_data(incarnation_data->child_list, 0); max_nodes = rsc->fns->num_allowed_nodes(rsc); /* generate up to max_nodes * incarnation_node_max constraints */ lpc = 0; crm_info("Distributing %d incarnations over %d nodes", incarnation_data->incarnation_max, max_nodes); for(; lpc < max_nodes && lpc < incarnation_data->incarnation_max; lpc++) { child_lh = child_0; incarnation_data->active_incarnation++; if(lpc != 0) { child_rh = g_list_nth_data(incarnation_data->child_list, lpc); crm_debug_4("Incarnation %d will run on a differnt node to 0", lpc); rsc_colocation_new("pe_incarnation_internal_must_not", pecs_must_not, child_lh, child_rh); } else { child_rh = child_0; } child_lh = child_rh; for(lpc2 = 1; lpc2 < incarnation_data->incarnation_max_node; lpc2++) { int offset = lpc + (lpc2 * max_nodes); if(offset >= incarnation_data->incarnation_max) { break; } crm_debug_4("Incarnation %d will run on the same node as %d", offset, lpc); incarnation_data->active_incarnation++; child_rh = g_list_nth_data( incarnation_data->child_list, offset); rsc_colocation_new("pe_incarnation_internal_must", pecs_must, child_lh, child_rh); } } slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, if(lpc < incarnation_data->active_incarnation) { crm_debug_4("Coloring Incarnation %d", lpc); child_rsc->fns->color(child_rsc, data_set); } else { /* TODO: assign "no color"? Doesnt seem to need it */ pe_warn("Incarnation %d cannot be started", lpc+1); /* native_assign_color(child_rsc, data_set->no_color); */ } ); crm_info("%d Incarnations are active", incarnation_data->active_incarnation); } void incarnation_update_pseudo_status(resource_t *parent, resource_t *child); void incarnation_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *op = NULL; resource_t *last_start_rsc = NULL; resource_t *last_stop_rsc = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); incarnation_update_pseudo_status(rsc, child_rsc); if(child_rsc->starting) { last_start_rsc = child_rsc; } if(child_rsc->stopping) { last_stop_rsc = child_rsc; } ); op = start_action(incarnation_data->self, NULL, !incarnation_data->child_starting); op->pseudo = TRUE; op = custom_action(incarnation_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !incarnation_data->child_starting, data_set); op->pseudo = TRUE; child_starting_constraints( incarnation_data, pe_ordering_optional, NULL, last_start_rsc, data_set); op = stop_action(incarnation_data->self, NULL, !incarnation_data->child_stopping); op->pseudo = TRUE; op = custom_action(incarnation_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !incarnation_data->child_stopping, data_set); op->pseudo = TRUE; child_stopping_constraints( incarnation_data, pe_ordering_optional, NULL, last_stop_rsc, data_set); } void incarnation_update_pseudo_status(resource_t *parent, resource_t *child) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, parent); if(incarnation_data->child_stopping && incarnation_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { incarnation_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { incarnation_data->child_starting = TRUE; } ); } void child_starting_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(incarnation_data->ordered || incarnation_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child start before global started */ custom_action_order( last, start_key(last), NULL, incarnation_data->self, started_key(incarnation_data->self), NULL, type, data_set); } } else if(incarnation_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global start before first child start */ last = incarnation_data->self; } /* else: child/child relative start */ order_start_start(last, child, type); } else { crm_debug_4("Un-ordered version"); /* child start before global started */ custom_action_order( child, start_key(child), NULL, incarnation_data->self, started_key(incarnation_data->self), NULL, type, data_set); /* global start before child start */ /* order_start_start(incarnation_data->self, child, type); */ order_start_start( incarnation_data->self, child, pe_ordering_manditory); } } void child_stopping_constraints( incarnation_variant_data_t *incarnation_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(incarnation_data->ordered || incarnation_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global stop before first child stop */ order_stop_stop(incarnation_data->self, last, pe_ordering_manditory); } } else if(incarnation_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative stop */ order_stop_stop(child, last, type); } else if(incarnation_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, incarnation_data->self, stopped_key(incarnation_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, incarnation_data->self, stopped_key(incarnation_data->self), NULL, type, data_set); /* global stop before child stop */ order_stop_stop(incarnation_data->self, child, type); } } void incarnation_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); /* global stopped before start */ custom_action_order( incarnation_data->self, stopped_key(incarnation_data->self), NULL, incarnation_data->self, start_key(incarnation_data->self), NULL, pe_ordering_manditory, data_set); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, /* child stop before start */ order_restart(child_rsc); child_starting_constraints( incarnation_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_stopping_constraints( incarnation_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } void incarnation_rsc_colocation_lh(rsc_colocation_t *constraint) { gboolean do_interleave = FALSE; resource_t *rsc = constraint->rsc_lh; incarnation_variant_data_t *incarnation_data = NULL; incarnation_variant_data_t *incarnation_data_rh = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_incarnation_variant_data(incarnation_data, rsc); if(constraint->rsc_rh->variant == pe_incarnation) { get_incarnation_variant_data( incarnation_data_rh, constraint->rsc_rh); if(incarnation_data->incarnation_max_node != incarnation_data_rh->incarnation_max_node) { pe_err("Cannot interleave incarnation %s and %s because" " they do not support the same number of" " resources per node", constraint->rsc_lh->id, constraint->rsc_rh->id); /* only the LHS side needs to be labeled as interleave */ } else if(incarnation_data->interleave) { do_interleave = TRUE; } } if(do_interleave) { resource_t *child_lh = NULL; resource_t *child_rh = NULL; resource_t *parent_rh = constraint->rsc_rh; GListPtr iter_lh = incarnation_data->child_list; GListPtr iter_rh = incarnation_data_rh->child_list; crm_debug_2("Interleaving %s with %s", constraint->rsc_lh->id, constraint->rsc_rh->id); /* If the resource have different numbers of incarnations, * then just do as many as are available */ while(iter_lh != NULL && iter_rh != NULL) { child_lh = iter_lh->data; child_rh = iter_rh->data; iter_lh = iter_lh->next; iter_rh = iter_rh->next; constraint->rsc_rh = child_rh; crm_debug_3("Colocating %s with %s", child_lh->id, child_rh->id); child_rh->fns->rsc_colocation_rh(child_lh, constraint); } /* restore the original RHS of the constraint */ constraint->rsc_rh = parent_rh; return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_colocations other than \"-INFINITY\"" " are not supported for non-interleaved" " incarnation resources"); return; } slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_action_debug_3(print_resource("LHS", child_rsc, TRUE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void incarnation_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { incarnation_variant_data_t *incarnation_data = NULL; crm_debug_3("Processing RH of constraint %s", constraint->id); if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_dependencies other than \"must_not\" " "are not supported for incarnation resources"); return; } else { crm_action_debug_3(print_resource("LHS", rsc, FALSE)); } get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_action_debug_3(print_resource("RHS", child_rsc, FALSE)); child_rsc->fns->rsc_colocation_rh(child_rsc, constraint); ); } void incarnation_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); incarnation_data->self->fns->rsc_order_lh(incarnation_data->self, order); } void incarnation_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); incarnation_data->self->fns->rsc_order_rh(lh_action, incarnation_data->self, order); } void incarnation_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); incarnation_data->self->fns->rsc_location(incarnation_data->self, constraint); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } void incarnation_expand(resource_t *rsc, pe_working_set_t *data_set) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); incarnation_data->self->fns->expand(incarnation_data->self, data_set); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->expand(child_rsc, data_set); ); } void incarnation_printw(resource_t *rsc, const char *pre_text, int *index) { -#ifdef CURSES_ENABLED +#if CURSES_ENABLED const char *child_text = NULL; incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } move(*index, 0); printw("Incarnation: %s\n", rsc->id); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, (*index)++; child_rsc->fns->printw(child_rsc, child_text, index); ); #else crm_err("printw support requires ncurses to be available during configure"); #endif } void incarnation_dump(resource_t *rsc, const char *pre_text, gboolean details) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); common_dump(rsc, pre_text, details); incarnation_data->self->fns->dump( incarnation_data->self, pre_text, details); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->dump(child_rsc, pre_text, details); ); } void incarnation_free(resource_t *rsc) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); free_xml(child_rsc->xml); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(incarnation_data->child_list, FALSE); free_xml(incarnation_data->self->xml); incarnation_data->self->fns->free(incarnation_data->self); common_free(rsc); } void incarnation_agent_constraints(resource_t *rsc) { incarnation_variant_data_t *incarnation_data = NULL; get_incarnation_variant_data(incarnation_data, rsc); slist_iter( child_rsc, resource_t, incarnation_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } diff --git a/crm/pengine/native.c b/crm/pengine/native.c index 92030a6330..15d36b7333 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,1283 +1,1283 @@ -/* $Id: native.c,v 1.56 2005/06/30 13:18:48 andrew Exp $ */ +/* $Id: native.c,v 1.57 2005/06/30 14:08:14 andrew 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 extern color_t *add_color(resource_t *rh_resource, color_t *color); gboolean native_choose_color(resource_t *lh_resource, color_t *no_color); void native_assign_color(resource_t *rsc, color_t *color); void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, const char *id, GListPtr nodes); void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void filter_nodes(resource_t *rsc); int num_allowed_nodes4color(color_t *color); void create_recurring_actions(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); action_t *create_recurring_action(resource_t *rsc, node_t *node, const char *action, const char *key); extern rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, double weight, node_t *node, pe_working_set_t *data_set); typedef struct native_variant_data_s { lrm_agent_t *agent; GListPtr running_on; /* node_t* */ color_t *color; GListPtr node_cons; /* rsc_to_node_t* */ GListPtr allowed_nodes; /* node_t* */ } native_variant_data_t; #define get_native_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_native); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (native_variant_data_t *)rsc->variant_opaque; void native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return; } slist_iter( a_node, node_t, native_data->running_on, lpc, CRM_DEV_ASSERT(a_node != NULL); if(safe_str_eq(a_node->details->id, node->details->id)) { return; } ); native_data->running_on = g_list_append(native_data->running_on, node); node->details->running_rsc = g_list_append( node->details->running_rsc, rsc); if(rsc->is_managed == FALSE) { rsc2node_new( "not_managed_default", rsc, INFINITY, node, data_set); return; } else if(rsc->stickiness > 0) { rsc2node_new("stickiness", rsc, INFINITY, node, data_set); } else if(rsc->stickiness < 0) { rsc2node_new("stickiness", rsc, -INFINITY, node, data_set); } if(g_list_length(native_data->running_on) > 1) { pe_warn("Resource %s is (potentially) active on %d nodes." " Latest: %s/%s", rsc->id, g_list_length(native_data->running_on), node->details->uname, node->details->id); } } void native_unpack(resource_t *rsc, pe_working_set_t *data_set) { crm_data_t * xml_obj = rsc->xml; native_variant_data_t *native_data = NULL; const char *version = crm_element_value(xml_obj, XML_ATTR_VERSION); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(native_data, sizeof(native_variant_data_t)); crm_malloc0(native_data->agent, sizeof(lrm_agent_t)); native_data->agent->class = crm_element_value(xml_obj, "class"); native_data->agent->type = crm_element_value(xml_obj, "type"); native_data->agent->version = version?version:"0.0"; native_data->color = NULL; native_data->allowed_nodes = NULL; native_data->node_cons = NULL; native_data->running_on = NULL; rsc->variant_opaque = native_data; } resource_t * native_find_child(resource_t *rsc, const char *id) { return NULL; } int native_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; native_variant_data_t *native_data = NULL; if(rsc->variant == pe_native) { native_data = (native_variant_data_t *)rsc->variant_opaque; } else { pe_err("Resource %s was not a \"native\" variant", rsc->id); return 0; } if(native_data->color) { crm_debug_4("Colored case"); num_nodes = num_allowed_nodes4color(native_data->color); } else if(rsc->candidate_colors) { /* TODO: sort colors first */ color_t *color = g_list_nth_data(rsc->candidate_colors, 0); crm_debug_4("Candidate colors case"); num_nodes = num_allowed_nodes4color(color); } else { crm_debug_4("Default case"); slist_iter( this_node, node_t, native_data->allowed_nodes, lpc, crm_debug_3("Rsc %s Checking %s: %f", rsc->id, this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); } crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes); return num_nodes; } int num_allowed_nodes4color(color_t *color) { int num_nodes = 0; if(color->details->pending == FALSE) { if(color->details->chosen_node) { return 1; } return 0; } slist_iter( this_node, node_t, color->details->candidate_nodes, lpc, crm_debug_3("Checking %s: %f", this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); return num_nodes; } void native_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *new_color = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if( native_choose_color(rsc, data_set->no_color) ) { crm_debug_3("Colored resource %s with color %d", rsc->id, native_data->color->id); } else { if(native_data->allowed_nodes != NULL) { /* filter out nodes with a negative weight */ filter_nodes(rsc); new_color = create_color(data_set, rsc, native_data->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { pe_warn("Resource %s cannot run anywhere", rsc->id); print_resource("ERROR: No color", rsc, FALSE); native_assign_color(rsc, data_set->no_color); } } rsc->provisional = FALSE; } void create_recurring_actions(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { action_t *mon = NULL; char *key = NULL; const char *name = NULL; const char *value = NULL; if(node == NULL || !node->details->online || node->details->unclean) { crm_debug_3("Not creating recurring actions"); return; } xml_child_iter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); value = crm_element_value(operation, "interval"); key = generate_op_key(rsc->id, name, crm_get_msec(value)); mon = custom_action(rsc, key, name, node, start->optional, data_set); if(mon->optional == FALSE && node != NULL) { crm_info(" %s:\t(%s)", mon->uuid, node->details->uname); } custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_ordering_manditory, data_set); ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; action_t *stop = NULL; node_t *chosen = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(native_data->color != NULL) { chosen = native_data->color->details->chosen_node; } if(chosen != NULL && g_list_length(native_data->running_on) == 0) { start = start_action(rsc, chosen, TRUE); if(start->runnable && data_set->have_quorum == FALSE && data_set->no_quorum_policy != no_quorum_ignore) { crm_warn("Start resource %s\t(%s) (cancelled : quorum)", rsc->id, chosen->details->uname); start->runnable = FALSE; } else { crm_info("Start resource %s\t(%s)", rsc->id, chosen->details->uname); start->optional = FALSE; start->rsc->start_pending = TRUE; } } else if(g_list_length(native_data->running_on) > 1) { pe_err("Attempting recovery of resource %s", rsc->id); if(rsc->recovery_type == recovery_stop_start || rsc->recovery_type == recovery_stop_only) { slist_iter( node, node_t, native_data->running_on, lpc, crm_info("Stop resource %s\t(%s) (recovery)", rsc->id, node->details->uname); stop = stop_action(rsc, node, FALSE); ); } if(rsc->recovery_type == recovery_stop_start && chosen) { /* if one of the "stops" is for a node outside * our partition, then this will block anyway */ start = start_action(rsc, chosen, FALSE); if(start->runnable) { crm_info("Recover resource %s\t(%s)", rsc->id, chosen->details->uname); } /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); } if(rsc->recovery_type == recovery_block) { pe_warn("RESOURCE %s WILL REMAIN ACTIVE ON MULTIPLE" " NODES PENDING MANUAL INTERVENTION", rsc->id); slist_iter( node, node_t, native_data->running_on, lpc, pe_warn("Resource %s active on %s", rsc->id, node->details->uname); ); } } else if(g_list_length(native_data->running_on) == 1) { node_t *node = native_data->running_on->data; crm_debug_2("Stop%s of %s", chosen?" and restart":"", rsc->id); CRM_DEV_ASSERT(node != NULL); if(chosen == NULL) { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); stop_action(rsc, node, FALSE); } else if(safe_str_eq(node->details->id, chosen->details->id)) { stop = stop_action(rsc, node, TRUE); start = start_action(rsc, chosen, TRUE); if(start->runnable == FALSE) { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); stop->optional = FALSE; } else if(rsc->recover) { crm_info("Restart resource %s\t(%s)", rsc->id, node->details->uname); /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); start->optional = FALSE; stop->optional = FALSE; } else { crm_info("Leave resource %s\t(%s)", rsc->id, node->details->uname); if(stop->optional == FALSE) { start->optional = FALSE; } else if(rsc->start_pending) { start->optional = FALSE; } } } else { /* move */ stop = stop_action(rsc, node, FALSE); start = start_action(rsc, chosen, FALSE); if(start->runnable) { crm_info("Move resource %s\t(%s -> %s)", rsc->id, node->details->uname, chosen->details->uname); } else { crm_info("Stop resource %s\t(%s)", rsc->id, node->details->uname); } /* make the restart required */ order_stop_start(rsc, rsc, pe_ordering_manditory); } } if(start != NULL && start->runnable) { create_recurring_actions(rsc, start, chosen, data_set); } } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); order_restart(rsc); } void native_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } constraint->rsc_rh->fns->rsc_colocation_rh(rsc, constraint); } void native_rsc_colocation_rh(resource_t *rsc, rsc_colocation_t *constraint) { gboolean do_check = FALSE; gboolean update_lh = FALSE; gboolean update_rh = FALSE; resource_t *rsc_lh = rsc; resource_t *rsc_rh = constraint->rsc_rh; native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); crm_debug_2("%sColocating %s with %s", constraint->strength == pecs_must?"":"Anti-", rsc_lh->id, rsc_rh->id); if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_debug_4("Skipping constraint type %d", constraint->strength); return; } if(rsc_lh->provisional && rsc_rh->provisional) { if(constraint->strength == pecs_must) { /* update effective_priorities */ native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); } else { /* nothing */ crm_debug_4( "Skipping constraint, both sides provisional"); } return; } else if( (!rsc_lh->provisional) && (!rsc_rh->provisional) && (!native_data_lh->color->details->pending) && (!native_data_rh->color->details->pending) ) { /* error check */ do_check = TRUE; if(rsc_lh->effective_priority < rsc_rh->effective_priority) { update_lh = TRUE; } else if(rsc_lh->effective_priority > rsc_rh->effective_priority) { update_rh = TRUE; } else { update_lh = TRUE; update_rh = TRUE; } } else if(rsc_lh->provisional == FALSE && native_data_lh->color->details->pending == FALSE) { /* update _them_ : postproc color version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE && native_data_rh->color->details->pending == FALSE) { /* update _us_ : postproc color alt version */ update_lh = TRUE; } else if(rsc_lh->provisional == FALSE) { /* update _them_ : preproc version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE) { /* update _us_ : postproc version */ update_lh = TRUE; } else { pe_warn("Un-expected combination of inputs"); return; } if(update_lh) { crm_debug_4("Updating LHS"); } if(update_rh) { crm_debug_4("Updating RHS"); } if(do_check) { if(native_constraint_violated( rsc_lh, rsc_rh, constraint) == FALSE) { crm_debug_4("Constraint satisfied"); return; } /* else constraint cant be satisified */ pe_warn("Constraint %s could not be satisfied", constraint->id); if(update_lh) { pe_warn("Marking resource %s unrunnable as a result", rsc_lh->id); rsc_lh->runnable = FALSE; } if(update_rh) { pe_warn("Marking resource %s unrunnable as a result", rsc_rh->id); rsc_rh->runnable = FALSE; } } if(constraint->strength == pecs_must) { native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); return; } else if(constraint->strength != pecs_must_not) { /* unknown type */ pe_err("Unknown constraint type %d", constraint->strength); return; } native_rsc_colocation_rh_mustnot(rsc_lh, update_lh,rsc_rh, update_rh); } void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order) { GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; crm_debug_3("Processing LH of ordering constraint %d", order->id); if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL && lh_rsc != NULL) { #if 0 /* this should be safe to remove */ if(order->strength == pecs_must) { crm_debug_4("No LH-Side (%s/%s) found for constraint..." " creating", lh_rsc->id, order->lh_action_task); pe_err("BROKEN CODE"); custom_action( lh_rsc, order->lh_action_task, NULL, NULL); } #endif lh_actions = find_actions( lh_rsc->actions, order->lh_action_task, NULL); if(lh_actions == NULL) { crm_debug_4("No LH-Side (%s/%s) found for constraint", lh_rsc->id, order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } } else { pe_warn("No LH-Side (%s) specified for constraint", order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } slist_iter( lh_action_iter, action_t, lh_actions, lpc, resource_t *rh_rsc = order->rh_rsc; if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { rh_rsc->fns->rsc_order_rh( lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions(lh_action_iter, order->rh_action, order); } ); pe_free_shallow_adv(lh_actions, FALSE); } void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { GListPtr rh_actions = NULL; action_t *rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_append(NULL, rh_action); } else if(rh_action == NULL && rsc != NULL) { rh_actions = find_actions( rsc->actions, order->rh_action_task, NULL); if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id, order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } } else if(rh_action == NULL) { crm_debug_4("No RH-Side (%s) specified for constraint..." " ignoring", order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } slist_iter( rh_action_iter, action_t, rh_actions, lpc, order_actions(lh_action, rh_action_iter, order); ); pe_free_shallow_adv(rh_actions, FALSE); } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr or_list; native_variant_data_t *native_data = NULL; crm_action_debug_3(print_rsc_to_node("Applying", constraint, FALSE)); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } get_native_variant_data(native_data, rsc); native_data->node_cons = g_list_append(native_data->node_cons, constraint); if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } crm_action_debug_3(print_resource("before update", rsc,TRUE)); or_list = node_list_or( native_data->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(native_data->allowed_nodes); native_data->allowed_nodes = or_list; slist_iter(node_rh, node_t, constraint->node_list_rh, lpc, native_update_node_weight( rsc, constraint, node_rh->details->uname, native_data->allowed_nodes)); crm_action_debug_3(print_resource("after update", rsc, TRUE)); } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, data_set); ); } void native_printw(resource_t *rsc, const char *pre_text, int *index) { -#ifdef CURSES_ENABLED +#if CURSES_ENABLED native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); common_printw(rsc, pre_text, index); if(g_list_length(native_data->running_on) == 0) { printw("NOT ACTIVE\n"); } else if(g_list_length(native_data->running_on) == 1) { node_t *node = native_data->running_on->data; printw("%s (%s)\n", node->details->uname, node->details->id); } else if(g_list_length(native_data->running_on) == 1) { printw("["); slist_iter(node, node_t, native_data->running_on, lpc, if(lpc > 0) { printw(", "); } printw("%s (%s)", node->details->uname, node->details->id); ); printw("]\n"); } #else crm_err("printw support requires ncurses to be available during configure"); #endif } void native_dump(resource_t *rsc, const char *pre_text, gboolean details) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); common_dump(rsc, pre_text, details); crm_debug_4("\t%d candidate colors, %d allowed nodes," " %d rsc_cons and %d node_cons", g_list_length(rsc->candidate_colors), g_list_length(native_data->allowed_nodes), g_list_length(rsc->rsc_cons), g_list_length(native_data->node_cons)); if(details) { crm_debug_4("\t=== Actions"); slist_iter( action, action_t, rsc->actions, lpc, print_action("\trsc action: ", action, FALSE); ); crm_debug_4("\t=== Colors"); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); crm_debug_4("\t=== Allowed Nodes"); slist_iter( node, node_t, native_data->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void native_free(resource_t *rsc) { native_variant_data_t *native_data = (native_variant_data_t *)rsc->variant_opaque; crm_debug_4("Freeing Allowed Nodes & Agent"); crm_free(native_data->color); pe_free_shallow(native_data->allowed_nodes); crm_free(native_data->agent); common_free(rsc); } void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; gboolean do_merge = FALSE; GListPtr old_list = NULL; GListPtr merged_node_list = NULL; float max_pri = rsc_lh->effective_priority; if(max_pri < rsc_rh->effective_priority) { max_pri = rsc_rh->effective_priority; } rsc_lh->effective_priority = max_pri; rsc_rh->effective_priority = max_pri; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); if(native_data_lh->color && native_data_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->color->details->candidate_nodes, native_data_rh->color->details->candidate_nodes, TRUE); } else if(native_data_lh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->color->details->candidate_nodes, native_data_rh->allowed_nodes, TRUE); } else if(native_data_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( native_data_lh->allowed_nodes, native_data_rh->color->details->candidate_nodes, TRUE); } if(update_lh && rsc_rh != rsc_lh) { CRM_DEV_ASSERT(native_data_lh->color != native_data_rh->color); crm_free(native_data_lh->color); rsc_lh->runnable = rsc_rh->runnable; rsc_lh->provisional = rsc_rh->provisional; native_data_lh->color = copy_color(native_data_rh->color); } if(update_rh && rsc_rh != rsc_lh) { CRM_DEV_ASSERT(native_data_lh->color != native_data_rh->color); crm_free(native_data_rh->color); rsc_rh->runnable = rsc_lh->runnable; rsc_rh->provisional = rsc_lh->provisional; native_data_rh->color = copy_color(native_data_lh->color); } if((update_rh || update_lh) && do_merge) { crm_debug_4("Merging candidate nodes"); old_list = native_data_rh->color->details->candidate_nodes; native_data_rh->color->details->candidate_nodes = merged_node_list; pe_free_shallow(old_list); } crm_debug_4("Finished processing pecs_must constraint"); } void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { color_t *color_lh = NULL; color_t *color_rh = NULL; native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); crm_debug_4("Processing pecs_must_not constraint"); /* pecs_must_not */ if(update_lh) { color_rh = native_data_rh->color; if(rsc_lh->provisional) { color_lh = find_color( rsc_lh->candidate_colors, color_rh); rsc_lh->candidate_colors = g_list_remove( rsc_lh->candidate_colors, color_lh); crm_action_debug_3( print_color("Removed LH", color_lh, FALSE)); crm_action_debug_3( print_resource("Modified LH", rsc_lh, TRUE)); crm_free(color_lh); } else if(native_data_lh->color && native_data_lh->color->details->pending) { node_t *node_lh = NULL; color_lh = native_data_lh->color; node_lh = pe_find_node( color_lh->details->candidate_nodes, safe_val5(NULL, color_rh, details, chosen_node, details, uname)); color_lh->details->candidate_nodes = g_list_remove( color_lh->details->candidate_nodes, node_lh); crm_action_debug_3( print_node("Removed LH", node_lh, FALSE)); crm_action_debug_3( print_color("Modified LH", color_lh, FALSE)); crm_free(node_lh); } else { /* error, rsc marked as unrunnable above */ pe_warn("lh else"); } } if(update_rh) { color_lh = native_data_lh->color; if(rsc_rh->provisional) { color_rh = find_color( rsc_rh->candidate_colors, color_lh); rsc_rh->candidate_colors = g_list_remove( rsc_rh->candidate_colors, color_rh); crm_action_debug_3( print_color("Removed RH", color_rh, FALSE)); crm_action_debug_3( print_resource("Modified RH", rsc_rh, TRUE)); crm_free(color_rh); } else if(native_data_rh->color && native_data_rh->color->details->pending) { node_t *node_rh = NULL; color_rh = native_data_rh->color; node_rh = pe_find_node( color_rh->details->candidate_nodes, safe_val5(NULL, color_lh, details, chosen_node, details, uname)); color_rh->details->candidate_nodes = g_list_remove( color_rh->details->candidate_nodes, node_rh); crm_action_debug_3( print_node("Removed RH", node_rh, FALSE)); crm_action_debug_3( print_color("Modified RH", color_rh, FALSE)); crm_free(node_rh); } else { /* error, rsc marked as unrunnable above */ pe_warn("rh else"); } } } void native_agent_constraints(resource_t *rsc) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); crm_debug_5("Applying RA restrictions to %s", rsc->id); common_agent_constraints( native_data->allowed_nodes, native_data->agent, rsc->id); } gboolean native_choose_color(resource_t *rsc, color_t *no_color) { GListPtr sorted_colors = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if(rsc->runnable == FALSE) { native_assign_color(rsc, no_color); } if(rsc->provisional == FALSE) { return !rsc->provisional; } sorted_colors = g_list_sort( rsc->candidate_colors, sort_color_weight); rsc->candidate_colors = sorted_colors; crm_debug_3("Choose a color from %d possibilities", g_list_length(sorted_colors)); slist_iter( this_color, color_t, rsc->candidate_colors, lpc, GListPtr intersection = NULL; GListPtr minus = NULL; int len = 0; if(this_color == NULL) { pe_err("color was NULL"); continue; } else if(rsc->effective_priority < this_color->details->highest_priority) { minus = node_list_minus( this_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); len = g_list_length(minus); pe_free_shallow(minus); if(len > 0) { native_assign_color(rsc, this_color); break; } } else { intersection = node_list_and( this_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); len = g_list_length(intersection); pe_free_shallow(intersection); if(len != 0) { native_assign_color(rsc, this_color); break; } } ); return !rsc->provisional; } void native_assign_color(resource_t *rsc, color_t *color) { color_t *local_color = add_color(rsc, color); GListPtr intersection = NULL; GListPtr old_list = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); native_data->color = copy_color(local_color); rsc->provisional = FALSE; if(local_color != NULL) { (local_color->details->num_resources)++; local_color->details->allocated_resources = g_list_append( local_color->details->allocated_resources,rsc); intersection = node_list_and( local_color->details->candidate_nodes, native_data->allowed_nodes, TRUE); old_list = local_color->details->candidate_nodes; pe_free_shallow(old_list); local_color->details->candidate_nodes = intersection; crm_debug_3("Colored resource %s with new color %d", rsc->id, native_data->color->id); crm_action_debug_3( print_resource("Colored Resource", rsc, TRUE)); } else { pe_err("local color was NULL"); } return; } void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, const char *id, GListPtr nodes) { node_t *node_rh = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); node_rh = pe_find_node(native_data->allowed_nodes, id); if(node_rh == NULL) { pe_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons->weight == -INFINITY) { pe_err("Constraint %s mixes +/- INFINITY", cons->id); } else if(node_rh->weight <= -INFINITY && cons->weight == INFINITY) { pe_err("Constraint %s mixes +/- INFINITY", cons->id); } if(node_rh->fixed) { /* warning */ crm_debug_2("Constraint %s is irrelevant as the" " weight of node %s is fixed as %f.", cons->id, node_rh->details->uname, node_rh->weight); return; } if(cons->weight != INFINITY && cons->weight != -INFINITY) { crm_debug_3("Constraint %s (%f): node %s weight %f.", cons->id, cons->weight, node_rh->details->uname, node_rh->weight); } else if(cons->weight == -INFINITY) { crm_debug_3("Constraint %s (-INFINITY): node %s weight %f.", cons->id, node_rh->details->uname, node_rh->weight); } else { crm_debug_3("Constraint %s (+INFINITY): node %s weight %f.", cons->id, node_rh->details->uname, node_rh->weight); } node_rh->weight = merge_weights(node_rh->weight, cons->weight); if(node_rh->weight < 0) { node_rh->fixed = TRUE; } crm_action_debug_3(print_node("Updated", node_rh, FALSE)); return; } gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { native_variant_data_t *native_data_lh = NULL; native_variant_data_t *native_data_rh = NULL; GListPtr result = NULL; color_t *color_lh = NULL; color_t *color_rh = NULL; GListPtr candidate_nodes_lh = NULL; GListPtr candidate_nodes_rh = NULL; gboolean matched = FALSE; get_native_variant_data(native_data_lh, rsc_lh); get_native_variant_data(native_data_rh, rsc_rh); color_lh = native_data_lh->color; color_rh = native_data_rh->color; if(constraint->strength == pecs_must_not) { matched = TRUE; } if(rsc_lh->provisional || rsc_rh->provisional) { return FALSE; } if(color_lh->details->pending && color_rh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = color_rh->details->candidate_nodes; } else if(color_lh->details->pending == FALSE && color_rh->details->pending == FALSE) { if(color_lh == NULL && color_rh == NULL) { return matched; } else if(color_lh == NULL || color_rh == NULL) { return !matched; } else if(color_lh->details->chosen_node == NULL && color_rh->details->chosen_node == NULL) { return matched; } else if(color_lh->details->chosen_node == NULL || color_rh->details->chosen_node == NULL) { return !matched; } else if(safe_str_eq( color_lh->details->chosen_node->details->id, color_rh->details->chosen_node->details->id)) { return matched; } return !matched; } else if(color_lh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = g_list_append( NULL, color_rh->details->chosen_node); } else if(color_rh->details->pending) { candidate_nodes_rh = color_rh->details->candidate_nodes; candidate_nodes_lh = g_list_append( NULL, color_lh->details->chosen_node); } result = node_list_and(candidate_nodes_lh, candidate_nodes_rh, TRUE); if(g_list_length(result) == 0 && constraint->strength == pecs_must) { /* free result */ return TRUE; } return FALSE; } /* * Remove any nodes with a -ve weight */ void filter_nodes(resource_t *rsc) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); crm_action_debug_3(print_resource("Filtering nodes for", rsc, FALSE)); slist_iter( node, node_t, native_data->allowed_nodes, lpc, if(node == NULL) { pe_err("Invalid NULL node"); } else if(node->weight < 0.0 || node->details->shutdown || node->details->online == FALSE || node->details->type == node_ping) { crm_action_debug_3(print_node("Removing", node, FALSE)); native_data->allowed_nodes = g_list_remove(native_data->allowed_nodes, node); crm_free(node); lpc = -1; /* restart the loop */ } ); } diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h index 9a510612b6..0360b0e300 100644 --- a/crm/pengine/pengine.h +++ b/crm/pengine/pengine.h @@ -1,398 +1,399 @@ -/* $Id: pengine.h,v 1.75 2005/06/30 13:18:48 andrew Exp $ */ +/* $Id: pengine.h,v 1.76 2005/06/30 14:08:14 andrew 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 */ #ifndef PENGINE__H #define PENGINE__H #include typedef struct node_s node_t; typedef struct color_s color_t; typedef struct rsc_to_node_s rsc_to_node_t; typedef struct rsc_colocation_s rsc_colocation_t; typedef struct resource_s resource_t; typedef struct lrm_agent_s lrm_agent_t; typedef struct order_constraint_s order_constraint_t; typedef struct action_s action_t; typedef struct action_wrapper_s action_wrapper_t; #include #include #include #include - #ifdef HAVE_LIBNCURSES # include -# define CURSES_ENABLED +# define CURSES_ENABLED 1 +#else +# define CURSES_ENABLED 0 #endif typedef enum no_quorum_policy_e { no_quorum_freeze, no_quorum_stop, no_quorum_ignore } no_quorum_policy_t; typedef struct pe_working_set_s { crm_data_t *input; /* options extracted from the input */ char *dc_uuid; node_t *dc_node; gboolean have_quorum; gboolean stonith_enabled; gboolean symmetric_cluster; int default_resource_stickiness; no_quorum_policy_t no_quorum_policy; /* intermediate steps */ color_t *no_color; GListPtr nodes; GListPtr resources; GListPtr placement_constraints; GListPtr ordering_constraints; GListPtr colors; GListPtr actions; /* stats */ int num_synapse; int max_valid_nodes; int order_id; int action_id; int color_id; /* final output */ crm_data_t *graph; } pe_working_set_t; #include enum con_type { type_none, rsc_colocation, rsc_to_node, rsc_to_attr, base_weight }; enum node_type { node_ping, node_member }; enum con_strength { pecs_ignore, pecs_must, pecs_must_not, pecs_startstop }; enum action_tasks { no_action, monitor_rsc, stop_rsc, stopped_rsc, start_rsc, started_rsc, shutdown_crm, stonith_node }; enum rsc_recovery_type { recovery_stop_start, recovery_stop_only, recovery_block }; enum rsc_start_requirement { rsc_req_nothing, rsc_req_quorum, rsc_req_stonith }; enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; enum pe_restart { pe_restart_restart, pe_restart_ignore }; enum pe_ordering { pe_ordering_manditory, pe_ordering_restart, pe_ordering_recover, pe_ordering_optional }; struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean unclean; gboolean shutdown; gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { float weight; gboolean fixed; struct node_shared_s *details; }; struct color_shared_s { int id; float highest_priority; GListPtr candidate_nodes; /* node_t* */ GListPtr allocated_resources; /* resources_t* */ node_t *chosen_node; gboolean pending; int num_resources; }; struct color_s { int id; struct color_shared_s *details; float local_weight; }; struct rsc_colocation_s { const char *id; resource_t *rsc_lh; resource_t *rsc_rh; enum con_strength strength; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; float weight; GListPtr node_list_rh; /* node_t* */ }; struct lrm_agent_s { const char *class; const char *type; const char *version; }; struct resource_s { const char *id; crm_data_t *xml; crm_data_t *ops_xml; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; enum rsc_recovery_type recovery_type; enum pe_restart restart_type; float priority; float stickiness; float effective_priority; gboolean is_managed; gboolean start_pending; gboolean recover; gboolean starting; gboolean stopping; gboolean runnable; gboolean provisional; gboolean unclean; GListPtr candidate_colors; /* color_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr actions; /* action_t* */ GHashTable * parameters; }; struct action_wrapper_s { enum pe_ordering type; action_t *action; }; enum action_fail_response { action_fail_nothing, action_fail_block, action_fail_stop, action_fail_fence }; struct action_s { int id; resource_t *rsc; void *rsc_opaque; node_t *node; const char *task; char *uuid; crm_data_t *op_entry; gboolean pseudo; gboolean runnable; gboolean optional; gboolean failure_is_fatal; enum rsc_start_requirement needs; enum action_fail_response on_fail; gboolean dumped; gboolean processed; int seen_count; /* crm_data_t *args; */ GHashTable *extra; GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; struct order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; extern gboolean stage0(pe_working_set_t *data_set); extern gboolean stage1(pe_working_set_t *data_set); extern gboolean stage2(pe_working_set_t *data_set); extern gboolean stage3(pe_working_set_t *data_set); extern gboolean stage4(pe_working_set_t *data_set); extern gboolean stage5(pe_working_set_t *data_set); extern gboolean stage6(pe_working_set_t *data_set); extern gboolean stage7(pe_working_set_t *data_set); extern gboolean stage8(pe_working_set_t *data_set); extern gboolean summary(GListPtr resources); extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data); extern gboolean process_pe_message( HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender); extern gboolean unpack_constraints( crm_data_t *xml_constraints, pe_working_set_t *data_set); extern gboolean unpack_resources( crm_data_t *xml_resources, pe_working_set_t *data_set); extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set); extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set); extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set); extern gboolean apply_placement_constraints(pe_working_set_t *data_set); extern void color_resource(resource_t *lh_resource, pe_working_set_t *data_set); extern gboolean choose_node_from_list(color_t *color); extern gboolean update_action_states(GListPtr actions); extern gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean stonith_constraints( node_t *node, action_t *stonith_op, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean custom_action_order( resource_t *lh_rsc, char *lh_task, action_t *lh_action, resource_t *rh_rsc, char *rh_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set); #define order_start_start(rsc1,rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_stop_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define order_restart(rsc1) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc1, start_key(rsc1), NULL, \ pe_ordering_restart, data_set) #define order_stop_start(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_start_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define pe_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } #define pe_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); extern gboolean process_colored_constraints(resource_t *rsc); extern void graph_element_from_action( action_t *action, pe_working_set_t *data_set); extern void set_working_set_defaults(pe_working_set_t *data_set); extern void cleanup_calculations(pe_working_set_t *data_set); extern const char* transition_idle_timeout; extern gboolean was_processing_error; extern gboolean was_processing_warning; #endif