diff --git a/crm/pengine/native.c b/crm/pengine/native.c index c2152ef1a9..d2ea2bf492 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,1207 +1,1248 @@ -/* $Id: native.c,v 1.33 2005/05/05 23:02:26 andrew Exp $ */ +/* $Id: native.c,v 1.34 2005/05/12 18:16:30 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 extern color_t *add_color(resource_t *rh_resource, color_t *color); gboolean native_choose_color(resource_t *lh_resource); 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, GListPtr *ordering_constraints); +action_t *create_recurring_action(resource_t *rsc, node_t *node, + const char *action, const char *key); 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) { 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(g_list_length(native_data->running_on) > 1) { crm_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) { 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_verbose("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 { crm_err("Resource %s was not a \"native\" variant", rsc->id); return 0; } if(native_data->color) { return 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); return num_allowed_nodes4color(color); } else { slist_iter( this_node, node_t, native_data->allowed_nodes, lpc, if(this_node->weight < 0) { continue; } 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, if(this_node->weight < 0) { continue; } num_nodes++; ); return num_nodes; } void native_color(resource_t *rsc, GListPtr *colors) { color_t *new_color = NULL; native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); if( native_choose_color(rsc) ) { crm_verbose("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( colors, rsc, native_data->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { crm_warn("Resource %s cannot run anywhere", rsc->id); print_resource("ERROR: No color", rsc, FALSE); native_assign_color(rsc, no_color); } } rsc->provisional = FALSE; } void create_recurring_actions(resource_t *rsc, action_t *start, node_t *node, - GListPtr *ordering_constraints) + GListPtr *ordering_constraints) { action_t *mon = NULL; + char *match_key = NULL; const char *name = NULL; const char *value = NULL; if(node == NULL || !node->details->online || node->details->unclean) { crm_verbose("Not creating recurring actions"); return; } xml_child_iter( rsc->ops_xml, operation, "op", + name = crm_element_value(operation, "name"); - if(safe_str_neq(name, CRMD_RSCSTATE_MON)) { - continue; + value = crm_element_value(operation, "interval"); + + match_key = generate_op_key(rsc->id, name, crm_atoi(value,"0")); + mon = create_recurring_action(rsc, node, name, match_key); + crm_free(match_key); + + if(start != NULL) { + order_new(rsc, start_rsc, NULL, + NULL, monitor_rsc, mon, + pecs_must, ordering_constraints); } + ); +} - value = crm_element_value(operation, "interval"); +action_t * +create_recurring_action(resource_t *rsc, node_t *node, + const char *action, const char *key) +{ + crm_data_t *op = NULL; - crm_info("\tStart %s[%s] for %s\t(%s)", - name, value, rsc->id, node->details->uname); - - mon = action_new(rsc, monitor_rsc, - crm_element_value(operation, "timeout"), node); + action_t *mon = NULL; + char *match_key = NULL; + const char *name = NULL; + const char *value = NULL; + if(safe_str_neq(action, CRMD_RSCSTATE_MON)) { + crm_err("Unsupported action: %s", action); + return NULL; + } - add_hash_param(mon->extra, "interval", value); + crm_info("\tStart %s\t(%s)", key, node?node->details->uname:""); - value = crm_element_value(operation, "start_delay"); - add_hash_param(mon->extra, "start_delay", value); + xml_child_iter( + rsc->ops_xml, operation, "op", - unpack_instance_attributes(operation, mon->extra); - if(start != NULL) { - order_new(NULL, start_rsc, start, - NULL, monitor_rsc, mon, - pecs_must, ordering_constraints); + name = crm_element_value(operation, "name"); + value = crm_element_value(operation, "interval"); + match_key = generate_op_key(rsc->id, name, crm_atoi(value,"0")); + if(safe_str_neq(key, match_key)) { + crm_free(match_key); + continue; } + crm_free(match_key); + op = operation; + break; ); + if(op == NULL) { + crm_err("Unmatched recurring op: %s", key); + return NULL; + } + + mon = action_new(rsc, monitor_rsc, + crm_element_value(op, "timeout"), node); + + mon->uuid = key; + add_hash_param(mon->extra, "interval", value); + + value = crm_element_value(op, "start_delay"); + add_hash_param(mon->extra, "start_delay", value); + + unpack_instance_attributes(op, mon->extra); + + return mon; } void native_create_actions(resource_t *rsc, GListPtr *ordering_constraints) { 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) { /* create start action */ start = action_new(rsc, start_rsc, NULL, chosen); if( !have_quorum && no_quorum_policy != no_quorum_ignore) { start->runnable = FALSE; } else { crm_info("Start resource %s (%s)", rsc->id, safe_val3( NULL, chosen, details, uname)); rsc->schedule_recurring = TRUE; } } else if(g_list_length(native_data->running_on) > 1) { crm_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, safe_val3(NULL, node, details, uname)); stop = action_new(rsc, stop_rsc, NULL, node); ); } 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 */ crm_info("Start resource %s (%s)\t(recovery)", rsc->id, safe_val3(NULL, chosen, details, uname)); start = action_new(rsc, start_rsc, NULL, chosen); rsc->schedule_recurring = TRUE; } if(rsc->recovery_type == recovery_block) { crm_warn("RESOURCE %s WILL REMAIN ACTIVE ON MULTIPLE" " NODES PENDING MANUAL INTERVENTION", rsc->id); slist_iter( node, node_t, native_data->running_on, lpc, crm_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("Stop%s of %s", chosen?" and restart":"", rsc->id); CRM_DEV_ASSERT(node != NULL); if(have_quorum == FALSE && no_quorum_policy == no_quorum_stop){ start = action_new(rsc, start_rsc, NULL, chosen); stop = action_new(rsc, stop_rsc, NULL, node); start->runnable = FALSE; } else if(chosen != NULL && safe_str_eq( node->details->id, chosen->details->id)) { /* restart */ if(rsc->recover) { crm_info("Restart resource %s\t(%s)",rsc->id, safe_val3(NULL,chosen,details,uname)); start = action_new(rsc, start_rsc, NULL,chosen); stop = action_new(rsc, stop_rsc, NULL,node); rsc->schedule_recurring = TRUE; } else { crm_info("Leave resource %s\t(%s)",rsc->id, safe_val3(NULL,chosen,details,uname)); start = action_new(rsc, start_rsc, NULL,chosen); if(rsc->start_pending == FALSE) { start->optional = TRUE; } else { rsc->schedule_recurring = TRUE; } stop = action_new(rsc, stop_rsc, NULL,node); stop->optional = TRUE; } } else if(chosen != NULL) { /* move */ crm_info("Move resource %s\t(%s -> %s)", rsc->id, safe_val3(NULL, node, details, uname), safe_val3(NULL, chosen, details, uname)); action_new(rsc, stop_rsc, NULL, node); start = action_new(rsc, start_rsc, NULL, chosen); rsc->schedule_recurring = TRUE; } else { crm_info("Stop resource %s\t(%s)", rsc->id, safe_val3(NULL, node, details, uname)); action_new(rsc, stop_rsc, NULL, node); } } - if(rsc->schedule_recurring == TRUE - && (start == NULL || start->runnable)) { + if(start != NULL && start->runnable) { create_recurring_actions( rsc, start, chosen, ordering_constraints); } } void native_internal_constraints(resource_t *rsc,GListPtr *ordering_constraints) { native_variant_data_t *native_data = NULL; get_native_variant_data(native_data, rsc); order_new(rsc, stop_rsc, NULL, rsc, start_rsc, NULL, pecs_startstop, ordering_constraints); } void native_rsc_colocation_lh(rsc_colocation_t *constraint) { resource_t *rsc = constraint->rsc_lh; if(rsc == NULL) { crm_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { crm_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_devel("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_verbose("Processing RH of constraint %s", constraint->id); crm_devel_action(print_resource("LHS", rsc_lh, TRUE)); crm_devel_action(print_resource("RHS", rsc_rh, TRUE)); if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_devel("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_devel( "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 { crm_warn("Un-expected combination of inputs"); return; } if(update_lh) { crm_devel("Updating LHS"); } if(update_rh) { crm_devel("Updating RHS"); } if(do_check) { if(native_constraint_violated( rsc_lh, rsc_rh, constraint) == FALSE) { crm_devel("Constraint satisfied"); return; } /* else constraint cant be satisified */ crm_warn("Constraint %s could not be satisfied", constraint->id); if(update_lh) { crm_warn("Marking resource %s unrunnable as a result", rsc_lh->id); rsc_lh->runnable = FALSE; } if(update_rh) { crm_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 */ crm_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_verbose("Processing LH of ordering constraint %d", order->id); switch(order->lh_action_task) { case start_rsc: case started_rsc: case stop_rsc: case stopped_rsc: break; default: crm_err("Task \"%s\" from ordering %d isnt a resource action", task2text(order->lh_action_task), order->id); return; } if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL && lh_rsc != NULL) { if(order->strength == pecs_must) { crm_devel("No LH-Side (%s/%s) found for constraint..." " creating", lh_rsc->id, task2text(order->lh_action_task)); action_new(lh_rsc, order->lh_action_task, NULL, NULL); } lh_actions = find_actions( lh_rsc->actions, order->lh_action_task, NULL); if(lh_actions == NULL) { crm_devel("No LH-Side (%s/%s) found for constraint", lh_rsc->id, task2text(order->lh_action_task)); crm_devel("RH-Side was: (%s/%s)", order->rh_rsc?order->rh_rsc->id:order->rh_action?order->rh_action->rsc->id:"", task2text(order->rh_action_task)); return; } } else { crm_warn("No LH-Side (%s) specified for constraint", task2text(order->lh_action_task)); crm_devel("RH-Side was: (%s/%s)", order->rh_rsc?order->rh_rsc->id:order->rh_action?order->rh_action->rsc->id:"", task2text(order->rh_action_task)); 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_verbose("Processing RH of ordering constraint %d", order->id); switch(order->rh_action_task) { case start_rsc: case started_rsc: case stop_rsc: case stopped_rsc: case monitor_rsc: break; default: crm_err("Task \"%s\" from ordering %d isnt a resource action", task2text(order->rh_action_task), order->id); return; } 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_devel("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id, task2text(order->rh_action_task)); crm_devel("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", task2text(order->lh_action_task)); return; } } else if(rh_action == NULL) { crm_devel("No RH-Side (%s) specified for constraint..." " ignoring", task2text(order->rh_action_task)); crm_devel("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", task2text(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_devel_action(print_rsc_to_node("Applying", constraint, FALSE)); /* take "lifetime" into account */ if(constraint == NULL) { crm_err("Constraint is NULL"); return; } else if(is_active(constraint) == FALSE) { crm_debug("Constraint (%s) is not active", constraint->id); return; } else if(rsc == NULL) { crm_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("RHS of constraint %s is NULL", constraint->id); return; } crm_devel_action(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_devel_action(print_resource("after update", rsc, TRUE)); } void native_expand(resource_t *rsc, crm_data_t * *graph) { slist_iter( action, action_t, rsc->actions, lpc, crm_devel("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, graph); ); } 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_devel("\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_devel("\t=== Actions"); slist_iter( action, action_t, rsc->actions, lpc, print_action("\trsc action: ", action, FALSE); ); crm_devel("\t=== Colors"); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); crm_devel("\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_devel("Freeing Allowed Nodes"); pe_free_shallow(native_data->allowed_nodes); 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) { 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) { 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_devel("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_devel("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_devel("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_devel_action( print_color("Removed LH", color_lh, FALSE)); crm_devel_action( 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_devel_action( print_node("Removed LH", node_lh, FALSE)); crm_devel_action( print_color("Modified LH", color_lh, FALSE)); crm_free(node_lh); } else { /* error, rsc marked as unrunnable above */ crm_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_devel_action( print_color("Removed RH", color_rh, FALSE)); crm_devel_action( 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_devel_action( print_node("Removed RH", node_rh, FALSE)); crm_devel_action( print_color("Modified RH", color_rh, FALSE)); crm_free(node_rh); } else { /* error, rsc marked as unrunnable above */ crm_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_trace("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) { 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_verbose("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) { crm_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 = 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_verbose("Colored resource %s with new color %d", rsc->id, native_data->color->id); crm_devel_action( print_resource("Colored Resource", rsc, TRUE)); } else { crm_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) { crm_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons->weight == -INFINITY) { crm_err("Constraint %s mixes +/- INFINITY", cons->id); } else if(node_rh->weight <= -INFINITY && cons->weight == INFINITY) { crm_err("Constraint %s mixes +/- INFINITY", cons->id); } if(node_rh->fixed) { /* warning */ crm_debug("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_verbose("Constraint %s (%f): node %s weight %f.", cons->id, cons->weight, node_rh->details->uname, node_rh->weight); } else if(cons->weight == -INFINITY) { crm_verbose("Constraint %s (-INFINITY): node %s weight %f.", cons->id, node_rh->details->uname, node_rh->weight); } else { crm_verbose("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_devel_action(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_devel_action(print_resource("Filtering nodes for", rsc, FALSE)); slist_iter( node, node_t, native_data->allowed_nodes, lpc, if(node == NULL) { crm_err("Invalid NULL node"); } else if(node->weight < 0.0 || node->details->online == FALSE || node->details->type == node_ping) { crm_devel_action(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/unpack.c b/crm/pengine/unpack.c index 7766901b88..e39d228a01 100644 --- a/crm/pengine/unpack.c +++ b/crm/pengine/unpack.c @@ -1,1314 +1,1339 @@ -/* $Id: unpack.c,v 1.86 2005/05/05 22:52:02 andrew Exp $ */ +/* $Id: unpack.c,v 1.87 2005/05/12 18:16:30 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 /* for ONLINESTATUS */ #include #include #include +extern action_t *create_recurring_action( + resource_t *rsc, node_t *node, const char *action, const char *key); + gint sort_op_by_callid(gconstpointer a, gconstpointer b); gboolean unpack_rsc_to_attr(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints); gboolean unpack_rsc_to_node(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints); gboolean unpack_rsc_order( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints); gboolean unpack_rsc_colocation( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints); gboolean unpack_rsc_location( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *ordering_constraints); gboolean unpack_lrm_rsc_state( node_t *node, crm_data_t * lrm_state, GListPtr rsc_list, GListPtr nodes, GListPtr *actions, GListPtr *placement_constraints); gboolean add_node_attrs(crm_data_t * attrs, node_t *node); gboolean unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, gboolean *running, gboolean *failed, int *max_call_id, GListPtr *placement_constraints); gboolean determine_online_status(crm_data_t * node_state, node_t *this_node); gboolean unpack_lrm_agents(node_t *node, crm_data_t * agent_list); gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); gboolean create_ordering( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, GListPtr *ordering_constraints); rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, double weight, gboolean can_run, node_t *node, GListPtr *placement_constraints); const char *get_agent_param(resource_t *rsc, const char *param); const char *get_agent_param_rsc(resource_t *rsc, const char *param); const void *get_agent_param_metadata(resource_t *rsc, const char *param); const char *get_agent_param_global(resource_t *rsc, const char *param); const char *param_value(crm_data_t * parent, const char *name); gboolean unpack_config(crm_data_t * config) { const char *value = NULL; value = param_value(config, "transition_timeout"); if(value != NULL) { long tmp = crm_get_msec(value); if(tmp > 0) { transition_timeout = value; } else { crm_warn("Invalid value for %s: %s", "transition_timeout", value); } } crm_devel("%s set to: %s", "transition_timeout", transition_timeout); value = param_value(config, "stonith_enabled"); if(value != NULL) { crm_str_to_boolean(value, &stonith_enabled); } crm_info("STONITH of failed nodes is %s", stonith_enabled?"enabled":"disabled"); value = param_value(config, "symmetric_cluster"); if(value != NULL) { crm_str_to_boolean(value, &symmetric_cluster); } if(symmetric_cluster) { crm_info("Cluster is symmetric" " - resources can run anywhere by default"); } value = param_value(config, "no_quorum_policy"); if(safe_str_eq(value, "ignore")) { no_quorum_policy = no_quorum_ignore; } else if(safe_str_eq(value, "freeze")) { no_quorum_policy = no_quorum_freeze; } else { no_quorum_policy = no_quorum_stop; } switch (no_quorum_policy) { case no_quorum_freeze: crm_info("On loss of CCM Quorum: Freeze resources"); break; case no_quorum_stop: crm_info("On loss of CCM Quorum: Stop ALL resources"); break; case no_quorum_ignore: crm_warn("On loss of CCM Quorum: Ignore"); break; } return TRUE; } const char * param_value(crm_data_t * parent, const char *name) { crm_data_t * a_default = NULL; if(parent != NULL) { a_default = find_entity( parent, XML_CIB_TAG_NVPAIR, name, FALSE); } if(a_default == NULL) { crm_warn("Option %s not set", name); return NULL; } return crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); } const char * get_agent_param(resource_t *rsc, const char *param) { const char *value = NULL; if(param == NULL) { return NULL; } value = get_agent_param_rsc(rsc, param); if(value == NULL) { value = get_agent_param_metadata(rsc, param); } if(value == NULL) { value = get_agent_param_global(rsc, param); } return value; } const char * get_agent_param_rsc(resource_t *rsc, const char *param) { crm_data_t * xml_rsc = rsc->xml; return crm_element_value(xml_rsc, param); } const void * get_agent_param_metadata(resource_t *rsc, const char *param) { return NULL; } const char * get_agent_param_global(resource_t *rsc, const char *param) { const char * value = NULL;/*g_hashtable_lookup(agent_global_defaults, param); */ if(value == NULL) { crm_err("No global value default for %s", param); } return value; } gboolean unpack_global_defaults(crm_data_t * defaults) { return TRUE; } gboolean unpack_nodes(crm_data_t * xml_nodes, GListPtr *nodes) { node_t *new_node = NULL; crm_data_t * attrs = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; crm_verbose("Begining unpack..."); xml_child_iter( xml_nodes, xml_obj, XML_CIB_TAG_NODE, new_node = NULL; id = crm_element_value(xml_obj, XML_ATTR_ID); uname = crm_element_value(xml_obj, XML_ATTR_UNAME); type = crm_element_value(xml_obj, XML_ATTR_TYPE); crm_verbose("Processing node %s/%s", uname, id); attrs = find_xml_node(xml_obj, "attributes", FALSE); if(id == NULL) { crm_err("Must specify id tag in "); continue; } if(type == NULL) { crm_err("Must specify type tag in "); continue; } crm_malloc0(new_node, sizeof(node_t)); if(new_node == NULL) { return FALSE; } new_node->weight = 0; new_node->fixed = FALSE; crm_malloc0(new_node->details, sizeof(struct node_shared_s)); if(new_node->details == NULL) { crm_free(new_node); return FALSE; } crm_verbose("Creaing node for entry %s/%s", uname, id); new_node->details->id = id; new_node->details->uname = uname; new_node->details->type = node_ping; new_node->details->online = FALSE; new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->agents = NULL; new_node->details->attrs = g_hash_table_new( g_str_hash, g_str_equal); if(have_quorum == FALSE && no_quorum_policy == no_quorum_stop) { /* start shutting resources down */ new_node->weight = -INFINITY; } if(stonith_enabled) { /* all nodes are unclean until we've seen their * status entry */ new_node->details->unclean = TRUE; } else { /* blind faith... */ new_node->details->unclean = FALSE; } if(safe_str_eq(type, "member")) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node); if(crm_is_true(g_hash_table_lookup( new_node->details->attrs, "standby"))) { crm_info("Node %s is in standby-mode", new_node->details->uname); new_node->weight = -INFINITY; } *nodes = g_list_append(*nodes, new_node); crm_verbose("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); crm_devel_action(print_node("Added", new_node, FALSE)); ); *nodes = g_list_sort(*nodes, sort_node_weight); return TRUE; } gboolean unpack_resources(crm_data_t * xml_resources, GListPtr *resources, GListPtr *actions, GListPtr *ordering_constraints, GListPtr *placement_constraints, GListPtr all_nodes) { crm_verbose("Begining unpack..."); xml_child_iter( xml_resources, xml_obj, NULL, resource_t *new_rsc = NULL; if(common_unpack(xml_obj, &new_rsc)) { *resources = g_list_append(*resources, new_rsc); crm_devel_action( print_resource("Added", new_rsc, FALSE)); if(symmetric_cluster) { rsc_to_node_t *new_con = rsc2node_new( "symmetric_default", new_rsc, 0, TRUE, NULL, placement_constraints); new_con->node_list_rh = node_list_dup(all_nodes, FALSE); } } else { crm_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); } ); *resources = g_list_sort(*resources, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(crm_data_t * xml_constraints, GListPtr nodes, GListPtr resources, GListPtr *placement_constraints, GListPtr *ordering_constraints) { crm_verbose("Begining unpack..."); xml_child_iter( xml_constraints, xml_obj, NULL, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { crm_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_verbose("Processing constraint %s %s", crm_element_name(xml_obj),id); if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order( xml_obj, resources, ordering_constraints); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation( xml_obj, resources, ordering_constraints); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location( xml_obj, resources,nodes,placement_constraints); } else { crm_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, double weight, gboolean can, node_t *node, GListPtr *placement_constraints) { rsc_to_node_t *new_con = NULL; if(rsc == NULL || id == NULL) { crm_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); return NULL; } crm_malloc0(new_con, sizeof(rsc_to_node_t)); if(new_con != NULL) { new_con->id = id; new_con->rsc_lh = rsc; new_con->node_list_rh = NULL; new_con->weight = weight; if(node != NULL) { new_con->node_list_rh = g_list_append(NULL, node); } *placement_constraints = g_list_append(*placement_constraints, new_con); } return new_con; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean unpack_status(crm_data_t * status, GListPtr nodes, GListPtr rsc_list, GListPtr *actions, GListPtr *placement_constraints) { const char *uname = NULL; crm_data_t * lrm_rsc = NULL; crm_data_t * lrm_agents = NULL; crm_data_t * attrs = NULL; node_t *this_node = NULL; crm_verbose("Begining unpack"); xml_child_iter( status, node_state, XML_CIB_TAG_STATE, /* id = crm_element_value(node_state, XML_ATTR_ID); */ uname = crm_element_value(node_state, XML_ATTR_UNAME); attrs = find_xml_node(node_state, XML_LRM_TAG_ATTRIBUTES,FALSE); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_agents = find_xml_node(lrm_rsc, XML_LRM_TAG_AGENTS, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_verbose("Processing node %s", uname); this_node = pe_find_node(nodes, uname); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { crm_warn("Node %s in status section no longer exists", uname); continue; } /* Mark the node as provisionally clean * - at least we have seen it in the current cluster's lifetime */ this_node->details->unclean = FALSE; crm_verbose("Adding runtime node attrs"); add_node_attrs(node_state, this_node); crm_verbose("determining node state"); determine_online_status(node_state, this_node); if(this_node->details->online || stonith_enabled) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ crm_verbose("Processing lrm resource entries"); unpack_lrm_rsc_state( this_node, lrm_rsc, rsc_list, nodes, actions, placement_constraints); } ); return TRUE; } gboolean determine_online_status(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *shutdown = crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN); if(this_node == NULL) { return online; } if(shutdown != NULL) { this_node->details->shutdown = TRUE; } if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { this_node->details->expected_up = TRUE; } if(stonith_enabled == FALSE) { if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){ crm_debug("Node is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); } else if(!crm_is_true(ccm_state) || safe_str_eq(ha_state, DEADSTATUS)) { } else if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && safe_str_eq(crm_state, ONLINESTATUS)) { online = TRUE; } else if(this_node->details->expected_up == FALSE) { crm_debug("CRMd is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_err("Node %s is partially & un-expectedly down", uname); crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } } else { if(crm_is_true(ccm_state) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && safe_str_eq(crm_state, ONLINESTATUS) && safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)) { online = TRUE; } else if(this_node->details->expected_up == FALSE) { crm_debug("CRMd on %s is down: ha_state=%s, ccm_state=%s", uname, crm_str(ha_state), crm_str(ccm_state)); crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_err("Node %s is un-expectedly down", uname); crm_debug("\tha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } } if(online) { crm_debug("Node %s is online", uname); this_node->details->online = TRUE; } else { /* remove node from contention */ crm_debug("Node %s is down", uname); this_node->weight = -INFINITY; this_node->fixed = TRUE; } if(this_node->details->unclean) { crm_warn("Node %s is unclean", uname); } if(this_node->details->shutdown) { /* dont run resources here */ this_node->weight = -INFINITY; this_node->fixed = TRUE; crm_debug("Node %s is due for shutdown", uname); } return online; } gboolean unpack_lrm_agents(node_t *node, crm_data_t * agent_list) { /* if the agent is not listed, remove the node from * the resource's list of allowed_nodes */ lrm_agent_t *agent = NULL; const char *version = NULL; if(agent_list == NULL) { return FALSE; } xml_child_iter( agent_list, xml_agent, XML_LRM_TAG_AGENT, crm_malloc0(agent, sizeof(lrm_agent_t)); if(agent == NULL) { continue; } agent->class = crm_element_value(xml_agent, XML_AGENT_ATTR_CLASS); agent->type = crm_element_value(xml_agent, XML_ATTR_TYPE); version = crm_element_value(xml_agent, XML_ATTR_VERSION); agent->version = version?version:"0.0"; crm_trace("Adding agent %s/%s %s to node %s", agent->class, agent->type, agent->version, node->details->uname); node->details->agents = g_list_append( node->details->agents, agent); ); return TRUE; } gboolean unpack_lrm_rsc_state(node_t *node, crm_data_t * lrm_rsc_list, GListPtr rsc_list, GListPtr nodes, GListPtr *actions, GListPtr *placement_constraints) { const char *rsc_id = NULL; const char *node_id = node->details->uname; const char *rsc_state = NULL; int max_call_id = -1; gboolean failed = FALSE; gboolean running = FALSE; resource_t *rsc = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return FALSE; } xml_child_iter( lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); rsc_state = crm_element_value(rsc_entry, XML_LRM_ATTR_RSCSTATE); rsc = pe_find_resource(rsc_list, rsc_id); crm_verbose("[%s] Processing %s on %s (%s)", crm_element_name(rsc_entry), rsc_id, node_id, rsc_state); if(rsc == NULL) { crm_err("Could not find a match for resource" " %s in %s's status section", rsc_id, node_id); crm_xml_debug(rsc_entry, "Invalid status entry"); continue; } failed = FALSE; running = FALSE; max_call_id = -1; op_list = NULL; sorted_op_list = NULL; xml_child_iter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); if(op_list == NULL) { continue; } sorted_op_list = g_list_sort(op_list, sort_op_by_callid); slist_iter( rsc_op, crm_data_t, sorted_op_list, lpc, unpack_rsc_op(rsc, node, rsc_op, &running, &failed, &max_call_id, placement_constraints); ); /* no need to free the contents */ g_list_free(sorted_op_list); if(running) { native_add_running(rsc, node); if(failed) { action_t *stop = action_new( rsc, stop_rsc, NULL, node); stop->optional = FALSE; rsc->recover = TRUE; } } ); return TRUE; } gint sort_op_by_callid(gconstpointer a, gconstpointer b) { const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID); const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID); /* if task id is NULL, then its a pending op * put pending ops last */ int a_id = -1; int b_id = -1; if(a_task_id == NULL && b_task_id == NULL) { return 0; } /* the reverse from normal so that NULLs appear last */ if(a_task_id == NULL) { return -1; } if(b_task_id == NULL) { return 1; } a_id = atoi(a_task_id); b_id = atoi(b_task_id); if(a_id < b_id) { return -1; } else if(a_id > b_id) { return 1; } return 0; } gboolean unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, gboolean *running, gboolean *failed, int *max_call_id, GListPtr *placement_constraints) { const char *task = NULL; const char *task_id = NULL; const char *task_status = NULL; int task_status_i = -2; int task_id_i = -1; CRM_DEV_ASSERT(rsc != NULL); if(crm_assert_failed) { return FALSE; } CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return FALSE; } CRM_DEV_ASSERT(xml_op != NULL); if(crm_assert_failed) { return FALSE; } task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); task_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); - CRM_DEV_ASSERT(task != NULL); if(crm_assert_failed) { return FALSE; } - CRM_DEV_ASSERT(task_status != NULL); if(crm_assert_failed) { return FALSE; } + CRM_DEV_ASSERT(task != NULL); + if(crm_assert_failed) { return FALSE; } + + CRM_DEV_ASSERT(task_status != NULL); + if(crm_assert_failed) { return FALSE; } task_status_i = atoi(task_status); - CRM_DEV_ASSERT(task_status_i <= LRM_OP_ERROR); if(crm_assert_failed) {return FALSE;} - CRM_DEV_ASSERT(task_status_i >= LRM_OP_PENDING);if(crm_assert_failed) {return FALSE;} + CRM_DEV_ASSERT(task_status_i <= LRM_OP_ERROR); + if(crm_assert_failed) {return FALSE;} + + CRM_DEV_ASSERT(task_status_i >= LRM_OP_PENDING); + if(crm_assert_failed) {return FALSE;} if(task_status_i != LRM_OP_PENDING) { task_id_i = crm_atoi(task_id, "-1"); - CRM_DEV_ASSERT(task_id != NULL); if(crm_assert_failed) { return FALSE; } - CRM_DEV_ASSERT(task_id_i >= 0); if(crm_assert_failed) { return FALSE; } + + CRM_DEV_ASSERT(task_id != NULL); + if(crm_assert_failed) { return FALSE; } + + CRM_DEV_ASSERT(task_id_i >= 0); + if(crm_assert_failed) { return FALSE; } if(task_id_i == *max_call_id) { crm_debug("Already processed this call"); return TRUE; } CRM_DEV_ASSERT(task_id_i > *max_call_id); if(crm_assert_failed) { return FALSE; } } if(*max_call_id < task_id_i) { *max_call_id = task_id_i; } if(node->details->unclean) { crm_debug("Node %s (where %s is running) is unclean." " Further action depends on the value of %s", node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL); } switch(task_status_i) { case LRM_OP_PENDING: /* * TODO: this may need some more thought * Some cases: * - PE reinvoked with pending action that will succeed * - PE reinvoked with pending action that will fail * - After DC election * - After startup * * pending start - required start * pending stop - required stop * pending on unavailable node - stonith * * For now this should do */ if(safe_str_eq(task, CRMD_RSCSTATE_STOP)) { /* re-issue the stop and return */ action_new(rsc, stop_rsc, NULL, node); *running = TRUE; rsc->recover = TRUE; } else if(safe_str_eq(task, CRMD_RSCSTATE_START)) { rsc->start_pending = TRUE; rsc->schedule_recurring = TRUE; *running = TRUE; /* make sure it is re-issued but, * only if we have quorum */ if(have_quorum == TRUE || no_quorum_policy == no_quorum_ignore){ /* do not specify the node, we may want * to start it elsewhere */ action_new(rsc, start_rsc, NULL, NULL); } } else if(*running == TRUE) { crm_devel("Re-issuing pending recurring task:" " %s for %s on %s", task, rsc->id, node->details->id); rsc->schedule_recurring = TRUE; } break; case LRM_OP_DONE: crm_verbose("%s/%s completed on %s", rsc->id, task, node->details->uname); if(safe_str_eq(task, CRMD_RSCSTATE_STOP)) { *failed = FALSE; *running = FALSE; rsc->schedule_recurring = FALSE; - } else { + } else if(safe_str_eq(task, CRMD_RSCSTATE_START)) { crm_verbose("%s active on %s", rsc->id, node->details->uname); - *running = TRUE; + *running = TRUE; + rsc->schedule_recurring = FALSE; + + } else if(*running) { + /* assume its a recurring action */ + action_t *mon = NULL; + + mon = create_recurring_action( + rsc, NULL, task, + crm_element_value(xml_op, XML_ATTR_ID)); + if(mon != NULL) { + mon->optional = TRUE; + } } break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: if(task_status_i == LRM_OP_NOTSUPPORTED || safe_str_eq(task, CRMD_RSCSTATE_STOP) || safe_str_eq(task, CRMD_RSCSTATE_START) ) { crm_warn("Handling failed %s for %s on %s", task, rsc->id, node->details->uname); rsc2node_new("dont_run__failed_stopstart", rsc, -INFINITY, FALSE, node, placement_constraints); } crm_debug("Processing last op (%s) for %s on %s", task, rsc->id, node->details->uname); if(safe_str_neq(task, CRMD_RSCSTATE_STOP)) { *failed = TRUE; *running = TRUE; } else if(rsc->stopfail_type == pesf_stonith) { /* treat it as if it is still running * but also mark the node as unclean */ rsc->unclean = TRUE; node->details->unclean = TRUE; *running = TRUE; } else if(rsc->stopfail_type == pesf_block) { /* let this depend on the stop action * which will fail but make sure the * transition continues... */ *running = TRUE; rsc->unclean = TRUE; } else { /* pretend the stop completed */ *running = FALSE; rsc->schedule_recurring = FALSE; } break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; } return TRUE; } gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh) { rsc_colocation_t *new_con = NULL; rsc_colocation_t *inverted_con = NULL; if(rsc_lh == NULL || rsc_rh == NULL){ /* error */ return FALSE; } crm_malloc0(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; inverted_con = invert_constraint(new_con); crm_devel("Adding constraint %s (%p) to %s", new_con->id, new_con, rsc_lh->id); rsc_lh->rsc_cons = g_list_insert_sorted( rsc_lh->rsc_cons, new_con, sort_cons_strength); crm_devel("Adding constraint %s (%p) to %s", inverted_con->id, inverted_con, rsc_rh->id); rsc_rh->rsc_cons = g_list_insert_sorted( rsc_rh->rsc_cons, inverted_con, sort_cons_strength); return TRUE; } gboolean order_new(resource_t *lh_rsc, enum action_tasks lh_action_task, action_t *lh_action, resource_t *rh_rsc, enum action_tasks rh_action_task, action_t *rh_action, enum con_strength strength, GListPtr *ordering_constraints) { order_constraint_t *order = NULL; if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL) || ordering_constraints == NULL){ crm_err("Invalid inputs lh_rsc=%p, lh_a=%p," " rh_rsc=%p, rh_a=%p, l=%p", lh_rsc, lh_action, rh_rsc, rh_action, ordering_constraints); return FALSE; } crm_malloc0(order, sizeof(order_constraint_t)); if(order == NULL) { return FALSE; } order->id = order_id++; order->strength = strength; order->lh_rsc = lh_rsc; order->rh_rsc = rh_rsc; order->lh_action = lh_action; order->rh_action = rh_action; order->lh_action_task = lh_action_task; order->rh_action_task = rh_action_task; *ordering_constraints = g_list_append( *ordering_constraints, order); if(lh_rsc != NULL && rh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " %s/%s before %s/%s", order->id, strength2text(order->strength), lh_rsc->id, task2text(lh_action_task), rh_rsc->id, task2text(rh_action_task)); } else if(lh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " %s/%s before action %d (%s)", order->id, strength2text(order->strength), lh_rsc->id, task2text(lh_action_task), rh_action->id, task2text(rh_action_task)); } else if(rh_rsc != NULL) { crm_devel("Created ordering constraint %d (%s):" " action %d (%s) before %s/%s", order->id, strength2text(order->strength), lh_action->id, task2text(lh_action_task), rh_rsc->id, task2text(rh_action_task)); } else { crm_devel("Created ordering constraint %d (%s):" " action %d (%s) before action %d (%s)", order->id, strength2text(order->strength), lh_action->id, task2text(lh_action_task), rh_action->id, task2text(rh_action_task)); } return TRUE; } gboolean unpack_rsc_colocation(crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints) { enum con_strength strength_e = pecs_ignore; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); if(rsc_lh == NULL) { crm_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_err("No resource (con=%s, rsc=%s)", id, id_rh); return FALSE; } /* the docs indicate that only +/- INFINITY are allowed, * but no-one ever reads the docs so all positive values will * count as "must" and negative values as "must not" */ if(score == NULL || score[0] != '-') { strength_e = pecs_must; } else { strength_e = pecs_must_not; } return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh); } gboolean unpack_rsc_order( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr *ordering_constraints) { gboolean type_is_after = TRUE; gboolean action_is_start = TRUE; gboolean symmetrical_bool = TRUE; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); const char *symmetrical = crm_element_value( xml_obj, XML_CONS_ATTR_SYMMETRICAL); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); if(xml_obj == NULL) { crm_err("No constraint object to process."); return FALSE; } else if(id == NULL) { crm_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } else if(rsc_lh == NULL || rsc_rh == NULL) { crm_err("Constraint %s needs two sides lh: %p rh: %p" " (NULL indicates missing side)", id, rsc_lh, rsc_rh); return FALSE; } crm_str_to_boolean(symmetrical, &symmetrical_bool); if(safe_str_eq(type, "before")) { type_is_after = FALSE; } if(safe_str_eq(action, CRMD_RSCSTATE_STOP)) { action_is_start = FALSE; } #if 1 if((type_is_after && action_is_start) || (type_is_after == FALSE && action_is_start == FALSE)){ if(symmetrical_bool || action_is_start == FALSE) { order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL, pecs_startstop, ordering_constraints); } if(symmetrical_bool || action_is_start) { order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL, pecs_startstop, ordering_constraints); } } else { if(symmetrical_bool || action_is_start == FALSE) { order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL, pecs_startstop, ordering_constraints); } if(symmetrical_bool || action_is_start) { order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL, pecs_startstop, ordering_constraints); } } #else if(type_is_after) { order_new(rsc_lh, stop_rsc, NULL, rsc_rh, stop_rsc, NULL, pecs_startstop, ordering_constraints); order_new(rsc_rh, start_rsc, NULL, rsc_lh, start_rsc, NULL, pecs_startstop, ordering_constraints); } else { order_new(rsc_rh, stop_rsc, NULL, rsc_lh, stop_rsc, NULL, pecs_startstop, ordering_constraints); order_new(rsc_lh, start_rsc, NULL, rsc_rh, start_rsc, NULL, pecs_startstop, ordering_constraints); } #endif return TRUE; } gboolean add_node_attrs(crm_data_t *xml_obj, node_t *node) { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_UNAME), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_ID), crm_strdup(node->details->id)); if(safe_str_eq(node->details->id, dc_uuid)) { node->details->is_dc = TRUE; g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_TRUE)); } else { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_FALSE)); } unpack_instance_attributes(xml_obj, node->details->attrs); return TRUE; } gboolean unpack_rsc_location( crm_data_t * xml_obj, GListPtr rsc_list, GListPtr node_list, GListPtr *placement_constraints) { gboolean were_rules = FALSE; const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { crm_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } xml_child_iter( xml_obj, rule, XML_TAG_RULE, gboolean first_expr = TRUE; gboolean can_run = FALSE; gboolean do_and = TRUE; gboolean rule_has_expressions; const char *rule_id = crm_element_value(rule, XML_ATTR_ID); const char *score = crm_element_value(rule, XML_RULE_ATTR_SCORE); const char *boolean = crm_element_value(rule, XML_RULE_ATTR_BOOLEAN_OP); GListPtr match_L = NULL; GListPtr old_list = NULL; float score_f = 0.0; rsc_to_node_t *new_con = NULL; were_rules = TRUE; if(score == NULL) { score_f = 0.0; } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else { score_f = atof(score); } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } if(score_f >= 0.0) { can_run = TRUE; } new_con = rsc2node_new(rule_id, rsc_lh, score_f, can_run, NULL, placement_constraints); if(new_con == NULL) { continue; } crm_trace("processing rule: %s", crm_element_value(rule, XML_ATTR_ID)); rule_has_expressions = FALSE; xml_child_iter( rule, expr, XML_TAG_EXPRESSION, const char *attr = crm_element_value( expr, XML_EXPR_ATTR_ATTRIBUTE); const char *op = crm_element_value( expr, XML_EXPR_ATTR_OPERATION); const char *value = crm_element_value( expr, XML_EXPR_ATTR_VALUE); const char *type = crm_element_value( expr, XML_EXPR_ATTR_TYPE); rule_has_expressions = TRUE; crm_trace("processing expression: %s", crm_element_value(expr, XML_ATTR_ID)); match_L = apply_node_expression( attr, op, value, type, node_list); if(first_expr) { new_con->node_list_rh = node_list_dup( match_L, FALSE); first_expr = FALSE; continue; } old_list = new_con->node_list_rh; if(do_and) { crm_trace("do_and"); new_con->node_list_rh = node_list_and( old_list, match_L, FALSE); } else { crm_trace("do_or"); new_con->node_list_rh = node_list_or( old_list, match_L, FALSE); } pe_free_shallow_adv(match_L, FALSE); pe_free_shallow_adv(old_list, TRUE); ); if(rule_has_expressions == FALSE && symmetric_cluster == FALSE) { /* feels like a hack */ crm_devel("Rule %s had no expressions," " adding all nodes", crm_element_value(rule, XML_ATTR_ID)); new_con->node_list_rh = node_list_dup(node_list,FALSE); } if(new_con->node_list_rh == NULL) { crm_debug("No matching nodes for constraint/rule %s/%s", id, crm_element_value(rule, XML_ATTR_ID)); } crm_devel_action(print_rsc_to_node("Added", new_con, FALSE)); ); if(were_rules == FALSE) { crm_debug("no rules for constraint %s", id); } return TRUE; }